@flink-app/flink 0.14.3 → 2.0.0-alpha.100
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/CHANGELOG.md +1051 -0
- package/SCHEMA_EXTRACTION_ANALYSIS.md +494 -0
- package/SIMPLE_AST_FEASIBILITY.md +570 -0
- package/bin/flink.ts +13 -2
- package/cli/build.ts +24 -44
- package/cli/clean.ts +13 -25
- package/cli/cli-utils.ts +190 -17
- package/cli/dev.ts +252 -0
- package/cli/loadEnvFiles.ts +116 -0
- package/cli/run.ts +45 -62
- package/dist/bin/flink.js +61 -2
- package/dist/cli/build.js +20 -25
- package/dist/cli/clean.js +12 -10
- package/dist/cli/cli-utils.d.ts +34 -3
- package/dist/cli/cli-utils.js +193 -12
- package/dist/cli/dev.d.ts +2 -0
- package/dist/cli/dev.js +279 -0
- package/dist/cli/loadEnvFiles.d.ts +30 -0
- package/dist/cli/loadEnvFiles.js +113 -0
- package/dist/cli/run.js +47 -46
- package/dist/src/DependencyTracker.d.ts +44 -0
- package/dist/src/DependencyTracker.js +239 -0
- package/dist/src/FlinkApp.d.ts +163 -10
- package/dist/src/FlinkApp.js +847 -184
- package/dist/src/FlinkContext.d.ts +41 -0
- package/dist/src/FlinkErrors.d.ts +19 -6
- package/dist/src/FlinkErrors.js +36 -42
- package/dist/src/FlinkHttpHandler.d.ts +219 -26
- package/dist/src/FlinkHttpHandler.js +37 -1
- package/dist/src/FlinkJob.d.ts +10 -0
- package/dist/src/FlinkLog.d.ts +82 -18
- package/dist/src/FlinkLog.js +165 -13
- package/dist/src/FlinkLogFactory.d.ts +288 -0
- package/dist/src/FlinkLogFactory.js +619 -0
- package/dist/src/FlinkRepo.d.ts +10 -2
- package/dist/src/FlinkRepo.js +11 -1
- package/dist/src/FlinkRequestContext.d.ts +63 -0
- package/dist/src/FlinkRequestContext.js +74 -0
- package/dist/src/FlinkResponse.d.ts +6 -0
- package/dist/src/FlinkService.d.ts +38 -0
- package/dist/src/FlinkService.js +46 -0
- package/dist/src/LeaderElection.d.ts +45 -0
- package/dist/src/LeaderElection.js +269 -0
- package/dist/src/SchemaCache.d.ts +84 -0
- package/dist/src/SchemaCache.js +289 -0
- package/dist/src/TypeScriptCompiler.d.ts +161 -51
- package/dist/src/TypeScriptCompiler.js +1253 -617
- package/dist/src/TypeScriptUtils.js +4 -0
- package/dist/src/ai/AgentRunner.d.ts +39 -0
- package/dist/src/ai/AgentRunner.js +760 -0
- package/dist/src/ai/ConversationAgent.d.ts +279 -0
- package/dist/src/ai/ConversationAgent.js +404 -0
- package/dist/src/ai/ConversationFlinkAgent.d.ts +278 -0
- package/dist/src/ai/ConversationFlinkAgent.js +404 -0
- package/dist/src/ai/FlinkAgent.d.ts +690 -0
- package/dist/src/ai/FlinkAgent.js +729 -0
- package/dist/src/ai/FlinkTool.d.ts +135 -0
- package/dist/src/ai/FlinkTool.js +2 -0
- package/dist/src/ai/InMemoryConversationAgent.d.ts +121 -0
- package/dist/src/ai/InMemoryConversationAgent.js +209 -0
- package/dist/src/ai/LLMAdapter.d.ts +148 -0
- package/dist/src/ai/LLMAdapter.js +2 -0
- package/dist/src/ai/PersistentFlinkAgent.d.ts +278 -0
- package/dist/src/ai/PersistentFlinkAgent.js +403 -0
- package/dist/src/ai/SubAgentExecutor.d.ts +38 -0
- package/dist/src/ai/SubAgentExecutor.js +223 -0
- package/dist/src/ai/ToolExecutor.d.ts +64 -0
- package/dist/src/ai/ToolExecutor.js +497 -0
- package/dist/src/ai/agentInstructions.d.ts +68 -0
- package/dist/src/ai/agentInstructions.js +286 -0
- package/dist/src/ai/index.d.ts +8 -0
- package/dist/src/ai/index.js +26 -0
- package/dist/src/ai/instructionFileLoader.d.ts +44 -0
- package/dist/src/ai/instructionFileLoader.js +179 -0
- package/dist/src/auth/FlinkAuthPlugin.d.ts +1 -1
- package/dist/src/handlers/StreamWriterFactory.d.ts +20 -0
- package/dist/src/handlers/StreamWriterFactory.js +83 -0
- package/dist/src/index.d.ts +14 -0
- package/dist/src/index.js +17 -0
- package/dist/src/loadPluginSchemas.d.ts +45 -0
- package/dist/src/loadPluginSchemas.js +143 -0
- package/dist/src/schema-extraction/ComplexTypeDetection.d.ts +40 -0
- package/dist/src/schema-extraction/ComplexTypeDetection.js +75 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.d.ts +321 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.js +925 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.spec.d.ts +1 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.spec.js +233 -0
- package/dist/src/schema-extraction/TypeScriptTokenizer.d.ts +57 -0
- package/dist/src/schema-extraction/TypeScriptTokenizer.js +177 -0
- package/dist/src/schema-extraction/index.d.ts +2 -0
- package/dist/src/schema-extraction/index.js +20 -0
- package/dist/src/schema-extraction/types.d.ts +31 -0
- package/dist/src/schema-extraction/types.js +2 -0
- package/dist/src/utils/loadFlinkConfig.d.ts +53 -0
- package/dist/src/utils/loadFlinkConfig.js +77 -0
- package/dist/src/utils.d.ts +30 -0
- package/dist/src/utils.js +52 -0
- package/dist/src/workers/SchemaGeneratorWorker.d.ts +1 -0
- package/dist/src/workers/SchemaGeneratorWorker.js +49 -0
- package/dist/src/workers/WorkerPool.d.ts +60 -0
- package/dist/src/workers/WorkerPool.js +306 -0
- package/examples/logging-hierarchical-example.ts +125 -0
- package/package.json +29 -4
- package/readme.md +499 -0
- package/spec/AgentDescendantDetection.spec.ts +335 -0
- package/spec/AgentDuplicateDetection.spec.ts +112 -0
- package/spec/AgentObserver.spec.ts +266 -0
- package/spec/AgentRunner.spec.ts +1062 -0
- package/spec/AsyncLocalStorageContext.spec.ts +223 -0
- package/spec/ConversationHooks.spec.ts +257 -0
- package/spec/FlinkAgent.spec.ts +681 -0
- package/spec/FlinkApp.htmlResponse.spec.ts +260 -0
- package/spec/FlinkApp.onError.invocation.spec.ts +151 -0
- package/spec/FlinkApp.onError.spec.ts +1 -2
- package/spec/FlinkApp.query.spec.ts +107 -0
- package/spec/FlinkApp.routeOrdering.spec.ts +61 -0
- package/spec/FlinkApp.undefinedResponse.spec.ts +123 -0
- package/spec/FlinkApp.validationMode.spec.ts +155 -0
- package/spec/FlinkJob.spec.ts +171 -0
- package/spec/FlinkLogFactory.spec.ts +337 -0
- package/spec/FlinkRepo.spec.ts +1 -1
- package/spec/LeaderElection.spec.ts +174 -0
- package/spec/StreamingIntegration.spec.ts +139 -0
- package/spec/ToolExecutor.spec.ts +465 -0
- package/spec/TypeScriptCompiler.spec.ts +1 -1
- package/spec/TypeScriptSourceParser.spec.ts +1215 -0
- package/spec/TypeScriptTokenizer.spec.ts +366 -0
- package/spec/ai/ContextCompaction.spec.ts +405 -0
- package/spec/ai/ConversationAgent.spec.ts +520 -0
- package/spec/ai/InMemoryConversationAgent.spec.ts +144 -0
- package/spec/ai/agentInstructions.spec.ts +358 -0
- package/spec/fixtures/agent-instructions/TestAgent.ts +24 -0
- package/spec/fixtures/agent-instructions/simple.md +3 -0
- package/spec/fixtures/agent-instructions/template.md +18 -0
- package/spec/fixtures/agent-instructions/yaml-format.yaml +9 -0
- package/spec/mock-project/dist/.tsbuildinfo +1 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar.js +56 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar2.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema.js +52 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema2.js +52 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema3.js +52 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema2.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile2.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler.js +53 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler2.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchCar.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOnboardingSession.js +75 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOrderWithComplexTypes.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchProductWithIntersection.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchUserWithUnion.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostCar.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogin.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogout.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PutCar.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/index.js +83 -0
- package/spec/mock-project/dist/spec/mock-project/src/repos/CarRepo.js +26 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/Car.js +2 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/DefaultExportSchema.js +2 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/FileWithTwoSchemas.js +2 -0
- package/spec/mock-project/dist/src/FlinkApp.js +1000 -0
- package/spec/mock-project/dist/src/FlinkContext.js +2 -0
- package/spec/mock-project/dist/src/FlinkErrors.js +143 -0
- package/spec/mock-project/dist/src/FlinkHttpHandler.js +47 -0
- package/spec/mock-project/dist/src/FlinkJob.js +2 -0
- package/spec/mock-project/dist/src/FlinkLog.js +119 -0
- package/spec/mock-project/dist/src/FlinkLogFactory.js +617 -0
- package/spec/mock-project/dist/src/FlinkPlugin.js +2 -0
- package/spec/mock-project/dist/src/FlinkRepo.js +224 -0
- package/spec/mock-project/dist/src/FlinkRequestContext.js +74 -0
- package/spec/mock-project/dist/src/FlinkResponse.js +2 -0
- package/spec/mock-project/dist/src/ai/AgentExecutor.js +279 -0
- package/spec/mock-project/dist/src/ai/AgentRunner.js +632 -0
- package/spec/mock-project/dist/src/ai/ConversationAgent.js +402 -0
- package/spec/mock-project/dist/src/ai/ConversationFlinkAgent.js +422 -0
- package/spec/mock-project/dist/src/ai/FlinkAgent.js +699 -0
- package/spec/mock-project/dist/src/ai/FlinkTool.js +2 -0
- package/spec/mock-project/dist/src/ai/InMemoryConversationAgent.js +209 -0
- package/spec/mock-project/dist/src/ai/LLMAdapter.js +2 -0
- package/spec/mock-project/dist/src/ai/SubAgentExecutor.js +223 -0
- package/spec/mock-project/dist/src/ai/ToolExecutor.js +412 -0
- package/spec/mock-project/dist/src/ai/agentInstructions.js +246 -0
- package/spec/mock-project/dist/src/auth/FlinkAuthPlugin.js +2 -0
- package/spec/mock-project/dist/src/auth/FlinkAuthUser.js +2 -0
- package/spec/mock-project/dist/src/handlers/GetCar.js +26 -52
- package/spec/mock-project/dist/src/handlers/GetCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCar2.js +32 -54
- package/spec/mock-project/dist/src/handlers/GetCar2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js +26 -48
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js +28 -48
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js +29 -48
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js +26 -50
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js +28 -50
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js +27 -53
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js +29 -53
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js +16 -49
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js +25 -50
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchCar.js +27 -53
- package/spec/mock-project/dist/src/handlers/PatchCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js +44 -70
- package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js +27 -53
- package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js +28 -54
- package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js +28 -54
- package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PostCar.js +24 -50
- package/spec/mock-project/dist/src/handlers/PostCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PostLogin.js +25 -51
- package/spec/mock-project/dist/src/handlers/PostLogin.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PostLogout.js +24 -50
- package/spec/mock-project/dist/src/handlers/PostLogout.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PutCar.js +24 -50
- package/spec/mock-project/dist/src/handlers/PutCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/StreamWriterFactory.js +83 -0
- package/spec/mock-project/dist/src/index.js +52 -76
- package/spec/mock-project/dist/src/index.js.map +1 -0
- package/spec/mock-project/dist/src/mock-data-generator.js +9 -0
- package/spec/mock-project/dist/src/repos/CarRepo.js +12 -24
- package/spec/mock-project/dist/src/repos/CarRepo.js.map +1 -0
- package/spec/mock-project/dist/src/schemas/Car.js +3 -1
- package/spec/mock-project/dist/src/schemas/Car.js.map +1 -0
- package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js +3 -1
- package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js.map +1 -0
- package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js +3 -1
- package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js.map +1 -0
- package/spec/mock-project/dist/src/utils.js +290 -0
- package/spec/mock-project/tsconfig.json +6 -1
- package/spec/schema-generation-nested-objects.spec.ts +97 -0
- package/spec/testHelpers.ts +49 -0
- package/spec/utils.caseConversion.spec.ts +78 -0
- package/spec/utils.spec.ts +13 -13
- package/src/DependencyTracker.ts +166 -0
- package/src/FlinkApp.ts +919 -155
- package/src/FlinkContext.ts +43 -0
- package/src/FlinkErrors.ts +32 -12
- package/src/FlinkHttpHandler.ts +246 -28
- package/src/FlinkJob.ts +11 -0
- package/src/FlinkLog.ts +119 -12
- package/src/FlinkLogFactory.ts +699 -0
- package/src/FlinkRepo.ts +10 -3
- package/src/FlinkRequestContext.ts +95 -0
- package/src/FlinkResponse.ts +6 -0
- package/src/FlinkService.ts +49 -0
- package/src/LeaderElection.ts +203 -0
- package/src/SchemaCache.ts +232 -0
- package/src/TypeScriptCompiler.ts +1347 -610
- package/src/TypeScriptUtils.ts +5 -0
- package/src/ai/AgentRunner.ts +646 -0
- package/src/ai/ConversationAgent.ts +413 -0
- package/src/ai/FlinkAgent.ts +1069 -0
- package/src/ai/FlinkTool.ts +165 -0
- package/src/ai/InMemoryConversationAgent.ts +149 -0
- package/src/ai/LLMAdapter.ts +126 -0
- package/src/ai/ToolExecutor.ts +485 -0
- package/src/ai/agentInstructions.ts +245 -0
- package/src/ai/index.ts +8 -0
- package/src/ai/instructionFileLoader.ts +156 -0
- package/src/auth/FlinkAuthPlugin.ts +2 -1
- package/src/handlers/StreamWriterFactory.ts +84 -0
- package/src/index.ts +14 -0
- package/src/loadPluginSchemas.ts +141 -0
- package/src/schema-extraction/TypeScriptSourceParser.ts +1058 -0
- package/src/schema-extraction/TypeScriptTokenizer.ts +205 -0
- package/src/schema-extraction/index.ts +2 -0
- package/src/schema-extraction/types.ts +34 -0
- package/src/utils/loadFlinkConfig.ts +89 -0
- package/src/utils.ts +52 -0
- package/tsconfig.json +6 -1
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { FlinkAgent, AgentExecuteInput, AgentExecuteResult, AgentFinishContext } from "./FlinkAgent";
|
|
2
|
+
import { FlinkContext } from "../FlinkContext";
|
|
3
|
+
/**
|
|
4
|
+
* Storage message format - flexible structure for conversation persistence.
|
|
5
|
+
*
|
|
6
|
+
* Supports text content, tool calls, and tool results in a single message.
|
|
7
|
+
* More flexible than FlinkAgent's union Message type for storage purposes.
|
|
8
|
+
*/
|
|
9
|
+
export interface StorageMessage {
|
|
10
|
+
role: "user" | "assistant" | "system" | "tool";
|
|
11
|
+
content?: string;
|
|
12
|
+
toolCalls?: Array<{
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
input: any;
|
|
16
|
+
}>;
|
|
17
|
+
toolResults?: Array<{
|
|
18
|
+
id: string;
|
|
19
|
+
result: any;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Conversation data structure for persistent storage.
|
|
24
|
+
*
|
|
25
|
+
* @property messages - Array of conversation messages in the storage format
|
|
26
|
+
* @property providerMetadata - Provider-specific metadata (e.g., OpenAI's responseId, instructionsHash)
|
|
27
|
+
*/
|
|
28
|
+
export interface ConversationData {
|
|
29
|
+
messages: StorageMessage[];
|
|
30
|
+
providerMetadata?: Record<string, any>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Abstract base class for agents with automatic conversation persistence.
|
|
34
|
+
*
|
|
35
|
+
* PersistentFlinkAgent eliminates boilerplate by automatically:
|
|
36
|
+
* - Loading conversation history before agent execution
|
|
37
|
+
* - Saving messages and provider metadata after execution
|
|
38
|
+
* - Enabling LLM provider optimizations (e.g., OpenAI's previousResponseId for 40-80% cost savings)
|
|
39
|
+
*
|
|
40
|
+
* ## Benefits
|
|
41
|
+
*
|
|
42
|
+
* - **Cost Savings**: Automatic provider metadata persistence enables server-side optimizations
|
|
43
|
+
* - **Type Safety**: Abstract methods enforce consistent storage implementation
|
|
44
|
+
* - **Backend Flexibility**: Works with MongoDB, Redis, in-memory, or any storage backend
|
|
45
|
+
* - **Sub-Agent Aware**: Automatically skips persistence for sub-agent calls (parent handles it)
|
|
46
|
+
*
|
|
47
|
+
* ## Usage Examples
|
|
48
|
+
*
|
|
49
|
+
* ### MongoDB Storage
|
|
50
|
+
* ```typescript
|
|
51
|
+
* export default class CarAgent extends PersistentFlinkAgent<AppContext> {
|
|
52
|
+
* id = "car-agent";
|
|
53
|
+
* description = "Car assistant with persistent conversations";
|
|
54
|
+
* instructions = "You are a helpful car expert...";
|
|
55
|
+
* tools = ["search-cars"];
|
|
56
|
+
*
|
|
57
|
+
* protected async loadConversation(conversationId: string) {
|
|
58
|
+
* const conv = await this.ctx.repos.conversationRepo.getById(conversationId);
|
|
59
|
+
* return conv ? {
|
|
60
|
+
* messages: conv.messages,
|
|
61
|
+
* providerMetadata: conv.providerMetadata,
|
|
62
|
+
* } : null;
|
|
63
|
+
* }
|
|
64
|
+
*
|
|
65
|
+
* protected async saveConversation(
|
|
66
|
+
* conversationId: string,
|
|
67
|
+
* data: ConversationData,
|
|
68
|
+
* result: AgentExecuteResult,
|
|
69
|
+
* context: AgentFinishContext
|
|
70
|
+
* ) {
|
|
71
|
+
* await this.ctx.repos.conversationRepo.upsert({
|
|
72
|
+
* _id: conversationId,
|
|
73
|
+
* agentId: this.id,
|
|
74
|
+
* userId: context.user?.id,
|
|
75
|
+
* messages: data.messages,
|
|
76
|
+
* providerMetadata: data.providerMetadata,
|
|
77
|
+
* updatedAt: new Date(),
|
|
78
|
+
* });
|
|
79
|
+
* }
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* ### Redis Storage
|
|
84
|
+
* ```typescript
|
|
85
|
+
* export default class CarAgent extends PersistentFlinkAgent<AppContext> {
|
|
86
|
+
* id = "car-agent";
|
|
87
|
+
* description = "Car assistant with Redis-backed conversations";
|
|
88
|
+
* instructions = "You are a helpful car expert...";
|
|
89
|
+
* tools = ["search-cars"];
|
|
90
|
+
*
|
|
91
|
+
* protected async loadConversation(conversationId: string) {
|
|
92
|
+
* const key = `conversation:${conversationId}`;
|
|
93
|
+
* const data = await this.ctx.redis.get(key);
|
|
94
|
+
* return data ? JSON.parse(data) : null;
|
|
95
|
+
* }
|
|
96
|
+
*
|
|
97
|
+
* protected async saveConversation(
|
|
98
|
+
* conversationId: string,
|
|
99
|
+
* data: ConversationData
|
|
100
|
+
* ) {
|
|
101
|
+
* const key = `conversation:${conversationId}`;
|
|
102
|
+
* await this.ctx.redis.setex(
|
|
103
|
+
* key,
|
|
104
|
+
* 86400, // 24 hour TTL
|
|
105
|
+
* JSON.stringify(data)
|
|
106
|
+
* );
|
|
107
|
+
* }
|
|
108
|
+
* }
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* ### In-Memory Storage (Development/Testing)
|
|
112
|
+
* ```typescript
|
|
113
|
+
* const conversationStore = new Map<string, ConversationData>();
|
|
114
|
+
*
|
|
115
|
+
* export default class CarAgent extends PersistentFlinkAgent<AppContext> {
|
|
116
|
+
* id = "car-agent";
|
|
117
|
+
* description = "Car assistant with in-memory conversations";
|
|
118
|
+
* instructions = "You are a helpful car expert...";
|
|
119
|
+
* tools = ["search-cars"];
|
|
120
|
+
*
|
|
121
|
+
* protected async loadConversation(conversationId: string) {
|
|
122
|
+
* return conversationStore.get(conversationId) || null;
|
|
123
|
+
* }
|
|
124
|
+
*
|
|
125
|
+
* protected async saveConversation(
|
|
126
|
+
* conversationId: string,
|
|
127
|
+
* data: ConversationData
|
|
128
|
+
* ) {
|
|
129
|
+
* conversationStore.set(conversationId, data);
|
|
130
|
+
* }
|
|
131
|
+
* }
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* ## Handler Usage
|
|
135
|
+
*
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const handler: PostHandler<AppContext, Input, Output> = async ({ ctx, body, req }) => {
|
|
138
|
+
* const conversationId = body.conversationId || generateId();
|
|
139
|
+
*
|
|
140
|
+
* const result = await ctx.agents.carAgent
|
|
141
|
+
* .withUser(req.user)
|
|
142
|
+
* .execute({ message: body.message, conversationId });
|
|
143
|
+
*
|
|
144
|
+
* return {
|
|
145
|
+
* conversationId,
|
|
146
|
+
* message: (await result.result).message,
|
|
147
|
+
* };
|
|
148
|
+
* };
|
|
149
|
+
* ```
|
|
150
|
+
*
|
|
151
|
+
* ## Provider Metadata Flow
|
|
152
|
+
*
|
|
153
|
+
* 1. First turn: Agent executes, LLM returns metadata (e.g., `{ openai: { responseId: "...", instructionsHash: "..." } }`)
|
|
154
|
+
* 2. saveConversation() stores messages + metadata
|
|
155
|
+
* 3. Second turn: loadConversation() returns messages + metadata
|
|
156
|
+
* 4. beforeRun() populates input.providerMetadata
|
|
157
|
+
* 5. LLM adapter uses metadata for server-side optimization (e.g., OpenAI's previousResponseId)
|
|
158
|
+
* 6. Result: 40-80% cost savings on subsequent turns
|
|
159
|
+
*
|
|
160
|
+
* @template Context - Application context type extending FlinkContext
|
|
161
|
+
*
|
|
162
|
+
* @see {@link https://flink.dev/docs/ai/agents/persistence | Persistence Guide}
|
|
163
|
+
* @see {@link https://platform.openai.com/docs/guides/conversation-history | OpenAI Conversation History}
|
|
164
|
+
*/
|
|
165
|
+
export declare abstract class PersistentFlinkAgent<Context extends FlinkContext = FlinkContext> extends FlinkAgent<Context> {
|
|
166
|
+
/**
|
|
167
|
+
* Load conversation history and provider metadata for the given conversation ID.
|
|
168
|
+
*
|
|
169
|
+
* Called automatically in beforeRun() before agent execution.
|
|
170
|
+
*
|
|
171
|
+
* @param conversationId - Unique identifier for the conversation
|
|
172
|
+
* @returns Conversation data (messages + providerMetadata), or null if not found
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* protected async loadConversation(conversationId: string) {
|
|
177
|
+
* const conv = await this.ctx.repos.conversationRepo.getById(conversationId);
|
|
178
|
+
* return conv ? {
|
|
179
|
+
* messages: conv.messages,
|
|
180
|
+
* providerMetadata: conv.providerMetadata,
|
|
181
|
+
* } : null;
|
|
182
|
+
* }
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
protected abstract loadConversation(conversationId: string): Promise<ConversationData | null>;
|
|
186
|
+
/**
|
|
187
|
+
* Save conversation history and provider metadata.
|
|
188
|
+
*
|
|
189
|
+
* Called automatically in afterRun() after agent execution completes successfully.
|
|
190
|
+
*
|
|
191
|
+
* @param conversationId - Unique identifier for the conversation
|
|
192
|
+
* @param data - Conversation data to save (messages + providerMetadata)
|
|
193
|
+
* @param result - Agent execution result (for access to final output if needed)
|
|
194
|
+
* @param context - Agent finish context (includes user, isSubAgent, etc.)
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* protected async saveConversation(
|
|
199
|
+
* conversationId: string,
|
|
200
|
+
* data: ConversationData,
|
|
201
|
+
* result: AgentExecuteResult,
|
|
202
|
+
* context: AgentFinishContext
|
|
203
|
+
* ) {
|
|
204
|
+
* await this.ctx.repos.conversationRepo.upsert({
|
|
205
|
+
* _id: conversationId,
|
|
206
|
+
* agentId: this.id,
|
|
207
|
+
* userId: context.user?.id,
|
|
208
|
+
* messages: data.messages,
|
|
209
|
+
* providerMetadata: data.providerMetadata,
|
|
210
|
+
* updatedAt: new Date(),
|
|
211
|
+
* });
|
|
212
|
+
* }
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
protected abstract saveConversation(conversationId: string, data: ConversationData, result: AgentExecuteResult, context: AgentFinishContext): Promise<void>;
|
|
216
|
+
/**
|
|
217
|
+
* Lifecycle hook: Load conversation history before agent execution.
|
|
218
|
+
*
|
|
219
|
+
* Automatically populates input.history and input.providerMetadata from storage.
|
|
220
|
+
*
|
|
221
|
+
* @internal
|
|
222
|
+
*/
|
|
223
|
+
protected beforeRun(input: AgentExecuteInput, context: AgentFinishContext): Promise<void>;
|
|
224
|
+
/**
|
|
225
|
+
* Lifecycle hook: Save conversation history after agent execution.
|
|
226
|
+
*
|
|
227
|
+
* Automatically converts LLM messages to storage format and saves with provider metadata.
|
|
228
|
+
* Skips save for sub-agent calls (parent agent handles persistence).
|
|
229
|
+
*
|
|
230
|
+
* @internal
|
|
231
|
+
*/
|
|
232
|
+
protected afterRun(result: AgentExecuteResult, context: AgentFinishContext): Promise<void>;
|
|
233
|
+
/**
|
|
234
|
+
* Convert storage messages back to agent Message format for input.history.
|
|
235
|
+
*
|
|
236
|
+
* @param storageMessages - Messages from storage in StorageMessage format
|
|
237
|
+
* @returns Message array compatible with AgentExecuteInput.history
|
|
238
|
+
*
|
|
239
|
+
* @internal
|
|
240
|
+
*/
|
|
241
|
+
private convertToAgentMessages;
|
|
242
|
+
/**
|
|
243
|
+
* Convert LLM adapter messages to storage format for persistence.
|
|
244
|
+
*
|
|
245
|
+
* @param llmMessages - Messages from LLM adapter in their native format
|
|
246
|
+
* @returns StorageMessage array
|
|
247
|
+
*
|
|
248
|
+
* @internal
|
|
249
|
+
*/
|
|
250
|
+
private convertToMessages;
|
|
251
|
+
/**
|
|
252
|
+
* Extract text content from message content blocks.
|
|
253
|
+
*
|
|
254
|
+
* @param blocks - Content blocks from LLM message
|
|
255
|
+
* @returns Concatenated text content, or undefined if no text blocks
|
|
256
|
+
*
|
|
257
|
+
* @internal
|
|
258
|
+
*/
|
|
259
|
+
private extractTextFromBlocks;
|
|
260
|
+
/**
|
|
261
|
+
* Extract tool calls from message content blocks.
|
|
262
|
+
*
|
|
263
|
+
* @param blocks - Content blocks from LLM message
|
|
264
|
+
* @returns Array of tool call objects
|
|
265
|
+
*
|
|
266
|
+
* @internal
|
|
267
|
+
*/
|
|
268
|
+
private extractToolCalls;
|
|
269
|
+
/**
|
|
270
|
+
* Extract tool results from message content blocks.
|
|
271
|
+
*
|
|
272
|
+
* @param blocks - Content blocks from LLM message
|
|
273
|
+
* @returns Array of tool result objects
|
|
274
|
+
*
|
|
275
|
+
* @internal
|
|
276
|
+
*/
|
|
277
|
+
private extractToolResults;
|
|
278
|
+
}
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __extends = (this && this.__extends) || (function () {
|
|
3
|
+
var extendStatics = function (d, b) {
|
|
4
|
+
extendStatics = Object.setPrototypeOf ||
|
|
5
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
7
|
+
return extendStatics(d, b);
|
|
8
|
+
};
|
|
9
|
+
return function (d, b) {
|
|
10
|
+
if (typeof b !== "function" && b !== null)
|
|
11
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
12
|
+
extendStatics(d, b);
|
|
13
|
+
function __() { this.constructor = d; }
|
|
14
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
15
|
+
};
|
|
16
|
+
})();
|
|
17
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
18
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
19
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
20
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
21
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
22
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
23
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
27
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
28
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
29
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
30
|
+
function step(op) {
|
|
31
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
32
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
33
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
34
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
35
|
+
switch (op[0]) {
|
|
36
|
+
case 0: case 1: t = op; break;
|
|
37
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
38
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
39
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
40
|
+
default:
|
|
41
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
42
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
43
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
44
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
45
|
+
if (t[2]) _.ops.pop();
|
|
46
|
+
_.trys.pop(); continue;
|
|
47
|
+
}
|
|
48
|
+
op = body.call(thisArg, _);
|
|
49
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
50
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
+
exports.PersistentFlinkAgent = void 0;
|
|
55
|
+
var FlinkAgent_1 = require("./FlinkAgent");
|
|
56
|
+
var FlinkLog_1 = require("../FlinkLog");
|
|
57
|
+
/**
|
|
58
|
+
* Abstract base class for agents with automatic conversation persistence.
|
|
59
|
+
*
|
|
60
|
+
* PersistentFlinkAgent eliminates boilerplate by automatically:
|
|
61
|
+
* - Loading conversation history before agent execution
|
|
62
|
+
* - Saving messages and provider metadata after execution
|
|
63
|
+
* - Enabling LLM provider optimizations (e.g., OpenAI's previousResponseId for 40-80% cost savings)
|
|
64
|
+
*
|
|
65
|
+
* ## Benefits
|
|
66
|
+
*
|
|
67
|
+
* - **Cost Savings**: Automatic provider metadata persistence enables server-side optimizations
|
|
68
|
+
* - **Type Safety**: Abstract methods enforce consistent storage implementation
|
|
69
|
+
* - **Backend Flexibility**: Works with MongoDB, Redis, in-memory, or any storage backend
|
|
70
|
+
* - **Sub-Agent Aware**: Automatically skips persistence for sub-agent calls (parent handles it)
|
|
71
|
+
*
|
|
72
|
+
* ## Usage Examples
|
|
73
|
+
*
|
|
74
|
+
* ### MongoDB Storage
|
|
75
|
+
* ```typescript
|
|
76
|
+
* export default class CarAgent extends PersistentFlinkAgent<AppContext> {
|
|
77
|
+
* id = "car-agent";
|
|
78
|
+
* description = "Car assistant with persistent conversations";
|
|
79
|
+
* instructions = "You are a helpful car expert...";
|
|
80
|
+
* tools = ["search-cars"];
|
|
81
|
+
*
|
|
82
|
+
* protected async loadConversation(conversationId: string) {
|
|
83
|
+
* const conv = await this.ctx.repos.conversationRepo.getById(conversationId);
|
|
84
|
+
* return conv ? {
|
|
85
|
+
* messages: conv.messages,
|
|
86
|
+
* providerMetadata: conv.providerMetadata,
|
|
87
|
+
* } : null;
|
|
88
|
+
* }
|
|
89
|
+
*
|
|
90
|
+
* protected async saveConversation(
|
|
91
|
+
* conversationId: string,
|
|
92
|
+
* data: ConversationData,
|
|
93
|
+
* result: AgentExecuteResult,
|
|
94
|
+
* context: AgentFinishContext
|
|
95
|
+
* ) {
|
|
96
|
+
* await this.ctx.repos.conversationRepo.upsert({
|
|
97
|
+
* _id: conversationId,
|
|
98
|
+
* agentId: this.id,
|
|
99
|
+
* userId: context.user?.id,
|
|
100
|
+
* messages: data.messages,
|
|
101
|
+
* providerMetadata: data.providerMetadata,
|
|
102
|
+
* updatedAt: new Date(),
|
|
103
|
+
* });
|
|
104
|
+
* }
|
|
105
|
+
* }
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* ### Redis Storage
|
|
109
|
+
* ```typescript
|
|
110
|
+
* export default class CarAgent extends PersistentFlinkAgent<AppContext> {
|
|
111
|
+
* id = "car-agent";
|
|
112
|
+
* description = "Car assistant with Redis-backed conversations";
|
|
113
|
+
* instructions = "You are a helpful car expert...";
|
|
114
|
+
* tools = ["search-cars"];
|
|
115
|
+
*
|
|
116
|
+
* protected async loadConversation(conversationId: string) {
|
|
117
|
+
* const key = `conversation:${conversationId}`;
|
|
118
|
+
* const data = await this.ctx.redis.get(key);
|
|
119
|
+
* return data ? JSON.parse(data) : null;
|
|
120
|
+
* }
|
|
121
|
+
*
|
|
122
|
+
* protected async saveConversation(
|
|
123
|
+
* conversationId: string,
|
|
124
|
+
* data: ConversationData
|
|
125
|
+
* ) {
|
|
126
|
+
* const key = `conversation:${conversationId}`;
|
|
127
|
+
* await this.ctx.redis.setex(
|
|
128
|
+
* key,
|
|
129
|
+
* 86400, // 24 hour TTL
|
|
130
|
+
* JSON.stringify(data)
|
|
131
|
+
* );
|
|
132
|
+
* }
|
|
133
|
+
* }
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* ### In-Memory Storage (Development/Testing)
|
|
137
|
+
* ```typescript
|
|
138
|
+
* const conversationStore = new Map<string, ConversationData>();
|
|
139
|
+
*
|
|
140
|
+
* export default class CarAgent extends PersistentFlinkAgent<AppContext> {
|
|
141
|
+
* id = "car-agent";
|
|
142
|
+
* description = "Car assistant with in-memory conversations";
|
|
143
|
+
* instructions = "You are a helpful car expert...";
|
|
144
|
+
* tools = ["search-cars"];
|
|
145
|
+
*
|
|
146
|
+
* protected async loadConversation(conversationId: string) {
|
|
147
|
+
* return conversationStore.get(conversationId) || null;
|
|
148
|
+
* }
|
|
149
|
+
*
|
|
150
|
+
* protected async saveConversation(
|
|
151
|
+
* conversationId: string,
|
|
152
|
+
* data: ConversationData
|
|
153
|
+
* ) {
|
|
154
|
+
* conversationStore.set(conversationId, data);
|
|
155
|
+
* }
|
|
156
|
+
* }
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* ## Handler Usage
|
|
160
|
+
*
|
|
161
|
+
* ```typescript
|
|
162
|
+
* const handler: PostHandler<AppContext, Input, Output> = async ({ ctx, body, req }) => {
|
|
163
|
+
* const conversationId = body.conversationId || generateId();
|
|
164
|
+
*
|
|
165
|
+
* const result = await ctx.agents.carAgent
|
|
166
|
+
* .withUser(req.user)
|
|
167
|
+
* .execute({ message: body.message, conversationId });
|
|
168
|
+
*
|
|
169
|
+
* return {
|
|
170
|
+
* conversationId,
|
|
171
|
+
* message: (await result.result).message,
|
|
172
|
+
* };
|
|
173
|
+
* };
|
|
174
|
+
* ```
|
|
175
|
+
*
|
|
176
|
+
* ## Provider Metadata Flow
|
|
177
|
+
*
|
|
178
|
+
* 1. First turn: Agent executes, LLM returns metadata (e.g., `{ openai: { responseId: "...", instructionsHash: "..." } }`)
|
|
179
|
+
* 2. saveConversation() stores messages + metadata
|
|
180
|
+
* 3. Second turn: loadConversation() returns messages + metadata
|
|
181
|
+
* 4. beforeRun() populates input.providerMetadata
|
|
182
|
+
* 5. LLM adapter uses metadata for server-side optimization (e.g., OpenAI's previousResponseId)
|
|
183
|
+
* 6. Result: 40-80% cost savings on subsequent turns
|
|
184
|
+
*
|
|
185
|
+
* @template Context - Application context type extending FlinkContext
|
|
186
|
+
*
|
|
187
|
+
* @see {@link https://flink.dev/docs/ai/agents/persistence | Persistence Guide}
|
|
188
|
+
* @see {@link https://platform.openai.com/docs/guides/conversation-history | OpenAI Conversation History}
|
|
189
|
+
*/
|
|
190
|
+
var PersistentFlinkAgent = /** @class */ (function (_super) {
|
|
191
|
+
__extends(PersistentFlinkAgent, _super);
|
|
192
|
+
function PersistentFlinkAgent() {
|
|
193
|
+
return _super !== null && _super.apply(this, arguments) || this;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Lifecycle hook: Load conversation history before agent execution.
|
|
197
|
+
*
|
|
198
|
+
* Automatically populates input.history and input.providerMetadata from storage.
|
|
199
|
+
*
|
|
200
|
+
* @internal
|
|
201
|
+
*/
|
|
202
|
+
PersistentFlinkAgent.prototype.beforeRun = function (input, context) {
|
|
203
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
204
|
+
var conversationId, conversationData, error_1;
|
|
205
|
+
return __generator(this, function (_a) {
|
|
206
|
+
switch (_a.label) {
|
|
207
|
+
case 0:
|
|
208
|
+
conversationId = input.conversationId;
|
|
209
|
+
if (!conversationId) {
|
|
210
|
+
FlinkLog_1.log.debug("[".concat(this.id, "] No conversationId provided, starting fresh conversation"));
|
|
211
|
+
return [2 /*return*/];
|
|
212
|
+
}
|
|
213
|
+
_a.label = 1;
|
|
214
|
+
case 1:
|
|
215
|
+
_a.trys.push([1, 3, , 4]);
|
|
216
|
+
return [4 /*yield*/, this.loadConversation(conversationId)];
|
|
217
|
+
case 2:
|
|
218
|
+
conversationData = _a.sent();
|
|
219
|
+
if (conversationData) {
|
|
220
|
+
input.history = this.convertToAgentMessages(conversationData.messages);
|
|
221
|
+
input.providerMetadata = conversationData.providerMetadata;
|
|
222
|
+
FlinkLog_1.log.debug("[".concat(this.id, "] Loaded conversation ").concat(conversationId, ": ").concat(conversationData.messages.length, " messages, metadata=").concat(JSON.stringify(conversationData.providerMetadata)));
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
FlinkLog_1.log.debug("[".concat(this.id, "] No conversation found for ").concat(conversationId, ", starting fresh"));
|
|
226
|
+
}
|
|
227
|
+
return [3 /*break*/, 4];
|
|
228
|
+
case 3:
|
|
229
|
+
error_1 = _a.sent();
|
|
230
|
+
FlinkLog_1.log.error("[".concat(this.id, "] Failed to load conversation ").concat(conversationId, ":"), error_1);
|
|
231
|
+
throw error_1; // Propagate load errors
|
|
232
|
+
case 4: return [2 /*return*/];
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Lifecycle hook: Save conversation history after agent execution.
|
|
239
|
+
*
|
|
240
|
+
* Automatically converts LLM messages to storage format and saves with provider metadata.
|
|
241
|
+
* Skips save for sub-agent calls (parent agent handles persistence).
|
|
242
|
+
*
|
|
243
|
+
* @internal
|
|
244
|
+
*/
|
|
245
|
+
PersistentFlinkAgent.prototype.afterRun = function (result, context) {
|
|
246
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
247
|
+
var conversationId, messages, providerMetadata, conversationData, error_2;
|
|
248
|
+
var _a;
|
|
249
|
+
return __generator(this, function (_b) {
|
|
250
|
+
switch (_b.label) {
|
|
251
|
+
case 0:
|
|
252
|
+
conversationId = (_a = context.input) === null || _a === void 0 ? void 0 : _a.conversationId;
|
|
253
|
+
if (!conversationId) {
|
|
254
|
+
FlinkLog_1.log.debug("[".concat(this.id, "] No conversationId provided, skipping save"));
|
|
255
|
+
return [2 /*return*/];
|
|
256
|
+
}
|
|
257
|
+
// Skip save for sub-agent calls - parent handles persistence
|
|
258
|
+
if (context.isSubAgent) {
|
|
259
|
+
FlinkLog_1.log.debug("[".concat(this.id, "] Sub-agent execution, skipping save (parent handles persistence)"));
|
|
260
|
+
return [2 /*return*/];
|
|
261
|
+
}
|
|
262
|
+
_b.label = 1;
|
|
263
|
+
case 1:
|
|
264
|
+
_b.trys.push([1, 3, , 4]);
|
|
265
|
+
messages = this.convertToMessages(context.messages);
|
|
266
|
+
providerMetadata = result.providerMetadata;
|
|
267
|
+
conversationData = {
|
|
268
|
+
messages: messages,
|
|
269
|
+
providerMetadata: providerMetadata,
|
|
270
|
+
};
|
|
271
|
+
return [4 /*yield*/, this.saveConversation(conversationId, conversationData, result, context)];
|
|
272
|
+
case 2:
|
|
273
|
+
_b.sent();
|
|
274
|
+
FlinkLog_1.log.debug("[".concat(this.id, "] Saved conversation ").concat(conversationId, ": ").concat(messages.length, " messages, metadata=").concat(JSON.stringify(providerMetadata)));
|
|
275
|
+
return [3 /*break*/, 4];
|
|
276
|
+
case 3:
|
|
277
|
+
error_2 = _b.sent();
|
|
278
|
+
// Log but don't throw - request already succeeded, don't fail it now
|
|
279
|
+
FlinkLog_1.log.error("[".concat(this.id, "] Failed to save conversation ").concat(conversationId, ":"), error_2);
|
|
280
|
+
return [3 /*break*/, 4];
|
|
281
|
+
case 4: return [2 /*return*/];
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
/**
|
|
287
|
+
* Convert storage messages back to agent Message format for input.history.
|
|
288
|
+
*
|
|
289
|
+
* @param storageMessages - Messages from storage in StorageMessage format
|
|
290
|
+
* @returns Message array compatible with AgentExecuteInput.history
|
|
291
|
+
*
|
|
292
|
+
* @internal
|
|
293
|
+
*/
|
|
294
|
+
PersistentFlinkAgent.prototype.convertToAgentMessages = function (storageMessages) {
|
|
295
|
+
return storageMessages.map(function (msg) {
|
|
296
|
+
if (msg.role === "user") {
|
|
297
|
+
return { role: "user", content: msg.content || "" };
|
|
298
|
+
}
|
|
299
|
+
else if (msg.role === "assistant") {
|
|
300
|
+
return {
|
|
301
|
+
role: "assistant",
|
|
302
|
+
content: msg.content || "",
|
|
303
|
+
toolCalls: msg.toolCalls,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
else if (msg.role === "tool" && msg.toolResults && msg.toolResults.length > 0) {
|
|
307
|
+
// Tool results stored in storage format, convert to agent format
|
|
308
|
+
var toolResult = msg.toolResults[0]; // Take first result
|
|
309
|
+
return {
|
|
310
|
+
role: "tool",
|
|
311
|
+
toolCallId: toolResult.id,
|
|
312
|
+
toolName: "", // Not stored, but required by type
|
|
313
|
+
result: JSON.stringify(toolResult.result),
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
// Fallback for unexpected cases
|
|
318
|
+
return { role: "user", content: msg.content || "" };
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
};
|
|
322
|
+
/**
|
|
323
|
+
* Convert LLM adapter messages to storage format for persistence.
|
|
324
|
+
*
|
|
325
|
+
* @param llmMessages - Messages from LLM adapter in their native format
|
|
326
|
+
* @returns StorageMessage array
|
|
327
|
+
*
|
|
328
|
+
* @internal
|
|
329
|
+
*/
|
|
330
|
+
PersistentFlinkAgent.prototype.convertToMessages = function (llmMessages) {
|
|
331
|
+
var _this = this;
|
|
332
|
+
return llmMessages.map(function (msg) {
|
|
333
|
+
var message = {
|
|
334
|
+
role: msg.role,
|
|
335
|
+
};
|
|
336
|
+
// Handle content blocks
|
|
337
|
+
if (Array.isArray(msg.content)) {
|
|
338
|
+
var text = _this.extractTextFromBlocks(msg.content);
|
|
339
|
+
if (text)
|
|
340
|
+
message.content = text;
|
|
341
|
+
var toolCalls = _this.extractToolCalls(msg.content);
|
|
342
|
+
if (toolCalls.length > 0)
|
|
343
|
+
message.toolCalls = toolCalls;
|
|
344
|
+
var toolResults = _this.extractToolResults(msg.content);
|
|
345
|
+
if (toolResults.length > 0)
|
|
346
|
+
message.toolResults = toolResults;
|
|
347
|
+
}
|
|
348
|
+
else if (typeof msg.content === "string") {
|
|
349
|
+
message.content = msg.content;
|
|
350
|
+
}
|
|
351
|
+
return message;
|
|
352
|
+
});
|
|
353
|
+
};
|
|
354
|
+
/**
|
|
355
|
+
* Extract text content from message content blocks.
|
|
356
|
+
*
|
|
357
|
+
* @param blocks - Content blocks from LLM message
|
|
358
|
+
* @returns Concatenated text content, or undefined if no text blocks
|
|
359
|
+
*
|
|
360
|
+
* @internal
|
|
361
|
+
*/
|
|
362
|
+
PersistentFlinkAgent.prototype.extractTextFromBlocks = function (blocks) {
|
|
363
|
+
var textBlocks = blocks.filter(function (block) { return block.type === "text"; });
|
|
364
|
+
if (textBlocks.length === 0)
|
|
365
|
+
return undefined;
|
|
366
|
+
return textBlocks.map(function (block) { return block.text; }).join("");
|
|
367
|
+
};
|
|
368
|
+
/**
|
|
369
|
+
* Extract tool calls from message content blocks.
|
|
370
|
+
*
|
|
371
|
+
* @param blocks - Content blocks from LLM message
|
|
372
|
+
* @returns Array of tool call objects
|
|
373
|
+
*
|
|
374
|
+
* @internal
|
|
375
|
+
*/
|
|
376
|
+
PersistentFlinkAgent.prototype.extractToolCalls = function (blocks) {
|
|
377
|
+
return blocks
|
|
378
|
+
.filter(function (block) { return block.type === "tool_use"; })
|
|
379
|
+
.map(function (block) { return ({
|
|
380
|
+
id: block.id,
|
|
381
|
+
name: block.name,
|
|
382
|
+
input: block.input,
|
|
383
|
+
}); });
|
|
384
|
+
};
|
|
385
|
+
/**
|
|
386
|
+
* Extract tool results from message content blocks.
|
|
387
|
+
*
|
|
388
|
+
* @param blocks - Content blocks from LLM message
|
|
389
|
+
* @returns Array of tool result objects
|
|
390
|
+
*
|
|
391
|
+
* @internal
|
|
392
|
+
*/
|
|
393
|
+
PersistentFlinkAgent.prototype.extractToolResults = function (blocks) {
|
|
394
|
+
return blocks
|
|
395
|
+
.filter(function (block) { return block.type === "tool_result"; })
|
|
396
|
+
.map(function (block) { return ({
|
|
397
|
+
id: block.tool_use_id,
|
|
398
|
+
result: block.content,
|
|
399
|
+
}); });
|
|
400
|
+
};
|
|
401
|
+
return PersistentFlinkAgent;
|
|
402
|
+
}(FlinkAgent_1.FlinkAgent));
|
|
403
|
+
exports.PersistentFlinkAgent = PersistentFlinkAgent;
|