@delofarag/ai-utils 1.4.3 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +354 -216
- package/dist/heart/agent.d.ts +1 -1
- package/dist/heart/agent.d.ts.map +1 -1
- package/dist/heart/agent.js +4 -9
- package/dist/heart/agent.js.map +1 -1
- package/dist/heart/chain.d.ts +1 -1
- package/dist/heart/chain.d.ts.map +1 -1
- package/dist/heart/chain.js +4 -4
- package/dist/heart/chain.js.map +1 -1
- package/dist/heart/chatbot.d.ts +1 -1
- package/dist/heart/memorychain.d.ts +2 -2
- package/dist/heart/memorychain.js +6 -6
- package/dist/heart/memorychain.js.map +1 -1
- package/dist/heart/tools/zodios/ZodiosToolRegistry.d.ts +1 -1
- package/dist/heart/tools/zodios/ZodiosToolRegistry.d.ts.map +1 -1
- package/dist/helpers/chatbot.d.ts +31 -0
- package/dist/helpers/chatbot.d.ts.map +1 -0
- package/dist/helpers/chatbot.js +71 -0
- package/dist/helpers/chatbot.js.map +1 -0
- package/dist/helpers/helpers.d.ts +25 -0
- package/dist/helpers/helpers.d.ts.map +1 -0
- package/dist/helpers/helpers.js +43 -0
- package/dist/helpers/helpers.js.map +1 -0
- package/dist/helpers/llms.d.ts +95 -0
- package/dist/helpers/llms.d.ts.map +1 -0
- package/dist/helpers/llms.js +62 -0
- package/dist/helpers/llms.js.map +1 -0
- package/dist/helpers/memory.d.ts +107 -0
- package/dist/helpers/memory.d.ts.map +1 -0
- package/dist/helpers/memory.js +497 -0
- package/dist/helpers/memory.js.map +1 -0
- package/dist/helpers/rag.d.ts +42 -0
- package/dist/helpers/rag.d.ts.map +1 -0
- package/dist/helpers/rag.js +66 -0
- package/dist/helpers/rag.js.map +1 -0
- package/dist/helpers.d.ts +3 -3
- package/dist/index.d.ts +10 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -10
- package/dist/index.js.map +1 -1
- package/dist/magic-funcs/answerers/ask.d.ts +18 -2
- package/dist/magic-funcs/answerers/ask.d.ts.map +1 -1
- package/dist/magic-funcs/answerers/ask.js +20 -9
- package/dist/magic-funcs/answerers/ask.js.map +1 -1
- package/dist/magic-funcs/answerers/websearch.d.ts +15 -0
- package/dist/magic-funcs/answerers/websearch.d.ts.map +1 -1
- package/dist/magic-funcs/answerers/websearch.js +15 -0
- package/dist/magic-funcs/answerers/websearch.js.map +1 -1
- package/dist/magic-funcs/evaluators/classify.d.ts +20 -1
- package/dist/magic-funcs/evaluators/classify.d.ts.map +1 -1
- package/dist/magic-funcs/evaluators/classify.js +22 -3
- package/dist/magic-funcs/evaluators/classify.js.map +1 -1
- package/dist/magic-funcs/evaluators/decide.d.ts +18 -0
- package/dist/magic-funcs/evaluators/decide.d.ts.map +1 -1
- package/dist/magic-funcs/evaluators/decide.js +21 -3
- package/dist/magic-funcs/evaluators/decide.js.map +1 -1
- package/dist/magic-funcs/optimizers/promptify.d.ts +18 -0
- package/dist/magic-funcs/optimizers/promptify.d.ts.map +1 -1
- package/dist/magic-funcs/optimizers/promptify.js +21 -3
- package/dist/magic-funcs/optimizers/promptify.js.map +1 -1
- package/dist/magic-funcs/optimizers/ragify.d.ts +16 -0
- package/dist/magic-funcs/optimizers/ragify.d.ts.map +1 -1
- package/dist/magic-funcs/optimizers/ragify.js +19 -3
- package/dist/magic-funcs/optimizers/ragify.js.map +1 -1
- package/dist/magic-funcs/parsers/extract.d.ts +23 -0
- package/dist/magic-funcs/parsers/extract.d.ts.map +1 -1
- package/dist/magic-funcs/parsers/extract.js +26 -3
- package/dist/magic-funcs/parsers/extract.js.map +1 -1
- package/dist/magic-funcs/parsers/rewrite.d.ts +19 -0
- package/dist/magic-funcs/parsers/rewrite.d.ts.map +1 -1
- package/dist/magic-funcs/parsers/rewrite.js +22 -2
- package/dist/magic-funcs/parsers/rewrite.js.map +1 -1
- package/dist/magic-funcs/parsers/structure.d.ts +22 -0
- package/dist/magic-funcs/parsers/structure.d.ts.map +1 -1
- package/dist/magic-funcs/parsers/structure.js +27 -4
- package/dist/magic-funcs/parsers/structure.js.map +1 -1
- package/dist/magic-funcs/parsers/summarize.d.ts +20 -0
- package/dist/magic-funcs/parsers/summarize.d.ts.map +1 -1
- package/dist/magic-funcs/parsers/summarize.js +23 -3
- package/dist/magic-funcs/parsers/summarize.js.map +1 -1
- package/dist/memory.d.ts +1 -1
- package/dist/modalities/image-gen/generateImages.d.ts +56 -0
- package/dist/modalities/image-gen/generateImages.d.ts.map +1 -0
- package/dist/modalities/image-gen/generateImages.js +66 -0
- package/dist/modalities/image-gen/generateImages.js.map +1 -0
- package/dist/modalities/image-gen/helpers.d.ts +15 -0
- package/dist/modalities/image-gen/helpers.d.ts.map +1 -0
- package/dist/modalities/image-gen/helpers.js +17 -0
- package/dist/modalities/image-gen/helpers.js.map +1 -0
- package/dist/modalities/openrouter.d.ts +11 -0
- package/dist/modalities/openrouter.d.ts.map +1 -0
- package/dist/modalities/openrouter.js +39 -0
- package/dist/modalities/openrouter.js.map +1 -0
- package/dist/modalities/speech/VoiceEngine.d.ts +3 -0
- package/dist/modalities/speech/VoiceEngine.d.ts.map +1 -0
- package/dist/modalities/speech/VoiceEngine.js +3 -0
- package/dist/modalities/speech/VoiceEngine.js.map +1 -0
- package/dist/modalities/speech/stt/helpers.d.ts +3 -0
- package/dist/modalities/speech/stt/helpers.d.ts.map +1 -0
- package/dist/modalities/speech/stt/helpers.js +28 -0
- package/dist/modalities/speech/stt/helpers.js.map +1 -0
- package/dist/modalities/speech/stt/stt.d.ts +113 -0
- package/dist/modalities/speech/stt/stt.d.ts.map +1 -0
- package/dist/modalities/speech/stt/stt.js +177 -0
- package/dist/modalities/speech/stt/stt.js.map +1 -0
- package/dist/modalities/speech/tts/helpers.d.ts +12 -0
- package/dist/modalities/speech/tts/helpers.d.ts.map +1 -0
- package/dist/modalities/speech/tts/helpers.js +10 -0
- package/dist/modalities/speech/tts/helpers.js.map +1 -0
- package/dist/modalities/speech/tts/tts.d.ts +115 -0
- package/dist/modalities/speech/tts/tts.d.ts.map +1 -0
- package/dist/modalities/speech/tts/tts.js +142 -0
- package/dist/modalities/speech/tts/tts.js.map +1 -0
- package/dist/modalities/vision/helpers.d.ts +3 -0
- package/dist/modalities/vision/helpers.d.ts.map +1 -0
- package/dist/modalities/vision/helpers.js +7 -0
- package/dist/modalities/vision/helpers.js.map +1 -0
- package/dist/modalities/vision/vision.d.ts +55 -0
- package/dist/modalities/vision/vision.d.ts.map +1 -0
- package/dist/modalities/vision/vision.js +71 -0
- package/dist/modalities/vision/vision.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ChatGroq, ChatOllama, ChatOpenAI } from "../imports";
|
|
2
|
+
/**
|
|
3
|
+
* env-var for openrouter: process.env.OPENROUTER_API_KEY
|
|
4
|
+
*
|
|
5
|
+
* env-var for chatgroq: process.env.CHATGROQ_API_KEY
|
|
6
|
+
*
|
|
7
|
+
* default llm for chatgroq: "llama-3.3-70b-versatile"
|
|
8
|
+
*
|
|
9
|
+
* default llm for openrouter: "openai/gpt-5.4-mini"
|
|
10
|
+
*
|
|
11
|
+
* default llm for local: "llama3.2:3b"
|
|
12
|
+
*/
|
|
13
|
+
export function getLLM(config) {
|
|
14
|
+
const type = config.type;
|
|
15
|
+
switch (config.provider) {
|
|
16
|
+
case "chatgroq":
|
|
17
|
+
return new ChatGroq({
|
|
18
|
+
apiKey: config.apikey ?? process.env.CHATGROQ_API_KEY,
|
|
19
|
+
model: config.model ?? (type === "vision"
|
|
20
|
+
? "meta-llama/llama-4-scout-17b-16e-instruct"
|
|
21
|
+
: type === "stt"
|
|
22
|
+
? "whisper-large-v3-turbo"
|
|
23
|
+
: type === "tts"
|
|
24
|
+
? "canopylabs/orpheus-v1-english"
|
|
25
|
+
: "llama-3.3-70b-versatile")
|
|
26
|
+
});
|
|
27
|
+
case "openrouter":
|
|
28
|
+
return new ChatOpenAI({
|
|
29
|
+
apiKey: config.apikey ?? process.env.OPENROUTER_API_KEY,
|
|
30
|
+
configuration: {
|
|
31
|
+
baseURL: config.dataSafe
|
|
32
|
+
? "https://eu.openrouter.ai/api/v1"
|
|
33
|
+
: "https://openrouter.ai/api/v1",
|
|
34
|
+
},
|
|
35
|
+
model: config.model ?? (type === "image-gen"
|
|
36
|
+
? "google/gemini-3.1-flash-image-preview"
|
|
37
|
+
: type === "stt"
|
|
38
|
+
? "google/gemini-2.5-flash"
|
|
39
|
+
: type === "tts"
|
|
40
|
+
? "openai/gpt-4o-mini-tts-2025-12-15"
|
|
41
|
+
: "openai/gpt-5.4-mini"),
|
|
42
|
+
...(config.dataSafe
|
|
43
|
+
? {
|
|
44
|
+
modelKwargs: {
|
|
45
|
+
provider: {
|
|
46
|
+
data_collection: "deny",
|
|
47
|
+
zdr: true,
|
|
48
|
+
allow_fallbacks: false,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
: {}),
|
|
53
|
+
});
|
|
54
|
+
case "local":
|
|
55
|
+
return new ChatOllama({
|
|
56
|
+
model: config.model ?? "llama3.2:3b"
|
|
57
|
+
});
|
|
58
|
+
default:
|
|
59
|
+
throw new Error("Unknown LLM provider");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=llms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llms.js","sourceRoot":"","sources":["../../src/helpers/llms.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAuQ5D;;;;;;;;;;GAUG;AACL,MAAM,UAAU,MAAM,CAAC,MAAiB;IACtC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;IAExB,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,UAAU;YACb,OAAO,IAAI,QAAQ,CAAC;gBAClB,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB;gBACrD,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,CACrB,IAAI,KAAK,QAAQ;oBACf,CAAC,CAAC,2CAA2C;oBAC7C,CAAC,CAAC,IAAI,KAAK,KAAK;wBACd,CAAC,CAAC,wBAAwB;wBAC1B,CAAC,CAAC,IAAI,KAAK,KAAK;4BACd,CAAC,CAAC,+BAA+B;4BACjC,CAAC,CAAC,yBAAyB,CAClC;aACF,CAAC,CAAC;QAEL,KAAK,YAAY;YACf,OAAO,IAAI,UAAU,CAAC;gBACpB,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB;gBACvD,aAAa,EAAE;oBACb,OAAO,EAAE,MAAM,CAAC,QAAQ;wBACtB,CAAC,CAAC,iCAAiC;wBACnC,CAAC,CAAC,8BAA8B;iBACnC;gBACD,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,CACrB,IAAI,KAAK,WAAW;oBAClB,CAAC,CAAC,uCAAuC;oBACzC,CAAC,CAAC,IAAI,KAAK,KAAK;wBACd,CAAC,CAAC,yBAAyB;wBAC3B,CAAC,CAAC,IAAI,KAAK,KAAK;4BACd,CAAC,CAAC,mCAAmC;4BACrC,CAAC,CAAC,qBAAqB,CAC9B;gBACD,GAAG,CAAC,MAAM,CAAC,QAAQ;oBACjB,CAAC,CAAC;wBACE,WAAW,EAAE;4BACX,QAAQ,EAAE;gCACR,eAAe,EAAE,MAAM;gCACvB,GAAG,EAAE,IAAI;gCACT,eAAe,EAAE,KAAK;6BACvB;yBACF;qBACF;oBACH,CAAC,CAAC,EAAE,CAAC;aACR,CAAC,CAAA;QAEJ,KAAK,OAAO;YACV,OAAO,IAAI,UAAU,CAAC;gBACpB,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,aAAa;aACrC,CAAC,CAAC;QAEL;YACE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { SupabaseTable } from "@delofarag/supabase-utils";
|
|
2
|
+
import { BaseCheckpointSaver, BaseChatModel, type Checkpoint, type CheckpointMetadata, type LangGraphRunnableConfig, type RunnableConfig, type CheckpointTuple, type CheckpointListOptions, type PendingWrite, type ChannelVersions } from "../imports";
|
|
3
|
+
/** Rolle einer Chat-Message im Checkpoint (Nach Json aus der DB oft Plain-Objects). */
|
|
4
|
+
export type CheckpointChatRole = "human" | "ai" | "system" | "tool" | "other";
|
|
5
|
+
export interface SupabaseCheckpointRow {
|
|
6
|
+
thread_id: string;
|
|
7
|
+
checkpoint: Checkpoint;
|
|
8
|
+
metadata: CheckpointMetadata;
|
|
9
|
+
created_at?: string;
|
|
10
|
+
updated_at?: string;
|
|
11
|
+
}
|
|
12
|
+
/** Nachrichten-Channel aus einem gespeicherten Checkpoint (meist `channel_values.messages`). */
|
|
13
|
+
export declare function getMessagesArrayFromCheckpoint(checkpoint: Checkpoint | undefined | null): unknown[];
|
|
14
|
+
export declare function checkpointMessageBody(message: unknown): string;
|
|
15
|
+
/** Erkennung Human / AI / System / Tool — funktioniert mit LangChain-Klassen und serialisierten JSON-Objekten. */
|
|
16
|
+
export declare function checkpointMessageRole(message: unknown): CheckpointChatRole;
|
|
17
|
+
/**
|
|
18
|
+
* Für Prompts/System-Kontext: klare Labels, Reihenfolge wie im Checkpoint-Channel `messages`,
|
|
19
|
+
* ohne extra DB-Spalte `conversation`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function formatCheckpointMessagesForLLM(messages: unknown[]): string;
|
|
22
|
+
/**
|
|
23
|
+
* needs testing!!!
|
|
24
|
+
*/
|
|
25
|
+
export declare class SupabaseCheckpointSaver extends BaseCheckpointSaver {
|
|
26
|
+
private table;
|
|
27
|
+
constructor(supabaseTable: SupabaseTable<SupabaseCheckpointRow>);
|
|
28
|
+
/** Messages aus gespeicherter `checkpoint`-Spalte (`channel_values.messages`). */
|
|
29
|
+
getCheckpointMessages(threadId: string): Promise<unknown[]>;
|
|
30
|
+
/** Lesbarer Kontext für Prompts (aus Checkpoint, keine `conversation`-Spalte). */
|
|
31
|
+
getConversationAsLLMContext(threadId: string): Promise<string>;
|
|
32
|
+
put(config: LangGraphRunnableConfig, checkpoint: Checkpoint, metadata: CheckpointMetadata, newVersions: ChannelVersions): Promise<RunnableConfig>;
|
|
33
|
+
get(config: LangGraphRunnableConfig): Promise<Checkpoint | undefined>;
|
|
34
|
+
list(config: LangGraphRunnableConfig, options?: CheckpointListOptions): AsyncGenerator<CheckpointTuple>;
|
|
35
|
+
delete(config: LangGraphRunnableConfig): Promise<void>;
|
|
36
|
+
getTuple(config: LangGraphRunnableConfig): Promise<CheckpointTuple | undefined>;
|
|
37
|
+
putWrites(_config: RunnableConfig, _writes: PendingWrite[], _taskId: string): Promise<void>;
|
|
38
|
+
deleteThread(threadId: string): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
interface SmartCheckpointSaverOptions {
|
|
41
|
+
messagesBeforeSummary?: number;
|
|
42
|
+
maxSummaries?: number;
|
|
43
|
+
llm?: BaseChatModel;
|
|
44
|
+
debug?: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* CONSTRUCTOR:
|
|
48
|
+
* @example
|
|
49
|
+
* constructor(
|
|
50
|
+
checkpointSaver: BaseCheckpointSaver,
|
|
51
|
+
{
|
|
52
|
+
messagesBeforeSummary = 12,
|
|
53
|
+
maxSummaries = 7,
|
|
54
|
+
llm = getLLM({ provider:"openrouter", model: "openai/gpt-5.4-mini"}),
|
|
55
|
+
debug = false
|
|
56
|
+
}: SmartCheckpointSaverOptions = {}
|
|
57
|
+
) {
|
|
58
|
+
super()
|
|
59
|
+
this.checkpointSaver = checkpointSaver
|
|
60
|
+
this.messagesBeforeSummary = messagesBeforeSummary
|
|
61
|
+
this.maxSummaries = maxSummaries
|
|
62
|
+
this.llm = llm
|
|
63
|
+
this.debug = debug
|
|
64
|
+
}
|
|
65
|
+
*/
|
|
66
|
+
export declare class SmartCheckpointSaver extends BaseCheckpointSaver {
|
|
67
|
+
private checkpointSaver;
|
|
68
|
+
private messagesBeforeSummary;
|
|
69
|
+
private maxSummaries;
|
|
70
|
+
private llm;
|
|
71
|
+
private debug;
|
|
72
|
+
private lastDebugState;
|
|
73
|
+
constructor(checkpointSaver: BaseCheckpointSaver, { messagesBeforeSummary, maxSummaries, llm, debug }?: SmartCheckpointSaverOptions);
|
|
74
|
+
private getMessageRole;
|
|
75
|
+
private getMessageContent;
|
|
76
|
+
/**
|
|
77
|
+
* Zählt User/AI Messages (ignoriert System-Messages)
|
|
78
|
+
*/
|
|
79
|
+
private countChatMessages;
|
|
80
|
+
/**
|
|
81
|
+
* Findet alle System-Messages die Zusammenfassungen sind
|
|
82
|
+
*/
|
|
83
|
+
private findSummaryMessages;
|
|
84
|
+
/**
|
|
85
|
+
* Konvertiert Messages zu Text für Summarization
|
|
86
|
+
*/
|
|
87
|
+
private messagesToText;
|
|
88
|
+
private applySmartSummarization;
|
|
89
|
+
put(config: LangGraphRunnableConfig, checkpoint: Checkpoint, metadata: CheckpointMetadata, newVersions: ChannelVersions): Promise<RunnableConfig>;
|
|
90
|
+
get(config: LangGraphRunnableConfig): Promise<Checkpoint | undefined>;
|
|
91
|
+
list(config: LangGraphRunnableConfig, options?: CheckpointListOptions): AsyncGenerator<CheckpointTuple>;
|
|
92
|
+
delete(config: LangGraphRunnableConfig): Promise<void>;
|
|
93
|
+
getTuple(config: LangGraphRunnableConfig): Promise<CheckpointTuple | undefined>;
|
|
94
|
+
putWrites(config: RunnableConfig, writes: PendingWrite[], taskId: string): Promise<void>;
|
|
95
|
+
deleteThread(threadId: string): Promise<void>;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* fasst eine Chat-Konversation zwischen User und Assistant zusammen
|
|
99
|
+
*/
|
|
100
|
+
export declare function chatSummarizer({ conversation, fokuss, llm, maxWords }: {
|
|
101
|
+
conversation: string;
|
|
102
|
+
fokuss?: string;
|
|
103
|
+
llm: BaseChatModel;
|
|
104
|
+
maxWords?: number;
|
|
105
|
+
}): Promise<string>;
|
|
106
|
+
export {};
|
|
107
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/helpers/memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
import { createSimpleChain } from "./helpers";
|
|
2
|
+
import { getLLM } from "./llms";
|
|
3
|
+
import { BaseCheckpointSaver, HumanMessage, AIMessage, SystemMessage, StringOutputParser, ChatPromptTemplate } from "../imports";
|
|
4
|
+
import { ToolMessage, } from "@langchain/core/messages";
|
|
5
|
+
/** Nachrichten-Channel aus einem gespeicherten Checkpoint (meist `channel_values.messages`). */
|
|
6
|
+
export function getMessagesArrayFromCheckpoint(checkpoint) {
|
|
7
|
+
if (!checkpoint?.channel_values)
|
|
8
|
+
return [];
|
|
9
|
+
const msgs = checkpoint.channel_values.messages;
|
|
10
|
+
return Array.isArray(msgs) ? msgs : [];
|
|
11
|
+
}
|
|
12
|
+
export function checkpointMessageBody(message) {
|
|
13
|
+
if (message === null || message === undefined)
|
|
14
|
+
return "";
|
|
15
|
+
const m = message;
|
|
16
|
+
const rawContent = m.content ??
|
|
17
|
+
(m.kwargs && typeof m.kwargs === "object"
|
|
18
|
+
? m.kwargs.content
|
|
19
|
+
: undefined) ??
|
|
20
|
+
"";
|
|
21
|
+
if (typeof rawContent === "string")
|
|
22
|
+
return rawContent;
|
|
23
|
+
if (Array.isArray(rawContent))
|
|
24
|
+
return rawContent
|
|
25
|
+
.map((part) => typeof part === "object" && part !== null && "text" in part
|
|
26
|
+
? String(part.text ?? "")
|
|
27
|
+
: JSON.stringify(part))
|
|
28
|
+
.join("");
|
|
29
|
+
return JSON.stringify(rawContent);
|
|
30
|
+
}
|
|
31
|
+
/** Erkennung Human / AI / System / Tool — funktioniert mit LangChain-Klassen und serialisierten JSON-Objekten. */
|
|
32
|
+
export function checkpointMessageRole(message) {
|
|
33
|
+
if (message === null || message === undefined || typeof message !== "object")
|
|
34
|
+
return "other";
|
|
35
|
+
const m = message;
|
|
36
|
+
if (m instanceof HumanMessage)
|
|
37
|
+
return "human";
|
|
38
|
+
if (m instanceof AIMessage)
|
|
39
|
+
return "ai";
|
|
40
|
+
if (m instanceof SystemMessage)
|
|
41
|
+
return "system";
|
|
42
|
+
if (m instanceof ToolMessage)
|
|
43
|
+
return "tool";
|
|
44
|
+
const raw = message;
|
|
45
|
+
const kw = raw.kwargs && typeof raw.kwargs === "object" ? raw.kwargs : {};
|
|
46
|
+
const t = typeof raw._getType === "function"
|
|
47
|
+
? raw._getType()
|
|
48
|
+
: typeof raw.type === "string"
|
|
49
|
+
? raw.type
|
|
50
|
+
: undefined;
|
|
51
|
+
if (t === "human" || t === "user")
|
|
52
|
+
return "human";
|
|
53
|
+
if (t === "ai" || t === "assistant")
|
|
54
|
+
return "ai";
|
|
55
|
+
if (t === "system")
|
|
56
|
+
return "system";
|
|
57
|
+
if (t === "tool")
|
|
58
|
+
return "tool";
|
|
59
|
+
const idArr = raw.id;
|
|
60
|
+
const idLast = Array.isArray(idArr) ? idArr[idArr.length - 1] : undefined;
|
|
61
|
+
if (idLast === "HumanMessage")
|
|
62
|
+
return "human";
|
|
63
|
+
if (idLast === "AIMessage" || idLast === "AIMessageChunk")
|
|
64
|
+
return "ai";
|
|
65
|
+
if (idLast === "SystemMessage")
|
|
66
|
+
return "system";
|
|
67
|
+
if (idLast === "ToolMessage")
|
|
68
|
+
return "tool";
|
|
69
|
+
const role = (kw.role ?? raw.role);
|
|
70
|
+
if (role === "human" || role === "user")
|
|
71
|
+
return "human";
|
|
72
|
+
if (role === "ai" || role === "assistant")
|
|
73
|
+
return "ai";
|
|
74
|
+
if (role === "system")
|
|
75
|
+
return "system";
|
|
76
|
+
if (role === "tool")
|
|
77
|
+
return "tool";
|
|
78
|
+
return "other";
|
|
79
|
+
}
|
|
80
|
+
function checkpointToolDisplayName(message) {
|
|
81
|
+
if (message === null || message === undefined || typeof message !== "object")
|
|
82
|
+
return undefined;
|
|
83
|
+
if (message instanceof ToolMessage)
|
|
84
|
+
return message.name ?? undefined;
|
|
85
|
+
const raw = message;
|
|
86
|
+
const kw = raw.kwargs && typeof raw.kwargs === "object" ? raw.kwargs : {};
|
|
87
|
+
const name = typeof raw.name === "string"
|
|
88
|
+
? raw.name
|
|
89
|
+
: typeof kw.name === "string"
|
|
90
|
+
? kw.name
|
|
91
|
+
: undefined;
|
|
92
|
+
return name || undefined;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Für Prompts/System-Kontext: klare Labels, Reihenfolge wie im Checkpoint-Channel `messages`,
|
|
96
|
+
* ohne extra DB-Spalte `conversation`.
|
|
97
|
+
*/
|
|
98
|
+
export function formatCheckpointMessagesForLLM(messages) {
|
|
99
|
+
if (!messages.length)
|
|
100
|
+
return "";
|
|
101
|
+
const blocks = [];
|
|
102
|
+
for (const msg of messages) {
|
|
103
|
+
const role = checkpointMessageRole(msg);
|
|
104
|
+
const body = checkpointMessageBody(msg).trim();
|
|
105
|
+
let heading;
|
|
106
|
+
if (role === "human")
|
|
107
|
+
heading = "**User** (human message)";
|
|
108
|
+
else if (role === "ai")
|
|
109
|
+
heading = "**Assistant** (AI message)";
|
|
110
|
+
else if (role === "system")
|
|
111
|
+
heading = "**System**";
|
|
112
|
+
else if (role === "tool") {
|
|
113
|
+
const toolName = checkpointToolDisplayName(msg);
|
|
114
|
+
heading = toolName ? `**Tool**: \`${toolName}\`` : "**Tool result**";
|
|
115
|
+
}
|
|
116
|
+
else
|
|
117
|
+
heading = "**Other / unknown role**";
|
|
118
|
+
if (!body)
|
|
119
|
+
continue;
|
|
120
|
+
blocks.push(`${heading}\n\n${body}`);
|
|
121
|
+
}
|
|
122
|
+
return blocks.join("\n\n---\n\n");
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* needs testing!!!
|
|
126
|
+
*/
|
|
127
|
+
export class SupabaseCheckpointSaver extends BaseCheckpointSaver {
|
|
128
|
+
table;
|
|
129
|
+
constructor(supabaseTable) {
|
|
130
|
+
super();
|
|
131
|
+
this.table = supabaseTable;
|
|
132
|
+
}
|
|
133
|
+
/** Messages aus gespeicherter `checkpoint`-Spalte (`channel_values.messages`). */
|
|
134
|
+
async getCheckpointMessages(threadId) {
|
|
135
|
+
const rows = await this.table.select({
|
|
136
|
+
columns: ["checkpoint"],
|
|
137
|
+
where: [{ column: "thread_id", is: threadId }],
|
|
138
|
+
limited_to: 1,
|
|
139
|
+
});
|
|
140
|
+
const ck = rows[0]?.checkpoint;
|
|
141
|
+
return getMessagesArrayFromCheckpoint(ck);
|
|
142
|
+
}
|
|
143
|
+
/** Lesbarer Kontext für Prompts (aus Checkpoint, keine `conversation`-Spalte). */
|
|
144
|
+
async getConversationAsLLMContext(threadId) {
|
|
145
|
+
const messages = await this.getCheckpointMessages(threadId);
|
|
146
|
+
return formatCheckpointMessagesForLLM(messages);
|
|
147
|
+
}
|
|
148
|
+
async put(config, checkpoint, metadata, newVersions) {
|
|
149
|
+
if (!checkpoint)
|
|
150
|
+
return config;
|
|
151
|
+
const threadId = config.configurable?.thread_id || "default";
|
|
152
|
+
const now = new Date().toISOString();
|
|
153
|
+
const existingRows = await this.table.select({
|
|
154
|
+
columns: ["created_at"],
|
|
155
|
+
where: [{ column: "thread_id", is: threadId }],
|
|
156
|
+
limited_to: 1,
|
|
157
|
+
});
|
|
158
|
+
const existing = existingRows[0];
|
|
159
|
+
const createdAt = existing?.created_at || now;
|
|
160
|
+
await this.table.upsert({
|
|
161
|
+
where: [{ column: "thread_id", is: threadId }],
|
|
162
|
+
upsert: {
|
|
163
|
+
checkpoint: checkpoint,
|
|
164
|
+
metadata: metadata,
|
|
165
|
+
created_at: createdAt,
|
|
166
|
+
updated_at: now,
|
|
167
|
+
},
|
|
168
|
+
onConflict: "thread_id",
|
|
169
|
+
});
|
|
170
|
+
const checkpoint_ns = config.configurable?.checkpoint_ns ?? "";
|
|
171
|
+
return {
|
|
172
|
+
configurable: {
|
|
173
|
+
thread_id: threadId,
|
|
174
|
+
checkpoint_ns,
|
|
175
|
+
checkpoint_id: checkpoint.id,
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
async get(config) {
|
|
180
|
+
const threadId = config.configurable?.thread_id || "default";
|
|
181
|
+
const rows = await this.table.select({
|
|
182
|
+
columns: ["checkpoint"],
|
|
183
|
+
where: [{ column: "thread_id", is: threadId }],
|
|
184
|
+
limited_to: 1,
|
|
185
|
+
});
|
|
186
|
+
return rows[0]?.checkpoint;
|
|
187
|
+
}
|
|
188
|
+
async *list(config, options) {
|
|
189
|
+
const threadId = config.configurable?.thread_id;
|
|
190
|
+
if (!threadId)
|
|
191
|
+
return;
|
|
192
|
+
const data = await this.table.select({
|
|
193
|
+
columns: ["checkpoint", "metadata"],
|
|
194
|
+
where: [{ column: "thread_id", is: threadId }],
|
|
195
|
+
});
|
|
196
|
+
const checkpoint_ns = config.configurable?.checkpoint_ns ?? "";
|
|
197
|
+
for (const row of data || []) {
|
|
198
|
+
const ckpt = row.checkpoint;
|
|
199
|
+
if (!ckpt)
|
|
200
|
+
continue;
|
|
201
|
+
yield {
|
|
202
|
+
config: {
|
|
203
|
+
configurable: {
|
|
204
|
+
thread_id: threadId,
|
|
205
|
+
checkpoint_ns,
|
|
206
|
+
checkpoint_id: ckpt.id,
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
checkpoint: ckpt,
|
|
210
|
+
metadata: (row.metadata ?? {}),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
async delete(config) {
|
|
215
|
+
const threadId = config.configurable?.thread_id || "default";
|
|
216
|
+
await this.table.delete({
|
|
217
|
+
where: [{ column: "thread_id", is: threadId }]
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
async getTuple(config) {
|
|
221
|
+
const threadId = config.configurable?.thread_id || "default";
|
|
222
|
+
const checkpoint_ns = config.configurable?.checkpoint_ns ?? "";
|
|
223
|
+
const rows = await this.table.select({
|
|
224
|
+
columns: ["checkpoint", "metadata"],
|
|
225
|
+
where: [{ column: "thread_id", is: threadId }],
|
|
226
|
+
limited_to: 1,
|
|
227
|
+
});
|
|
228
|
+
const row = rows[0];
|
|
229
|
+
const checkpoint = row?.checkpoint;
|
|
230
|
+
if (!checkpoint)
|
|
231
|
+
return undefined;
|
|
232
|
+
return {
|
|
233
|
+
config: {
|
|
234
|
+
configurable: {
|
|
235
|
+
thread_id: threadId,
|
|
236
|
+
checkpoint_ns,
|
|
237
|
+
checkpoint_id: checkpoint.id,
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
checkpoint,
|
|
241
|
+
metadata: (row.metadata ?? {}),
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
async putWrites(_config, _writes, _taskId) {
|
|
245
|
+
// pending writes brauchen wir nicht separat zu persistieren -
|
|
246
|
+
// der finale Checkpoint kommt sowieso über put() rein
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
async deleteThread(threadId) {
|
|
250
|
+
await this.table.delete({
|
|
251
|
+
where: [{ column: "thread_id", is: threadId }]
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* CONSTRUCTOR:
|
|
257
|
+
* @example
|
|
258
|
+
* constructor(
|
|
259
|
+
checkpointSaver: BaseCheckpointSaver,
|
|
260
|
+
{
|
|
261
|
+
messagesBeforeSummary = 12,
|
|
262
|
+
maxSummaries = 7,
|
|
263
|
+
llm = getLLM({ provider:"openrouter", model: "openai/gpt-5.4-mini"}),
|
|
264
|
+
debug = false
|
|
265
|
+
}: SmartCheckpointSaverOptions = {}
|
|
266
|
+
) {
|
|
267
|
+
super()
|
|
268
|
+
this.checkpointSaver = checkpointSaver
|
|
269
|
+
this.messagesBeforeSummary = messagesBeforeSummary
|
|
270
|
+
this.maxSummaries = maxSummaries
|
|
271
|
+
this.llm = llm
|
|
272
|
+
this.debug = debug
|
|
273
|
+
}
|
|
274
|
+
*/
|
|
275
|
+
export class SmartCheckpointSaver extends BaseCheckpointSaver {
|
|
276
|
+
checkpointSaver;
|
|
277
|
+
messagesBeforeSummary;
|
|
278
|
+
maxSummaries;
|
|
279
|
+
llm;
|
|
280
|
+
debug;
|
|
281
|
+
lastDebugState;
|
|
282
|
+
constructor(checkpointSaver, { messagesBeforeSummary = 12, maxSummaries = 7, llm = getLLM({ provider: "openrouter", model: "openai/gpt-5.4-mini" }), debug = false } = {}) {
|
|
283
|
+
super();
|
|
284
|
+
this.checkpointSaver = checkpointSaver;
|
|
285
|
+
this.messagesBeforeSummary = messagesBeforeSummary;
|
|
286
|
+
this.maxSummaries = maxSummaries;
|
|
287
|
+
this.llm = llm;
|
|
288
|
+
this.debug = debug;
|
|
289
|
+
}
|
|
290
|
+
getMessageRole(message) {
|
|
291
|
+
const r = checkpointMessageRole(message);
|
|
292
|
+
if (r === "tool" || r === "other")
|
|
293
|
+
return "other";
|
|
294
|
+
return r;
|
|
295
|
+
}
|
|
296
|
+
getMessageContent(message) {
|
|
297
|
+
return checkpointMessageBody(message);
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Zählt User/AI Messages (ignoriert System-Messages)
|
|
301
|
+
*/
|
|
302
|
+
countChatMessages(messages) {
|
|
303
|
+
return messages.filter(msg => {
|
|
304
|
+
const role = this.getMessageRole(msg);
|
|
305
|
+
return role === "human" || role === "ai";
|
|
306
|
+
}).length;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Findet alle System-Messages die Zusammenfassungen sind
|
|
310
|
+
*/
|
|
311
|
+
findSummaryMessages(messages) {
|
|
312
|
+
const summaries = [];
|
|
313
|
+
messages.forEach((msg, index) => {
|
|
314
|
+
if (this.getMessageRole(msg) === "system" && this.getMessageContent(msg).includes("Zusammenfassung")) {
|
|
315
|
+
summaries.push({ index, message: msg });
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
return summaries;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Konvertiert Messages zu Text für Summarization
|
|
322
|
+
*/
|
|
323
|
+
messagesToText(messages) {
|
|
324
|
+
return messages.map(msg => {
|
|
325
|
+
const role = this.getMessageRole(msg);
|
|
326
|
+
const label = role === "human" ? "User" : role === "ai" ? "Assistant" : "System";
|
|
327
|
+
return `${label}: ${this.getMessageContent(msg)}`;
|
|
328
|
+
}).join('\n\n');
|
|
329
|
+
}
|
|
330
|
+
async applySmartSummarization(checkpoint) {
|
|
331
|
+
// Guard: Wenn checkpoint undefined ist, gib ihn zurück
|
|
332
|
+
if (!checkpoint) {
|
|
333
|
+
return checkpoint;
|
|
334
|
+
}
|
|
335
|
+
// Messages sind in channel_values gespeichert
|
|
336
|
+
const channelValues = checkpoint.channel_values || {};
|
|
337
|
+
const messages = channelValues.messages || [];
|
|
338
|
+
// Finde alle Zusammenfassungs-System-Messages
|
|
339
|
+
const summaryMessages = this.findSummaryMessages(messages);
|
|
340
|
+
// Finde den Index der letzten Zusammenfassung (falls vorhanden)
|
|
341
|
+
const lastSummaryIndex = summaryMessages.length > 0
|
|
342
|
+
? summaryMessages[summaryMessages.length - 1].index
|
|
343
|
+
: -1;
|
|
344
|
+
// Finde die Messages NACH der letzten Zusammenfassung
|
|
345
|
+
const messagesAfterLastSummary = messages.slice(lastSummaryIndex + 1);
|
|
346
|
+
const chatMessagesAfterLastSummary = messagesAfterLastSummary.filter(msg => {
|
|
347
|
+
const role = this.getMessageRole(msg);
|
|
348
|
+
return role === "human" || role === "ai";
|
|
349
|
+
});
|
|
350
|
+
const lastChatMessageRole = chatMessagesAfterLastSummary.length > 0
|
|
351
|
+
? this.getMessageRole(chatMessagesAfterLastSummary[chatMessagesAfterLastSummary.length - 1])
|
|
352
|
+
: "other";
|
|
353
|
+
// Zähle nur User/AI Messages NACH der letzten Zusammenfassung
|
|
354
|
+
const chatMessageCount = chatMessagesAfterLastSummary.length;
|
|
355
|
+
if (this.debug) {
|
|
356
|
+
const missingUntilNextSummary = Math.max(0, this.messagesBeforeSummary - chatMessageCount);
|
|
357
|
+
const debugState = `${summaryMessages.length}:${chatMessageCount}:${missingUntilNextSummary}:${lastChatMessageRole}`;
|
|
358
|
+
if (debugState !== this.lastDebugState) {
|
|
359
|
+
console.log(`[SmartCheckpointSaver] Chat messages since last summary: ${chatMessageCount}`);
|
|
360
|
+
console.log(`[SmartCheckpointSaver] Messages until next summary: ${missingUntilNextSummary}`);
|
|
361
|
+
this.lastDebugState = debugState;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// Wenn noch nicht genug Messages nach der letzten Zusammenfassung, keine Summarization
|
|
365
|
+
if (chatMessageCount < this.messagesBeforeSummary || lastChatMessageRole !== "ai") {
|
|
366
|
+
return checkpoint;
|
|
367
|
+
}
|
|
368
|
+
// Finde die Indizes der letzten X User/AI Messages NACH der letzten Zusammenfassung die zusammengefasst werden sollen
|
|
369
|
+
const indicesToSummarize = [];
|
|
370
|
+
const messagesToSummarize = [];
|
|
371
|
+
let chatCount = 0;
|
|
372
|
+
// Gehe rückwärts durch Messages NACH der letzten Zusammenfassung
|
|
373
|
+
for (let i = messagesAfterLastSummary.length - 1; i >= 0 && chatCount < this.messagesBeforeSummary; i--) {
|
|
374
|
+
const msg = messagesAfterLastSummary[i];
|
|
375
|
+
const role = this.getMessageRole(msg);
|
|
376
|
+
if (role === "human" || role === "ai") {
|
|
377
|
+
const originalIndex = lastSummaryIndex + 1 + i; // Original-Index im messages Array
|
|
378
|
+
indicesToSummarize.unshift(originalIndex); // Am Anfang einfügen für korrekte Reihenfolge
|
|
379
|
+
messagesToSummarize.unshift(msg); // Am Anfang einfügen für korrekte Reihenfolge
|
|
380
|
+
chatCount++;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
if (messagesToSummarize.length === 0) {
|
|
384
|
+
return checkpoint;
|
|
385
|
+
}
|
|
386
|
+
// Erstelle Zusammenfassung
|
|
387
|
+
const conversationText = this.messagesToText(messagesToSummarize);
|
|
388
|
+
const summary = await chatSummarizer({
|
|
389
|
+
conversation: conversationText,
|
|
390
|
+
llm: this.llm,
|
|
391
|
+
maxWords: 150
|
|
392
|
+
});
|
|
393
|
+
if (this.debug) {
|
|
394
|
+
console.log(`Summary erstellt beim SmartCheckpointSaver: ${summary}`);
|
|
395
|
+
}
|
|
396
|
+
// Erstelle neue System-Message mit Zusammenfassung
|
|
397
|
+
const summarySystemMessage = new SystemMessage(`Zusammenfassung der vorherigen Konversation:\n${summary}`);
|
|
398
|
+
// Entferne die Messages die zusammengefasst wurden (verwende Indizes)
|
|
399
|
+
const remainingMessages = messages.filter((_, index) => !indicesToSummarize.includes(index));
|
|
400
|
+
// Finde die Position der letzten Zusammenfassung im remainingMessages Array
|
|
401
|
+
// (Die Indizes haben sich verschoben, aber die letzte Zusammenfassung sollte noch da sein)
|
|
402
|
+
const remainingSummaryMessages = this.findSummaryMessages(remainingMessages);
|
|
403
|
+
const lastSummaryIndexInRemaining = remainingSummaryMessages.length > 0
|
|
404
|
+
? remainingSummaryMessages[remainingSummaryMessages.length - 1].index
|
|
405
|
+
: -1;
|
|
406
|
+
// Füge Zusammenfassung direkt nach der letzten Zusammenfassung ein
|
|
407
|
+
// Wenn keine Zusammenfassung vorhanden, füge am Anfang ein (nach System-Messages)
|
|
408
|
+
let newMessages;
|
|
409
|
+
if (lastSummaryIndexInRemaining >= 0) {
|
|
410
|
+
const beforeSummary = remainingMessages.slice(0, lastSummaryIndexInRemaining + 1);
|
|
411
|
+
const afterSummary = remainingMessages.slice(lastSummaryIndexInRemaining + 1);
|
|
412
|
+
newMessages = [...beforeSummary, summarySystemMessage, ...afterSummary];
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
// Keine Zusammenfassung vorhanden: Füge nach System-Messages ein
|
|
416
|
+
const systemMessages = remainingMessages.filter((msg) => this.getMessageRole(msg) === "system");
|
|
417
|
+
const nonSystemMessages = remainingMessages.filter((msg) => this.getMessageRole(msg) !== "system");
|
|
418
|
+
newMessages = [...systemMessages, summarySystemMessage, ...nonSystemMessages];
|
|
419
|
+
}
|
|
420
|
+
// Prüfe ob zu viele Zusammenfassungen vorhanden sind
|
|
421
|
+
const allSummaries = this.findSummaryMessages(newMessages);
|
|
422
|
+
if (allSummaries.length > this.maxSummaries) {
|
|
423
|
+
// Entferne die älteste Zusammenfassung
|
|
424
|
+
const oldestSummary = allSummaries[0];
|
|
425
|
+
const finalMessages = newMessages.filter((_, index) => index !== oldestSummary.index);
|
|
426
|
+
return {
|
|
427
|
+
...checkpoint,
|
|
428
|
+
channel_values: {
|
|
429
|
+
...channelValues,
|
|
430
|
+
messages: finalMessages
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
return {
|
|
435
|
+
...checkpoint,
|
|
436
|
+
channel_values: {
|
|
437
|
+
...channelValues,
|
|
438
|
+
messages: newMessages
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
async put(config, checkpoint, metadata, newVersions) {
|
|
443
|
+
// Guard: Wenn checkpoint undefined ist, gib ihn direkt weiter
|
|
444
|
+
if (!checkpoint) {
|
|
445
|
+
return await this.checkpointSaver.put(config, checkpoint, metadata, newVersions);
|
|
446
|
+
}
|
|
447
|
+
// Wende Smart Summarization an
|
|
448
|
+
const optimizedCheckpoint = await this.applySmartSummarization(checkpoint);
|
|
449
|
+
// Speichere im unterliegenden CheckpointSaver
|
|
450
|
+
return await this.checkpointSaver.put(config, optimizedCheckpoint, metadata, newVersions);
|
|
451
|
+
}
|
|
452
|
+
async get(config) {
|
|
453
|
+
return await this.checkpointSaver.get(config);
|
|
454
|
+
}
|
|
455
|
+
async *list(config, options) {
|
|
456
|
+
yield* this.checkpointSaver.list(config, options);
|
|
457
|
+
}
|
|
458
|
+
async delete(config) {
|
|
459
|
+
const threadId = config.configurable?.thread_id || "default";
|
|
460
|
+
return await this.checkpointSaver.deleteThread(threadId);
|
|
461
|
+
}
|
|
462
|
+
async getTuple(config) {
|
|
463
|
+
return await this.checkpointSaver.getTuple(config);
|
|
464
|
+
}
|
|
465
|
+
async putWrites(config, writes, taskId) {
|
|
466
|
+
// putWrites wird für Channel-Updates verwendet, nicht für vollständige Checkpoints
|
|
467
|
+
// Summarization wird nur in put() angewendet, wo vollständige Checkpoints gespeichert werden
|
|
468
|
+
// Daher delegieren wir direkt an den unterliegenden Saver
|
|
469
|
+
await this.checkpointSaver.putWrites(config, writes, taskId);
|
|
470
|
+
}
|
|
471
|
+
async deleteThread(threadId) {
|
|
472
|
+
return await this.checkpointSaver.deleteThread(threadId);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* fasst eine Chat-Konversation zwischen User und Assistant zusammen
|
|
477
|
+
*/
|
|
478
|
+
export async function chatSummarizer({ conversation, fokuss, llm, maxWords = 150 }) {
|
|
479
|
+
const focusMessage = fokuss
|
|
480
|
+
? [["system", `Fokussiere dich besonders auf die folgenden Themen:\n${fokuss}`]]
|
|
481
|
+
: [];
|
|
482
|
+
const prompt = ChatPromptTemplate.fromMessages([
|
|
483
|
+
["system", `Du fasst eine Chat-Konversation zwischen User und Assistant zusammen.
|
|
484
|
+
WICHTIG:
|
|
485
|
+
- Behalte ALLE wichtigen Fakten: Namen, Präferenzen, Entscheidungen, Vereinbarungen
|
|
486
|
+
- Behalte chronologischen Kontext wo relevant für Verständnis
|
|
487
|
+
- Fasse auf max. ${maxWords} Wörter zusammen
|
|
488
|
+
- Format: Kurze, prägnante Zusammenfassung ohne Bullet-Points
|
|
489
|
+
- Ignoriere Small-Talk, fokussiere auf inhaltliche Punkte`],
|
|
490
|
+
...focusMessage,
|
|
491
|
+
["human", "{conversation}"]
|
|
492
|
+
]);
|
|
493
|
+
const chain = createSimpleChain(prompt, llm, new StringOutputParser());
|
|
494
|
+
const result = await chain.invoke({ conversation });
|
|
495
|
+
return typeof result === "string" ? result : String(result);
|
|
496
|
+
}
|
|
497
|
+
//# sourceMappingURL=memory.js.map
|