@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.
Files changed (280) hide show
  1. package/CHANGELOG.md +1051 -0
  2. package/SCHEMA_EXTRACTION_ANALYSIS.md +494 -0
  3. package/SIMPLE_AST_FEASIBILITY.md +570 -0
  4. package/bin/flink.ts +13 -2
  5. package/cli/build.ts +24 -44
  6. package/cli/clean.ts +13 -25
  7. package/cli/cli-utils.ts +190 -17
  8. package/cli/dev.ts +252 -0
  9. package/cli/loadEnvFiles.ts +116 -0
  10. package/cli/run.ts +45 -62
  11. package/dist/bin/flink.js +61 -2
  12. package/dist/cli/build.js +20 -25
  13. package/dist/cli/clean.js +12 -10
  14. package/dist/cli/cli-utils.d.ts +34 -3
  15. package/dist/cli/cli-utils.js +193 -12
  16. package/dist/cli/dev.d.ts +2 -0
  17. package/dist/cli/dev.js +279 -0
  18. package/dist/cli/loadEnvFiles.d.ts +30 -0
  19. package/dist/cli/loadEnvFiles.js +113 -0
  20. package/dist/cli/run.js +47 -46
  21. package/dist/src/DependencyTracker.d.ts +44 -0
  22. package/dist/src/DependencyTracker.js +239 -0
  23. package/dist/src/FlinkApp.d.ts +163 -10
  24. package/dist/src/FlinkApp.js +847 -184
  25. package/dist/src/FlinkContext.d.ts +41 -0
  26. package/dist/src/FlinkErrors.d.ts +19 -6
  27. package/dist/src/FlinkErrors.js +36 -42
  28. package/dist/src/FlinkHttpHandler.d.ts +219 -26
  29. package/dist/src/FlinkHttpHandler.js +37 -1
  30. package/dist/src/FlinkJob.d.ts +10 -0
  31. package/dist/src/FlinkLog.d.ts +82 -18
  32. package/dist/src/FlinkLog.js +165 -13
  33. package/dist/src/FlinkLogFactory.d.ts +288 -0
  34. package/dist/src/FlinkLogFactory.js +619 -0
  35. package/dist/src/FlinkRepo.d.ts +10 -2
  36. package/dist/src/FlinkRepo.js +11 -1
  37. package/dist/src/FlinkRequestContext.d.ts +63 -0
  38. package/dist/src/FlinkRequestContext.js +74 -0
  39. package/dist/src/FlinkResponse.d.ts +6 -0
  40. package/dist/src/FlinkService.d.ts +38 -0
  41. package/dist/src/FlinkService.js +46 -0
  42. package/dist/src/LeaderElection.d.ts +45 -0
  43. package/dist/src/LeaderElection.js +269 -0
  44. package/dist/src/SchemaCache.d.ts +84 -0
  45. package/dist/src/SchemaCache.js +289 -0
  46. package/dist/src/TypeScriptCompiler.d.ts +161 -51
  47. package/dist/src/TypeScriptCompiler.js +1253 -617
  48. package/dist/src/TypeScriptUtils.js +4 -0
  49. package/dist/src/ai/AgentRunner.d.ts +39 -0
  50. package/dist/src/ai/AgentRunner.js +760 -0
  51. package/dist/src/ai/ConversationAgent.d.ts +279 -0
  52. package/dist/src/ai/ConversationAgent.js +404 -0
  53. package/dist/src/ai/ConversationFlinkAgent.d.ts +278 -0
  54. package/dist/src/ai/ConversationFlinkAgent.js +404 -0
  55. package/dist/src/ai/FlinkAgent.d.ts +690 -0
  56. package/dist/src/ai/FlinkAgent.js +729 -0
  57. package/dist/src/ai/FlinkTool.d.ts +135 -0
  58. package/dist/src/ai/FlinkTool.js +2 -0
  59. package/dist/src/ai/InMemoryConversationAgent.d.ts +121 -0
  60. package/dist/src/ai/InMemoryConversationAgent.js +209 -0
  61. package/dist/src/ai/LLMAdapter.d.ts +148 -0
  62. package/dist/src/ai/LLMAdapter.js +2 -0
  63. package/dist/src/ai/PersistentFlinkAgent.d.ts +278 -0
  64. package/dist/src/ai/PersistentFlinkAgent.js +403 -0
  65. package/dist/src/ai/SubAgentExecutor.d.ts +38 -0
  66. package/dist/src/ai/SubAgentExecutor.js +223 -0
  67. package/dist/src/ai/ToolExecutor.d.ts +64 -0
  68. package/dist/src/ai/ToolExecutor.js +497 -0
  69. package/dist/src/ai/agentInstructions.d.ts +68 -0
  70. package/dist/src/ai/agentInstructions.js +286 -0
  71. package/dist/src/ai/index.d.ts +8 -0
  72. package/dist/src/ai/index.js +26 -0
  73. package/dist/src/ai/instructionFileLoader.d.ts +44 -0
  74. package/dist/src/ai/instructionFileLoader.js +179 -0
  75. package/dist/src/auth/FlinkAuthPlugin.d.ts +1 -1
  76. package/dist/src/handlers/StreamWriterFactory.d.ts +20 -0
  77. package/dist/src/handlers/StreamWriterFactory.js +83 -0
  78. package/dist/src/index.d.ts +14 -0
  79. package/dist/src/index.js +17 -0
  80. package/dist/src/loadPluginSchemas.d.ts +45 -0
  81. package/dist/src/loadPluginSchemas.js +143 -0
  82. package/dist/src/schema-extraction/ComplexTypeDetection.d.ts +40 -0
  83. package/dist/src/schema-extraction/ComplexTypeDetection.js +75 -0
  84. package/dist/src/schema-extraction/TypeScriptSourceParser.d.ts +321 -0
  85. package/dist/src/schema-extraction/TypeScriptSourceParser.js +925 -0
  86. package/dist/src/schema-extraction/TypeScriptSourceParser.spec.d.ts +1 -0
  87. package/dist/src/schema-extraction/TypeScriptSourceParser.spec.js +233 -0
  88. package/dist/src/schema-extraction/TypeScriptTokenizer.d.ts +57 -0
  89. package/dist/src/schema-extraction/TypeScriptTokenizer.js +177 -0
  90. package/dist/src/schema-extraction/index.d.ts +2 -0
  91. package/dist/src/schema-extraction/index.js +20 -0
  92. package/dist/src/schema-extraction/types.d.ts +31 -0
  93. package/dist/src/schema-extraction/types.js +2 -0
  94. package/dist/src/utils/loadFlinkConfig.d.ts +53 -0
  95. package/dist/src/utils/loadFlinkConfig.js +77 -0
  96. package/dist/src/utils.d.ts +30 -0
  97. package/dist/src/utils.js +52 -0
  98. package/dist/src/workers/SchemaGeneratorWorker.d.ts +1 -0
  99. package/dist/src/workers/SchemaGeneratorWorker.js +49 -0
  100. package/dist/src/workers/WorkerPool.d.ts +60 -0
  101. package/dist/src/workers/WorkerPool.js +306 -0
  102. package/examples/logging-hierarchical-example.ts +125 -0
  103. package/package.json +29 -4
  104. package/readme.md +499 -0
  105. package/spec/AgentDescendantDetection.spec.ts +335 -0
  106. package/spec/AgentDuplicateDetection.spec.ts +112 -0
  107. package/spec/AgentObserver.spec.ts +266 -0
  108. package/spec/AgentRunner.spec.ts +1062 -0
  109. package/spec/AsyncLocalStorageContext.spec.ts +223 -0
  110. package/spec/ConversationHooks.spec.ts +257 -0
  111. package/spec/FlinkAgent.spec.ts +681 -0
  112. package/spec/FlinkApp.htmlResponse.spec.ts +260 -0
  113. package/spec/FlinkApp.onError.invocation.spec.ts +151 -0
  114. package/spec/FlinkApp.onError.spec.ts +1 -2
  115. package/spec/FlinkApp.query.spec.ts +107 -0
  116. package/spec/FlinkApp.routeOrdering.spec.ts +61 -0
  117. package/spec/FlinkApp.undefinedResponse.spec.ts +123 -0
  118. package/spec/FlinkApp.validationMode.spec.ts +155 -0
  119. package/spec/FlinkJob.spec.ts +171 -0
  120. package/spec/FlinkLogFactory.spec.ts +337 -0
  121. package/spec/FlinkRepo.spec.ts +1 -1
  122. package/spec/LeaderElection.spec.ts +174 -0
  123. package/spec/StreamingIntegration.spec.ts +139 -0
  124. package/spec/ToolExecutor.spec.ts +465 -0
  125. package/spec/TypeScriptCompiler.spec.ts +1 -1
  126. package/spec/TypeScriptSourceParser.spec.ts +1215 -0
  127. package/spec/TypeScriptTokenizer.spec.ts +366 -0
  128. package/spec/ai/ContextCompaction.spec.ts +405 -0
  129. package/spec/ai/ConversationAgent.spec.ts +520 -0
  130. package/spec/ai/InMemoryConversationAgent.spec.ts +144 -0
  131. package/spec/ai/agentInstructions.spec.ts +358 -0
  132. package/spec/fixtures/agent-instructions/TestAgent.ts +24 -0
  133. package/spec/fixtures/agent-instructions/simple.md +3 -0
  134. package/spec/fixtures/agent-instructions/template.md +18 -0
  135. package/spec/fixtures/agent-instructions/yaml-format.yaml +9 -0
  136. package/spec/mock-project/dist/.tsbuildinfo +1 -0
  137. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar.js +56 -0
  138. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar2.js +58 -0
  139. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema.js +52 -0
  140. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema2.js +52 -0
  141. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema3.js +52 -0
  142. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema.js +54 -0
  143. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema2.js +54 -0
  144. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile.js +57 -0
  145. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile2.js +57 -0
  146. package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler.js +53 -0
  147. package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler2.js +55 -0
  148. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchCar.js +57 -0
  149. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOnboardingSession.js +75 -0
  150. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOrderWithComplexTypes.js +57 -0
  151. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchProductWithIntersection.js +58 -0
  152. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchUserWithUnion.js +58 -0
  153. package/spec/mock-project/dist/spec/mock-project/src/handlers/PostCar.js +54 -0
  154. package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogin.js +55 -0
  155. package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogout.js +54 -0
  156. package/spec/mock-project/dist/spec/mock-project/src/handlers/PutCar.js +54 -0
  157. package/spec/mock-project/dist/spec/mock-project/src/index.js +83 -0
  158. package/spec/mock-project/dist/spec/mock-project/src/repos/CarRepo.js +26 -0
  159. package/spec/mock-project/dist/spec/mock-project/src/schemas/Car.js +2 -0
  160. package/spec/mock-project/dist/spec/mock-project/src/schemas/DefaultExportSchema.js +2 -0
  161. package/spec/mock-project/dist/spec/mock-project/src/schemas/FileWithTwoSchemas.js +2 -0
  162. package/spec/mock-project/dist/src/FlinkApp.js +1000 -0
  163. package/spec/mock-project/dist/src/FlinkContext.js +2 -0
  164. package/spec/mock-project/dist/src/FlinkErrors.js +143 -0
  165. package/spec/mock-project/dist/src/FlinkHttpHandler.js +47 -0
  166. package/spec/mock-project/dist/src/FlinkJob.js +2 -0
  167. package/spec/mock-project/dist/src/FlinkLog.js +119 -0
  168. package/spec/mock-project/dist/src/FlinkLogFactory.js +617 -0
  169. package/spec/mock-project/dist/src/FlinkPlugin.js +2 -0
  170. package/spec/mock-project/dist/src/FlinkRepo.js +224 -0
  171. package/spec/mock-project/dist/src/FlinkRequestContext.js +74 -0
  172. package/spec/mock-project/dist/src/FlinkResponse.js +2 -0
  173. package/spec/mock-project/dist/src/ai/AgentExecutor.js +279 -0
  174. package/spec/mock-project/dist/src/ai/AgentRunner.js +632 -0
  175. package/spec/mock-project/dist/src/ai/ConversationAgent.js +402 -0
  176. package/spec/mock-project/dist/src/ai/ConversationFlinkAgent.js +422 -0
  177. package/spec/mock-project/dist/src/ai/FlinkAgent.js +699 -0
  178. package/spec/mock-project/dist/src/ai/FlinkTool.js +2 -0
  179. package/spec/mock-project/dist/src/ai/InMemoryConversationAgent.js +209 -0
  180. package/spec/mock-project/dist/src/ai/LLMAdapter.js +2 -0
  181. package/spec/mock-project/dist/src/ai/SubAgentExecutor.js +223 -0
  182. package/spec/mock-project/dist/src/ai/ToolExecutor.js +412 -0
  183. package/spec/mock-project/dist/src/ai/agentInstructions.js +246 -0
  184. package/spec/mock-project/dist/src/auth/FlinkAuthPlugin.js +2 -0
  185. package/spec/mock-project/dist/src/auth/FlinkAuthUser.js +2 -0
  186. package/spec/mock-project/dist/src/handlers/GetCar.js +26 -52
  187. package/spec/mock-project/dist/src/handlers/GetCar.js.map +1 -0
  188. package/spec/mock-project/dist/src/handlers/GetCar2.js +32 -54
  189. package/spec/mock-project/dist/src/handlers/GetCar2.js.map +1 -0
  190. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js +26 -48
  191. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js.map +1 -0
  192. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js +28 -48
  193. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js.map +1 -0
  194. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js +29 -48
  195. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js.map +1 -0
  196. package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js +26 -50
  197. package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js.map +1 -0
  198. package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js +28 -50
  199. package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js.map +1 -0
  200. package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js +27 -53
  201. package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js.map +1 -0
  202. package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js +29 -53
  203. package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js.map +1 -0
  204. package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js +16 -49
  205. package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js.map +1 -0
  206. package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js +25 -50
  207. package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js.map +1 -0
  208. package/spec/mock-project/dist/src/handlers/PatchCar.js +27 -53
  209. package/spec/mock-project/dist/src/handlers/PatchCar.js.map +1 -0
  210. package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js +44 -70
  211. package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js.map +1 -0
  212. package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js +27 -53
  213. package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js.map +1 -0
  214. package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js +28 -54
  215. package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js.map +1 -0
  216. package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js +28 -54
  217. package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js.map +1 -0
  218. package/spec/mock-project/dist/src/handlers/PostCar.js +24 -50
  219. package/spec/mock-project/dist/src/handlers/PostCar.js.map +1 -0
  220. package/spec/mock-project/dist/src/handlers/PostLogin.js +25 -51
  221. package/spec/mock-project/dist/src/handlers/PostLogin.js.map +1 -0
  222. package/spec/mock-project/dist/src/handlers/PostLogout.js +24 -50
  223. package/spec/mock-project/dist/src/handlers/PostLogout.js.map +1 -0
  224. package/spec/mock-project/dist/src/handlers/PutCar.js +24 -50
  225. package/spec/mock-project/dist/src/handlers/PutCar.js.map +1 -0
  226. package/spec/mock-project/dist/src/handlers/StreamWriterFactory.js +83 -0
  227. package/spec/mock-project/dist/src/index.js +52 -76
  228. package/spec/mock-project/dist/src/index.js.map +1 -0
  229. package/spec/mock-project/dist/src/mock-data-generator.js +9 -0
  230. package/spec/mock-project/dist/src/repos/CarRepo.js +12 -24
  231. package/spec/mock-project/dist/src/repos/CarRepo.js.map +1 -0
  232. package/spec/mock-project/dist/src/schemas/Car.js +3 -1
  233. package/spec/mock-project/dist/src/schemas/Car.js.map +1 -0
  234. package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js +3 -1
  235. package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js.map +1 -0
  236. package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js +3 -1
  237. package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js.map +1 -0
  238. package/spec/mock-project/dist/src/utils.js +290 -0
  239. package/spec/mock-project/tsconfig.json +6 -1
  240. package/spec/schema-generation-nested-objects.spec.ts +97 -0
  241. package/spec/testHelpers.ts +49 -0
  242. package/spec/utils.caseConversion.spec.ts +78 -0
  243. package/spec/utils.spec.ts +13 -13
  244. package/src/DependencyTracker.ts +166 -0
  245. package/src/FlinkApp.ts +919 -155
  246. package/src/FlinkContext.ts +43 -0
  247. package/src/FlinkErrors.ts +32 -12
  248. package/src/FlinkHttpHandler.ts +246 -28
  249. package/src/FlinkJob.ts +11 -0
  250. package/src/FlinkLog.ts +119 -12
  251. package/src/FlinkLogFactory.ts +699 -0
  252. package/src/FlinkRepo.ts +10 -3
  253. package/src/FlinkRequestContext.ts +95 -0
  254. package/src/FlinkResponse.ts +6 -0
  255. package/src/FlinkService.ts +49 -0
  256. package/src/LeaderElection.ts +203 -0
  257. package/src/SchemaCache.ts +232 -0
  258. package/src/TypeScriptCompiler.ts +1347 -610
  259. package/src/TypeScriptUtils.ts +5 -0
  260. package/src/ai/AgentRunner.ts +646 -0
  261. package/src/ai/ConversationAgent.ts +413 -0
  262. package/src/ai/FlinkAgent.ts +1069 -0
  263. package/src/ai/FlinkTool.ts +165 -0
  264. package/src/ai/InMemoryConversationAgent.ts +149 -0
  265. package/src/ai/LLMAdapter.ts +126 -0
  266. package/src/ai/ToolExecutor.ts +485 -0
  267. package/src/ai/agentInstructions.ts +245 -0
  268. package/src/ai/index.ts +8 -0
  269. package/src/ai/instructionFileLoader.ts +156 -0
  270. package/src/auth/FlinkAuthPlugin.ts +2 -1
  271. package/src/handlers/StreamWriterFactory.ts +84 -0
  272. package/src/index.ts +14 -0
  273. package/src/loadPluginSchemas.ts +141 -0
  274. package/src/schema-extraction/TypeScriptSourceParser.ts +1058 -0
  275. package/src/schema-extraction/TypeScriptTokenizer.ts +205 -0
  276. package/src/schema-extraction/index.ts +2 -0
  277. package/src/schema-extraction/types.ts +34 -0
  278. package/src/utils/loadFlinkConfig.ts +89 -0
  279. package/src/utils.ts +52 -0
  280. package/tsconfig.json +6 -1
@@ -0,0 +1,690 @@
1
+ import { FlinkContext } from "../FlinkContext";
2
+ import { FlinkToolFile, FlinkToolProps } from "./FlinkTool";
3
+ import { type InstructionsReturn } from "./instructionFileLoader";
4
+ export type { InstructionsReturn } from "./instructionFileLoader";
5
+ import { LLMContentBlock, LLMMessage } from "./LLMAdapter";
6
+ import { ToolExecutor } from "./ToolExecutor";
7
+ /**
8
+ * Callback function for dynamic instruction generation
9
+ * Receives agent context and execution context to build custom instructions
10
+ *
11
+ * @param ctx - FlinkContext with access to repos, plugins, etc.
12
+ * @param agentContext - AgentExecuteContext with user, conversationId, metadata, etc.
13
+ * @returns Instructions string (can be async)
14
+ *
15
+ * @example
16
+ * const instructions = async (ctx, agentContext) => {
17
+ * const profile = await ctx.repos.userRepo.getById(agentContext.user.id);
18
+ * return `You are a support agent. Customer tier: ${profile.tier}`;
19
+ * };
20
+ */
21
+ export type InstructionsCallback<Ctx extends FlinkContext> = (ctx: Ctx, agentContext: AgentExecuteContext) => Promise<string> | string;
22
+ /**
23
+ * Agent instructions can be either a static string or a dynamic callback
24
+ */
25
+ export type AgentInstructions<Ctx extends FlinkContext> = string | InstructionsCallback<Ctx>;
26
+ /**
27
+ * Callback to determine if history compaction is needed
28
+ * Called before each LLM call to check if messages should be compacted
29
+ *
30
+ * @param messages - Current conversation messages
31
+ * @param step - Current step number (1-indexed)
32
+ * @returns true if compaction should be performed
33
+ *
34
+ * @example Check message count
35
+ * shouldCompact: (messages) => messages.length > 20
36
+ *
37
+ * @example Check total size in bytes
38
+ * shouldCompact: (messages) => {
39
+ * const totalSize = JSON.stringify(messages).length;
40
+ * return totalSize > 100_000; // ~100KB
41
+ * }
42
+ *
43
+ * @example Estimate token count (rough: 1 token ≈ 4 chars)
44
+ * shouldCompact: (messages) => {
45
+ * const totalChars = messages.reduce((sum, m) => {
46
+ * if (typeof m.content === 'string') return sum + m.content.length;
47
+ * if (Array.isArray(m.content)) {
48
+ * return sum + m.content.reduce((s, block) => {
49
+ * if (block.type === 'text') return s + block.text.length;
50
+ * if (block.type === 'tool_result') return s + JSON.stringify(block.content).length;
51
+ * return s;
52
+ * }, 0);
53
+ * }
54
+ * return sum;
55
+ * }, 0);
56
+ * return totalChars > 60_000; // ~15k tokens
57
+ * }
58
+ */
59
+ export type ShouldCompactCallback = (messages: LLMMessage[], step: number) => boolean | Promise<boolean>;
60
+ /**
61
+ * Callback to compact conversation history
62
+ * Called when shouldCompact returns true
63
+ *
64
+ * @param messages - Current conversation messages to compact
65
+ * @param step - Current step number (1-indexed)
66
+ * @returns Compacted messages array (must not be empty)
67
+ *
68
+ * @example Sliding window (keep last N messages)
69
+ * compactHistory: (messages) => messages.slice(-10)
70
+ *
71
+ * @example Keep first message + last N (preserve initial context)
72
+ * compactHistory: (messages) => [messages[0], ...messages.slice(-8)]
73
+ *
74
+ * @example LLM-based summarization
75
+ * compactHistory: async (messages, step) => {
76
+ * const oldMessages = messages.slice(0, -5);
77
+ * const recentMessages = messages.slice(-5);
78
+ * const summary = await this.summarize(oldMessages);
79
+ * return [
80
+ * { role: "user", content: `[Summary: ${summary}]` },
81
+ * ...recentMessages
82
+ * ];
83
+ * }
84
+ */
85
+ export type CompactHistoryCallback = (messages: LLMMessage[], step: number) => Promise<LLMMessage[]> | LLMMessage[];
86
+ export interface FlinkAgentProps<Ctx extends FlinkContext> {
87
+ id: string;
88
+ description: string;
89
+ /**
90
+ * Instructions that define the agent's behavior and personality.
91
+ * Can be a static string or a callback function that generates dynamic instructions.
92
+ *
93
+ * @example Static instructions
94
+ * instructions: "You are a helpful customer support agent."
95
+ *
96
+ * @example Dynamic instructions
97
+ * instructions: async (ctx, agentContext) => {
98
+ * const user = await ctx.repos.userRepo.getById(agentContext.user.id);
99
+ * return `You are a support agent. Customer: ${user.name}, Tier: ${user.tier}`;
100
+ * }
101
+ */
102
+ instructions: string | InstructionsCallback<Ctx>;
103
+ tools?: Array<string | FlinkToolFile | FlinkToolProps>;
104
+ model?: {
105
+ /**
106
+ * ID of the LLM adapter to use (must be registered in FlinkOptions.ai.llmAdapters)
107
+ * Examples: "anthropic", "openai", "anthropic-eu", "gpt4", etc.
108
+ * Defaults to "default" if not specified
109
+ */
110
+ adapterId?: string;
111
+ maxTokens?: number;
112
+ temperature?: number;
113
+ };
114
+ limits?: {
115
+ maxSteps?: number;
116
+ timeoutMs?: number;
117
+ };
118
+ permissions?: string | string[] | ((user?: any) => boolean);
119
+ /**
120
+ * Callback to determine if history compaction is needed
121
+ * Called before each LLM call in the agentic loop
122
+ *
123
+ * When shouldCompact returns true, the framework calls compactHistory
124
+ * to reduce the message array size before the next LLM call
125
+ *
126
+ * If not provided, no compaction occurs (backward compatible)
127
+ */
128
+ shouldCompact?: ShouldCompactCallback;
129
+ /**
130
+ * Callback to compact conversation history
131
+ * Called when shouldCompact returns true
132
+ *
133
+ * Must return a non-empty array of messages
134
+ * If not provided but shouldCompact triggers, uses default strategy (keep last 10 messages)
135
+ */
136
+ compactHistory?: CompactHistoryCallback;
137
+ beforeRun?: (input: AgentExecuteInput<any>, context: AgentExecuteContext) => void | Promise<void>;
138
+ onStep?: (context: AgentStepContext) => void | Promise<void>;
139
+ afterRun?: (result: AgentExecuteResult, context: AgentFinishContext) => void | Promise<void>;
140
+ }
141
+ export type FlinkAgentFile<Ctx extends FlinkContext, ConversationCtx = any> = {
142
+ default?: new () => FlinkAgent<Ctx, ConversationCtx>;
143
+ __file?: string;
144
+ };
145
+ /**
146
+ * Base class for Flink agents (similar to FlinkRepo pattern)
147
+ *
148
+ * Agents extend this class and define their configuration as properties.
149
+ * Auto-registered by scanning src/agents/ directory.
150
+ *
151
+ * Tool references are validated at startup to ensure all referenced tools exist.
152
+ *
153
+ * Agents define their own domain-specific entry points that call `this.execute()`.
154
+ * This provides better type safety and developer experience than a generic `run()` method.
155
+ *
156
+ * ## Lifecycle Hooks
157
+ *
158
+ * Agents support lifecycle hooks for advanced orchestration:
159
+ * - `beforeRun`: Load conversation history, prepare context
160
+ * - `onStep`: Save state after each LLM turn
161
+ * - `afterRun`: Persist final conversation state
162
+ *
163
+ * ## Context Compaction
164
+ *
165
+ * Long-running agents can accumulate large message histories. Use context compaction
166
+ * to automatically manage history size during execution:
167
+ *
168
+ * ```typescript
169
+ * export default class MyAgent extends FlinkAgent<AppCtx> {
170
+ * id = "my-agent";
171
+ * description = "Agent with automatic context management";
172
+ * instructions = "You are a helpful assistant...";
173
+ *
174
+ * // Compact when history exceeds 20 messages
175
+ * shouldCompact = (messages) => messages.length > 20;
176
+ *
177
+ * // Keep only last 10 messages
178
+ * compactHistory = (messages) => messages.slice(-10);
179
+ * }
180
+ * ```
181
+ *
182
+ * Compaction happens before each LLM call in the agentic loop, ensuring consistent
183
+ * token usage and preventing context window overflow.
184
+ *
185
+ * Example:
186
+ * ```typescript
187
+ * import { Tool as GetCarsTool } from "./tools/GetCarsTool";
188
+ * import * as UpdateCarTool from "./tools/UpdateCarTool";
189
+ *
190
+ * export default class CarAgent extends FlinkAgent<AppCtx> {
191
+ * id = "car-agent"; // Optional: defaults to kebab-case class name "car-agent"
192
+ * description = "Expert in car models";
193
+ * instructions = "You are a car expert...";
194
+ * tools = [
195
+ * "get-cars-tool", // String ID reference
196
+ * GetCarsTool, // Direct FlinkToolProps import
197
+ * UpdateCarTool, // Tool file reference
198
+ * ];
199
+ *
200
+ * // Domain-specific entry points with proper types
201
+ * async searchByBrand(brand: string) {
202
+ * const response = this.run({
203
+ * message: `Find all ${brand} cars`
204
+ * });
205
+ * return await response.result;
206
+ * }
207
+ *
208
+ * async compareModels(model1: string, model2: string) {
209
+ * const response = this.run({
210
+ * message: `Compare ${model1} and ${model2}`
211
+ * });
212
+ * return await response.result;
213
+ * }
214
+ *
215
+ * // Lifecycle hook: Load conversation history
216
+ * protected async beforeRun(input, context) {
217
+ * if (context.conversationId) {
218
+ * const conv = await this.ctx.repos.conversationRepo.getById(context.conversationId);
219
+ * input.history = conv.messages;
220
+ * }
221
+ * }
222
+ * }
223
+ * ```
224
+ */
225
+ export declare abstract class FlinkAgent<Ctx extends FlinkContext, ConversationCtx = any> {
226
+ ctx: Ctx;
227
+ private runner?;
228
+ private _boundUser?;
229
+ private _boundUserPermissions?;
230
+ private _boundConversationContext?;
231
+ private _llmAdapters?;
232
+ private _tools?;
233
+ private _observer?;
234
+ abstract id: string;
235
+ abstract description: string;
236
+ /**
237
+ * Define the agent's instructions. Override this method in your agent subclass.
238
+ *
239
+ * `ctx` is automatically typed as your app's context — no annotation needed.
240
+ *
241
+ * Supported return values:
242
+ * - `string` — Plain text used as-is
243
+ * - `string` ending with a known text extension (`.md`, `.txt`, `.yaml`, `.yml`, `.xml`, …) — Auto-loaded from disk (project-root-relative)
244
+ * - `{ file, params? }` — Explicitly load a file (any extension) with optional Handlebars template params
245
+ *
246
+ * @example Plain text
247
+ * instructions() {
248
+ * return "You are a helpful car assistant.";
249
+ * }
250
+ *
251
+ * @example Dynamic instructions using ctx and agentContext
252
+ * async instructions(ctx, agentContext) {
253
+ * const user = await ctx.repos.userRepo.getById(agentContext.user?.id);
254
+ * return `You are a support agent for ${user.name}.`;
255
+ * }
256
+ *
257
+ * @example Auto-load file by extension (.md, .txt, .yaml, .yml, .xml, … — path relative to project root)
258
+ * instructions() {
259
+ * return "src/agents/instructions/car-agent.md";
260
+ * }
261
+ *
262
+ * @example File with template params
263
+ * async instructions(ctx, agentContext) {
264
+ * return {
265
+ * file: "src/agents/instructions/support.md",
266
+ * params: {
267
+ * customerTier: agentContext.user?.tier || "standard",
268
+ * isBusinessHours: new Date().getHours() >= 9,
269
+ * },
270
+ * };
271
+ * }
272
+ *
273
+ * @example Agent-file-relative path (use agentInstructions helper)
274
+ * instructions(ctx, agentContext) {
275
+ * return agentInstructions("./instructions/support.md", { date: new Date() })(ctx, agentContext);
276
+ * }
277
+ */
278
+ abstract instructions(ctx: Ctx, agentContext: AgentExecuteContext): Promise<InstructionsReturn> | InstructionsReturn;
279
+ tools?: Array<string | FlinkToolFile | FlinkToolProps>;
280
+ model?: {
281
+ adapterId?: string;
282
+ maxTokens?: number;
283
+ temperature?: number;
284
+ };
285
+ limits?: {
286
+ maxSteps?: number;
287
+ timeoutMs?: number;
288
+ };
289
+ permissions?: string | string[] | ((user?: any) => boolean);
290
+ protected shouldCompact?: ShouldCompactCallback;
291
+ protected compactHistory?: CompactHistoryCallback;
292
+ /**
293
+ * Internal initialization called by FlinkApp
294
+ * @internal
295
+ */
296
+ __init(llmAdapters: Map<string, any>, tools: {
297
+ [x: string]: ToolExecutor<Ctx>;
298
+ }, observer?: AgentObserver): void;
299
+ /**
300
+ * Bind a user to this agent for permission checks
301
+ *
302
+ * This creates a new agent instance with the user bound, allowing clean API:
303
+ * ```typescript
304
+ * const result = await ctx.agents.carAgent
305
+ * .withUser(req.user)
306
+ * .searchByBrand("Volvo");
307
+ * ```
308
+ *
309
+ * The bound user is used for:
310
+ * - Agent-level permission checks
311
+ * - Tool filtering (only allowed tools shown to LLM)
312
+ * - Tool-level permission checks
313
+ */
314
+ withUser(user: any): this;
315
+ /**
316
+ * Bind resolved permissions to this agent for permission checks
317
+ *
318
+ * This creates a new agent instance with permissions bound, allowing clean API:
319
+ * ```typescript
320
+ * const result = await ctx.agents.carAgent
321
+ * .withUser(req.user)
322
+ * .withPermissions(req.userPermissions) // Resolved permissions from auth plugin
323
+ * .searchByBrand("Volvo");
324
+ * ```
325
+ *
326
+ * The bound permissions are used for:
327
+ * - Tool filtering (only allowed tools shown to LLM)
328
+ * - Tool-level permission checks
329
+ *
330
+ * Permissions are typically populated by auth plugins during authentication
331
+ * based on roles, dynamic roles, or custom permission resolution.
332
+ */
333
+ withPermissions(userPermissions?: string[]): this;
334
+ /**
335
+ * Override the LLM adapter for this agent
336
+ *
337
+ * This creates a new agent instance with a different LLM adapter, allowing runtime selection:
338
+ * ```typescript
339
+ * const result = await ctx.agents.carAgent
340
+ * .withUser(req.user)
341
+ * .withLlm("fast") // Use fast LLM instead of default
342
+ * .searchByBrand("Volvo");
343
+ * ```
344
+ *
345
+ * The LLM adapter ID must be registered in FlinkApp's ai.llms configuration.
346
+ *
347
+ * @param adapterId - The ID of the LLM adapter to use (e.g., "default", "fake", "fast", "anthropic")
348
+ * @returns A new agent instance with the specified LLM adapter
349
+ */
350
+ withLlm(adapterId: string): this;
351
+ /**
352
+ * Bind conversation context to this agent for passing to tools
353
+ *
354
+ * This creates a new agent instance with the conversation context bound, allowing clean API:
355
+ * ```typescript
356
+ * const result = await ctx.agents.carAgent
357
+ * .withUser(req.user)
358
+ * .withConversationContext({ sessionId: req.session.id, featureFlags: req.flags })
359
+ * .searchByBrand("Volvo");
360
+ * ```
361
+ *
362
+ * The bound conversation context is used for:
363
+ * - Passing request-scoped data to tools
364
+ * - Sharing state between agent and tools without polluting global context
365
+ * - Propagating to sub-agents automatically
366
+ */
367
+ withConversationContext(conversationContext: ConversationCtx): this;
368
+ /**
369
+ * Public execution method for external callers (handlers, sub-agents, etc.)
370
+ *
371
+ * Use this when calling an agent from outside the agent class.
372
+ * For internal use within agent subclasses, use `execute()` instead.
373
+ */
374
+ run(input: AgentExecuteInput<ConversationCtx>): AgentResponse;
375
+ /**
376
+ * Internal execution method - supports both awaiting and streaming
377
+ *
378
+ * Uses lazy generator pattern (similar to Vercel AI SDK) to allow
379
+ * multiple consumption without re-execution.
380
+ *
381
+ * Agents call this method from their run() implementation to execute the AI logic.
382
+ *
383
+ * Examples:
384
+ * const response = this.execute({ message: "Hello" });
385
+ * const result = await response.result; // Await final result
386
+ * for await (const text of response.textStream) { ... } // Stream text
387
+ * for await (const chunk of response.fullStream) { ... } // Stream all events
388
+ */
389
+ protected execute(input: AgentExecuteInput<ConversationCtx>): AgentResponse;
390
+ /**
391
+ * Called before agent execution starts
392
+ * Use this to load conversation history, prepare context, etc.
393
+ *
394
+ * @example
395
+ * protected async beforeRun(input: AgentExecuteInput, context: AgentExecuteContext) {
396
+ * if (input.conversationId) {
397
+ * const conv = await this.ctx.repos.conversationRepo.getById(input.conversationId);
398
+ * input.history = conv?.messages;
399
+ * }
400
+ * }
401
+ */
402
+ protected beforeRun?(input: AgentExecuteInput<ConversationCtx>, context: AgentExecuteContext): void | Promise<void>;
403
+ /**
404
+ * Called after each step (LLM call + tool executions)
405
+ * Use this to save intermediate state, emit progress events, etc.
406
+ *
407
+ * @example
408
+ * protected async onStep(context: AgentStepContext) {
409
+ * if (context.conversationId) {
410
+ * await this.saveConversationState(context.conversationId, context.messages);
411
+ * }
412
+ * }
413
+ */
414
+ protected onStep?(context: AgentStepContext): void | Promise<void>;
415
+ /**
416
+ * Called when agent execution completes
417
+ * This is where you typically save the final conversation state
418
+ *
419
+ * @example
420
+ * protected async afterRun(result: AgentExecuteResult, context: AgentFinishContext) {
421
+ * if (context.conversationId && !context.isSubAgent) {
422
+ * await this.ctx.repos.conversationRepo.save({
423
+ * id: context.conversationId,
424
+ * messages: context.messages,
425
+ * result
426
+ * });
427
+ * }
428
+ * }
429
+ */
430
+ protected afterRun?(result: AgentExecuteResult, context: AgentFinishContext): void | Promise<void>;
431
+ /**
432
+ * Consume stream as final result (for await pattern)
433
+ */
434
+ private consumeAsResult;
435
+ /**
436
+ * Consume stream as text-only stream (for simple streaming UX)
437
+ */
438
+ private consumeAsTextStream;
439
+ private getRunner;
440
+ /**
441
+ * Get agent id - uses explicit id property or falls back to kebab-case class name
442
+ *
443
+ * Examples:
444
+ * - CarAgent → car-agent
445
+ * - APIAgent → api-agent
446
+ * - HTMLParserAgent → html-parser-agent
447
+ */
448
+ private getAgentId;
449
+ private toAgentProps;
450
+ private resolveTools;
451
+ private checkPermissionsSync;
452
+ }
453
+ /**
454
+ * Execution context shared across agent lifecycle hooks
455
+ */
456
+ export interface AgentExecuteContext {
457
+ agentId: string;
458
+ conversationId?: string;
459
+ user?: any;
460
+ metadata?: Record<string, any>;
461
+ conversationContext?: any;
462
+ }
463
+ /**
464
+ * Context for onStep hook - includes current conversation state
465
+ */
466
+ export interface AgentStepContext extends AgentExecuteContext {
467
+ step: number;
468
+ maxSteps: number;
469
+ messages: LLMMessage[];
470
+ }
471
+ /**
472
+ * Context for afterRun hook - includes final conversation and result
473
+ */
474
+ export interface AgentFinishContext extends AgentExecuteContext {
475
+ messages: LLMMessage[];
476
+ result: AgentExecuteResult;
477
+ }
478
+ /**
479
+ * Message structure for agent conversations
480
+ * Supports both simple strings and structured message arrays
481
+ */
482
+ export type Message = {
483
+ role: "user";
484
+ content: string;
485
+ } | {
486
+ role: "assistant";
487
+ content: string;
488
+ toolCalls?: ToolCall[];
489
+ } | {
490
+ role: "tool";
491
+ toolCallId: string;
492
+ toolName: string;
493
+ result: string;
494
+ };
495
+ export interface ToolCall {
496
+ id: string;
497
+ name: string;
498
+ input: any;
499
+ }
500
+ export interface AgentExecuteInput<ConversationCtx = any> {
501
+ message: string | LLMContentBlock[] | Message[];
502
+ user?: any;
503
+ userPermissions?: string[];
504
+ /**
505
+ * Optional ID for tracking multi-turn conversations
506
+ * Used in lifecycle hooks (beforeRun/onStep/afterRun) to load/save conversation state
507
+ * @example "conv_abc123" - caller-provided ID to persist conversation history
508
+ */
509
+ conversationId?: string;
510
+ /**
511
+ * Transient, conversation-scoped data that flows from agent to tools
512
+ * Examples: session IDs, feature flags, request tracing, tenant config
513
+ * Typed by agent's ConversationCtx parameter
514
+ */
515
+ conversationContext?: ConversationCtx;
516
+ /**
517
+ * Previous conversation messages for context, in chronological order (oldest first).
518
+ * The new `message` will be appended after these history messages.
519
+ * Agent can load this in beforeRun hook based on conversationId.
520
+ */
521
+ history?: Message[];
522
+ /**
523
+ * Provider-specific metadata for optimizations like server-side persistence
524
+ *
525
+ * Examples:
526
+ * - OpenAI Responses API: `{ openai: { previousResponseId: "resp_123" } }`
527
+ * - Anthropic: `{ anthropic: { ... } }`
528
+ *
529
+ * When provided, adapters may use this instead of full history for better performance
530
+ */
531
+ providerMetadata?: Record<string, any>;
532
+ /**
533
+ * Arbitrary metadata that flows through the execution
534
+ * Available in all callbacks
535
+ */
536
+ metadata?: Record<string, any>;
537
+ options?: {
538
+ maxSteps?: number;
539
+ timeoutMs?: number;
540
+ };
541
+ }
542
+ export interface AgentExecuteResult {
543
+ /**
544
+ * Framework-generated unique ID for this agent execution.
545
+ * Matches the `runId` emitted in AgentObserver events, enabling apps to
546
+ * correlate persisted results with observer traces.
547
+ */
548
+ runId: string;
549
+ message: string;
550
+ toolCalls: Array<{
551
+ name: string;
552
+ input: any;
553
+ output: any;
554
+ error?: string;
555
+ }>;
556
+ stepsUsed: number;
557
+ usage?: import("./LLMAdapter").LLMUsage;
558
+ stoppedEarly: boolean;
559
+ /**
560
+ * Provider-specific metadata for conversation continuation
561
+ *
562
+ * Examples:
563
+ * - OpenAI Responses API: `{ openai: { responseId: "resp_123" } }`
564
+ * - Anthropic: `{ anthropic: { ... } }`
565
+ *
566
+ * Use this for next turn's `providerMetadata` input for optimized server-side history
567
+ */
568
+ providerMetadata?: Record<string, any>;
569
+ }
570
+ /**
571
+ * Stream chunk types for different streaming events
572
+ *
573
+ * Phase 1: Only "complete" event is emitted
574
+ * Phase 2: Will emit real-time "text_delta", "tool_call_start", and "tool_call_result" events
575
+ */
576
+ export type StreamChunk = {
577
+ type: "text_delta";
578
+ delta: string;
579
+ } | {
580
+ type: "tool_call_start";
581
+ toolCall: ToolCall;
582
+ } | {
583
+ type: "tool_call_result";
584
+ toolCall: ToolCall;
585
+ output: any;
586
+ error?: string;
587
+ } | {
588
+ type: "complete";
589
+ result: AgentExecuteResult;
590
+ };
591
+ /**
592
+ * Unified response that supports both awaiting and streaming
593
+ */
594
+ export interface AgentResponse {
595
+ result: Promise<AgentExecuteResult>;
596
+ textStream: AsyncGenerator<string>;
597
+ fullStream: AsyncGenerator<StreamChunk>;
598
+ }
599
+ /**
600
+ * Event fired once per agent execution, before the first LLM call.
601
+ * Contains the resolved system instructions and the initial message array
602
+ * (post-history, pre-compaction, pre-tool-filtering).
603
+ */
604
+ export interface AgentObserverRunEvent {
605
+ runId: string;
606
+ agentId: string;
607
+ instructions: string;
608
+ input: AgentExecuteInput;
609
+ messages: LLMMessage[];
610
+ tools: string[];
611
+ model: {
612
+ adapterId?: string;
613
+ maxTokens?: number;
614
+ temperature?: number;
615
+ };
616
+ context: AgentExecuteContext;
617
+ }
618
+ /**
619
+ * Event fired immediately before each LLM call in the agentic loop.
620
+ * Reflects the messages and tools actually sent to the model after
621
+ * compaction and per-step permission filtering.
622
+ */
623
+ export interface AgentObserverLlmCallEvent {
624
+ runId: string;
625
+ agentId: string;
626
+ step: number;
627
+ maxSteps: number;
628
+ instructions: string;
629
+ messages: LLMMessage[];
630
+ tools: string[];
631
+ model: {
632
+ adapterId?: string;
633
+ maxTokens?: number;
634
+ temperature?: number;
635
+ };
636
+ context: AgentExecuteContext;
637
+ }
638
+ /**
639
+ * Event fired after each step (LLM call + tool executions) completes.
640
+ * `toolCalls` contains only the tool calls executed during this step.
641
+ */
642
+ export interface AgentObserverStepEvent {
643
+ runId: string;
644
+ agentId: string;
645
+ step: number;
646
+ maxSteps: number;
647
+ messages: LLMMessage[];
648
+ assistantText?: string;
649
+ toolCalls: AgentExecuteResult["toolCalls"];
650
+ usage?: import("./LLMAdapter").LLMUsage;
651
+ context: AgentExecuteContext;
652
+ }
653
+ /**
654
+ * Event fired when an agent execution completes (successfully or with error).
655
+ * On error, `result` contains whatever was accumulated before the throw.
656
+ */
657
+ export interface AgentObserverFinishEvent {
658
+ runId: string;
659
+ agentId: string;
660
+ result: AgentExecuteResult;
661
+ messages: LLMMessage[];
662
+ durationMs: number;
663
+ error?: string;
664
+ context: AgentExecuteContext;
665
+ }
666
+ /**
667
+ * Global agent observer for app-level tracing, APM, cost accounting, dev tools, etc.
668
+ *
669
+ * Register once on `FlinkOptions.ai.observer`; fires for every agent execution in the app.
670
+ *
671
+ * Observer callbacks are invoked fire-and-forget: they may return a Promise but the
672
+ * framework does not await them, and any thrown/rejected errors are caught and logged
673
+ * without affecting agent execution. Observers are read-only — they must not mutate
674
+ * inputs, messages, or results. Use the per-agent `beforeRun`/`onStep`/`afterRun` hooks
675
+ * for business logic that needs to block or mutate.
676
+ *
677
+ * Typical use cases:
678
+ * - Persisted traces for a dev tools page (correlate via `context.metadata`)
679
+ * - OpenTelemetry / Sentry integration
680
+ * - Cost accounting and token-usage dashboards
681
+ *
682
+ * All events share a stable `runId` per execution so persisted records can be joined
683
+ * across events. The same `runId` is returned on `AgentExecuteResult.runId`.
684
+ */
685
+ export interface AgentObserver {
686
+ onRun?(event: AgentObserverRunEvent): void | Promise<void>;
687
+ onLlmCall?(event: AgentObserverLlmCallEvent): void | Promise<void>;
688
+ onStep?(event: AgentObserverStepEvent): void | Promise<void>;
689
+ onFinish?(event: AgentObserverFinishEvent): void | Promise<void>;
690
+ }