mirror of
https://github.com/eliasstepanik/core.git
synced 2026-01-11 10:08:27 +00:00
bump: new version 0.1.22
This commit is contained in:
parent
d4c4e16ac2
commit
3de929cdd1
@ -1,4 +1,4 @@
|
||||
VERSION=0.1.21
|
||||
VERSION=0.1.22
|
||||
|
||||
# Nest run in docker, change host to database container name
|
||||
DB_HOST=localhost
|
||||
|
||||
@ -1,16 +1,65 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState, useEffect, ReactNode } from "react";
|
||||
import { useFetcher } from "@remix-run/react";
|
||||
import { AlertCircle, Loader2 } from "lucide-react";
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/dialog";
|
||||
import { Badge } from "../ui/badge";
|
||||
import { Badge, BadgeColor } from "../ui/badge";
|
||||
import { type LogItem } from "~/hooks/use-logs";
|
||||
import Markdown from "react-markdown";
|
||||
import { getIconForAuthorise } from "../icon-utils";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { getStatusColor } from "./utils";
|
||||
|
||||
interface LogDetailsProps {
|
||||
error?: string;
|
||||
log: LogItem;
|
||||
}
|
||||
|
||||
interface PropertyItemProps {
|
||||
label: string;
|
||||
value?: string | ReactNode;
|
||||
icon?: ReactNode;
|
||||
variant?: "default" | "secondary" | "outline" | "status";
|
||||
statusColor?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function PropertyItem({
|
||||
label,
|
||||
value,
|
||||
icon,
|
||||
variant = "secondary",
|
||||
statusColor,
|
||||
className,
|
||||
}: PropertyItemProps) {
|
||||
if (!value) return null;
|
||||
|
||||
return (
|
||||
<div className="flex items-center py-1">
|
||||
<span className="text-muted-foreground min-w-[160px]">{label}</span>
|
||||
|
||||
{variant === "status" ? (
|
||||
<Badge
|
||||
className={cn(
|
||||
"!bg-grayAlpha-100 text-muted-foreground h-7 rounded px-4 text-xs",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{statusColor && (
|
||||
<BadgeColor className={cn(statusColor, "h-2.5 w-2.5")} />
|
||||
)}
|
||||
{typeof value === "string"
|
||||
? value.charAt(0).toUpperCase() + value.slice(1).toLowerCase()
|
||||
: value}
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge variant={variant} className={cn("h-7 rounded px-4", className)}>
|
||||
{icon}
|
||||
{value}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface EpisodeFact {
|
||||
uuid: string;
|
||||
fact: string;
|
||||
@ -24,7 +73,7 @@ interface EpisodeFactsResponse {
|
||||
invalidFacts: EpisodeFact[];
|
||||
}
|
||||
|
||||
export function LogDetails({ error, log }: LogDetailsProps) {
|
||||
export function LogDetails({ log }: LogDetailsProps) {
|
||||
const [facts, setFacts] = useState<any[]>([]);
|
||||
const [invalidFacts, setInvalidFacts] = useState<any[]>([]);
|
||||
const [factsLoading, setFactsLoading] = useState(false);
|
||||
@ -32,11 +81,35 @@ export function LogDetails({ error, log }: LogDetailsProps) {
|
||||
|
||||
// Fetch episode facts when dialog opens and episodeUUID exists
|
||||
useEffect(() => {
|
||||
if (log.episodeUUID && facts.length === 0) {
|
||||
if (facts.length === 0) {
|
||||
if (log.data?.type === "DOCUMENT" && log.data?.episodes?.length > 0) {
|
||||
setFactsLoading(true);
|
||||
// Fetch facts for all episodes in DOCUMENT type
|
||||
Promise.all(
|
||||
log.data.episodes.map((episodeId: string) =>
|
||||
fetch(`/api/v1/episodes/${episodeId}/facts`).then((res) =>
|
||||
res.json(),
|
||||
),
|
||||
),
|
||||
)
|
||||
.then((results) => {
|
||||
const allFacts = results.flatMap((result) => result.facts || []);
|
||||
const allInvalidFacts = results.flatMap(
|
||||
(result) => result.invalidFacts || [],
|
||||
);
|
||||
setFacts(allFacts);
|
||||
setInvalidFacts(allInvalidFacts);
|
||||
setFactsLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
setFactsLoading(false);
|
||||
});
|
||||
} else if (log.episodeUUID) {
|
||||
setFactsLoading(true);
|
||||
fetcher.load(`/api/v1/episodes/${log.episodeUUID}/facts`);
|
||||
}
|
||||
}, [log.episodeUUID, facts.length]);
|
||||
}
|
||||
}, [log.episodeUUID, log.data?.type, log.data?.episodes, facts.length]);
|
||||
|
||||
// Handle fetcher response
|
||||
useEffect(() => {
|
||||
@ -49,37 +122,80 @@ export function LogDetails({ error, log }: LogDetailsProps) {
|
||||
}, [fetcher.data, fetcher.state]);
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl">
|
||||
<div className="flex w-full flex-col items-center">
|
||||
<div className="w-4xl">
|
||||
<div className="px-4 pt-4">
|
||||
<div className="mb-4 flex w-full items-center justify-between">
|
||||
<span>Log Details</span>
|
||||
<div className="flex gap-0.5">
|
||||
{log.episodeUUID && (
|
||||
<Badge variant="secondary" className="rounded text-xs">
|
||||
Episode: {log.episodeUUID.slice(0, 8)}...
|
||||
</Badge>
|
||||
)}
|
||||
{log.source && (
|
||||
<Badge variant="secondary" className="rounded text-xs">
|
||||
Source: {log.source}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<span>Episode Details</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-h-[90vh] overflow-auto p-4 pt-0">
|
||||
{/* Log Content */}
|
||||
<div className="mb-4 text-sm break-words whitespace-pre-wrap">
|
||||
<div className="rounded-md">
|
||||
<Markdown>{log.ingestText}</Markdown>
|
||||
<div className="mb-10 px-4">
|
||||
<div className="space-y-3">
|
||||
{log.data?.type === "DOCUMENT" && log.data?.episodes ? (
|
||||
<PropertyItem
|
||||
label="Episodes"
|
||||
value={
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{log.data.episodes.map(
|
||||
(episodeId: string, index: number) => (
|
||||
<Badge
|
||||
key={index}
|
||||
variant="outline"
|
||||
className="text-xs"
|
||||
>
|
||||
{episodeId}
|
||||
</Badge>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
variant="secondary"
|
||||
/>
|
||||
) : (
|
||||
<PropertyItem
|
||||
label="Episode Id"
|
||||
value={log.episodeUUID}
|
||||
variant="secondary"
|
||||
/>
|
||||
)}
|
||||
<PropertyItem
|
||||
label="Session Id"
|
||||
value={log.data?.sessionId?.toLowerCase()}
|
||||
variant="secondary"
|
||||
/>
|
||||
<PropertyItem
|
||||
label="Type"
|
||||
value={
|
||||
log.data?.type ? log.data.type.toLowerCase() : "conversation"
|
||||
}
|
||||
variant="secondary"
|
||||
/>
|
||||
<PropertyItem
|
||||
label="Source"
|
||||
value={log.source?.toLowerCase()}
|
||||
icon={
|
||||
log.source &&
|
||||
getIconForAuthorise(log.source.toLowerCase(), 16, undefined)
|
||||
}
|
||||
variant="secondary"
|
||||
/>
|
||||
|
||||
<PropertyItem
|
||||
label="Status"
|
||||
value={log.status}
|
||||
variant="status"
|
||||
statusColor={log.status && getStatusColor(log.status)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Error Details */}
|
||||
{log.error && (
|
||||
<div className="mb-4">
|
||||
<h3 className="mb-2 text-sm font-medium">Error Details</h3>
|
||||
<div className="mb-6 px-4">
|
||||
<div className="mb-2 flex w-full items-center justify-between">
|
||||
<span>Error Details</span>
|
||||
</div>
|
||||
<div className="bg-destructive/10 rounded-md p-3">
|
||||
<div className="flex items-start gap-2 text-red-600">
|
||||
<AlertCircle className="mt-0.5 h-4 w-4 flex-shrink-0" />
|
||||
@ -92,9 +208,10 @@ export function LogDetails({ error, log }: LogDetailsProps) {
|
||||
)}
|
||||
|
||||
{/* Episode Facts */}
|
||||
{log.episodeUUID && (
|
||||
<div className="mb-4">
|
||||
<h3 className="text-muted-foreground mb-2 text-sm">Facts</h3>
|
||||
<div className="mb-6 px-4">
|
||||
<div className="mb-2 flex w-full items-center justify-between">
|
||||
<span>Facts</span>
|
||||
</div>
|
||||
<div className="rounded-md">
|
||||
{factsLoading ? (
|
||||
<div className="flex items-center justify-center gap-2 p-4 text-sm">
|
||||
@ -153,7 +270,15 @@ export function LogDetails({ error, log }: LogDetailsProps) {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex max-h-[88vh] flex-col items-center overflow-auto p-4 pt-0">
|
||||
{/* Log Content */}
|
||||
<div className="mb-4 text-sm break-words whitespace-pre-wrap">
|
||||
<div className="rounded-md">
|
||||
<Markdown>{log.ingestText}</Markdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -3,6 +3,7 @@ import { Badge, BadgeColor } from "../ui/badge";
|
||||
import { type LogItem } from "~/hooks/use-logs";
|
||||
import { getIconForAuthorise } from "../icon-utils";
|
||||
import { useNavigate, useParams } from "@remix-run/react";
|
||||
import { getStatusColor } from "./utils";
|
||||
|
||||
interface LogTextCollapseProps {
|
||||
text?: string;
|
||||
@ -13,21 +14,6 @@ interface LogTextCollapseProps {
|
||||
reset?: () => void;
|
||||
}
|
||||
|
||||
const getStatusColor = (status: string) => {
|
||||
switch (status) {
|
||||
case "PROCESSING":
|
||||
return "bg-blue-800";
|
||||
case "PENDING":
|
||||
return "bg-warning";
|
||||
case "FAILED":
|
||||
return "bg-destructive";
|
||||
case "CANCELLED":
|
||||
return "bg-gray-800";
|
||||
default:
|
||||
return "bg-gray-800";
|
||||
}
|
||||
};
|
||||
|
||||
export function LogTextCollapse({ text, log }: LogTextCollapseProps) {
|
||||
const { logId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
@ -13,8 +13,10 @@ interface LogsFiltersProps {
|
||||
availableSources: Array<{ name: string; slug: string }>;
|
||||
selectedSource?: string;
|
||||
selectedStatus?: string;
|
||||
selectedType?: string;
|
||||
onSourceChange: (source?: string) => void;
|
||||
onStatusChange: (status?: string) => void;
|
||||
onTypeChange: (type?: string) => void;
|
||||
}
|
||||
|
||||
const statusOptions = [
|
||||
@ -23,14 +25,21 @@ const statusOptions = [
|
||||
{ value: "COMPLETED", label: "Completed" },
|
||||
];
|
||||
|
||||
type FilterStep = "main" | "source" | "status";
|
||||
const typeOptions = [
|
||||
{ value: "CONVERSATION", label: "Conversation" },
|
||||
{ value: "DOCUMENT", label: "Document" },
|
||||
];
|
||||
|
||||
type FilterStep = "main" | "source" | "status" | "type";
|
||||
|
||||
export function LogsFilters({
|
||||
availableSources,
|
||||
selectedSource,
|
||||
selectedStatus,
|
||||
selectedType,
|
||||
onSourceChange,
|
||||
onStatusChange,
|
||||
onTypeChange,
|
||||
}: LogsFiltersProps) {
|
||||
const [popoverOpen, setPopoverOpen] = useState(false);
|
||||
const [step, setStep] = useState<FilterStep>("main");
|
||||
@ -44,8 +53,11 @@ export function LogsFilters({
|
||||
const selectedStatusLabel = statusOptions.find(
|
||||
(s) => s.value === selectedStatus,
|
||||
)?.label;
|
||||
const selectedTypeLabel = typeOptions.find(
|
||||
(s) => s.value === selectedType,
|
||||
)?.label;
|
||||
|
||||
const hasFilters = selectedSource || selectedStatus;
|
||||
const hasFilters = selectedSource || selectedStatus || selectedType;
|
||||
|
||||
return (
|
||||
<div className="mb-2 flex w-full items-center justify-start gap-2 px-3">
|
||||
@ -85,6 +97,13 @@ export function LogsFilters({
|
||||
>
|
||||
Status
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="justify-start"
|
||||
onClick={() => setStep("type")}
|
||||
>
|
||||
Type
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -155,6 +174,40 @@ export function LogsFilters({
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{step === "type" && (
|
||||
<div className="flex flex-col gap-1 p-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="w-full justify-start"
|
||||
onClick={() => {
|
||||
onTypeChange(undefined);
|
||||
setPopoverOpen(false);
|
||||
setStep("main");
|
||||
}}
|
||||
>
|
||||
All types
|
||||
</Button>
|
||||
{typeOptions.map((type) => (
|
||||
<Button
|
||||
key={type.value}
|
||||
variant="ghost"
|
||||
className="w-full justify-start"
|
||||
onClick={() => {
|
||||
onTypeChange(
|
||||
type.value === selectedType
|
||||
? undefined
|
||||
: type.value,
|
||||
);
|
||||
setPopoverOpen(false);
|
||||
setStep("main");
|
||||
}}
|
||||
>
|
||||
{type.label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</PopoverContent>
|
||||
</PopoverPortal>
|
||||
</Popover>
|
||||
@ -180,6 +233,15 @@ export function LogsFilters({
|
||||
/>
|
||||
</Badge>
|
||||
)}
|
||||
{selectedType && (
|
||||
<Badge variant="secondary" className="h-7 gap-1 rounded px-2">
|
||||
{selectedTypeLabel}
|
||||
<X
|
||||
className="hover:text-destructive h-3.5 w-3.5 cursor-pointer"
|
||||
onClick={() => onTypeChange(undefined)}
|
||||
/>
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
16
apps/webapp/app/components/logs/utils.ts
Normal file
16
apps/webapp/app/components/logs/utils.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export const getStatusColor = (status: string) => {
|
||||
switch (status) {
|
||||
case "PROCESSING":
|
||||
return "bg-blue-800";
|
||||
case "PENDING":
|
||||
return "bg-warning";
|
||||
case "COMPLETED":
|
||||
return "bg-success";
|
||||
case "FAILED":
|
||||
return "bg-destructive";
|
||||
case "CANCELLED":
|
||||
return "bg-gray-800";
|
||||
default:
|
||||
return "bg-gray-800";
|
||||
}
|
||||
};
|
||||
@ -8,7 +8,7 @@ import { extensionsForConversation } from "../conversation/editor-extensions";
|
||||
export const SpaceSummary = ({ summary }: { summary?: string | null }) => {
|
||||
const editor = useEditor({
|
||||
extensions: [...extensionsForConversation, skillExtension],
|
||||
editable: true,
|
||||
editable: false,
|
||||
content: summary,
|
||||
});
|
||||
|
||||
|
||||
@ -67,7 +67,7 @@ const EnvironmentSchema = z.object({
|
||||
//OpenAI
|
||||
OPENAI_API_KEY: z.string(),
|
||||
|
||||
EMAIL_TRANSPORT: z.enum(["resend", "smtp", "aws-ses"]).optional(),
|
||||
EMAIL_TRANSPORT: z.string().optional(),
|
||||
FROM_EMAIL: z.string().optional(),
|
||||
REPLY_TO_EMAIL: z.string().optional(),
|
||||
RESEND_API_KEY: z.string().optional(),
|
||||
|
||||
@ -30,9 +30,10 @@ export interface UseLogsOptions {
|
||||
endpoint: string; // '/api/v1/logs/all' or '/api/v1/logs/activity'
|
||||
source?: string;
|
||||
status?: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export function useLogs({ endpoint, source, status }: UseLogsOptions) {
|
||||
export function useLogs({ endpoint, source, status, type }: UseLogsOptions) {
|
||||
const fetcher = useFetcher<LogsResponse>();
|
||||
const [logs, setLogs] = useState<LogItem[]>([]);
|
||||
const [page, setPage] = useState(1);
|
||||
@ -49,9 +50,10 @@ export function useLogs({ endpoint, source, status }: UseLogsOptions) {
|
||||
params.set("limit", "5");
|
||||
if (source) params.set("source", source);
|
||||
if (status) params.set("status", status);
|
||||
if (type) params.set("type", type);
|
||||
return `${endpoint}?${params.toString()}`;
|
||||
},
|
||||
[endpoint, source, status],
|
||||
[endpoint, source, status, type],
|
||||
);
|
||||
|
||||
const loadMore = useCallback(() => {
|
||||
@ -100,7 +102,7 @@ export function useLogs({ endpoint, source, status }: UseLogsOptions) {
|
||||
setHasMore(true);
|
||||
setIsInitialLoad(true);
|
||||
fetcher.load(buildUrl(1));
|
||||
}, [source, status, buildUrl]); // Inline reset logic to avoid dependency issues
|
||||
}, [source, status, type, buildUrl]); // Inline reset logic to avoid dependency issues
|
||||
|
||||
// Initial load
|
||||
useEffect(() => {
|
||||
|
||||
@ -18,6 +18,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const limit = parseInt(url.searchParams.get("limit") || "20");
|
||||
const source = url.searchParams.get("source");
|
||||
const status = url.searchParams.get("status");
|
||||
const type = url.searchParams.get("type");
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
// Get user and workspace in one query
|
||||
@ -39,6 +40,13 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
whereClause.status = status;
|
||||
}
|
||||
|
||||
if (type) {
|
||||
whereClause.data = {
|
||||
path: ["type"],
|
||||
equals: type,
|
||||
};
|
||||
}
|
||||
|
||||
// If source filter is provided, filter by integration source
|
||||
if (source) {
|
||||
whereClause.activity = {
|
||||
|
||||
@ -16,6 +16,7 @@ import { cn } from "~/lib/utils";
|
||||
export default function LogsAll() {
|
||||
const [selectedSource, setSelectedSource] = useState<string | undefined>();
|
||||
const [selectedStatus, setSelectedStatus] = useState<string | undefined>();
|
||||
const [selectedType, setSelectedType] = useState<string | undefined>();
|
||||
|
||||
const { logId } = useParams();
|
||||
|
||||
@ -30,6 +31,7 @@ export default function LogsAll() {
|
||||
endpoint: "/api/v1/logs",
|
||||
source: selectedSource,
|
||||
status: selectedStatus,
|
||||
type: selectedType,
|
||||
});
|
||||
|
||||
return (
|
||||
@ -37,15 +39,15 @@ export default function LogsAll() {
|
||||
<ResizablePanelGroup direction="horizontal">
|
||||
<ResizablePanel
|
||||
maxSize={50}
|
||||
defaultSize={35}
|
||||
minSize={35}
|
||||
defaultSize={30}
|
||||
minSize={30}
|
||||
collapsible
|
||||
collapsedSize={35}
|
||||
collapsedSize={30}
|
||||
>
|
||||
<div className="flex h-full flex-col">
|
||||
<PageHeader title="Inbox" />
|
||||
|
||||
<div className="flex h-[calc(100vh_-_56px)] w-full flex-col items-center space-y-6 pt-3 pb-4">
|
||||
<div className="flex h-[calc(100vh_-_56px)] w-full flex-col items-center space-y-6 pt-3">
|
||||
{isInitialLoad ? (
|
||||
<>
|
||||
<LoaderCircle className="text-primary h-4 w-4 animate-spin" />
|
||||
@ -58,12 +60,14 @@ export default function LogsAll() {
|
||||
availableSources={availableSources}
|
||||
selectedSource={selectedSource}
|
||||
selectedStatus={selectedStatus}
|
||||
selectedType={selectedType}
|
||||
onSourceChange={setSelectedSource}
|
||||
onStatusChange={setSelectedStatus}
|
||||
onTypeChange={setSelectedType}
|
||||
/>
|
||||
|
||||
{/* Logs List */}
|
||||
<div className="flex h-full w-full space-y-4">
|
||||
<div className="flex h-full w-full space-y-4 pb-2">
|
||||
{logs.length === 0 ? (
|
||||
<Card className="bg-background-2 w-full">
|
||||
<CardContent className="bg-background-2 flex w-full items-center justify-center py-16">
|
||||
@ -73,7 +77,7 @@ export default function LogsAll() {
|
||||
No logs found
|
||||
</h3>
|
||||
<p className="text-muted-foreground">
|
||||
{selectedSource || selectedStatus
|
||||
{selectedSource || selectedStatus || selectedType
|
||||
? "Try adjusting your filters to see more results."
|
||||
: "No ingestion logs are available yet."}
|
||||
</p>
|
||||
|
||||
@ -88,7 +88,7 @@ export default function Facts() {
|
||||
onSpaceFilterChange={setSelectedSpaceFilter}
|
||||
/>
|
||||
|
||||
<div className="flex h-[calc(100vh_-_140px)] w-full">
|
||||
<div className="flex h-[calc(100vh_-_56px)] w-full">
|
||||
<ClientOnly
|
||||
fallback={<LoaderCircle className="mr-2 h-4 w-4 animate-spin" />}
|
||||
>
|
||||
|
||||
@ -88,7 +88,7 @@ export default function Patterns() {
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col pt-2">
|
||||
<div className="flex h-[calc(100vh_-_140px)] w-full">
|
||||
<div className="flex h-[calc(100vh_-_56px)] w-full">
|
||||
<ClientOnly
|
||||
fallback={<LoaderCircle className="mr-2 h-4 w-4 animate-spin" />}
|
||||
>
|
||||
|
||||
@ -43,44 +43,3 @@ export async function getEpisodeFacts(episodeUuid: string, userId: string) {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function getDocumentFacts(documentId: string, userId: string) {
|
||||
try {
|
||||
const facts = await getEpisodeStatements({
|
||||
episodeUuid,
|
||||
userId,
|
||||
});
|
||||
|
||||
const invalidFacts = await getStatementsInvalidatedByEpisode({
|
||||
episodeUuid,
|
||||
userId,
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
facts: facts.map((fact) => ({
|
||||
uuid: fact.uuid,
|
||||
fact: fact.fact,
|
||||
createdAt: fact.createdAt.toISOString(),
|
||||
validAt: fact.validAt.toISOString(),
|
||||
invalidAt: fact.invalidAt ? fact.invalidAt.toISOString() : null,
|
||||
attributes: fact.attributes,
|
||||
})),
|
||||
invalidFacts: invalidFacts.map((fact) => ({
|
||||
uuid: fact.uuid,
|
||||
fact: fact.fact,
|
||||
createdAt: fact.createdAt.toISOString(),
|
||||
validAt: fact.validAt.toISOString(),
|
||||
invalidAt: fact.invalidAt ? fact.invalidAt.toISOString() : null,
|
||||
attributes: fact.attributes,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching episode facts:", error);
|
||||
return {
|
||||
success: false,
|
||||
error: "Failed to fetch episode facts",
|
||||
facts: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { runQuery } from "~/lib/neo4j.server";
|
||||
import { type EntityNode, EpisodeType, type EpisodicNode } from "@core/types";
|
||||
import { type EntityNode, type EpisodicNode } from "@core/types";
|
||||
|
||||
export async function saveEpisode(episode: EpisodicNode): Promise<string> {
|
||||
const query = `
|
||||
|
||||
@ -14,7 +14,6 @@ import { callMemoryTool, memoryTools } from "~/utils/mcp/memory";
|
||||
import { logger } from "~/services/logger.service";
|
||||
import { type Response, type Request } from "express";
|
||||
import { getWorkspaceByUser } from "~/models/workspace.server";
|
||||
import { Workspace } from "@prisma/client";
|
||||
|
||||
const QueryParams = z.object({
|
||||
source: z.string().optional(),
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
VERSION=0.1.21
|
||||
VERSION=0.1.22
|
||||
|
||||
# Nest run in docker, change host to database container name
|
||||
DB_HOST=postgres
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "core",
|
||||
"private": true,
|
||||
"version": "0.1.21",
|
||||
"version": "0.1.22",
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"packages/*"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user