@illuma-ai/agents 1.0.89 → 1.0.93
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/dist/cjs/agents/AgentContext.cjs +98 -49
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/constants.cjs +25 -0
- package/dist/cjs/common/constants.cjs.map +1 -0
- package/dist/cjs/common/enum.cjs +30 -0
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/events.cjs +9 -4
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +397 -92
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +223 -92
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/instrumentation.cjs +30 -14
- package/dist/cjs/instrumentation.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/index.cjs +43 -11
- package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +10 -7
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +32 -0
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/tools.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +129 -101
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +489 -0
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -0
- package/dist/cjs/llm/bedrock/utils/message_outputs.cjs +176 -0
- package/dist/cjs/llm/bedrock/utils/message_outputs.cjs.map +1 -0
- package/dist/cjs/llm/fake.cjs.map +1 -1
- package/dist/cjs/llm/google/index.cjs.map +1 -1
- package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +1 -1
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/index.cjs +59 -5
- package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
- package/dist/cjs/llm/providers.cjs.map +1 -1
- package/dist/cjs/llm/text.cjs.map +1 -1
- package/dist/cjs/llm/vertexai/index.cjs +80 -2
- package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +60 -27
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/cache.cjs +131 -108
- package/dist/cjs/messages/cache.cjs.map +1 -1
- package/dist/cjs/messages/content.cjs.map +1 -1
- package/dist/cjs/messages/core.cjs +3 -0
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +265 -47
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/ids.cjs.map +1 -1
- package/dist/cjs/messages/prune.cjs +55 -2
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/messages/summarize.cjs +170 -0
- package/dist/cjs/messages/summarize.cjs.map +1 -0
- package/dist/cjs/messages/tools.cjs.map +1 -1
- package/dist/cjs/run.cjs +87 -30
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/schemas/validate.cjs.map +1 -1
- package/dist/cjs/splitStream.cjs.map +1 -1
- package/dist/cjs/stream.cjs +59 -25
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/AskUser.cjs +131 -0
- package/dist/cjs/tools/AskUser.cjs.map +1 -0
- package/dist/cjs/tools/BrowserTools.cjs +11 -7
- package/dist/cjs/tools/BrowserTools.cjs.map +1 -1
- package/dist/cjs/tools/Calculator.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +46 -4
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +36 -53
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/StreamingToolCallBuffer.cjs +208 -0
- package/dist/cjs/tools/StreamingToolCallBuffer.cjs.map +1 -0
- package/dist/cjs/tools/ToolNode.cjs +333 -30
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearch.cjs +66 -30
- package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
- package/dist/cjs/tools/handlers.cjs +94 -8
- package/dist/cjs/tools/handlers.cjs.map +1 -1
- package/dist/cjs/tools/schema.cjs.map +1 -1
- package/dist/cjs/tools/search/content.cjs.map +1 -1
- package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
- package/dist/cjs/tools/search/format.cjs.map +1 -1
- package/dist/cjs/tools/search/highlights.cjs.map +1 -1
- package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
- package/dist/cjs/tools/search/schema.cjs.map +1 -1
- package/dist/cjs/tools/search/search.cjs +1 -0
- package/dist/cjs/tools/search/search.cjs.map +1 -1
- package/dist/cjs/tools/search/serper-scraper.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/search/utils.cjs.map +1 -1
- package/dist/cjs/types/graph.cjs +1 -1
- package/dist/cjs/types/graph.cjs.map +1 -1
- package/dist/cjs/utils/contextAnalytics.cjs +23 -6
- package/dist/cjs/utils/contextAnalytics.cjs.map +1 -1
- package/dist/cjs/utils/events.cjs.map +1 -1
- package/dist/cjs/utils/graph.cjs.map +1 -1
- package/dist/cjs/utils/handlers.cjs.map +1 -1
- package/dist/cjs/utils/llm.cjs.map +1 -1
- package/dist/cjs/utils/misc.cjs.map +1 -1
- package/dist/cjs/utils/run.cjs +3 -1
- package/dist/cjs/utils/run.cjs.map +1 -1
- package/dist/cjs/utils/schema.cjs.map +1 -1
- package/dist/cjs/utils/title.cjs.map +1 -1
- package/dist/cjs/utils/tokens.cjs +33 -58
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/cjs/utils/toolCallContinuation.cjs +55 -0
- package/dist/cjs/utils/toolCallContinuation.cjs.map +1 -0
- package/dist/cjs/utils/toonFormat.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +98 -49
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/constants.mjs +22 -0
- package/dist/esm/common/constants.mjs.map +1 -0
- package/dist/esm/common/enum.mjs +31 -1
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/events.mjs +9 -4
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +393 -88
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +224 -93
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/instrumentation.mjs +30 -14
- package/dist/esm/instrumentation.mjs.map +1 -1
- package/dist/esm/llm/anthropic/index.mjs +43 -11
- package/dist/esm/llm/anthropic/index.mjs.map +1 -1
- package/dist/esm/llm/anthropic/types.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +10 -7
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs +32 -0
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/tools.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +128 -101
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs +484 -0
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -0
- package/dist/esm/llm/bedrock/utils/message_outputs.mjs +171 -0
- package/dist/esm/llm/bedrock/utils/message_outputs.mjs.map +1 -0
- package/dist/esm/llm/fake.mjs.map +1 -1
- package/dist/esm/llm/google/index.mjs.map +1 -1
- package/dist/esm/llm/google/utils/common.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +1 -1
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/index.mjs +59 -5
- package/dist/esm/llm/openrouter/index.mjs.map +1 -1
- package/dist/esm/llm/providers.mjs.map +1 -1
- package/dist/esm/llm/text.mjs.map +1 -1
- package/dist/esm/llm/vertexai/index.mjs +80 -2
- package/dist/esm/llm/vertexai/index.mjs.map +1 -1
- package/dist/esm/main.mjs +8 -3
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/messages/cache.mjs +131 -108
- package/dist/esm/messages/cache.mjs.map +1 -1
- package/dist/esm/messages/content.mjs.map +1 -1
- package/dist/esm/messages/core.mjs +4 -1
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +267 -49
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/ids.mjs.map +1 -1
- package/dist/esm/messages/prune.mjs +56 -4
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/messages/summarize.mjs +161 -0
- package/dist/esm/messages/summarize.mjs.map +1 -0
- package/dist/esm/messages/tools.mjs.map +1 -1
- package/dist/esm/run.mjs +88 -31
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/schemas/validate.mjs.map +1 -1
- package/dist/esm/splitStream.mjs.map +1 -1
- package/dist/esm/stream.mjs +60 -26
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/AskUser.mjs +125 -0
- package/dist/esm/tools/AskUser.mjs.map +1 -0
- package/dist/esm/tools/BrowserTools.mjs +11 -7
- package/dist/esm/tools/BrowserTools.mjs.map +1 -1
- package/dist/esm/tools/Calculator.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +46 -4
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +37 -54
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/StreamingToolCallBuffer.mjs +206 -0
- package/dist/esm/tools/StreamingToolCallBuffer.mjs.map +1 -0
- package/dist/esm/tools/ToolNode.mjs +333 -30
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearch.mjs +66 -30
- package/dist/esm/tools/ToolSearch.mjs.map +1 -1
- package/dist/esm/tools/handlers.mjs +95 -9
- package/dist/esm/tools/handlers.mjs.map +1 -1
- package/dist/esm/tools/schema.mjs.map +1 -1
- package/dist/esm/tools/search/content.mjs.map +1 -1
- package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
- package/dist/esm/tools/search/format.mjs.map +1 -1
- package/dist/esm/tools/search/highlights.mjs.map +1 -1
- package/dist/esm/tools/search/rerankers.mjs.map +1 -1
- package/dist/esm/tools/search/schema.mjs.map +1 -1
- package/dist/esm/tools/search/search.mjs +1 -0
- package/dist/esm/tools/search/search.mjs.map +1 -1
- package/dist/esm/tools/search/serper-scraper.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/search/utils.mjs.map +1 -1
- package/dist/esm/types/graph.mjs +1 -1
- package/dist/esm/types/graph.mjs.map +1 -1
- package/dist/esm/utils/contextAnalytics.mjs +23 -6
- package/dist/esm/utils/contextAnalytics.mjs.map +1 -1
- package/dist/esm/utils/events.mjs.map +1 -1
- package/dist/esm/utils/graph.mjs.map +1 -1
- package/dist/esm/utils/handlers.mjs.map +1 -1
- package/dist/esm/utils/llm.mjs.map +1 -1
- package/dist/esm/utils/misc.mjs.map +1 -1
- package/dist/esm/utils/run.mjs +3 -1
- package/dist/esm/utils/run.mjs.map +1 -1
- package/dist/esm/utils/schema.mjs.map +1 -1
- package/dist/esm/utils/title.mjs.map +1 -1
- package/dist/esm/utils/tokens.mjs +33 -59
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/esm/utils/toolCallContinuation.mjs +52 -0
- package/dist/esm/utils/toolCallContinuation.mjs.map +1 -0
- package/dist/esm/utils/toonFormat.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +14 -7
- package/dist/types/common/constants.d.ts +18 -0
- package/dist/types/common/enum.d.ts +28 -0
- package/dist/types/common/index.d.ts +1 -0
- package/dist/types/events.d.ts +10 -3
- package/dist/types/graphs/Graph.d.ts +37 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/llm/anthropic/index.d.ts +7 -1
- package/dist/types/llm/anthropic/types.d.ts +5 -2
- package/dist/types/llm/anthropic/utils/message_outputs.d.ts +1 -1
- package/dist/types/llm/bedrock/index.d.ts +40 -33
- package/dist/types/llm/bedrock/utils/message_outputs.d.ts +1 -1
- package/dist/types/llm/google/index.d.ts +2 -3
- package/dist/types/llm/openrouter/index.d.ts +21 -1
- package/dist/types/llm/vertexai/index.d.ts +3 -2
- package/dist/types/messages/cache.d.ts +1 -1
- package/dist/types/messages/index.d.ts +1 -0
- package/dist/types/messages/prune.d.ts +2 -7
- package/dist/types/messages/summarize.d.ts +33 -0
- package/dist/types/run.d.ts +6 -0
- package/dist/types/tools/AskUser.d.ts +408 -0
- package/dist/types/tools/BrowserTools.d.ts +2 -2
- package/dist/types/tools/CodeExecutor.d.ts +2 -2
- package/dist/types/tools/StreamingToolCallBuffer.d.ts +106 -0
- package/dist/types/tools/ToolNode.d.ts +55 -3
- package/dist/types/tools/ToolSearch.d.ts +9 -5
- package/dist/types/tools/handlers.d.ts +2 -2
- package/dist/types/types/graph.d.ts +9 -2
- package/dist/types/types/llm.d.ts +8 -3
- package/dist/types/types/run.d.ts +2 -0
- package/dist/types/types/tools.d.ts +20 -2
- package/dist/types/utils/contextAnalytics.d.ts +5 -4
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/tokens.d.ts +6 -19
- package/dist/types/utils/toolCallContinuation.d.ts +30 -0
- package/package.json +15 -8
- package/src/agents/AgentContext.js +782 -0
- package/src/agents/AgentContext.js.map +1 -0
- package/src/agents/AgentContext.test.js +421 -0
- package/src/agents/AgentContext.test.js.map +1 -0
- package/src/agents/AgentContext.ts +132 -64
- package/src/agents/__tests__/AgentContext.test.js +678 -0
- package/src/agents/__tests__/AgentContext.test.js.map +1 -0
- package/src/agents/__tests__/AgentContext.test.ts +25 -4
- package/src/agents/__tests__/resolveStructuredOutputMode.test.js +117 -0
- package/src/agents/__tests__/resolveStructuredOutputMode.test.js.map +1 -0
- package/src/common/__tests__/enum.test.ts +135 -0
- package/src/common/constants.ts +21 -0
- package/src/common/enum.js +192 -0
- package/src/common/enum.js.map +1 -0
- package/src/common/enum.ts +30 -0
- package/src/common/index.js +3 -0
- package/src/common/index.js.map +1 -0
- package/src/common/index.ts +2 -1
- package/src/events.js +166 -0
- package/src/events.js.map +1 -0
- package/src/events.ts +11 -14
- package/src/graphs/Graph.js +1857 -0
- package/src/graphs/Graph.js.map +1 -0
- package/src/graphs/Graph.ts +580 -162
- package/src/graphs/MultiAgentGraph.js +1092 -0
- package/src/graphs/MultiAgentGraph.js.map +1 -0
- package/src/graphs/MultiAgentGraph.ts +331 -112
- package/src/graphs/__tests__/adaptive-thinking.test.ts +369 -0
- package/src/graphs/__tests__/graph-direct-tool-names.test.ts +210 -0
- package/src/graphs/__tests__/multi-agent-edges.test.ts +237 -0
- package/src/graphs/__tests__/structured-output.integration.test.js +624 -0
- package/src/graphs/__tests__/structured-output.integration.test.js.map +1 -0
- package/src/graphs/__tests__/structured-output.test.js +144 -0
- package/src/graphs/__tests__/structured-output.test.js.map +1 -0
- package/src/graphs/contextManagement.e2e.test.js +718 -0
- package/src/graphs/contextManagement.e2e.test.js.map +1 -0
- package/src/graphs/contextManagement.e2e.test.ts +990 -0
- package/src/graphs/contextManagement.test.js +485 -0
- package/src/graphs/contextManagement.test.js.map +1 -0
- package/src/graphs/contextManagement.test.ts +625 -0
- package/src/graphs/handoffValidation.test.js +276 -0
- package/src/graphs/handoffValidation.test.js.map +1 -0
- package/src/graphs/handoffValidation.test.ts +353 -0
- package/src/graphs/index.js +3 -0
- package/src/graphs/index.js.map +1 -0
- package/src/index.js +28 -0
- package/src/index.js.map +1 -0
- package/src/index.ts +13 -0
- package/src/instrumentation.js +21 -0
- package/src/instrumentation.js.map +1 -0
- package/src/instrumentation.ts +38 -17
- package/src/llm/anthropic/index.js +319 -0
- package/src/llm/anthropic/index.js.map +1 -0
- package/src/llm/anthropic/index.ts +68 -15
- package/src/llm/anthropic/llm.spec.ts +402 -0
- package/src/llm/anthropic/types.js +46 -0
- package/src/llm/anthropic/types.js.map +1 -0
- package/src/llm/anthropic/types.ts +8 -2
- package/src/llm/anthropic/utils/message_inputs.js +627 -0
- package/src/llm/anthropic/utils/message_inputs.js.map +1 -0
- package/src/llm/anthropic/utils/message_inputs.ts +16 -33
- package/src/llm/anthropic/utils/message_outputs.js +290 -0
- package/src/llm/anthropic/utils/message_outputs.js.map +1 -0
- package/src/llm/anthropic/utils/message_outputs.ts +40 -1
- package/src/llm/anthropic/utils/output_parsers.js +89 -0
- package/src/llm/anthropic/utils/output_parsers.js.map +1 -0
- package/src/llm/anthropic/utils/tools.js +25 -0
- package/src/llm/anthropic/utils/tools.js.map +1 -0
- package/src/llm/bedrock/__tests__/bedrock-caching.test.js +392 -0
- package/src/llm/bedrock/__tests__/bedrock-caching.test.js.map +1 -0
- package/src/llm/bedrock/__tests__/bedrock-caching.test.ts +24 -40
- package/src/llm/bedrock/index.js +303 -0
- package/src/llm/bedrock/index.js.map +1 -0
- package/src/llm/bedrock/index.ts +171 -134
- package/src/llm/bedrock/llm.spec.ts +395 -52
- package/src/llm/bedrock/types.js +2 -0
- package/src/llm/bedrock/types.js.map +1 -0
- package/src/llm/bedrock/utils/index.js +6 -0
- package/src/llm/bedrock/utils/index.js.map +1 -0
- package/src/llm/bedrock/utils/message_inputs.js +463 -0
- package/src/llm/bedrock/utils/message_inputs.js.map +1 -0
- package/src/llm/bedrock/utils/message_inputs.ts +30 -5
- package/src/llm/bedrock/utils/message_outputs.js +269 -0
- package/src/llm/bedrock/utils/message_outputs.js.map +1 -0
- package/src/llm/bedrock/utils/message_outputs.ts +70 -22
- package/src/llm/fake.js +92 -0
- package/src/llm/fake.js.map +1 -0
- package/src/llm/google/index.js +215 -0
- package/src/llm/google/index.js.map +1 -0
- package/src/llm/google/index.ts +2 -3
- package/src/llm/google/types.js +12 -0
- package/src/llm/google/types.js.map +1 -0
- package/src/llm/google/utils/common.js +670 -0
- package/src/llm/google/utils/common.js.map +1 -0
- package/src/llm/google/utils/tools.js +111 -0
- package/src/llm/google/utils/tools.js.map +1 -0
- package/src/llm/google/utils/zod_to_genai_parameters.js +47 -0
- package/src/llm/google/utils/zod_to_genai_parameters.js.map +1 -0
- package/src/llm/openai/index.js +1033 -0
- package/src/llm/openai/index.js.map +1 -0
- package/src/llm/openai/types.js +2 -0
- package/src/llm/openai/types.js.map +1 -0
- package/src/llm/openai/utils/index.js +756 -0
- package/src/llm/openai/utils/index.js.map +1 -0
- package/src/llm/openai/utils/isReasoningModel.test.js +79 -0
- package/src/llm/openai/utils/isReasoningModel.test.js.map +1 -0
- package/src/llm/openrouter/index.js +261 -0
- package/src/llm/openrouter/index.js.map +1 -0
- package/src/llm/openrouter/index.ts +117 -6
- package/src/llm/openrouter/reasoning.test.js +181 -0
- package/src/llm/openrouter/reasoning.test.js.map +1 -0
- package/src/llm/openrouter/reasoning.test.ts +207 -0
- package/src/llm/providers.js +36 -0
- package/src/llm/providers.js.map +1 -0
- package/src/llm/text.js +65 -0
- package/src/llm/text.js.map +1 -0
- package/src/llm/vertexai/index.js +402 -0
- package/src/llm/vertexai/index.js.map +1 -0
- package/src/llm/vertexai/index.ts +115 -5
- package/src/llm/vertexai/llm.spec.ts +114 -0
- package/src/messages/__tests__/tools.test.js +392 -0
- package/src/messages/__tests__/tools.test.js.map +1 -0
- package/src/messages/cache.js +404 -0
- package/src/messages/cache.js.map +1 -0
- package/src/messages/cache.test.js +1167 -0
- package/src/messages/cache.test.js.map +1 -0
- package/src/messages/cache.test.ts +178 -16
- package/src/messages/cache.ts +152 -147
- package/src/messages/content.js +48 -0
- package/src/messages/content.js.map +1 -0
- package/src/messages/content.test.js +314 -0
- package/src/messages/content.test.js.map +1 -0
- package/src/messages/core.js +359 -0
- package/src/messages/core.js.map +1 -0
- package/src/messages/core.ts +5 -0
- package/src/messages/ensureThinkingBlock.test.js +997 -0
- package/src/messages/ensureThinkingBlock.test.js.map +1 -0
- package/src/messages/ensureThinkingBlock.test.ts +751 -10
- package/src/messages/format.js +973 -0
- package/src/messages/format.js.map +1 -0
- package/src/messages/format.ts +334 -57
- package/src/messages/formatAgentMessages.test.js +2278 -0
- package/src/messages/formatAgentMessages.test.js.map +1 -0
- package/src/messages/formatAgentMessages.test.ts +1175 -1
- package/src/messages/formatAgentMessages.tools.test.js +362 -0
- package/src/messages/formatAgentMessages.tools.test.js.map +1 -0
- package/src/messages/formatMessage.test.js +608 -0
- package/src/messages/formatMessage.test.js.map +1 -0
- package/src/messages/ids.js +18 -0
- package/src/messages/ids.js.map +1 -0
- package/src/messages/index.js +9 -0
- package/src/messages/index.js.map +1 -0
- package/src/messages/index.ts +1 -0
- package/src/messages/labelContentByAgent.test.js +725 -0
- package/src/messages/labelContentByAgent.test.js.map +1 -0
- package/src/messages/prune.js +438 -0
- package/src/messages/prune.js.map +1 -0
- package/src/messages/prune.ts +87 -25
- package/src/messages/reducer.js +60 -0
- package/src/messages/reducer.js.map +1 -0
- package/src/messages/shiftIndexTokenCountMap.test.js +63 -0
- package/src/messages/shiftIndexTokenCountMap.test.js.map +1 -0
- package/src/messages/summarize.js +146 -0
- package/src/messages/summarize.js.map +1 -0
- package/src/messages/summarize.test.js +332 -0
- package/src/messages/summarize.test.js.map +1 -0
- package/src/messages/summarize.test.ts +466 -0
- package/src/messages/summarize.ts +222 -0
- package/src/messages/tools.js +90 -0
- package/src/messages/tools.js.map +1 -0
- package/src/mockStream.js +81 -0
- package/src/mockStream.js.map +1 -0
- package/src/prompts/collab.js +7 -0
- package/src/prompts/collab.js.map +1 -0
- package/src/prompts/index.js +3 -0
- package/src/prompts/index.js.map +1 -0
- package/src/prompts/taskmanager.js +58 -0
- package/src/prompts/taskmanager.js.map +1 -0
- package/src/run.js +427 -0
- package/src/run.js.map +1 -0
- package/src/run.ts +101 -33
- package/src/schemas/index.js +3 -0
- package/src/schemas/index.js.map +1 -0
- package/src/schemas/schema-preparation.test.js +370 -0
- package/src/schemas/schema-preparation.test.js.map +1 -0
- package/src/schemas/validate.js +314 -0
- package/src/schemas/validate.js.map +1 -0
- package/src/schemas/validate.test.js +264 -0
- package/src/schemas/validate.test.js.map +1 -0
- package/src/scripts/abort.js +127 -0
- package/src/scripts/abort.js.map +1 -0
- package/src/scripts/ant_web_search.js +130 -0
- package/src/scripts/ant_web_search.js.map +1 -0
- package/src/scripts/ant_web_search.ts +1 -0
- package/src/scripts/ant_web_search_edge_case.js +133 -0
- package/src/scripts/ant_web_search_edge_case.js.map +1 -0
- package/src/scripts/ant_web_search_edge_case.ts +1 -0
- package/src/scripts/ant_web_search_error_edge_case.js +119 -0
- package/src/scripts/ant_web_search_error_edge_case.js.map +1 -0
- package/src/scripts/ant_web_search_error_edge_case.ts +1 -0
- package/src/scripts/args.js +41 -0
- package/src/scripts/args.js.map +1 -0
- package/src/scripts/bedrock-cache-debug.js +186 -0
- package/src/scripts/bedrock-cache-debug.js.map +1 -0
- package/src/scripts/bedrock-cache-debug.ts +250 -0
- package/src/scripts/bedrock-content-aggregation-test.js +195 -0
- package/src/scripts/bedrock-content-aggregation-test.js.map +1 -0
- package/src/scripts/bedrock-content-aggregation-test.ts +266 -0
- package/src/scripts/bedrock-merge-test.js +80 -0
- package/src/scripts/bedrock-merge-test.js.map +1 -0
- package/src/scripts/bedrock-merge-test.ts +107 -0
- package/src/scripts/bedrock-parallel-tools-test.js +150 -0
- package/src/scripts/bedrock-parallel-tools-test.js.map +1 -0
- package/src/scripts/bedrock-parallel-tools-test.ts +204 -0
- package/src/scripts/caching.js +106 -0
- package/src/scripts/caching.js.map +1 -0
- package/src/scripts/caching.ts +1 -0
- package/src/scripts/cli.js +152 -0
- package/src/scripts/cli.js.map +1 -0
- package/src/scripts/cli2.js +119 -0
- package/src/scripts/cli2.js.map +1 -0
- package/src/scripts/cli3.js +163 -0
- package/src/scripts/cli3.js.map +1 -0
- package/src/scripts/cli4.js +165 -0
- package/src/scripts/cli4.js.map +1 -0
- package/src/scripts/cli5.js +165 -0
- package/src/scripts/cli5.js.map +1 -0
- package/src/scripts/code_exec.js +171 -0
- package/src/scripts/code_exec.js.map +1 -0
- package/src/scripts/code_exec.ts +1 -0
- package/src/scripts/code_exec_files.js +180 -0
- package/src/scripts/code_exec_files.js.map +1 -0
- package/src/scripts/code_exec_files.ts +1 -0
- package/src/scripts/code_exec_multi_session.js +185 -0
- package/src/scripts/code_exec_multi_session.js.map +1 -0
- package/src/scripts/code_exec_multi_session.ts +9 -13
- package/src/scripts/code_exec_ptc.js +265 -0
- package/src/scripts/code_exec_ptc.js.map +1 -0
- package/src/scripts/code_exec_ptc.ts +1 -0
- package/src/scripts/code_exec_session.js +217 -0
- package/src/scripts/code_exec_session.js.map +1 -0
- package/src/scripts/code_exec_session.ts +1 -0
- package/src/scripts/code_exec_simple.js +120 -0
- package/src/scripts/code_exec_simple.js.map +1 -0
- package/src/scripts/code_exec_simple.ts +1 -0
- package/src/scripts/content.js +111 -0
- package/src/scripts/content.js.map +1 -0
- package/src/scripts/content.ts +1 -0
- package/src/scripts/empty_input.js +125 -0
- package/src/scripts/empty_input.js.map +1 -0
- package/src/scripts/handoff-test.js +96 -0
- package/src/scripts/handoff-test.js.map +1 -0
- package/src/scripts/image.js +138 -0
- package/src/scripts/image.js.map +1 -0
- package/src/scripts/image.ts +3 -1
- package/src/scripts/memory.js +83 -0
- package/src/scripts/memory.js.map +1 -0
- package/src/scripts/memory.ts +16 -6
- package/src/scripts/multi-agent-chain.js +271 -0
- package/src/scripts/multi-agent-chain.js.map +1 -0
- package/src/scripts/multi-agent-chain.ts +1 -0
- package/src/scripts/multi-agent-conditional.js +185 -0
- package/src/scripts/multi-agent-conditional.js.map +1 -0
- package/src/scripts/multi-agent-conditional.ts +1 -0
- package/src/scripts/multi-agent-document-review-chain.js +171 -0
- package/src/scripts/multi-agent-document-review-chain.js.map +1 -0
- package/src/scripts/multi-agent-document-review-chain.ts +1 -0
- package/src/scripts/multi-agent-hybrid-flow.js +264 -0
- package/src/scripts/multi-agent-hybrid-flow.js.map +1 -0
- package/src/scripts/multi-agent-hybrid-flow.ts +1 -0
- package/src/scripts/multi-agent-parallel-start.js +214 -0
- package/src/scripts/multi-agent-parallel-start.js.map +1 -0
- package/src/scripts/multi-agent-parallel-start.ts +4 -4
- package/src/scripts/multi-agent-parallel.js +346 -0
- package/src/scripts/multi-agent-parallel.js.map +1 -0
- package/src/scripts/multi-agent-parallel.ts +1 -0
- package/src/scripts/multi-agent-sequence.js +184 -0
- package/src/scripts/multi-agent-sequence.js.map +1 -0
- package/src/scripts/multi-agent-sequence.ts +4 -4
- package/src/scripts/multi-agent-supervisor.js +324 -0
- package/src/scripts/multi-agent-supervisor.js.map +1 -0
- package/src/scripts/multi-agent-supervisor.ts +1 -0
- package/src/scripts/multi-agent-test.js +147 -0
- package/src/scripts/multi-agent-test.js.map +1 -0
- package/src/scripts/multi-agent-test.ts +1 -0
- package/src/scripts/parallel-asymmetric-tools-test.js +202 -0
- package/src/scripts/parallel-asymmetric-tools-test.js.map +1 -0
- package/src/scripts/parallel-asymmetric-tools-test.ts +1 -0
- package/src/scripts/parallel-full-metadata-test.js +176 -0
- package/src/scripts/parallel-full-metadata-test.js.map +1 -0
- package/src/scripts/parallel-full-metadata-test.ts +1 -0
- package/src/scripts/parallel-tools-test.js +256 -0
- package/src/scripts/parallel-tools-test.js.map +1 -0
- package/src/scripts/parallel-tools-test.ts +1 -0
- package/src/scripts/poc-multi-agent-comprehensive.ts +1222 -0
- package/src/scripts/programmatic_exec.js +277 -0
- package/src/scripts/programmatic_exec.js.map +1 -0
- package/src/scripts/programmatic_exec_agent.js +168 -0
- package/src/scripts/programmatic_exec_agent.js.map +1 -0
- package/src/scripts/programmatic_exec_agent.ts +1 -0
- package/src/scripts/search.js +118 -0
- package/src/scripts/search.js.map +1 -0
- package/src/scripts/search.ts +1 -0
- package/src/scripts/sequential-full-metadata-test.js +143 -0
- package/src/scripts/sequential-full-metadata-test.js.map +1 -0
- package/src/scripts/sequential-full-metadata-test.ts +1 -0
- package/src/scripts/simple.js +174 -0
- package/src/scripts/simple.js.map +1 -0
- package/src/scripts/simple.ts +2 -1
- package/src/scripts/single-agent-metadata-test.js +152 -0
- package/src/scripts/single-agent-metadata-test.js.map +1 -0
- package/src/scripts/single-agent-metadata-test.ts +4 -6
- package/src/scripts/stream.js +113 -0
- package/src/scripts/stream.js.map +1 -0
- package/src/scripts/stream.ts +1 -0
- package/src/scripts/test-custom-prompt-key.js +132 -0
- package/src/scripts/test-custom-prompt-key.js.map +1 -0
- package/src/scripts/test-handoff-input.js +143 -0
- package/src/scripts/test-handoff-input.js.map +1 -0
- package/src/scripts/test-handoff-preamble.js +227 -0
- package/src/scripts/test-handoff-preamble.js.map +1 -0
- package/src/scripts/test-handoff-preamble.ts +1 -0
- package/src/scripts/test-handoff-steering.js +353 -0
- package/src/scripts/test-handoff-steering.js.map +1 -0
- package/src/scripts/test-handoff-steering.ts +430 -0
- package/src/scripts/test-multi-agent-list-handoff.js +318 -0
- package/src/scripts/test-multi-agent-list-handoff.js.map +1 -0
- package/src/scripts/test-multi-agent-list-handoff.ts +1 -0
- package/src/scripts/test-parallel-agent-labeling.js +253 -0
- package/src/scripts/test-parallel-agent-labeling.js.map +1 -0
- package/src/scripts/test-parallel-agent-labeling.ts +2 -0
- package/src/scripts/test-parallel-handoffs.js +229 -0
- package/src/scripts/test-parallel-handoffs.js.map +1 -0
- package/src/scripts/test-parallel-handoffs.ts +1 -0
- package/src/scripts/test-thinking-handoff-bedrock.js +132 -0
- package/src/scripts/test-thinking-handoff-bedrock.js.map +1 -0
- package/src/scripts/test-thinking-handoff-bedrock.ts +1 -0
- package/src/scripts/test-thinking-handoff.js +132 -0
- package/src/scripts/test-thinking-handoff.js.map +1 -0
- package/src/scripts/test-thinking-handoff.ts +1 -0
- package/src/scripts/test-thinking-to-thinking-handoff-bedrock.js +140 -0
- package/src/scripts/test-thinking-to-thinking-handoff-bedrock.js.map +1 -0
- package/src/scripts/test-thinking-to-thinking-handoff-bedrock.ts +166 -0
- package/src/scripts/test-tool-before-handoff-role-order.js +223 -0
- package/src/scripts/test-tool-before-handoff-role-order.js.map +1 -0
- package/src/scripts/test-tool-before-handoff-role-order.ts +276 -0
- package/src/scripts/test-tools-before-handoff.js +187 -0
- package/src/scripts/test-tools-before-handoff.js.map +1 -0
- package/src/scripts/test-tools-before-handoff.ts +4 -8
- package/src/scripts/test_code_api.js +263 -0
- package/src/scripts/test_code_api.js.map +1 -0
- package/src/scripts/thinking-bedrock.js +128 -0
- package/src/scripts/thinking-bedrock.js.map +1 -0
- package/src/scripts/thinking-bedrock.ts +1 -0
- package/src/scripts/thinking-vertexai.js +130 -0
- package/src/scripts/thinking-vertexai.js.map +1 -0
- package/src/scripts/thinking-vertexai.ts +168 -0
- package/src/scripts/thinking.js +134 -0
- package/src/scripts/thinking.js.map +1 -0
- package/src/scripts/thinking.ts +1 -0
- package/src/scripts/tool_search.js +114 -0
- package/src/scripts/tool_search.js.map +1 -0
- package/src/scripts/tools.js +125 -0
- package/src/scripts/tools.js.map +1 -0
- package/src/scripts/tools.ts +5 -19
- package/src/specs/agent-handoffs-bedrock.integration.test.js +280 -0
- package/src/specs/agent-handoffs-bedrock.integration.test.js.map +1 -0
- package/src/specs/agent-handoffs-bedrock.integration.test.ts +412 -375
- package/src/specs/agent-handoffs.test.js +924 -0
- package/src/specs/agent-handoffs.test.js.map +1 -0
- package/src/specs/agent-handoffs.test.ts +152 -39
- package/src/specs/anthropic.simple.test.js +287 -0
- package/src/specs/anthropic.simple.test.js.map +1 -0
- package/src/specs/anthropic.simple.test.ts +7 -4
- package/src/specs/azure.simple.test.js +381 -0
- package/src/specs/azure.simple.test.js.map +1 -0
- package/src/specs/azure.simple.test.ts +143 -5
- package/src/specs/cache.simple.test.js +282 -0
- package/src/specs/cache.simple.test.js.map +1 -0
- package/src/specs/cache.simple.test.ts +9 -2
- package/src/specs/custom-event-await.test.js +148 -0
- package/src/specs/custom-event-await.test.js.map +1 -0
- package/src/specs/custom-event-await.test.ts +215 -0
- package/src/specs/deepseek.simple.test.js +189 -0
- package/src/specs/deepseek.simple.test.js.map +1 -0
- package/src/specs/deepseek.simple.test.ts +4 -2
- package/src/specs/emergency-prune.test.js +308 -0
- package/src/specs/emergency-prune.test.js.map +1 -0
- package/src/specs/moonshot.simple.test.js +237 -0
- package/src/specs/moonshot.simple.test.js.map +1 -0
- package/src/specs/moonshot.simple.test.ts +6 -2
- package/src/specs/observability.integration.test.js +1337 -0
- package/src/specs/observability.integration.test.js.map +1 -0
- package/src/specs/observability.integration.test.ts +2223 -0
- package/src/specs/openai.simple.test.js +233 -0
- package/src/specs/openai.simple.test.js.map +1 -0
- package/src/specs/openai.simple.test.ts +4 -2
- package/src/specs/openrouter.simple.test.js +202 -0
- package/src/specs/openrouter.simple.test.js.map +1 -0
- package/src/specs/openrouter.simple.test.ts +165 -4
- package/src/specs/prune.test.js +733 -0
- package/src/specs/prune.test.js.map +1 -0
- package/src/specs/prune.test.ts +1 -0
- package/src/specs/reasoning.test.js +144 -0
- package/src/specs/reasoning.test.js.map +1 -0
- package/src/specs/reasoning.test.ts +2 -2
- package/src/specs/spec.utils.js +4 -0
- package/src/specs/spec.utils.js.map +1 -0
- package/src/specs/thinking-handoff.test.js +486 -0
- package/src/specs/thinking-handoff.test.js.map +1 -0
- package/src/specs/thinking-handoff.test.ts +3 -2
- package/src/specs/thinking-prune.test.js +600 -0
- package/src/specs/thinking-prune.test.js.map +1 -0
- package/src/specs/token-distribution-edge-case.test.js +246 -0
- package/src/specs/token-distribution-edge-case.test.js.map +1 -0
- package/src/specs/token-memoization.test.js +32 -0
- package/src/specs/token-memoization.test.js.map +1 -0
- package/src/specs/token-memoization.test.ts +14 -5
- package/src/specs/tokens.test.js +49 -0
- package/src/specs/tokens.test.js.map +1 -0
- package/src/specs/tokens.test.ts +64 -0
- package/src/specs/tool-error.test.js +139 -0
- package/src/specs/tool-error.test.js.map +1 -0
- package/src/specs/tool-error.test.ts +2 -2
- package/src/splitStream.js +204 -0
- package/src/splitStream.js.map +1 -0
- package/src/splitStream.test.js +504 -0
- package/src/splitStream.test.js.map +1 -0
- package/src/stream.js +650 -0
- package/src/stream.js.map +1 -0
- package/src/stream.test.js +225 -0
- package/src/stream.test.js.map +1 -0
- package/src/stream.test.ts +25 -15
- package/src/stream.ts +82 -32
- package/src/test/mockTools.js +340 -0
- package/src/test/mockTools.js.map +1 -0
- package/src/tools/AskUser.ts +159 -0
- package/src/tools/BrowserTools.js +245 -0
- package/src/tools/BrowserTools.js.map +1 -0
- package/src/tools/BrowserTools.ts +12 -8
- package/src/tools/Calculator.js +38 -0
- package/src/tools/Calculator.js.map +1 -0
- package/src/tools/Calculator.test.js +225 -0
- package/src/tools/Calculator.test.js.map +1 -0
- package/src/tools/CodeExecutor.js +233 -0
- package/src/tools/CodeExecutor.js.map +1 -0
- package/src/tools/CodeExecutor.selfhealing.test.ts +435 -0
- package/src/tools/CodeExecutor.ts +62 -4
- package/src/tools/ProgrammaticToolCalling.js +602 -0
- package/src/tools/ProgrammaticToolCalling.js.map +1 -0
- package/src/tools/ProgrammaticToolCalling.ts +40 -52
- package/src/tools/StreamingToolCallBuffer.js +179 -0
- package/src/tools/StreamingToolCallBuffer.js.map +1 -0
- package/src/tools/StreamingToolCallBuffer.ts +218 -0
- package/src/tools/ToolNode.js +930 -0
- package/src/tools/ToolNode.js.map +1 -0
- package/src/tools/ToolNode.ts +454 -41
- package/src/tools/ToolSearch.js +904 -0
- package/src/tools/ToolSearch.js.map +1 -0
- package/src/tools/ToolSearch.ts +84 -33
- package/src/tools/__tests__/AskUser.test.ts +537 -0
- package/src/tools/__tests__/BrowserTools.test.js +306 -0
- package/src/tools/__tests__/BrowserTools.test.js.map +1 -0
- package/src/tools/__tests__/BrowserTools.test.ts +131 -6
- package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.js +276 -0
- package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.js.map +1 -0
- package/src/tools/__tests__/ProgrammaticToolCalling.test.js +807 -0
- package/src/tools/__tests__/ProgrammaticToolCalling.test.js.map +1 -0
- package/src/tools/__tests__/StreamingToolCallBuffer.test.js +175 -0
- package/src/tools/__tests__/StreamingToolCallBuffer.test.js.map +1 -0
- package/src/tools/__tests__/StreamingToolCallBuffer.test.ts +263 -0
- package/src/tools/__tests__/ToolApproval.test.js +675 -0
- package/src/tools/__tests__/ToolApproval.test.js.map +1 -0
- package/src/tools/__tests__/ToolApproval.test.ts +194 -20
- package/src/tools/__tests__/ToolNode.hitl.test.ts +267 -0
- package/src/tools/__tests__/ToolNode.recovery.test.js +200 -0
- package/src/tools/__tests__/ToolNode.recovery.test.js.map +1 -0
- package/src/tools/__tests__/ToolNode.recovery.test.ts +276 -0
- package/src/tools/__tests__/ToolNode.session.test.js +319 -0
- package/src/tools/__tests__/ToolNode.session.test.js.map +1 -0
- package/src/tools/__tests__/ToolNode.session.test.ts +465 -0
- package/src/tools/__tests__/ToolSearch.integration.test.js +125 -0
- package/src/tools/__tests__/ToolSearch.integration.test.js.map +1 -0
- package/src/tools/__tests__/ToolSearch.test.js +812 -0
- package/src/tools/__tests__/ToolSearch.test.js.map +1 -0
- package/src/tools/__tests__/ToolSearch.test.ts +78 -5
- package/src/tools/__tests__/handlers.test.js +799 -0
- package/src/tools/__tests__/handlers.test.js.map +1 -0
- package/src/tools/__tests__/handlers.test.ts +1100 -0
- package/src/tools/__tests__/truncation-recovery.integration.test.js +362 -0
- package/src/tools/__tests__/truncation-recovery.integration.test.js.map +1 -0
- package/src/tools/__tests__/truncation-recovery.integration.test.ts +560 -0
- package/src/tools/handlers.js +306 -0
- package/src/tools/handlers.js.map +1 -0
- package/src/tools/handlers.ts +119 -16
- package/src/tools/schema.js +25 -0
- package/src/tools/schema.js.map +1 -0
- package/src/tools/search/anthropic.js +34 -0
- package/src/tools/search/anthropic.js.map +1 -0
- package/src/tools/search/content.js +116 -0
- package/src/tools/search/content.js.map +1 -0
- package/src/tools/search/content.test.js +133 -0
- package/src/tools/search/content.test.js.map +1 -0
- package/src/tools/search/firecrawl.js +173 -0
- package/src/tools/search/firecrawl.js.map +1 -0
- package/src/tools/search/format.js +198 -0
- package/src/tools/search/format.js.map +1 -0
- package/src/tools/search/highlights.js +241 -0
- package/src/tools/search/highlights.js.map +1 -0
- package/src/tools/search/index.js +3 -0
- package/src/tools/search/index.js.map +1 -0
- package/src/tools/search/jina-reranker.test.js +106 -0
- package/src/tools/search/jina-reranker.test.js.map +1 -0
- package/src/tools/search/rerankers.js +165 -0
- package/src/tools/search/rerankers.js.map +1 -0
- package/src/tools/search/schema.js +102 -0
- package/src/tools/search/schema.js.map +1 -0
- package/src/tools/search/search.js +561 -0
- package/src/tools/search/search.js.map +1 -0
- package/src/tools/search/serper-scraper.js +126 -0
- package/src/tools/search/serper-scraper.js.map +1 -0
- package/src/tools/search/test.js +129 -0
- package/src/tools/search/test.js.map +1 -0
- package/src/tools/search/tool.js +453 -0
- package/src/tools/search/tool.js.map +1 -0
- package/src/tools/search/types.js +2 -0
- package/src/tools/search/types.js.map +1 -0
- package/src/tools/search/utils.js +59 -0
- package/src/tools/search/utils.js.map +1 -0
- package/src/types/graph.js +24 -0
- package/src/types/graph.js.map +1 -0
- package/src/types/graph.test.js +192 -0
- package/src/types/graph.test.js.map +1 -0
- package/src/types/graph.ts +26 -6
- package/src/types/index.js +7 -0
- package/src/types/index.js.map +1 -0
- package/src/types/llm.js +2 -0
- package/src/types/llm.js.map +1 -0
- package/src/types/llm.ts +8 -3
- package/src/types/messages.js +2 -0
- package/src/types/messages.js.map +1 -0
- package/src/types/run.js +2 -0
- package/src/types/run.js.map +1 -0
- package/src/types/run.ts +2 -0
- package/src/types/stream.js +2 -0
- package/src/types/stream.js.map +1 -0
- package/src/types/tools.js +2 -0
- package/src/types/tools.js.map +1 -0
- package/src/types/tools.ts +21 -2
- package/src/utils/contextAnalytics.js +79 -0
- package/src/utils/contextAnalytics.js.map +1 -0
- package/src/utils/contextAnalytics.test.js +166 -0
- package/src/utils/contextAnalytics.test.js.map +1 -0
- package/src/utils/contextAnalytics.test.ts +222 -0
- package/src/utils/contextAnalytics.ts +27 -9
- package/src/utils/events.js +26 -0
- package/src/utils/events.js.map +1 -0
- package/src/utils/graph.js +11 -0
- package/src/utils/graph.js.map +1 -0
- package/src/utils/handlers.js +65 -0
- package/src/utils/handlers.js.map +1 -0
- package/src/utils/index.js +10 -0
- package/src/utils/index.js.map +1 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/llm.js +21 -0
- package/src/utils/llm.js.map +1 -0
- package/src/utils/llmConfig.js +205 -0
- package/src/utils/llmConfig.js.map +1 -0
- package/src/utils/llmConfig.ts +5 -5
- package/src/utils/logging.js +37 -0
- package/src/utils/logging.js.map +1 -0
- package/src/utils/misc.js +51 -0
- package/src/utils/misc.js.map +1 -0
- package/src/utils/run.js +69 -0
- package/src/utils/run.js.map +1 -0
- package/src/utils/run.ts +108 -106
- package/src/utils/schema.js +21 -0
- package/src/utils/schema.js.map +1 -0
- package/src/utils/title.js +119 -0
- package/src/utils/title.js.map +1 -0
- package/src/utils/tokens.js +92 -0
- package/src/utils/tokens.js.map +1 -0
- package/src/utils/tokens.ts +118 -142
- package/src/utils/toolCallContinuation.ts +55 -0
- package/src/utils/toonFormat.js +379 -0
- package/src/utils/toonFormat.js.map +1 -0
|
@@ -0,0 +1,990 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-End tests for context management across subagents, handoffs, and chaining.
|
|
3
|
+
*
|
|
4
|
+
* These tests exercise the full lifecycle of context management scenarios that
|
|
5
|
+
* span multiple agents and turns, validating that context is preserved, compacted,
|
|
6
|
+
* and transferred correctly across all agent execution patterns.
|
|
7
|
+
*
|
|
8
|
+
* Run with:
|
|
9
|
+
* npx jest --no-coverage --forceExit src/graphs/contextManagement.e2e.test.ts
|
|
10
|
+
*/
|
|
11
|
+
import {
|
|
12
|
+
HumanMessage,
|
|
13
|
+
AIMessage,
|
|
14
|
+
SystemMessage,
|
|
15
|
+
ToolMessage,
|
|
16
|
+
BaseMessage,
|
|
17
|
+
} from '@langchain/core/messages';
|
|
18
|
+
import type { TokenCounter } from '@/types/run';
|
|
19
|
+
import {
|
|
20
|
+
summarize,
|
|
21
|
+
createEmergencySummary,
|
|
22
|
+
formatMessagesForSummary,
|
|
23
|
+
buildFullSummaryPrompt,
|
|
24
|
+
} from '@/messages/summarize';
|
|
25
|
+
import { getContextUtilization } from '@/messages/prune';
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Helpers
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
/** Simple token counter: 1 token ≈ 4 chars */
|
|
32
|
+
const simpleTokenCounter: TokenCounter = (msg: BaseMessage): number => {
|
|
33
|
+
const content =
|
|
34
|
+
typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
|
|
35
|
+
return Math.ceil(content.length / 4);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** Create a realistic conversation with N turns */
|
|
39
|
+
function buildConversation(turns: number, charPerMessage = 200): BaseMessage[] {
|
|
40
|
+
const messages: BaseMessage[] = [];
|
|
41
|
+
for (let i = 0; i < turns; i++) {
|
|
42
|
+
messages.push(
|
|
43
|
+
new HumanMessage({
|
|
44
|
+
content: `User message ${i}: ${'x'.repeat(charPerMessage)}`,
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
messages.push(
|
|
48
|
+
new AIMessage({
|
|
49
|
+
content: `AI response ${i}: ${'y'.repeat(charPerMessage)}`,
|
|
50
|
+
})
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return messages;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Simulates a summarize callback that returns a structured summary */
|
|
57
|
+
const mockSummarizeCallback = async (
|
|
58
|
+
prompt: string,
|
|
59
|
+
_maxTokens: number
|
|
60
|
+
): Promise<string> => {
|
|
61
|
+
return `[Summary] Conversation covered ${prompt.length} chars of content. Key topics discussed. Active context preserved.`;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** Simulates a summarize callback that always fails */
|
|
65
|
+
const failingSummarizeCallback = async (): Promise<string> => {
|
|
66
|
+
throw new Error('LLM unavailable');
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// ============================================================================
|
|
70
|
+
// 1. Subagent Result Truncation E2E
|
|
71
|
+
// ============================================================================
|
|
72
|
+
|
|
73
|
+
describe('Subagent result truncation E2E', () => {
|
|
74
|
+
it('truncated subagent result fits within parent context budget', () => {
|
|
75
|
+
// Simulate: subagent produces 50K chars, parent has 10K token budget
|
|
76
|
+
const subagentResult = 'Finding: '.repeat(5000) + 'Conclusion reached.';
|
|
77
|
+
const parentMaxTokens = 10000;
|
|
78
|
+
const maxResultChars = 8192 * 4; // 8192 tokens * 4 chars/token = 32768
|
|
79
|
+
|
|
80
|
+
// Truncation logic (mirrors TaskTool.truncateResult)
|
|
81
|
+
const truncationNotice =
|
|
82
|
+
'\n\n[... sub-agent output truncated — middle section omitted to fit parent context ...]\n\n';
|
|
83
|
+
const available = maxResultChars - truncationNotice.length;
|
|
84
|
+
const headSize = Math.floor(available * 0.6);
|
|
85
|
+
const tailSize = available - headSize;
|
|
86
|
+
const truncated =
|
|
87
|
+
subagentResult.substring(0, headSize) +
|
|
88
|
+
truncationNotice +
|
|
89
|
+
subagentResult.substring(subagentResult.length - tailSize);
|
|
90
|
+
|
|
91
|
+
// Result fits in parent budget (32768 chars ≈ 8192 tokens)
|
|
92
|
+
const resultTokens = Math.ceil(truncated.length / 4);
|
|
93
|
+
expect(resultTokens).toBeLessThanOrEqual(parentMaxTokens);
|
|
94
|
+
expect(truncated).toContain('Finding:');
|
|
95
|
+
expect(truncated).toContain('Conclusion reached.');
|
|
96
|
+
expect(truncated).toContain('sub-agent output truncated');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('multiple subagent results combined still fit parent context', () => {
|
|
100
|
+
// Simulate 3 parallel subagent tasks each returning large results
|
|
101
|
+
const maxResultCharsPerSubagent = 8192;
|
|
102
|
+
const results = [
|
|
103
|
+
'A'.repeat(maxResultCharsPerSubagent),
|
|
104
|
+
'B'.repeat(maxResultCharsPerSubagent),
|
|
105
|
+
'C'.repeat(maxResultCharsPerSubagent),
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
// Parent context: system + messages + 3 tool results
|
|
109
|
+
const systemTokens = 500;
|
|
110
|
+
const conversationTokens = 2000;
|
|
111
|
+
const totalResultTokens = results.reduce(
|
|
112
|
+
(sum, r) => sum + Math.ceil(r.length / 4),
|
|
113
|
+
0
|
|
114
|
+
);
|
|
115
|
+
const totalUsed = systemTokens + conversationTokens + totalResultTokens;
|
|
116
|
+
|
|
117
|
+
// With 3 subagents at 8192 chars each (≈2048 tokens each), total ≈ 6144 + 2500 = 8644 tokens
|
|
118
|
+
// Fits within a 16K context window
|
|
119
|
+
expect(totalUsed).toBeLessThan(16000);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('subagent result truncation preserves actionable content', () => {
|
|
123
|
+
// Simulate a subagent that found code, data, and conclusions
|
|
124
|
+
const codeBlock = '```typescript\nfunction process() { return 42; }\n```\n';
|
|
125
|
+
const dataSection =
|
|
126
|
+
'Data: ' + JSON.stringify({ metric: 99.5, status: 'healthy' }) + '\n';
|
|
127
|
+
const middlePadding = 'Analysis details '.repeat(3000); // ~51K chars
|
|
128
|
+
const conclusion =
|
|
129
|
+
'\nFinal answer: The system is operating within normal parameters.';
|
|
130
|
+
|
|
131
|
+
const fullResult = codeBlock + dataSection + middlePadding + conclusion;
|
|
132
|
+
const maxChars = 2000;
|
|
133
|
+
|
|
134
|
+
// Truncation keeps head (60%) and tail (40%)
|
|
135
|
+
const notice =
|
|
136
|
+
'\n\n[... sub-agent output truncated — middle section omitted to fit parent context ...]\n\n';
|
|
137
|
+
const available = maxChars - notice.length;
|
|
138
|
+
const headSize = Math.floor(available * 0.6);
|
|
139
|
+
const tailSize = available - headSize;
|
|
140
|
+
const truncated =
|
|
141
|
+
fullResult.substring(0, headSize) +
|
|
142
|
+
notice +
|
|
143
|
+
fullResult.substring(fullResult.length - tailSize);
|
|
144
|
+
|
|
145
|
+
// Head should contain the code and data (actionable)
|
|
146
|
+
expect(truncated).toContain('function process()');
|
|
147
|
+
expect(truncated).toContain('metric');
|
|
148
|
+
// Tail should contain the conclusion
|
|
149
|
+
expect(truncated).toContain('Final answer');
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// ============================================================================
|
|
154
|
+
// 2. Agent Handoff with Context Compaction E2E
|
|
155
|
+
// ============================================================================
|
|
156
|
+
|
|
157
|
+
describe('Agent handoff with context compaction E2E', () => {
|
|
158
|
+
it('compacts context before handoff when sender exceeds receiver budget', async () => {
|
|
159
|
+
// Agent A has 200K context, Agent B has 32K context
|
|
160
|
+
const senderMessages = buildConversation(50, 500); // 50 turns, ~500 chars each ≈ lots of tokens
|
|
161
|
+
const receiverMaxTokens = 8000; // 32K chars
|
|
162
|
+
|
|
163
|
+
// Calculate sender's context tokens
|
|
164
|
+
const senderTokens = senderMessages.reduce(
|
|
165
|
+
(sum, m) => sum + simpleTokenCounter(m),
|
|
166
|
+
0
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
// Check if compaction needed (>70% of receiver budget)
|
|
170
|
+
const compactionThreshold = receiverMaxTokens * 0.7;
|
|
171
|
+
expect(senderTokens).toBeGreaterThan(compactionThreshold);
|
|
172
|
+
|
|
173
|
+
// Compact: summarize + keep last 3 messages
|
|
174
|
+
const result = await summarize(senderMessages, mockSummarizeCallback, {
|
|
175
|
+
tokenCounter: simpleTokenCounter,
|
|
176
|
+
summaryBudget: Math.floor(receiverMaxTokens * 0.2),
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
expect(result.tier).toBe('full');
|
|
180
|
+
expect(result.summary).toBeTruthy();
|
|
181
|
+
|
|
182
|
+
// Build compacted messages: system summary + last 3 messages
|
|
183
|
+
const compactedMessages = [
|
|
184
|
+
new SystemMessage({ content: `[Handoff Briefing]\n${result.summary}` }),
|
|
185
|
+
...senderMessages.slice(-3),
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
// Compacted context fits receiver budget
|
|
189
|
+
const compactedTokens = compactedMessages.reduce(
|
|
190
|
+
(sum, m) => sum + simpleTokenCounter(m),
|
|
191
|
+
0
|
|
192
|
+
);
|
|
193
|
+
expect(compactedTokens).toBeLessThan(receiverMaxTokens);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('preserves critical context through handoff compaction', async () => {
|
|
197
|
+
// First message has the user's original intent
|
|
198
|
+
const messages: BaseMessage[] = [
|
|
199
|
+
new HumanMessage({
|
|
200
|
+
content:
|
|
201
|
+
'Create a quarterly revenue report for Q4 2025 with charts and analysis',
|
|
202
|
+
}),
|
|
203
|
+
new AIMessage({ content: 'I will analyze the revenue data.' }),
|
|
204
|
+
// ... many intermediate messages ...
|
|
205
|
+
...buildConversation(20, 300),
|
|
206
|
+
// Last messages have current progress
|
|
207
|
+
new HumanMessage({
|
|
208
|
+
content: 'Now add the competitor comparison section',
|
|
209
|
+
}),
|
|
210
|
+
new AIMessage({
|
|
211
|
+
content: 'Adding competitor analysis from the market data...',
|
|
212
|
+
}),
|
|
213
|
+
];
|
|
214
|
+
|
|
215
|
+
// Emergency summary should capture first user intent and last state
|
|
216
|
+
const emergency = createEmergencySummary(messages);
|
|
217
|
+
expect(emergency).toContain('quarterly revenue report');
|
|
218
|
+
expect(emergency).toContain('competitor');
|
|
219
|
+
|
|
220
|
+
// Full summary should also capture it
|
|
221
|
+
const result = await summarize(messages, mockSummarizeCallback, {
|
|
222
|
+
tokenCounter: simpleTokenCounter,
|
|
223
|
+
});
|
|
224
|
+
expect(result.summary.length).toBeGreaterThan(0);
|
|
225
|
+
expect(result.messagesCompacted).toBe(messages.length);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('handles handoff to agent with smaller context gracefully', async () => {
|
|
229
|
+
// Simulate large context being handed to a mini agent
|
|
230
|
+
const largeContext = buildConversation(100, 400); // Very large conversation
|
|
231
|
+
const miniAgentBudget = 4000; // Very small budget (~16K chars)
|
|
232
|
+
|
|
233
|
+
// First try full summarize
|
|
234
|
+
const result = await summarize(largeContext, mockSummarizeCallback, {
|
|
235
|
+
tokenCounter: simpleTokenCounter,
|
|
236
|
+
summaryBudget: Math.floor(miniAgentBudget * 0.2),
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Should produce a summary
|
|
240
|
+
expect(result.summary.length).toBeGreaterThan(0);
|
|
241
|
+
|
|
242
|
+
// Build handoff context
|
|
243
|
+
const handoffMessages = [
|
|
244
|
+
new SystemMessage({ content: `[Handoff Briefing]\n${result.summary}` }),
|
|
245
|
+
...largeContext.slice(-2), // Keep last exchange
|
|
246
|
+
];
|
|
247
|
+
|
|
248
|
+
const handoffTokens = handoffMessages.reduce(
|
|
249
|
+
(sum, m) => sum + simpleTokenCounter(m),
|
|
250
|
+
0
|
|
251
|
+
);
|
|
252
|
+
// Should fit within mini agent budget with room for its own responses
|
|
253
|
+
expect(handoffTokens).toBeLessThan(miniAgentBudget * 0.5);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('generates error ToolMessage for invalid handoff destination', () => {
|
|
257
|
+
const agentContexts = new Map([
|
|
258
|
+
['research-agent', { name: 'Research Agent', maxContextTokens: 200000 }],
|
|
259
|
+
['writing-agent', { name: 'Writing Agent', maxContextTokens: 32000 }],
|
|
260
|
+
]);
|
|
261
|
+
|
|
262
|
+
const invalidDest = 'coding-agent';
|
|
263
|
+
expect(agentContexts.has(invalidDest)).toBe(false);
|
|
264
|
+
|
|
265
|
+
// Build error message for self-correction
|
|
266
|
+
const availableAgents = Array.from(agentContexts.keys()).join(', ');
|
|
267
|
+
const errorMsg = new ToolMessage({
|
|
268
|
+
content: `Agent "${invalidDest}" does not exist. Available agents: ${availableAgents}. Please choose a valid agent.`,
|
|
269
|
+
tool_call_id: 'handoff_call_123',
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
expect(errorMsg.content).toContain('coding-agent');
|
|
273
|
+
expect(errorMsg.content).toContain('research-agent');
|
|
274
|
+
expect(errorMsg.content).toContain('writing-agent');
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// ============================================================================
|
|
279
|
+
// 3. Agent Chaining with Rolling Summaries
|
|
280
|
+
// ============================================================================
|
|
281
|
+
|
|
282
|
+
describe('Agent chaining with rolling summaries', () => {
|
|
283
|
+
it('maintains context across 3-agent chain via rolling summaries', async () => {
|
|
284
|
+
// Agent A: Research phase
|
|
285
|
+
const agentAMessages: BaseMessage[] = [
|
|
286
|
+
new HumanMessage({ content: 'Research the impact of AI on healthcare' }),
|
|
287
|
+
new AIMessage({
|
|
288
|
+
content:
|
|
289
|
+
'Found 15 papers on AI diagnostics, drug discovery, and telemedicine.',
|
|
290
|
+
}),
|
|
291
|
+
new HumanMessage({ content: 'Focus on drug discovery findings' }),
|
|
292
|
+
new AIMessage({
|
|
293
|
+
content:
|
|
294
|
+
'Drug discovery: AI reduces development time by 40%. Key compounds identified.',
|
|
295
|
+
}),
|
|
296
|
+
];
|
|
297
|
+
|
|
298
|
+
// Summarize Agent A context before passing to Agent B
|
|
299
|
+
const summaryA = await summarize(agentAMessages, mockSummarizeCallback, {
|
|
300
|
+
tokenCounter: simpleTokenCounter,
|
|
301
|
+
});
|
|
302
|
+
expect(summaryA.tier).toBe('full');
|
|
303
|
+
|
|
304
|
+
// Agent B: Analysis phase — receives Agent A's summary
|
|
305
|
+
const agentBMessages: BaseMessage[] = [
|
|
306
|
+
new SystemMessage({
|
|
307
|
+
content: `[Previous Agent Summary]\n${summaryA.summary}`,
|
|
308
|
+
}),
|
|
309
|
+
new HumanMessage({
|
|
310
|
+
content: 'Analyze the drug discovery data and create visualizations',
|
|
311
|
+
}),
|
|
312
|
+
new AIMessage({
|
|
313
|
+
content:
|
|
314
|
+
'Created 3 charts showing AI impact on drug development timelines.',
|
|
315
|
+
}),
|
|
316
|
+
];
|
|
317
|
+
|
|
318
|
+
// Summarize Agent B context (including Agent A's summary) before passing to Agent C
|
|
319
|
+
const summaryB = await summarize(agentBMessages, mockSummarizeCallback, {
|
|
320
|
+
tokenCounter: simpleTokenCounter,
|
|
321
|
+
});
|
|
322
|
+
expect(summaryB.tier).toBe('full');
|
|
323
|
+
// Agent B's summary should reference Agent A's work
|
|
324
|
+
expect(summaryB.messagesCompacted).toBe(agentBMessages.length);
|
|
325
|
+
|
|
326
|
+
// Agent C: Report generation — receives accumulated summaries
|
|
327
|
+
const agentCMessages: BaseMessage[] = [
|
|
328
|
+
new SystemMessage({ content: `[Chain Summary]\n${summaryB.summary}` }),
|
|
329
|
+
new HumanMessage({
|
|
330
|
+
content:
|
|
331
|
+
'Generate the final report with all findings and visualizations',
|
|
332
|
+
}),
|
|
333
|
+
];
|
|
334
|
+
|
|
335
|
+
// Agent C has enough context to generate the report
|
|
336
|
+
const cTokens = agentCMessages.reduce(
|
|
337
|
+
(sum, m) => sum + simpleTokenCounter(m),
|
|
338
|
+
0
|
|
339
|
+
);
|
|
340
|
+
expect(cTokens).toBeLessThan(8000); // Well within any model's budget
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('chain summary grows but stays within budget', async () => {
|
|
344
|
+
// Simulate a 5-agent chain where each adds to the rolling summary
|
|
345
|
+
let rollingSummary = '';
|
|
346
|
+
|
|
347
|
+
for (let i = 0; i < 5; i++) {
|
|
348
|
+
const agentMessages: BaseMessage[] = [
|
|
349
|
+
...(rollingSummary
|
|
350
|
+
? [
|
|
351
|
+
new SystemMessage({
|
|
352
|
+
content: `[Chain Summary]\n${rollingSummary}`,
|
|
353
|
+
}),
|
|
354
|
+
]
|
|
355
|
+
: []),
|
|
356
|
+
new HumanMessage({ content: `Agent ${i} task: process step ${i}` }),
|
|
357
|
+
new AIMessage({
|
|
358
|
+
content: `Agent ${i} completed step ${i}. ${'Result data '.repeat(50)}`,
|
|
359
|
+
}),
|
|
360
|
+
];
|
|
361
|
+
|
|
362
|
+
const result = await summarize(agentMessages, mockSummarizeCallback, {
|
|
363
|
+
tokenCounter: simpleTokenCounter,
|
|
364
|
+
summaryBudget: 500,
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
rollingSummary = result.summary;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// After 5 agents, rolling summary should still be manageable
|
|
371
|
+
const summaryTokens = Math.ceil(rollingSummary.length / 4);
|
|
372
|
+
expect(summaryTokens).toBeLessThan(1000); // Summary stays compact
|
|
373
|
+
expect(rollingSummary.length).toBeGreaterThan(0);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it('emergency summary preserves chain context when LLM fails', async () => {
|
|
377
|
+
// Agent chain where LLM fails mid-chain
|
|
378
|
+
const chainMessages: BaseMessage[] = [
|
|
379
|
+
new SystemMessage({
|
|
380
|
+
content: '[Chain Summary] Previous agents researched AI healthcare.',
|
|
381
|
+
}),
|
|
382
|
+
new HumanMessage({
|
|
383
|
+
content: 'Continue the analysis with cost projections',
|
|
384
|
+
}),
|
|
385
|
+
new AIMessage({ content: 'Cost analysis shows 30% reduction possible.' }),
|
|
386
|
+
new ToolMessage({
|
|
387
|
+
content: 'spreadsheet data loaded',
|
|
388
|
+
tool_call_id: 'tool_1',
|
|
389
|
+
}),
|
|
390
|
+
new HumanMessage({ content: 'Add regulatory compliance section' }),
|
|
391
|
+
new AIMessage({
|
|
392
|
+
content: 'Regulatory review completed for FDA pathways.',
|
|
393
|
+
}),
|
|
394
|
+
];
|
|
395
|
+
|
|
396
|
+
// LLM unavailable — falls to emergency
|
|
397
|
+
const result = await summarize(chainMessages, failingSummarizeCallback, {
|
|
398
|
+
tokenCounter: simpleTokenCounter,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
expect(result.tier).toBe('emergency');
|
|
402
|
+
expect(result.summary).toContain('cost projections'); // First user msg
|
|
403
|
+
expect(result.summary).toContain('FDA'); // Last AI msg
|
|
404
|
+
expect(result.summary).toContain('Messages compacted: 6'); // Total count
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// ============================================================================
|
|
409
|
+
// 4. Continuation Exhaustion and Retry
|
|
410
|
+
// ============================================================================
|
|
411
|
+
|
|
412
|
+
describe('Continuation exhaustion and retry', () => {
|
|
413
|
+
it('detects max_tokens finish reason requiring continuation', () => {
|
|
414
|
+
const finishReasons = ['length', 'max_tokens', 'end_turn', 'stop', null];
|
|
415
|
+
const needsContinuation = finishReasons.filter(
|
|
416
|
+
(r) => r === 'length' || r === 'max_tokens'
|
|
417
|
+
);
|
|
418
|
+
expect(needsContinuation).toEqual(['length', 'max_tokens']);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('enforces maxContinuations limit', () => {
|
|
422
|
+
const maxContinuations = 5;
|
|
423
|
+
let continuationCount = 0;
|
|
424
|
+
const results: string[] = [];
|
|
425
|
+
|
|
426
|
+
// Simulate continuation loop
|
|
427
|
+
while (continuationCount < maxContinuations) {
|
|
428
|
+
const finishReason = 'max_tokens'; // Always hits limit
|
|
429
|
+
if (finishReason !== 'max_tokens' && finishReason !== 'length') {
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
continuationCount++;
|
|
433
|
+
results.push(`Continuation ${continuationCount}`);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
expect(continuationCount).toBe(maxContinuations);
|
|
437
|
+
expect(results.length).toBe(maxContinuations);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it('appends truncation notice when all continuations exhausted', () => {
|
|
441
|
+
const maxContinuations = 5;
|
|
442
|
+
const continuationCount = 5;
|
|
443
|
+
const lastFinishReason = 'max_tokens';
|
|
444
|
+
|
|
445
|
+
const isExhausted =
|
|
446
|
+
continuationCount >= maxContinuations &&
|
|
447
|
+
lastFinishReason === 'max_tokens';
|
|
448
|
+
expect(isExhausted).toBe(true);
|
|
449
|
+
|
|
450
|
+
// Truncation notice appended to last content
|
|
451
|
+
const truncationNotice =
|
|
452
|
+
'\n\n[Note: Response was truncated due to length. Ask me to continue if you need the rest.]';
|
|
453
|
+
const lastContent = 'Some AI response that was cut off';
|
|
454
|
+
const withNotice = lastContent + truncationNotice;
|
|
455
|
+
expect(withNotice).toContain('truncated due to length');
|
|
456
|
+
expect(withNotice).toContain('continue');
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it('retry-once logic: retries after 2s delay then gives up', async () => {
|
|
460
|
+
let attempts = 0;
|
|
461
|
+
let retried = false;
|
|
462
|
+
|
|
463
|
+
const simulateContinuation = async (): Promise<string> => {
|
|
464
|
+
attempts++;
|
|
465
|
+
if (attempts === 1) {
|
|
466
|
+
throw new Error('Temporary failure');
|
|
467
|
+
}
|
|
468
|
+
return 'Recovered content';
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
// First attempt fails, retry once
|
|
472
|
+
try {
|
|
473
|
+
await simulateContinuation();
|
|
474
|
+
} catch {
|
|
475
|
+
if (!retried) {
|
|
476
|
+
retried = true;
|
|
477
|
+
// In real code: await new Promise(r => setTimeout(r, 2000));
|
|
478
|
+
const result = await simulateContinuation();
|
|
479
|
+
expect(result).toBe('Recovered content');
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
expect(attempts).toBe(2);
|
|
484
|
+
expect(retried).toBe(true);
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
it('saves partial response with interruption notice on final failure', () => {
|
|
488
|
+
const partialResponse = 'Here is the beginning of the analysis...';
|
|
489
|
+
const interruptionNotice =
|
|
490
|
+
'\n\n[Response interrupted: An error occurred while generating this response. The content above may be incomplete.]';
|
|
491
|
+
|
|
492
|
+
const finalContent = partialResponse + interruptionNotice;
|
|
493
|
+
expect(finalContent).toContain('interrupted');
|
|
494
|
+
expect(finalContent).toContain('beginning of the analysis');
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
it('context compaction enables additional continuations', async () => {
|
|
498
|
+
// After 5 continuations, compact context to free space for more
|
|
499
|
+
const longConversation = buildConversation(30, 400); // 30 turns
|
|
500
|
+
|
|
501
|
+
// Before compaction: high utilization
|
|
502
|
+
const totalTokens = longConversation.reduce(
|
|
503
|
+
(sum, m) => sum + simpleTokenCounter(m),
|
|
504
|
+
0
|
|
505
|
+
);
|
|
506
|
+
const maxTokens = totalTokens + 2000; // Just barely fits
|
|
507
|
+
const utilBefore = getContextUtilization(
|
|
508
|
+
Object.fromEntries(
|
|
509
|
+
longConversation.map((_, i) => [
|
|
510
|
+
String(i),
|
|
511
|
+
simpleTokenCounter(longConversation[i]),
|
|
512
|
+
])
|
|
513
|
+
),
|
|
514
|
+
500,
|
|
515
|
+
maxTokens
|
|
516
|
+
);
|
|
517
|
+
expect(utilBefore).toBeGreaterThan(80);
|
|
518
|
+
|
|
519
|
+
// After compaction
|
|
520
|
+
const result = await summarize(longConversation, mockSummarizeCallback, {
|
|
521
|
+
tokenCounter: simpleTokenCounter,
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
const compactedMessages = [
|
|
525
|
+
new SystemMessage({
|
|
526
|
+
content: `[Conversation Summary]\n${result.summary}`,
|
|
527
|
+
}),
|
|
528
|
+
...longConversation.slice(-3),
|
|
529
|
+
];
|
|
530
|
+
const compactedTokens = compactedMessages.reduce(
|
|
531
|
+
(sum, m) => sum + simpleTokenCounter(m),
|
|
532
|
+
0
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
// After compaction, plenty of room for more continuations
|
|
536
|
+
expect(compactedTokens).toBeLessThan(maxTokens * 0.5);
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
// ============================================================================
|
|
541
|
+
// 5. Pre-invocation Utilization Gate
|
|
542
|
+
// ============================================================================
|
|
543
|
+
|
|
544
|
+
describe('Pre-invocation utilization gate', () => {
|
|
545
|
+
it('emits warning at 70-85% utilization', () => {
|
|
546
|
+
const maxContextTokens = 10000;
|
|
547
|
+
const currentTokens = 7500; // 75%
|
|
548
|
+
|
|
549
|
+
const utilization = (currentTokens / maxContextTokens) * 100;
|
|
550
|
+
const events: Array<{ type: string; level: string }> = [];
|
|
551
|
+
|
|
552
|
+
if (utilization > 95) {
|
|
553
|
+
events.push({ type: 'ON_CONTEXT_PRESSURE', level: 'emergency' });
|
|
554
|
+
} else if (utilization > 85) {
|
|
555
|
+
events.push({ type: 'ON_CONTEXT_PRESSURE', level: 'critical' });
|
|
556
|
+
} else if (utilization > 70) {
|
|
557
|
+
events.push({ type: 'ON_CONTEXT_PRESSURE', level: 'warning' });
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
expect(events).toHaveLength(1);
|
|
561
|
+
expect(events[0].level).toBe('warning');
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
it('triggers proactive compaction at 85-95% utilization', async () => {
|
|
565
|
+
const maxContextTokens = 10000;
|
|
566
|
+
const currentTokens = 9000; // 90%
|
|
567
|
+
const utilization = (currentTokens / maxContextTokens) * 100;
|
|
568
|
+
|
|
569
|
+
expect(utilization).toBeGreaterThan(85);
|
|
570
|
+
expect(utilization).toBeLessThan(95);
|
|
571
|
+
|
|
572
|
+
// Should trigger proactive compaction
|
|
573
|
+
const messages = buildConversation(20, 200);
|
|
574
|
+
const result = await summarize(messages, mockSummarizeCallback, {
|
|
575
|
+
tokenCounter: simpleTokenCounter,
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
expect(result.summary.length).toBeGreaterThan(0);
|
|
579
|
+
// After compaction, utilization should drop significantly
|
|
580
|
+
const compactedTokens = Math.ceil(result.summary.length / 4) + 500; // summary + last few messages
|
|
581
|
+
const newUtilization = (compactedTokens / maxContextTokens) * 100;
|
|
582
|
+
expect(newUtilization).toBeLessThan(50);
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
it('triggers emergency compaction at >95% utilization', async () => {
|
|
586
|
+
const maxContextTokens = 10000;
|
|
587
|
+
const currentTokens = 9600; // 96%
|
|
588
|
+
const utilization = (currentTokens / maxContextTokens) * 100;
|
|
589
|
+
|
|
590
|
+
expect(utilization).toBeGreaterThan(95);
|
|
591
|
+
|
|
592
|
+
// Emergency: no LLM call, pure extraction
|
|
593
|
+
const messages = buildConversation(30, 300);
|
|
594
|
+
const emergency = createEmergencySummary(messages);
|
|
595
|
+
expect(emergency).toBeTruthy();
|
|
596
|
+
expect(emergency.length).toBeLessThan(2000); // Emergency summaries are compact
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
it('injects delegation hint at >70% utilization for agents with task tool', () => {
|
|
600
|
+
const utilization = 75;
|
|
601
|
+
const hasTaskTool = true;
|
|
602
|
+
|
|
603
|
+
if (utilization > 70 && hasTaskTool) {
|
|
604
|
+
const delegationHint = new HumanMessage({
|
|
605
|
+
content:
|
|
606
|
+
'[System] Context window is at 75% capacity. Consider delegating complex sub-tasks ' +
|
|
607
|
+
'to the task tool to maintain context availability.',
|
|
608
|
+
});
|
|
609
|
+
expect(delegationHint.content).toContain('75%');
|
|
610
|
+
expect(delegationHint.content).toContain('task tool');
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
it('does not inject delegation hint below 70%', () => {
|
|
615
|
+
const utilization = 65;
|
|
616
|
+
let delegationInjected = false;
|
|
617
|
+
|
|
618
|
+
if (utilization > 70) {
|
|
619
|
+
delegationInjected = true;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
expect(delegationInjected).toBe(false);
|
|
623
|
+
});
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
// ============================================================================
|
|
627
|
+
// 6. Emergency Context Preservation (First+Last Pair)
|
|
628
|
+
// ============================================================================
|
|
629
|
+
|
|
630
|
+
describe('Emergency context preservation', () => {
|
|
631
|
+
it('preserves first user message and last AI message from 50-turn conversation', () => {
|
|
632
|
+
const messages = buildConversation(50, 200);
|
|
633
|
+
const emergency = createEmergencySummary(messages);
|
|
634
|
+
|
|
635
|
+
// Should contain first user intent
|
|
636
|
+
expect(emergency).toContain('User message 0');
|
|
637
|
+
// Should contain last AI state
|
|
638
|
+
expect(emergency).toContain('AI response 49');
|
|
639
|
+
// Should report correct count
|
|
640
|
+
expect(emergency).toContain('Messages compacted: 100');
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
it('captures tool names in emergency summary', () => {
|
|
644
|
+
const messages: BaseMessage[] = [
|
|
645
|
+
new HumanMessage({ content: 'Search for revenue data' }),
|
|
646
|
+
new ToolMessage({
|
|
647
|
+
content: 'Found 5 documents',
|
|
648
|
+
tool_call_id: 'tc_1',
|
|
649
|
+
name: 'file_search',
|
|
650
|
+
}),
|
|
651
|
+
new ToolMessage({
|
|
652
|
+
content: 'Web results for Q4',
|
|
653
|
+
tool_call_id: 'tc_2',
|
|
654
|
+
name: 'web_search',
|
|
655
|
+
}),
|
|
656
|
+
new ToolMessage({
|
|
657
|
+
content: 'Code executed successfully',
|
|
658
|
+
tool_call_id: 'tc_3',
|
|
659
|
+
name: 'code_execution',
|
|
660
|
+
}),
|
|
661
|
+
new AIMessage({ content: 'Analysis complete' }),
|
|
662
|
+
];
|
|
663
|
+
|
|
664
|
+
const emergency = createEmergencySummary(messages);
|
|
665
|
+
expect(emergency).toContain('file_search');
|
|
666
|
+
expect(emergency).toContain('web_search');
|
|
667
|
+
expect(emergency).toContain('code_execution');
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
it('emergency summary never throws even with malformed messages', () => {
|
|
671
|
+
const weirdMessages: BaseMessage[] = [
|
|
672
|
+
new HumanMessage({ content: '' }), // Empty
|
|
673
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
674
|
+
new AIMessage({ content: [{ type: 'text', text: '' }] as any }), // Complex empty
|
|
675
|
+
new SystemMessage({ content: 'system' }),
|
|
676
|
+
];
|
|
677
|
+
|
|
678
|
+
expect(() => createEmergencySummary(weirdMessages)).not.toThrow();
|
|
679
|
+
const result = createEmergencySummary(weirdMessages);
|
|
680
|
+
expect(typeof result).toBe('string');
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
it('preserves context even when all intermediate messages are removed', async () => {
|
|
684
|
+
const messages: BaseMessage[] = [
|
|
685
|
+
new HumanMessage({
|
|
686
|
+
content: 'CRITICAL: Build the authentication system for the app',
|
|
687
|
+
}),
|
|
688
|
+
...buildConversation(40, 300), // 40 turns of intermediate work
|
|
689
|
+
new HumanMessage({ content: 'Now deploy to production' }),
|
|
690
|
+
new AIMessage({
|
|
691
|
+
content: 'Deploying the authentication system to AWS ECS...',
|
|
692
|
+
}),
|
|
693
|
+
];
|
|
694
|
+
|
|
695
|
+
const emergency = createEmergencySummary(messages);
|
|
696
|
+
// First user message preserved
|
|
697
|
+
expect(emergency).toContain('authentication system');
|
|
698
|
+
// Last AI response preserved
|
|
699
|
+
expect(emergency).toContain('Deploying');
|
|
700
|
+
});
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
// ============================================================================
|
|
704
|
+
// 7. Multi-Agent Context Handoff Scenarios
|
|
705
|
+
// ============================================================================
|
|
706
|
+
|
|
707
|
+
describe('Multi-agent context handoff scenarios', () => {
|
|
708
|
+
it('research agent → writing agent handoff preserves findings', async () => {
|
|
709
|
+
const researchMessages: BaseMessage[] = [
|
|
710
|
+
new HumanMessage({
|
|
711
|
+
content: 'Research competitors: Acme Corp, Beta Inc, Gamma Ltd',
|
|
712
|
+
}),
|
|
713
|
+
new ToolMessage({
|
|
714
|
+
content: 'Acme Corp: $50M revenue, 200 employees',
|
|
715
|
+
tool_call_id: 'ws_1',
|
|
716
|
+
name: 'web_search',
|
|
717
|
+
}),
|
|
718
|
+
new ToolMessage({
|
|
719
|
+
content: 'Beta Inc: $30M revenue, 150 employees',
|
|
720
|
+
tool_call_id: 'ws_2',
|
|
721
|
+
name: 'web_search',
|
|
722
|
+
}),
|
|
723
|
+
new AIMessage({
|
|
724
|
+
content:
|
|
725
|
+
'Found competitive data: Acme leads with $50M, Beta at $30M, Gamma data unavailable.',
|
|
726
|
+
}),
|
|
727
|
+
];
|
|
728
|
+
|
|
729
|
+
// Summarize for handoff
|
|
730
|
+
const result = await summarize(researchMessages, mockSummarizeCallback, {
|
|
731
|
+
tokenCounter: simpleTokenCounter,
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
expect(result.tier).toBe('full');
|
|
735
|
+
expect(result.messagesCompacted).toBe(4);
|
|
736
|
+
|
|
737
|
+
// Writing agent receives the summary
|
|
738
|
+
const writingContext = [
|
|
739
|
+
new SystemMessage({
|
|
740
|
+
content: `[Handoff from Research Agent]\n${result.summary}\n\nYou are the Writing Agent. Create a report based on the research above.`,
|
|
741
|
+
}),
|
|
742
|
+
];
|
|
743
|
+
|
|
744
|
+
const writingTokens = writingContext.reduce(
|
|
745
|
+
(sum, m) => sum + simpleTokenCounter(m),
|
|
746
|
+
0
|
|
747
|
+
);
|
|
748
|
+
expect(writingTokens).toBeLessThan(2000);
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
it('handles cascade handoff: A → B → C → A (circular)', async () => {
|
|
752
|
+
// A → B handoff
|
|
753
|
+
const summaryAB = await summarize(
|
|
754
|
+
buildConversation(5, 200),
|
|
755
|
+
mockSummarizeCallback,
|
|
756
|
+
{
|
|
757
|
+
tokenCounter: simpleTokenCounter,
|
|
758
|
+
}
|
|
759
|
+
);
|
|
760
|
+
|
|
761
|
+
// B → C handoff
|
|
762
|
+
const summaryBC = await summarize(
|
|
763
|
+
[
|
|
764
|
+
new SystemMessage({ content: `[From A]\n${summaryAB.summary}` }),
|
|
765
|
+
...buildConversation(3, 200),
|
|
766
|
+
],
|
|
767
|
+
mockSummarizeCallback,
|
|
768
|
+
{ tokenCounter: simpleTokenCounter }
|
|
769
|
+
);
|
|
770
|
+
|
|
771
|
+
// C → A handoff (back to original)
|
|
772
|
+
const summaryCA = await summarize(
|
|
773
|
+
[
|
|
774
|
+
new SystemMessage({ content: `[From B via A]\n${summaryBC.summary}` }),
|
|
775
|
+
...buildConversation(3, 200),
|
|
776
|
+
],
|
|
777
|
+
mockSummarizeCallback,
|
|
778
|
+
{ tokenCounter: simpleTokenCounter }
|
|
779
|
+
);
|
|
780
|
+
|
|
781
|
+
// All summaries should exist and be compact
|
|
782
|
+
expect(summaryAB.summary.length).toBeGreaterThan(0);
|
|
783
|
+
expect(summaryBC.summary.length).toBeGreaterThan(0);
|
|
784
|
+
expect(summaryCA.summary.length).toBeGreaterThan(0);
|
|
785
|
+
|
|
786
|
+
// Final summary shouldn't have exploded in size
|
|
787
|
+
const finalTokens = Math.ceil(summaryCA.summary.length / 4);
|
|
788
|
+
expect(finalTokens).toBeLessThan(1000);
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
it('multi-agent workflow state is included in full summary prompt', () => {
|
|
792
|
+
const messages: BaseMessage[] = [
|
|
793
|
+
new HumanMessage({ content: 'Start multi-agent research' }),
|
|
794
|
+
new AIMessage({ content: 'Delegating to specialized agents.' }),
|
|
795
|
+
];
|
|
796
|
+
|
|
797
|
+
const formatted = formatMessagesForSummary(messages);
|
|
798
|
+
const prompt = buildFullSummaryPrompt(formatted, {
|
|
799
|
+
isMultiAgent: true,
|
|
800
|
+
agentWorkflowState: {
|
|
801
|
+
currentAgentId: 'analysis-agent',
|
|
802
|
+
agentChain: ['research-agent', 'analysis-agent'],
|
|
803
|
+
pendingAgents: ['writing-agent'],
|
|
804
|
+
},
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
expect(prompt).toContain('analysis-agent');
|
|
808
|
+
expect(prompt).toContain('research-agent');
|
|
809
|
+
expect(prompt).toContain('writing-agent');
|
|
810
|
+
expect(prompt).toContain('Agent Workflow State');
|
|
811
|
+
});
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
// ============================================================================
|
|
815
|
+
// 8. summaryModel Dedicated Cheap Model Usage
|
|
816
|
+
// ============================================================================
|
|
817
|
+
|
|
818
|
+
describe('summaryModel dedicated cheap model usage', () => {
|
|
819
|
+
it('summarize passes maxOutputTokens to callback for model configuration', async () => {
|
|
820
|
+
let capturedMaxTokens: number | undefined;
|
|
821
|
+
|
|
822
|
+
const trackingCallback = async (
|
|
823
|
+
prompt: string,
|
|
824
|
+
maxTokens: number
|
|
825
|
+
): Promise<string> => {
|
|
826
|
+
capturedMaxTokens = maxTokens;
|
|
827
|
+
return '[Summary] Tracked callback.';
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
await summarize(buildConversation(5, 200), trackingCallback, {
|
|
831
|
+
tokenCounter: simpleTokenCounter,
|
|
832
|
+
maxOutputTokens: 2048,
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
expect(capturedMaxTokens).toBe(2048);
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
it('Tier 2 uses lower maxTokens (512) than Tier 1', async () => {
|
|
839
|
+
const capturedMaxTokens: number[] = [];
|
|
840
|
+
let callCount = 0;
|
|
841
|
+
|
|
842
|
+
const tieredCallback = async (
|
|
843
|
+
prompt: string,
|
|
844
|
+
maxTokens: number
|
|
845
|
+
): Promise<string> => {
|
|
846
|
+
capturedMaxTokens.push(maxTokens);
|
|
847
|
+
callCount++;
|
|
848
|
+
if (callCount === 1) {
|
|
849
|
+
throw new Error('Tier 1 failed'); // Force fallback to Tier 2
|
|
850
|
+
}
|
|
851
|
+
return '[Simple Summary]';
|
|
852
|
+
};
|
|
853
|
+
|
|
854
|
+
await summarize(buildConversation(5, 200), tieredCallback, {
|
|
855
|
+
tokenCounter: simpleTokenCounter,
|
|
856
|
+
maxOutputTokens: 1024,
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
// Tier 1 tried with 1024, Tier 2 tried with 512
|
|
860
|
+
expect(capturedMaxTokens[0]).toBe(1024);
|
|
861
|
+
expect(capturedMaxTokens[1]).toBe(512);
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
it('summaryModel config follows titleModel pattern', () => {
|
|
865
|
+
// Verify the config structure matches expectations
|
|
866
|
+
const endpointConfig = {
|
|
867
|
+
titleModel: 'us.amazon.nova-micro-v1:0',
|
|
868
|
+
summaryModel: 'us.anthropic.claude-haiku-4-5-20251001-v1:0',
|
|
869
|
+
modelDisplayLabel: 'Ranger',
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
// summaryModel should be a different, cheaper model than the main model
|
|
873
|
+
expect(endpointConfig.summaryModel).not.toBe(endpointConfig.titleModel);
|
|
874
|
+
expect(endpointConfig.summaryModel).toContain('haiku'); // Cheap model
|
|
875
|
+
});
|
|
876
|
+
|
|
877
|
+
it('falls back through provider defaults when no summaryModel configured', () => {
|
|
878
|
+
const providers = [
|
|
879
|
+
{ name: 'bedrock', expected: 'claude-3-haiku-20240307' },
|
|
880
|
+
{ name: 'anthropic', expected: 'claude-3-haiku-20240307' },
|
|
881
|
+
{ name: 'openAI', expected: 'gpt-4o-mini' },
|
|
882
|
+
{ name: 'google', expected: 'gemini-2.0-flash' },
|
|
883
|
+
{ name: 'unknown', expected: 'claude-3-haiku-20240307' },
|
|
884
|
+
];
|
|
885
|
+
|
|
886
|
+
for (const { name, expected } of providers) {
|
|
887
|
+
let summaryModel: string;
|
|
888
|
+
if (name === 'bedrock' || name === 'anthropic') {
|
|
889
|
+
summaryModel = 'claude-3-haiku-20240307';
|
|
890
|
+
} else if (name === 'openAI' || name === 'azureOpenAI') {
|
|
891
|
+
summaryModel = 'gpt-4o-mini';
|
|
892
|
+
} else if (name === 'google') {
|
|
893
|
+
summaryModel = 'gemini-2.0-flash';
|
|
894
|
+
} else {
|
|
895
|
+
summaryModel = 'claude-3-haiku-20240307';
|
|
896
|
+
}
|
|
897
|
+
expect(summaryModel).toBe(expected);
|
|
898
|
+
}
|
|
899
|
+
});
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
// ============================================================================
|
|
903
|
+
// 9. Config Wiring Validation
|
|
904
|
+
// ============================================================================
|
|
905
|
+
|
|
906
|
+
describe('Config wiring validation', () => {
|
|
907
|
+
it('contextManagement config has all required fields', () => {
|
|
908
|
+
const config = {
|
|
909
|
+
compactMode: 'auto',
|
|
910
|
+
recoveryMode: 'summarize',
|
|
911
|
+
continuationRetries: 1,
|
|
912
|
+
toolResultBudgetPct: 0.3,
|
|
913
|
+
subagentMaxResultTokens: 8192,
|
|
914
|
+
chainRollingSummary: false,
|
|
915
|
+
fileReadDedup: true,
|
|
916
|
+
compactionAudit: true,
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
// All fields present
|
|
920
|
+
expect(config.compactMode).toBeDefined();
|
|
921
|
+
expect(config.recoveryMode).toBeDefined();
|
|
922
|
+
expect(config.continuationRetries).toBeDefined();
|
|
923
|
+
expect(config.toolResultBudgetPct).toBeDefined();
|
|
924
|
+
expect(config.subagentMaxResultTokens).toBeDefined();
|
|
925
|
+
expect(config.chainRollingSummary).toBeDefined();
|
|
926
|
+
expect(config.fileReadDedup).toBeDefined();
|
|
927
|
+
expect(config.compactionAudit).toBeDefined();
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
it('subagentMaxResultTokens converts to chars correctly', () => {
|
|
931
|
+
const tokenValues = [4096, 8192, 16384, 32768];
|
|
932
|
+
for (const tokens of tokenValues) {
|
|
933
|
+
const chars = tokens * 4;
|
|
934
|
+
expect(chars).toBe(tokens * 4);
|
|
935
|
+
// Chars should be reasonable (not exceeding 200K chars)
|
|
936
|
+
expect(chars).toBeLessThan(200000);
|
|
937
|
+
}
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
it('compactMode values are valid', () => {
|
|
941
|
+
const validModes = ['auto', 'summarize', 'prune'];
|
|
942
|
+
for (const mode of validModes) {
|
|
943
|
+
expect(['auto', 'summarize', 'prune']).toContain(mode);
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
it('recoveryMode values are valid', () => {
|
|
948
|
+
const validModes = ['summarize', 'prune', 'emergency'];
|
|
949
|
+
for (const mode of validModes) {
|
|
950
|
+
expect(['summarize', 'prune', 'emergency']).toContain(mode);
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
});
|
|
954
|
+
|
|
955
|
+
// ============================================================================
|
|
956
|
+
// 10. Stress Tests: Large Conversations
|
|
957
|
+
// ============================================================================
|
|
958
|
+
|
|
959
|
+
describe('Stress tests with large conversations', () => {
|
|
960
|
+
it('handles 200-turn conversation summarization', async () => {
|
|
961
|
+
const messages = buildConversation(200, 100); // 400 messages
|
|
962
|
+
expect(messages.length).toBe(400);
|
|
963
|
+
|
|
964
|
+
const result = await summarize(messages, mockSummarizeCallback, {
|
|
965
|
+
tokenCounter: simpleTokenCounter,
|
|
966
|
+
});
|
|
967
|
+
|
|
968
|
+
expect(result.summary.length).toBeGreaterThan(0);
|
|
969
|
+
expect(result.messagesCompacted).toBe(400);
|
|
970
|
+
});
|
|
971
|
+
|
|
972
|
+
it('emergency summary from 500-turn conversation is still compact', () => {
|
|
973
|
+
const messages = buildConversation(500, 50); // 1000 messages
|
|
974
|
+
const emergency = createEmergencySummary(messages);
|
|
975
|
+
|
|
976
|
+
// Emergency summary should be compact regardless of input size
|
|
977
|
+
expect(emergency.length).toBeLessThan(3000);
|
|
978
|
+
expect(emergency).toContain('Messages compacted: 1000');
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
it('getContextUtilization handles 1000-message token map', () => {
|
|
982
|
+
const map: Record<string, number> = {};
|
|
983
|
+
for (let i = 0; i < 1000; i++) {
|
|
984
|
+
map[String(i)] = 100;
|
|
985
|
+
}
|
|
986
|
+
const result = getContextUtilization(map, 500, 200000);
|
|
987
|
+
// 1000 * 100 + 500 = 100500 / 200000 = 50.25%
|
|
988
|
+
expect(result).toBeCloseTo(50.25, 1);
|
|
989
|
+
});
|
|
990
|
+
});
|