@librechat/agents 3.2.2 → 3.2.31
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 +3 -2
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +200 -54
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +13 -7
- package/dist/cjs/hooks/createWorkspacePolicyHook.cjs.map +1 -1
- package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
- package/dist/cjs/hooks/types.cjs.map +1 -1
- package/dist/cjs/instrumentation.cjs +33 -0
- package/dist/cjs/instrumentation.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +17 -1
- package/dist/cjs/langfuse.cjs.map +1 -1
- package/dist/cjs/langfuseToolOutputTracing.cjs +2 -2
- package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/index.cjs +1 -1
- package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +1 -1
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +2 -2
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/toolCache.cjs +8 -5
- package/dist/cjs/llm/bedrock/toolCache.cjs.map +1 -1
- package/dist/cjs/llm/fake.cjs +16 -14
- package/dist/cjs/llm/fake.cjs.map +1 -1
- package/dist/cjs/llm/google/index.cjs +22 -0
- package/dist/cjs/llm/google/index.cjs.map +1 -1
- package/dist/cjs/llm/google/utils/common.cjs +88 -27
- package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
- package/dist/cjs/llm/init.cjs +2 -2
- package/dist/cjs/llm/invoke.cjs +108 -11
- package/dist/cjs/llm/invoke.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 +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
- package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +1 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/cache.cjs +8 -7
- package/dist/cjs/messages/cache.cjs.map +1 -1
- package/dist/cjs/messages/content.cjs.map +1 -1
- package/dist/cjs/messages/contextPruning.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +124 -17
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/messages/reducer.cjs +1 -1
- package/dist/cjs/messages/reducer.cjs.map +1 -1
- package/dist/cjs/messages/tools.cjs +1 -1
- package/dist/cjs/messages/tools.cjs.map +1 -1
- package/dist/cjs/openai/index.cjs.map +1 -1
- package/dist/cjs/responses/index.cjs.map +1 -1
- package/dist/cjs/run.cjs +47 -21
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +4 -4
- package/dist/cjs/session/AgentSession.cjs.map +1 -1
- package/dist/cjs/session/JsonlSessionStore.cjs +2 -2
- package/dist/cjs/session/JsonlSessionStore.cjs.map +1 -1
- package/dist/cjs/session/handlers.cjs +2 -2
- package/dist/cjs/session/handlers.cjs.map +1 -1
- package/dist/cjs/stream.cjs +248 -25
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/Calculator.cjs +1 -1
- package/dist/cjs/tools/Calculator.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +37 -18
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearch.cjs +1 -1
- package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
- package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs +7 -4
- package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs.map +1 -1
- package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs +4 -4
- package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs.map +1 -1
- package/dist/cjs/tools/handlers.cjs +2 -1
- package/dist/cjs/tools/handlers.cjs.map +1 -1
- package/dist/cjs/tools/local/CompileCheckTool.cjs.map +1 -1
- package/dist/cjs/tools/local/FileCheckpointer.cjs +2 -1
- package/dist/cjs/tools/local/FileCheckpointer.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalCodingTools.cjs +45 -19
- package/dist/cjs/tools/local/LocalCodingTools.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs +3 -3
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalExecutionTools.cjs +2 -2
- package/dist/cjs/tools/local/LocalExecutionTools.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +4 -3
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/local/attachments.cjs +0 -5
- package/dist/cjs/tools/local/attachments.cjs.map +1 -1
- package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +4 -4
- package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -1
- package/dist/cjs/tools/search/firecrawl.cjs +1 -1
- package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
- package/dist/cjs/tools/search/rerankers.cjs +7 -3
- package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
- package/dist/cjs/tools/search/tavily-search.cjs +1 -1
- package/dist/cjs/tools/search/tavily-search.cjs.map +1 -1
- package/dist/cjs/tools/search/utils.cjs +76 -8
- package/dist/cjs/tools/search/utils.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/utils/handlers.cjs +1 -1
- package/dist/cjs/utils/handlers.cjs.map +1 -1
- package/dist/cjs/utils/run.cjs +1 -1
- package/dist/cjs/utils/run.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +3 -2
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +200 -54
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/hooks/createWorkspacePolicyHook.mjs +13 -7
- package/dist/esm/hooks/createWorkspacePolicyHook.mjs.map +1 -1
- package/dist/esm/hooks/executeHooks.mjs.map +1 -1
- package/dist/esm/hooks/types.mjs.map +1 -1
- package/dist/esm/instrumentation.mjs +33 -1
- package/dist/esm/instrumentation.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +17 -2
- package/dist/esm/langfuse.mjs.map +1 -1
- package/dist/esm/langfuseToolOutputTracing.mjs +2 -2
- package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
- package/dist/esm/llm/anthropic/index.mjs +1 -1
- package/dist/esm/llm/anthropic/index.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs +1 -1
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +2 -2
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/llm/bedrock/toolCache.mjs +8 -5
- package/dist/esm/llm/bedrock/toolCache.mjs.map +1 -1
- package/dist/esm/llm/fake.mjs +16 -14
- package/dist/esm/llm/fake.mjs.map +1 -1
- package/dist/esm/llm/google/index.mjs +23 -1
- package/dist/esm/llm/google/index.mjs.map +1 -1
- package/dist/esm/llm/google/utils/common.mjs +88 -27
- package/dist/esm/llm/google/utils/common.mjs.map +1 -1
- package/dist/esm/llm/init.mjs +2 -2
- package/dist/esm/llm/invoke.mjs +104 -7
- package/dist/esm/llm/invoke.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 +1 -1
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/index.mjs.map +1 -1
- package/dist/esm/llm/vertexai/index.mjs.map +1 -1
- package/dist/esm/main.mjs +1 -1
- package/dist/esm/messages/cache.mjs +8 -7
- package/dist/esm/messages/cache.mjs.map +1 -1
- package/dist/esm/messages/content.mjs.map +1 -1
- package/dist/esm/messages/contextPruning.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +124 -18
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/messages/reducer.mjs +1 -1
- package/dist/esm/messages/reducer.mjs.map +1 -1
- package/dist/esm/messages/tools.mjs +1 -1
- package/dist/esm/messages/tools.mjs.map +1 -1
- package/dist/esm/openai/index.mjs.map +1 -1
- package/dist/esm/responses/index.mjs.map +1 -1
- package/dist/esm/run.mjs +47 -21
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +4 -4
- package/dist/esm/session/AgentSession.mjs.map +1 -1
- package/dist/esm/session/JsonlSessionStore.mjs +2 -2
- package/dist/esm/session/JsonlSessionStore.mjs.map +1 -1
- package/dist/esm/session/handlers.mjs +2 -2
- package/dist/esm/session/handlers.mjs.map +1 -1
- package/dist/esm/stream.mjs +248 -25
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/Calculator.mjs +1 -1
- package/dist/esm/tools/Calculator.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +1 -1
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/SubagentTool.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +37 -18
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearch.mjs +1 -1
- package/dist/esm/tools/ToolSearch.mjs.map +1 -1
- package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs +7 -4
- package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs.map +1 -1
- package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs +4 -4
- package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs.map +1 -1
- package/dist/esm/tools/handlers.mjs +2 -1
- package/dist/esm/tools/handlers.mjs.map +1 -1
- package/dist/esm/tools/local/CompileCheckTool.mjs.map +1 -1
- package/dist/esm/tools/local/FileCheckpointer.mjs +2 -1
- package/dist/esm/tools/local/FileCheckpointer.mjs.map +1 -1
- package/dist/esm/tools/local/LocalCodingTools.mjs +45 -19
- package/dist/esm/tools/local/LocalCodingTools.mjs.map +1 -1
- package/dist/esm/tools/local/LocalExecutionEngine.mjs +3 -3
- package/dist/esm/tools/local/LocalExecutionEngine.mjs.map +1 -1
- package/dist/esm/tools/local/LocalExecutionTools.mjs +2 -2
- package/dist/esm/tools/local/LocalExecutionTools.mjs.map +1 -1
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +4 -3
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/local/attachments.mjs +0 -5
- package/dist/esm/tools/local/attachments.mjs.map +1 -1
- package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +4 -4
- package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -1
- package/dist/esm/tools/search/firecrawl.mjs +1 -1
- package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
- package/dist/esm/tools/search/rerankers.mjs +8 -4
- package/dist/esm/tools/search/rerankers.mjs.map +1 -1
- package/dist/esm/tools/search/tavily-search.mjs +1 -1
- package/dist/esm/tools/search/tavily-search.mjs.map +1 -1
- package/dist/esm/tools/search/utils.mjs +76 -9
- package/dist/esm/tools/search/utils.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/utils/handlers.mjs +1 -1
- package/dist/esm/utils/handlers.mjs.map +1 -1
- package/dist/esm/utils/run.mjs +1 -1
- package/dist/esm/utils/run.mjs.map +1 -1
- package/dist/types/agents/__tests__/promptCacheLiveHelpers.d.ts +1 -1
- package/dist/types/events.d.ts +1 -1
- package/dist/types/graphs/Graph.d.ts +7 -1
- package/dist/types/hooks/executeHooks.d.ts +1 -1
- package/dist/types/hooks/types.d.ts +5 -0
- package/dist/types/instrumentation.d.ts +1 -0
- package/dist/types/langfuse.d.ts +4 -0
- package/dist/types/llm/anthropic/utils/message_inputs.d.ts +1 -1
- package/dist/types/llm/anthropic/utils/message_outputs.d.ts +1 -1
- package/dist/types/llm/anthropic/utils/output_parsers.d.ts +2 -2
- package/dist/types/llm/bedrock/index.d.ts +2 -2
- package/dist/types/llm/fake.d.ts +3 -3
- package/dist/types/llm/google/index.d.ts +1 -0
- package/dist/types/llm/google/types.d.ts +1 -1
- package/dist/types/llm/google/utils/common.d.ts +2 -2
- package/dist/types/llm/google/utils/tools.d.ts +1 -1
- package/dist/types/llm/google/utils/zod_to_genai_parameters.d.ts +1 -1
- package/dist/types/llm/openai/index.d.ts +2 -2
- package/dist/types/llm/openai/utils/index.d.ts +1 -1
- package/dist/types/llm/openrouter/index.d.ts +4 -4
- package/dist/types/messages/contextPruning.d.ts +1 -1
- package/dist/types/messages/format.d.ts +9 -4
- package/dist/types/messages/prune.d.ts +1 -1
- package/dist/types/session/JsonlSessionStore.d.ts +1 -1
- package/dist/types/session/handlers.d.ts +1 -1
- package/dist/types/session/types.d.ts +1 -1
- package/dist/types/summarization/node.d.ts +1 -1
- package/dist/types/tools/SubagentTool.d.ts +2 -2
- package/dist/types/tools/ToolNode.d.ts +9 -2
- package/dist/types/tools/cloudflare/CloudflareSandboxExecutionEngine.d.ts +1 -1
- package/dist/types/tools/search/types.d.ts +1 -1
- package/dist/types/tools/search/utils.d.ts +11 -0
- package/dist/types/types/graph.d.ts +12 -4
- package/dist/types/types/llm.d.ts +4 -3
- package/dist/types/types/messages.d.ts +1 -1
- package/dist/types/types/run.d.ts +6 -6
- package/dist/types/types/stream.d.ts +2 -2
- package/dist/types/types/tools.d.ts +5 -1
- package/dist/types/utils/handlers.d.ts +2 -2
- package/dist/types/utils/run.d.ts +1 -1
- package/package.json +6 -3
- package/src/__tests__/stream.eagerEventExecution.test.ts +543 -6
- package/src/agents/AgentContext.ts +2 -2
- package/src/agents/__tests__/AgentContext.test.ts +3 -3
- package/src/agents/__tests__/promptCacheLiveHelpers.ts +1 -1
- package/src/events.ts +1 -1
- package/src/graphs/Graph.ts +329 -72
- package/src/graphs/MultiAgentGraph.ts +1 -1
- package/src/graphs/__tests__/Graph.reasoning.test.ts +919 -6
- package/src/graphs/__tests__/MultiAgentGraph.test.ts +1 -1
- package/src/graphs/__tests__/composition.smoke.test.ts +1 -1
- package/src/hooks/__tests__/HookRegistry.test.ts +1 -1
- package/src/hooks/__tests__/compactHooks.test.ts +8 -8
- package/src/hooks/__tests__/createWorkspacePolicyHook.test.ts +34 -22
- package/src/hooks/__tests__/executeHooks.test.ts +3 -3
- package/src/hooks/__tests__/integration.test.ts +3 -3
- package/src/hooks/__tests__/toolHooks.test.ts +10 -10
- package/src/hooks/createWorkspacePolicyHook.ts +17 -14
- package/src/hooks/executeHooks.ts +1 -1
- package/src/hooks/types.ts +5 -0
- package/src/instrumentation.ts +49 -8
- package/src/langfuse.ts +35 -1
- package/src/langfuseToolOutputTracing.ts +2 -2
- package/src/llm/anthropic/index.ts +1 -1
- package/src/llm/anthropic/utils/message_inputs.ts +1 -1
- package/src/llm/anthropic/utils/message_outputs.ts +3 -5
- package/src/llm/anthropic/utils/output_parsers.ts +5 -5
- package/src/llm/bedrock/index.ts +4 -4
- package/src/llm/bedrock/toolCache.test.ts +48 -9
- package/src/llm/bedrock/toolCache.ts +11 -6
- package/src/llm/custom-chat-models.smoke.test.ts +114 -0
- package/src/llm/fake.ts +30 -25
- package/src/llm/google/index.ts +43 -1
- package/src/llm/google/llm.spec.ts +173 -1
- package/src/llm/google/types.ts +1 -1
- package/src/llm/google/utils/common.ts +154 -45
- package/src/llm/google/utils/tools.ts +8 -8
- package/src/llm/google/utils/zod_to_genai_parameters.ts +4 -4
- package/src/llm/invoke.test.ts +3 -3
- package/src/llm/invoke.ts +170 -10
- package/src/llm/openai/index.ts +4 -4
- package/src/llm/openai/utils/index.ts +14 -14
- package/src/llm/openrouter/index.ts +4 -4
- package/src/llm/openrouter/reasoning.test.ts +2 -2
- package/src/llm/vertexai/fixThoughtSignatures.test.ts +1 -1
- package/src/llm/vertexai/index.ts +1 -1
- package/src/messages/cache.test.ts +22 -0
- package/src/messages/cache.ts +25 -12
- package/src/messages/content.ts +1 -1
- package/src/messages/contextPruning.ts +1 -1
- package/src/messages/format.ts +227 -43
- package/src/messages/formatAgentMessages.skills.test.ts +105 -26
- package/src/messages/formatAgentMessages.test.ts +841 -10
- package/src/messages/labelContentByAgent.test.ts +2 -2
- package/src/messages/prune.ts +1 -1
- package/src/messages/reducer.ts +1 -1
- package/src/messages/tools.ts +1 -1
- package/src/openai/__tests__/openai.test.ts +2 -2
- package/src/openai/index.ts +1 -1
- package/src/responses/__tests__/responses.test.ts +2 -2
- package/src/responses/index.ts +1 -1
- package/src/run.ts +82 -47
- package/src/session/AgentSession.ts +6 -6
- package/src/session/JsonlSessionStore.ts +3 -3
- package/src/session/__tests__/JsonlSessionStore.test.ts +5 -5
- package/src/session/__tests__/handlers.test.ts +2 -2
- package/src/session/handlers.ts +5 -5
- package/src/session/types.ts +1 -1
- package/src/specs/agent-handoffs.test.ts +1 -1
- package/src/specs/deterministic-trace-id.test.ts +50 -0
- package/src/specs/langfuse-callbacks.test.ts +2 -2
- package/src/specs/langfuse-metadata.test.ts +39 -0
- package/src/specs/langfuse-tool-output-tracing.test.ts +1 -1
- package/src/specs/multi-agent-summarization.test.ts +4 -4
- package/src/specs/subagent.test.ts +3 -3
- package/src/specs/summarization-unit.test.ts +1 -1
- package/src/specs/thinking-handoff.test.ts +1 -1
- package/src/splitStream.test.ts +48 -0
- package/src/stream.test.ts +53 -3
- package/src/stream.ts +450 -39
- package/src/summarization/__tests__/aggregator.test.ts +2 -2
- package/src/summarization/__tests__/node.test.ts +2 -2
- package/src/summarization/node.ts +1 -1
- package/src/tools/BashProgrammaticToolCalling.ts +5 -5
- package/src/tools/Calculator.ts +1 -1
- package/src/tools/CodeExecutor.ts +2 -4
- package/src/tools/SubagentTool.ts +2 -2
- package/src/tools/ToolNode.ts +37 -16
- package/src/tools/ToolSearch.ts +1 -1
- package/src/tools/__tests__/CloudflareSandboxExecution.test.ts +4 -4
- package/src/tools/__tests__/CodeApiAuthHeaders.test.ts +12 -12
- package/src/tools/__tests__/LocalExecutionTools.test.ts +125 -93
- package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +29 -5
- package/src/tools/__tests__/ReadFile.test.ts +1 -1
- package/src/tools/__tests__/SkillTool.test.ts +4 -4
- package/src/tools/__tests__/SubagentExecutor.test.ts +17 -13
- package/src/tools/__tests__/SubagentTool.test.ts +2 -2
- package/src/tools/__tests__/ToolNode.eagerEventExecution.test.ts +1 -1
- package/src/tools/__tests__/ToolNode.outputReferences.test.ts +2 -5
- package/src/tools/__tests__/ToolNode.session.test.ts +1 -1
- package/src/tools/__tests__/ToolSearch.test.ts +1 -1
- package/src/tools/__tests__/annotateMessagesForLLM.test.ts +1 -1
- package/src/tools/__tests__/directToolHITLResumeScope.test.ts +35 -32
- package/src/tools/__tests__/directToolHooks.test.ts +41 -0
- package/src/tools/__tests__/handlers.test.ts +2 -2
- package/src/tools/__tests__/hitl.test.ts +11 -11
- package/src/tools/__tests__/localToolNames.test.ts +8 -6
- package/src/tools/__tests__/skillCatalog.test.ts +1 -1
- package/src/tools/__tests__/subagentHooks.test.ts +20 -10
- package/src/tools/__tests__/workspaceSeam.test.ts +20 -7
- package/src/tools/cloudflare/CloudflareSandboxExecutionEngine.ts +9 -6
- package/src/tools/cloudflare/CloudflareSandboxTools.ts +19 -19
- package/src/tools/handlers.ts +5 -5
- package/src/tools/local/CompileCheckTool.ts +4 -7
- package/src/tools/local/FileCheckpointer.ts +6 -5
- package/src/tools/local/LocalCodingTools.ts +100 -45
- package/src/tools/local/LocalExecutionEngine.ts +5 -5
- package/src/tools/local/LocalExecutionTools.ts +9 -9
- package/src/tools/local/LocalProgrammaticToolCalling.ts +5 -4
- package/src/tools/local/attachments.ts +0 -6
- package/src/tools/local/resolveLocalExecutionTools.ts +15 -15
- package/src/tools/search/firecrawl.ts +1 -1
- package/src/tools/search/jina-reranker.test.ts +148 -37
- package/src/tools/search/rerankers.ts +14 -4
- package/src/tools/search/tavily-search.ts +2 -2
- package/src/tools/search/types.ts +1 -1
- package/src/tools/search/utils.ts +99 -9
- package/src/tools/subagent/SubagentExecutor.ts +12 -6
- package/src/types/graph.ts +20 -12
- package/src/types/llm.ts +7 -6
- package/src/types/messages.ts +1 -1
- package/src/types/run.ts +7 -7
- package/src/types/stream.ts +2 -2
- package/src/types/tools.ts +5 -1
- package/src/utils/handlers.ts +2 -2
- package/src/utils/llmConfig.ts +1 -1
- package/src/utils/logging.ts +20 -10
- package/src/utils/run.ts +2 -2
|
@@ -2,6 +2,16 @@ import { z } from 'zod';
|
|
|
2
2
|
import { tmpdir } from 'os';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import { spawnSync } from 'child_process';
|
|
5
|
+
import { tool } from '@langchain/core/tools';
|
|
6
|
+
import { AIMessage, ToolMessage } from '@langchain/core/messages';
|
|
7
|
+
import {
|
|
8
|
+
describe,
|
|
9
|
+
it,
|
|
10
|
+
expect,
|
|
11
|
+
afterEach,
|
|
12
|
+
beforeEach,
|
|
13
|
+
jest,
|
|
14
|
+
} from '@jest/globals';
|
|
5
15
|
import {
|
|
6
16
|
mkdtemp,
|
|
7
17
|
rm,
|
|
@@ -9,21 +19,15 @@ import {
|
|
|
9
19
|
writeFile as fsWriteFile,
|
|
10
20
|
readFile as fsReadFile,
|
|
11
21
|
} from 'fs/promises';
|
|
12
|
-
import { tool } from '@langchain/core/tools';
|
|
13
|
-
import { AIMessage, ToolMessage } from '@langchain/core/messages';
|
|
14
|
-
import type { BaseMessage } from '@langchain/core/messages';
|
|
15
|
-
import { describe, it, expect, afterEach, beforeEach, jest } from '@jest/globals';
|
|
16
22
|
import type { StructuredToolInterface } from '@langchain/core/tools';
|
|
23
|
+
import type { BaseMessage } from '@langchain/core/messages';
|
|
17
24
|
import type * as t from '@/types';
|
|
18
|
-
import { Constants, Providers } from '@/common';
|
|
19
|
-
import { ToolNode } from '../ToolNode';
|
|
20
25
|
import {
|
|
21
26
|
executeLocalBash,
|
|
22
27
|
executeLocalCode,
|
|
23
28
|
validateBashCommand,
|
|
24
29
|
_resetLocalEngineWarningsForTests,
|
|
25
30
|
} from '../local/LocalExecutionEngine';
|
|
26
|
-
import { resolveLocalToolsForBinding } from '../local/resolveLocalExecutionTools';
|
|
27
31
|
import {
|
|
28
32
|
createLocalCodingToolBundle,
|
|
29
33
|
_resetRipgrepCacheForTests,
|
|
@@ -32,9 +36,12 @@ import {
|
|
|
32
36
|
runPostEditSyntaxCheck,
|
|
33
37
|
_resetSyntaxCheckProbeCacheForTests,
|
|
34
38
|
} from '../local/syntaxCheck';
|
|
39
|
+
import { resolveLocalToolsForBinding } from '../local/resolveLocalExecutionTools';
|
|
40
|
+
import { LocalFileCheckpointerImpl } from '../local/FileCheckpointer';
|
|
35
41
|
import { createCompileCheckTool } from '../local/CompileCheckTool';
|
|
36
42
|
import { runBashAstChecks } from '../local/bashAst';
|
|
37
|
-
import {
|
|
43
|
+
import { Constants, Providers } from '@/common';
|
|
44
|
+
import { ToolNode } from '../ToolNode';
|
|
38
45
|
|
|
39
46
|
const hasPython3 = spawnSync('python3', ['--version']).status === 0;
|
|
40
47
|
|
|
@@ -47,14 +54,11 @@ async function createTempDir(): Promise<string> {
|
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
function createRemoteBashStub(): StructuredToolInterface {
|
|
50
|
-
return tool(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
schema: z.object({ command: z.string() }),
|
|
56
|
-
}
|
|
57
|
-
) as unknown as StructuredToolInterface;
|
|
57
|
+
return tool(async () => 'remote bash should not run', {
|
|
58
|
+
name: Constants.BASH_TOOL,
|
|
59
|
+
description: 'Remote bash stub',
|
|
60
|
+
schema: z.object({ command: z.string() }),
|
|
61
|
+
}) as unknown as StructuredToolInterface;
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
function messagesFromResult(
|
|
@@ -216,7 +220,9 @@ describe('local execution tools', () => {
|
|
|
216
220
|
describe('local engine bashAst', () => {
|
|
217
221
|
it('flags command substitution in auto mode', () => {
|
|
218
222
|
const findings = runBashAstChecks('echo $(whoami)', 'auto');
|
|
219
|
-
expect(findings.some((f) => f.code === 'cmd-subst-dollar-paren')).toBe(
|
|
223
|
+
expect(findings.some((f) => f.code === 'cmd-subst-dollar-paren')).toBe(
|
|
224
|
+
true
|
|
225
|
+
);
|
|
220
226
|
});
|
|
221
227
|
|
|
222
228
|
it('escalates command substitution to deny in strict mode', () => {
|
|
@@ -227,7 +233,11 @@ describe('local engine bashAst', () => {
|
|
|
227
233
|
|
|
228
234
|
it('always denies /proc/<pid>/environ access', () => {
|
|
229
235
|
const findings = runBashAstChecks('cat /proc/1/environ', 'auto');
|
|
230
|
-
expect(
|
|
236
|
+
expect(
|
|
237
|
+
findings.some(
|
|
238
|
+
(f) => f.code === 'proc-environ-read' && f.severity === 'deny'
|
|
239
|
+
)
|
|
240
|
+
).toBe(true);
|
|
231
241
|
});
|
|
232
242
|
|
|
233
243
|
it('never produces findings when off', () => {
|
|
@@ -432,8 +442,7 @@ describe('local edit fuzzy matching', () => {
|
|
|
432
442
|
// LLM emits a trailing-whitespace-stripped version.
|
|
433
443
|
old_text:
|
|
434
444
|
'function greet(name: string) {\n return `Hello, ${name}!`;\n}',
|
|
435
|
-
new_text:
|
|
436
|
-
'function greet(name: string) {\n return `Hi, ${name}!`;\n}',
|
|
445
|
+
new_text: 'function greet(name: string) {\n return `Hi, ${name}!`;\n}',
|
|
437
446
|
});
|
|
438
447
|
expect(String(result)).toContain('strategies: line-trimmed');
|
|
439
448
|
const after = await fsReadFile(file, 'utf8');
|
|
@@ -701,7 +710,10 @@ describe('compile_check', () => {
|
|
|
701
710
|
name: 'compile_check',
|
|
702
711
|
args: { command: 'echo hello && false' },
|
|
703
712
|
type: 'tool_call',
|
|
704
|
-
})) as {
|
|
713
|
+
})) as {
|
|
714
|
+
content: string;
|
|
715
|
+
artifact: { passed: boolean; exit_code: number | null };
|
|
716
|
+
};
|
|
705
717
|
expect(message.content).toContain('FAILED');
|
|
706
718
|
expect(message.content).toContain('hello');
|
|
707
719
|
expect(message.artifact.passed).toBe(false);
|
|
@@ -764,18 +776,20 @@ describe('codex review fixes', () => {
|
|
|
764
776
|
// Backend A: pretends rg works (returns a fake spawn whose
|
|
765
777
|
// process exits 0 on every call). The cache should record true
|
|
766
778
|
// for THIS backend.
|
|
767
|
-
const okBackend = jest.fn(
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
779
|
+
const okBackend = jest.fn(
|
|
780
|
+
(cmd: string, _args: string[], _opts: unknown) => {
|
|
781
|
+
const ok = require('child_process').spawn('echo', [cmd]);
|
|
782
|
+
return ok;
|
|
783
|
+
}
|
|
784
|
+
) as unknown as t.LocalSpawn;
|
|
771
785
|
// Backend B: pretends rg does not exist (returns a child that
|
|
772
786
|
// exits 127, the "command not found" code).
|
|
773
787
|
const missingBackend = jest.fn(
|
|
774
788
|
(_cmd: string, _args: string[], _opts: unknown) => {
|
|
775
|
-
const child = require('child_process').spawn(
|
|
776
|
-
'
|
|
777
|
-
|
|
778
|
-
);
|
|
789
|
+
const child = require('child_process').spawn('sh', [
|
|
790
|
+
'-c',
|
|
791
|
+
'exit 127',
|
|
792
|
+
]);
|
|
779
793
|
return child;
|
|
780
794
|
}
|
|
781
795
|
) as unknown as t.LocalSpawn;
|
|
@@ -798,9 +812,11 @@ describe('codex review fixes', () => {
|
|
|
798
812
|
});
|
|
799
813
|
|
|
800
814
|
// Run grep against A first — populates cache for A's backend.
|
|
801
|
-
await bundleA.tools
|
|
802
|
-
|
|
803
|
-
|
|
815
|
+
await bundleA.tools
|
|
816
|
+
.find((t_) => t_.name === 'grep_search')!
|
|
817
|
+
.invoke({
|
|
818
|
+
pattern: 'needle',
|
|
819
|
+
});
|
|
804
820
|
// Run grep against B — must NOT see cached "true" from A's
|
|
805
821
|
// backend. With the bug, B would try to spawn rg, fail, and
|
|
806
822
|
// throw instead of falling back to the Node walker.
|
|
@@ -825,7 +841,9 @@ describe('codex review fixes', () => {
|
|
|
825
841
|
additionalRoots: ['../shared'],
|
|
826
842
|
},
|
|
827
843
|
});
|
|
828
|
-
const readTool = bundle.tools.find(
|
|
844
|
+
const readTool = bundle.tools.find(
|
|
845
|
+
(t_) => t_.name === Constants.READ_FILE
|
|
846
|
+
);
|
|
829
847
|
// Without the fix, '../shared/lib.ts' would resolve relative to
|
|
830
848
|
// process.cwd (this test runner), miss the boundary check, and
|
|
831
849
|
// throw "Path is outside the local workspace".
|
|
@@ -842,7 +860,10 @@ describe('codex review fixes', () => {
|
|
|
842
860
|
|
|
843
861
|
describe('codex review fixes (round 2)', () => {
|
|
844
862
|
describe('streaming output cap (Codex P1)', () => {
|
|
845
|
-
const {
|
|
863
|
+
const {
|
|
864
|
+
spawnLocalProcess,
|
|
865
|
+
_resetLocalEngineWarningsForTests: _,
|
|
866
|
+
} = require('../local/LocalExecutionEngine');
|
|
846
867
|
|
|
847
868
|
it('hard-kills the child when total streamed bytes exceed maxSpawnedBytes', async () => {
|
|
848
869
|
// Cap at 64 KiB. `yes` would otherwise run unbounded.
|
|
@@ -877,7 +898,10 @@ describe('codex review fixes (round 2)', () => {
|
|
|
877
898
|
expect(result.exitCode).toBe(0);
|
|
878
899
|
expect(result.fullOutputPath).toBeTruthy();
|
|
879
900
|
const fs = await import('fs/promises');
|
|
880
|
-
const spilled = await fs.readFile(
|
|
901
|
+
const spilled = await fs.readFile(
|
|
902
|
+
result.fullOutputPath as string,
|
|
903
|
+
'utf8'
|
|
904
|
+
);
|
|
881
905
|
// The spill file holds more bytes than the in-memory truncation.
|
|
882
906
|
expect(spilled.length).toBeGreaterThan(result.stdout.length);
|
|
883
907
|
});
|
|
@@ -902,7 +926,10 @@ describe('codex review fixes (round 2)', () => {
|
|
|
902
926
|
const result = await bashTool!.invoke({
|
|
903
927
|
id: 'b1',
|
|
904
928
|
name: Constants.BASH_TOOL,
|
|
905
|
-
args: {
|
|
929
|
+
args: {
|
|
930
|
+
command: 'echo "first=$1 second=$2"',
|
|
931
|
+
args: ['hello', 'world'],
|
|
932
|
+
},
|
|
906
933
|
type: 'tool_call',
|
|
907
934
|
});
|
|
908
935
|
const text = JSON.stringify(result);
|
|
@@ -939,7 +966,8 @@ describe('codex review fixes (round 3)', () => {
|
|
|
939
966
|
) => {
|
|
940
967
|
calls.push(command);
|
|
941
968
|
// Fall through to a real spawn so the call resolves cleanly.
|
|
942
|
-
const { spawn: realSpawn } =
|
|
969
|
+
const { spawn: realSpawn } =
|
|
970
|
+
require('child_process') as typeof import('child_process');
|
|
943
971
|
return realSpawn(command, args, opts);
|
|
944
972
|
}) as unknown as t.LocalSpawn;
|
|
945
973
|
|
|
@@ -959,7 +987,9 @@ describe('codex review fixes (round 3)', () => {
|
|
|
959
987
|
_resetSyntaxCheckProbeCacheForTests();
|
|
960
988
|
|
|
961
989
|
// Backend A: probes succeed (real spawn).
|
|
962
|
-
const realSpawn = (
|
|
990
|
+
const realSpawn = (
|
|
991
|
+
require('child_process') as typeof import('child_process')
|
|
992
|
+
).spawn;
|
|
963
993
|
const okBackend: t.LocalSpawn = ((
|
|
964
994
|
cmd: string,
|
|
965
995
|
args: string[],
|
|
@@ -970,7 +1000,8 @@ describe('codex review fixes (round 3)', () => {
|
|
|
970
1000
|
_cmd: string,
|
|
971
1001
|
_args: string[],
|
|
972
1002
|
opts: import('child_process').SpawnOptions
|
|
973
|
-
) =>
|
|
1003
|
+
) =>
|
|
1004
|
+
realSpawn('sh', ['-c', 'exit 127'], opts)) as unknown as t.LocalSpawn;
|
|
974
1005
|
|
|
975
1006
|
const cwdA = await createTempDir();
|
|
976
1007
|
const cwdB = await createTempDir();
|
|
@@ -1039,7 +1070,7 @@ describe('codex review fixes (round 4)', () => {
|
|
|
1039
1070
|
});
|
|
1040
1071
|
|
|
1041
1072
|
it('blocks rm -rf \'/\' (target inside single quotes)', async () => {
|
|
1042
|
-
const result = await validateBashCommand(
|
|
1073
|
+
const result = await validateBashCommand('rm -rf \'/\'');
|
|
1043
1074
|
expect(result.valid).toBe(false);
|
|
1044
1075
|
expect(result.errors.join('\n')).toContain('destructive command pattern');
|
|
1045
1076
|
});
|
|
@@ -1067,7 +1098,6 @@ describe('codex review fixes (round 4)', () => {
|
|
|
1067
1098
|
|
|
1068
1099
|
describe('codex review fixes (round 5)', () => {
|
|
1069
1100
|
describe('maxSpawnedBytes=0 disables the cap (Codex P2 #11)', () => {
|
|
1070
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
1071
1101
|
const { spawnLocalProcess } = require('../local/LocalExecutionEngine');
|
|
1072
1102
|
|
|
1073
1103
|
it('does not kill on first byte when maxSpawnedBytes is 0', async () => {
|
|
@@ -1109,7 +1139,7 @@ describe('codex review fixes (round 5)', () => {
|
|
|
1109
1139
|
// happy path here; the static `createWriteStream` import means a
|
|
1110
1140
|
// ReferenceError would surface as a test failure regardless of
|
|
1111
1141
|
// which build runs the test.
|
|
1112
|
-
|
|
1142
|
+
|
|
1113
1143
|
const { spawnLocalProcess } = require('../local/LocalExecutionEngine');
|
|
1114
1144
|
|
|
1115
1145
|
it('writes a spill file without a runtime require', async () => {
|
|
@@ -1136,8 +1166,9 @@ describe('codex review fixes (round 5)', () => {
|
|
|
1136
1166
|
});
|
|
1137
1167
|
|
|
1138
1168
|
describe('sandbox config: loopback bridge access (Codex P1 #14)', () => {
|
|
1139
|
-
|
|
1140
|
-
|
|
1169
|
+
const {
|
|
1170
|
+
buildSandboxRuntimeConfig,
|
|
1171
|
+
} = require('../local/LocalExecutionEngine');
|
|
1141
1172
|
|
|
1142
1173
|
it('seeds allowedDomains with loopback hosts so the bridge works under sandbox', () => {
|
|
1143
1174
|
const cfg = buildSandboxRuntimeConfig({}, '/tmp/ws', () => []);
|
|
@@ -1148,7 +1179,11 @@ describe('codex review fixes (round 5)', () => {
|
|
|
1148
1179
|
|
|
1149
1180
|
it('keeps user-supplied allowedDomains and does not duplicate loopback', () => {
|
|
1150
1181
|
const cfg = buildSandboxRuntimeConfig(
|
|
1151
|
-
{
|
|
1182
|
+
{
|
|
1183
|
+
sandbox: {
|
|
1184
|
+
network: { allowedDomains: ['api.example.com', '127.0.0.1'] },
|
|
1185
|
+
},
|
|
1186
|
+
},
|
|
1152
1187
|
'/tmp/ws',
|
|
1153
1188
|
() => []
|
|
1154
1189
|
);
|
|
@@ -1175,8 +1210,9 @@ describe('codex review fixes (round 5)', () => {
|
|
|
1175
1210
|
});
|
|
1176
1211
|
|
|
1177
1212
|
describe('sandbox allowWrite includes additionalRoots (Codex P2 #15)', () => {
|
|
1178
|
-
|
|
1179
|
-
|
|
1213
|
+
const {
|
|
1214
|
+
buildSandboxRuntimeConfig,
|
|
1215
|
+
} = require('../local/LocalExecutionEngine');
|
|
1180
1216
|
|
|
1181
1217
|
it('adds workspace.additionalRoots to allowWrite alongside cwd', () => {
|
|
1182
1218
|
const cfg = buildSandboxRuntimeConfig(
|
|
@@ -1188,7 +1224,7 @@ describe('codex review fixes (round 5)', () => {
|
|
|
1188
1224
|
},
|
|
1189
1225
|
},
|
|
1190
1226
|
'/tmp/repo/app',
|
|
1191
|
-
() => ['/tmp/runtime-default']
|
|
1227
|
+
() => ['/tmp/runtime-default']
|
|
1192
1228
|
);
|
|
1193
1229
|
expect(cfg.filesystem.allowWrite).toEqual(
|
|
1194
1230
|
expect.arrayContaining([
|
|
@@ -1209,7 +1245,7 @@ describe('codex review fixes (round 5)', () => {
|
|
|
1209
1245
|
},
|
|
1210
1246
|
},
|
|
1211
1247
|
'/tmp/repo/app',
|
|
1212
|
-
() => []
|
|
1248
|
+
() => []
|
|
1213
1249
|
);
|
|
1214
1250
|
// ../shared anchored to root: /tmp/repo/app -> /tmp/repo/shared.
|
|
1215
1251
|
expect(cfg.filesystem.allowWrite).toContain('/tmp/repo/shared');
|
|
@@ -1253,7 +1289,6 @@ describe('codex review fixes (round 5)', () => {
|
|
|
1253
1289
|
// flagged. Pre-fix, glob_search dropped exitCode/stderr on
|
|
1254
1290
|
// the floor and returned "No files found." regardless.
|
|
1255
1291
|
const realSpawn = (
|
|
1256
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
1257
1292
|
require('child_process') as typeof import('child_process')
|
|
1258
1293
|
).spawn;
|
|
1259
1294
|
const fakeRgBackend: t.LocalSpawn = ((
|
|
@@ -1304,7 +1339,6 @@ describe('codex review fixes (round 5)', () => {
|
|
|
1304
1339
|
// glob_search had this fix but grep_search hadn't been
|
|
1305
1340
|
// updated to match).
|
|
1306
1341
|
const realSpawn = (
|
|
1307
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
1308
1342
|
require('child_process') as typeof import('child_process')
|
|
1309
1343
|
).spawn;
|
|
1310
1344
|
const fakeRgBackend: t.LocalSpawn = ((
|
|
@@ -1435,13 +1469,13 @@ describe('comprehensive review (round 7) — manual finding C', () => {
|
|
|
1435
1469
|
});
|
|
1436
1470
|
|
|
1437
1471
|
it('blocks sh -c "chmod -R 777 /"', async () => {
|
|
1438
|
-
const result = await validateBashCommand(
|
|
1472
|
+
const result = await validateBashCommand('sh -c \'chmod -R 777 /\'');
|
|
1439
1473
|
expect(result.valid).toBe(false);
|
|
1440
1474
|
expect(result.errors.join('\n')).toMatch(/destructive command pattern/);
|
|
1441
1475
|
});
|
|
1442
1476
|
|
|
1443
1477
|
it('blocks eval "rm -rf /"', async () => {
|
|
1444
|
-
const result = await validateBashCommand(
|
|
1478
|
+
const result = await validateBashCommand('eval \'rm -rf /\'');
|
|
1445
1479
|
expect(result.valid).toBe(false);
|
|
1446
1480
|
expect(result.errors.join('\n')).toMatch(/destructive command pattern/);
|
|
1447
1481
|
});
|
|
@@ -1631,7 +1665,6 @@ describe('comprehensive review (round 7) — manual finding E', () => {
|
|
|
1631
1665
|
describe('comprehensive review (round 8) — Codex P1 #24 / P1 #25', () => {
|
|
1632
1666
|
describe('JSON post-edit syntax check uses WorkspaceFS (Codex P1 #24)', () => {
|
|
1633
1667
|
it('routes the JSON read through `local.exec.fs` instead of host fs', async () => {
|
|
1634
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
1635
1668
|
const { runPostEditSyntaxCheck } = require('../local/syntaxCheck');
|
|
1636
1669
|
|
|
1637
1670
|
const reads: string[] = [];
|
|
@@ -1669,7 +1702,6 @@ describe('comprehensive review (round 8) — Codex P1 #24 / P1 #25', () => {
|
|
|
1669
1702
|
});
|
|
1670
1703
|
|
|
1671
1704
|
it('flags invalid JSON returned by the WorkspaceFS', async () => {
|
|
1672
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
1673
1705
|
const { runPostEditSyntaxCheck } = require('../local/syntaxCheck');
|
|
1674
1706
|
const fakeFs = {
|
|
1675
1707
|
readFile: async () => '{ invalid: json',
|
|
@@ -1764,7 +1796,6 @@ describe('comprehensive review (round 8) — Codex P1 #24 / P1 #25', () => {
|
|
|
1764
1796
|
|
|
1765
1797
|
describe('comprehensive review (round 9) — Codex P1 (overflow-killed) + audit findings', () => {
|
|
1766
1798
|
describe('overflow-killed processes report as failures (Codex P1)', () => {
|
|
1767
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
1768
1799
|
const { spawnLocalProcess } = require('../local/LocalExecutionEngine');
|
|
1769
1800
|
|
|
1770
1801
|
it('reports overflowKilled=true and a non-null exit code when maxSpawnedBytes is exceeded', async () => {
|
|
@@ -1811,7 +1842,6 @@ describe('comprehensive review (round 9) — Codex P1 (overflow-killed) + audit
|
|
|
1811
1842
|
});
|
|
1812
1843
|
|
|
1813
1844
|
describe('signal-killed processes report as failures (Codex P2 — generalizes the overflow fix)', () => {
|
|
1814
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
1815
1845
|
const { spawnLocalProcess } = require('../local/LocalExecutionEngine');
|
|
1816
1846
|
|
|
1817
1847
|
it('synthesizes a non-zero exit code and surfaces the signal name on `kill -9 $$`', async () => {
|
|
@@ -1861,7 +1891,6 @@ describe('comprehensive review (round 9) — Codex P1 (overflow-killed) + audit
|
|
|
1861
1891
|
// is unavailable (the rg --version probe always fails). This
|
|
1862
1892
|
// way the fallback compileFallbackRegex actually runs.
|
|
1863
1893
|
const realSpawn = (
|
|
1864
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
1865
1894
|
require('child_process') as typeof import('child_process')
|
|
1866
1895
|
).spawn;
|
|
1867
1896
|
const noRgBackend: t.LocalSpawn = ((
|
|
@@ -1907,7 +1936,7 @@ describe('comprehensive review (round 9) — Codex P1 (overflow-killed) + audit
|
|
|
1907
1936
|
toolExecution: { engine: 'local' },
|
|
1908
1937
|
});
|
|
1909
1938
|
// Capture the bash_tool instance
|
|
1910
|
-
|
|
1939
|
+
|
|
1911
1940
|
const m1 = (node1 as unknown as { toolMap: Map<string, unknown> })
|
|
1912
1941
|
.toolMap;
|
|
1913
1942
|
expect(m1.has(Constants.BASH_TOOL)).toBe(true);
|
|
@@ -1930,7 +1959,6 @@ describe('comprehensive review (round 9) — Codex P1 (overflow-killed) + audit
|
|
|
1930
1959
|
|
|
1931
1960
|
describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
|
|
1932
1961
|
describe('SIGKILL escalation defeats SIGTERM-trapping processes (Codex P1 #28)', () => {
|
|
1933
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
1934
1962
|
const { spawnLocalProcess } = require('../local/LocalExecutionEngine');
|
|
1935
1963
|
|
|
1936
1964
|
it('escalates to SIGKILL when timeoutMs elapses and the child traps SIGTERM', async () => {
|
|
@@ -1942,7 +1970,7 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
|
|
|
1942
1970
|
const start = Date.now();
|
|
1943
1971
|
const result = await spawnLocalProcess(
|
|
1944
1972
|
'bash',
|
|
1945
|
-
['-c',
|
|
1973
|
+
['-c', 'trap \'\' TERM; while true; do sleep 0.1; done'],
|
|
1946
1974
|
{ timeoutMs: 1500, sandbox: { enabled: false } }
|
|
1947
1975
|
);
|
|
1948
1976
|
const elapsed = Date.now() - start;
|
|
@@ -1968,7 +1996,6 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
|
|
|
1968
1996
|
// verdict and tried to use rg under an env without it,
|
|
1969
1997
|
// failing with ENOENT.
|
|
1970
1998
|
const realSpawn = (
|
|
1971
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
1972
1999
|
require('child_process') as typeof import('child_process')
|
|
1973
2000
|
).spawn;
|
|
1974
2001
|
|
|
@@ -1993,14 +2020,12 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
|
|
|
1993
2020
|
|
|
1994
2021
|
const cwdA = await createTempDir();
|
|
1995
2022
|
const cwdB = await createTempDir();
|
|
1996
|
-
await (
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
'needle\n'
|
|
2003
|
-
);
|
|
2023
|
+
await (
|
|
2024
|
+
await import('fs/promises')
|
|
2025
|
+
).writeFile(join(cwdA, 'a.ts'), 'needle\n');
|
|
2026
|
+
await (
|
|
2027
|
+
await import('fs/promises')
|
|
2028
|
+
).writeFile(join(cwdB, 'b.ts'), 'needle\n');
|
|
2004
2029
|
|
|
2005
2030
|
// Run A: env says rg is available → cache records `true` for
|
|
2006
2031
|
// (backend, env-A).
|
|
@@ -2009,12 +2034,14 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
|
|
|
2009
2034
|
exec: { spawn: envSensitive },
|
|
2010
2035
|
env: { PATH: '/with/rg' },
|
|
2011
2036
|
});
|
|
2012
|
-
await bundleA.tools
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2037
|
+
await bundleA.tools
|
|
2038
|
+
.find((t_) => t_.name === 'grep_search')!
|
|
2039
|
+
.invoke({
|
|
2040
|
+
id: 'gA',
|
|
2041
|
+
name: 'grep_search',
|
|
2042
|
+
args: { pattern: 'needle' },
|
|
2043
|
+
type: 'tool_call',
|
|
2044
|
+
});
|
|
2018
2045
|
|
|
2019
2046
|
// Run B: same backend, DIFFERENT env (PATH excludes rg). Must
|
|
2020
2047
|
// run a fresh probe and fall back to the Node walker, NOT
|
|
@@ -2042,14 +2069,12 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
|
|
|
2042
2069
|
});
|
|
2043
2070
|
|
|
2044
2071
|
describe('compile-style runtimes honor local.shell (Codex P2 #29)', () => {
|
|
2045
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
2046
2072
|
const { executeLocalCode } = require('../local/LocalExecutionEngine');
|
|
2047
2073
|
|
|
2048
2074
|
it('routes the rust runtime through `local.shell` instead of bare `bash`', async () => {
|
|
2049
2075
|
// Intercept spawn — assert the configured shell is used for
|
|
2050
2076
|
// the rs runtime, not hardcoded `bash`.
|
|
2051
2077
|
const realSpawn = (
|
|
2052
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
2053
2078
|
require('child_process') as typeof import('child_process')
|
|
2054
2079
|
).spawn;
|
|
2055
2080
|
const calls: string[] = [];
|
|
@@ -2065,7 +2090,11 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
|
|
|
2065
2090
|
|
|
2066
2091
|
await executeLocalCode(
|
|
2067
2092
|
{ lang: 'rs', code: 'fn main() {}', args: [] },
|
|
2068
|
-
{
|
|
2093
|
+
{
|
|
2094
|
+
shell: '/bin/sh',
|
|
2095
|
+
exec: { spawn: intercept },
|
|
2096
|
+
sandbox: { enabled: false },
|
|
2097
|
+
}
|
|
2069
2098
|
);
|
|
2070
2099
|
|
|
2071
2100
|
// The rust path's compile-and-run command should have been
|
|
@@ -2077,8 +2106,10 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
|
|
|
2077
2106
|
|
|
2078
2107
|
describe('comprehensive review (round 12) — Codex P1 #36', () => {
|
|
2079
2108
|
describe('granular workspace flags override the legacy allowOutsideWorkspace', () => {
|
|
2080
|
-
|
|
2081
|
-
|
|
2109
|
+
const {
|
|
2110
|
+
getWriteRoots,
|
|
2111
|
+
getReadRoots,
|
|
2112
|
+
} = require('../local/LocalExecutionEngine');
|
|
2082
2113
|
|
|
2083
2114
|
it('workspace.allowWriteOutside=false beats allowOutsideWorkspace=true (Codex P1 #36)', () => {
|
|
2084
2115
|
// Pre-fix the OR short-circuited on the legacy flag, returning
|
|
@@ -2190,8 +2221,9 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
|
|
|
2190
2221
|
});
|
|
2191
2222
|
|
|
2192
2223
|
it('blocks the positional-arg dot-glob form too', async () => {
|
|
2193
|
-
|
|
2194
|
-
|
|
2224
|
+
const {
|
|
2225
|
+
executeLocalBashWithArgs,
|
|
2226
|
+
} = require('../local/LocalExecutionEngine');
|
|
2195
2227
|
await expect(
|
|
2196
2228
|
executeLocalBashWithArgs('rm -rf "$1"', ['/.*'], {
|
|
2197
2229
|
sandbox: { enabled: false },
|
|
@@ -2291,7 +2323,6 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
|
|
|
2291
2323
|
it('reports `matches: 0` when only oversize files are present', async () => {
|
|
2292
2324
|
_resetRipgrepCacheForTests();
|
|
2293
2325
|
const realSpawn = (
|
|
2294
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
2295
2326
|
require('child_process') as typeof import('child_process')
|
|
2296
2327
|
).spawn;
|
|
2297
2328
|
const noRgBackend: t.LocalSpawn = ((
|
|
@@ -2386,8 +2417,9 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
|
|
|
2386
2417
|
});
|
|
2387
2418
|
|
|
2388
2419
|
describe('bash args validated against destructive-target patterns (Codex P1 [45])', () => {
|
|
2389
|
-
|
|
2390
|
-
|
|
2420
|
+
const {
|
|
2421
|
+
executeLocalBashWithArgs,
|
|
2422
|
+
} = require('../local/LocalExecutionEngine');
|
|
2391
2423
|
|
|
2392
2424
|
it('blocks `rm -rf "$1"` + args=["/"]', async () => {
|
|
2393
2425
|
await expect(
|
|
@@ -2495,8 +2527,9 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
|
|
|
2495
2527
|
|
|
2496
2528
|
describe('resolveWorkspacePathSafe routes through WorkspaceFS.realpath (Codex P2 #38)', () => {
|
|
2497
2529
|
it('honors a custom workspace fs realpath impl', async () => {
|
|
2498
|
-
|
|
2499
|
-
|
|
2530
|
+
const {
|
|
2531
|
+
resolveWorkspacePathSafe,
|
|
2532
|
+
} = require('../local/LocalExecutionEngine');
|
|
2500
2533
|
const calls: string[] = [];
|
|
2501
2534
|
const fakeFs = {
|
|
2502
2535
|
readFile: async () => '',
|
|
@@ -2539,7 +2572,6 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
|
|
|
2539
2572
|
it('does not bleed `hasNode` verdict from one env to another on the same backend', async () => {
|
|
2540
2573
|
_resetSyntaxCheckProbeCacheForTests();
|
|
2541
2574
|
const realSpawn = (
|
|
2542
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
2543
2575
|
require('child_process') as typeof import('child_process')
|
|
2544
2576
|
).spawn;
|
|
2545
2577
|
const calls: Array<{ cmd: string; env?: NodeJS.ProcessEnv }> = [];
|
|
@@ -2563,7 +2595,6 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
|
|
|
2563
2595
|
return realSpawn('sh', ['-c', 'exit 0'], opts);
|
|
2564
2596
|
}) as unknown as t.LocalSpawn;
|
|
2565
2597
|
|
|
2566
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
2567
2598
|
const { runPostEditSyntaxCheck } = require('../local/syntaxCheck');
|
|
2568
2599
|
const cwd = await createTempDir();
|
|
2569
2600
|
const file = join(cwd, 'a.js');
|
|
@@ -2581,14 +2612,16 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
|
|
|
2581
2612
|
// syntax-check via the missing node. Now: separate cache slot
|
|
2582
2613
|
// for envB → its own probe → records `false` → skips check.
|
|
2583
2614
|
const probeCallsBefore = calls.filter(
|
|
2584
|
-
(c) =>
|
|
2615
|
+
(c) =>
|
|
2616
|
+
c.cmd === 'node' && c.env?.PATH?.includes('without-node') === true
|
|
2585
2617
|
).length;
|
|
2586
2618
|
await runPostEditSyntaxCheck(file, {
|
|
2587
2619
|
exec: { spawn: envSensitive },
|
|
2588
2620
|
env: { PATH: '/without-node' },
|
|
2589
2621
|
});
|
|
2590
2622
|
const probeCallsAfter = calls.filter(
|
|
2591
|
-
(c) =>
|
|
2623
|
+
(c) =>
|
|
2624
|
+
c.cmd === 'node' && c.env?.PATH?.includes('without-node') === true
|
|
2592
2625
|
).length;
|
|
2593
2626
|
// A fresh probe must have run for envB (count went up).
|
|
2594
2627
|
expect(probeCallsAfter).toBeGreaterThan(probeCallsBefore);
|
|
@@ -2599,7 +2632,6 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
|
|
|
2599
2632
|
it('emits a sentinel and continues instead of reading multi-MB files into memory', async () => {
|
|
2600
2633
|
_resetRipgrepCacheForTests();
|
|
2601
2634
|
const realSpawn = (
|
|
2602
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
2603
2635
|
require('child_process') as typeof import('child_process')
|
|
2604
2636
|
).spawn;
|
|
2605
2637
|
// Force the Node fallback by making rg unavailable.
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { describe, it, expect, jest, beforeEach } from '@jest/globals';
|
|
7
7
|
import type * as t from '@/types';
|
|
8
|
-
import { Constants } from '@/common';
|
|
9
8
|
import {
|
|
10
9
|
createProgrammaticToolCallingTool,
|
|
11
10
|
createProgrammaticToolCallingSchema,
|
|
@@ -16,10 +15,6 @@ import {
|
|
|
16
15
|
normalizeToPythonIdentifier,
|
|
17
16
|
unwrapToolResponse,
|
|
18
17
|
} from '../ProgrammaticToolCalling';
|
|
19
|
-
import {
|
|
20
|
-
createBashProgrammaticToolCallingSchema,
|
|
21
|
-
normalizeBashToolResultsForReplay,
|
|
22
|
-
} from '../BashProgrammaticToolCalling';
|
|
23
18
|
import {
|
|
24
19
|
createProgrammaticToolRegistry,
|
|
25
20
|
createGetTeamMembersTool,
|
|
@@ -27,6 +22,11 @@ import {
|
|
|
27
22
|
createGetWeatherTool,
|
|
28
23
|
createCalculatorTool,
|
|
29
24
|
} from '@/test/mockTools';
|
|
25
|
+
import {
|
|
26
|
+
createBashProgrammaticToolCallingSchema,
|
|
27
|
+
normalizeBashToolResultsForReplay,
|
|
28
|
+
} from '../BashProgrammaticToolCalling';
|
|
29
|
+
import { Constants } from '@/common';
|
|
30
30
|
|
|
31
31
|
describe('ProgrammaticToolCalling', () => {
|
|
32
32
|
describe('tool descriptions', () => {
|
|
@@ -1464,6 +1464,30 @@ for member in team:
|
|
|
1464
1464
|
expect(gate.denyReason).toContain('no writes from bridge');
|
|
1465
1465
|
});
|
|
1466
1466
|
|
|
1467
|
+
it('threads executingAgentId from the hook context to bridge PreToolUse hooks', async () => {
|
|
1468
|
+
const { HookRegistry } = await import('@/hooks');
|
|
1469
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
1470
|
+
const ptcMod = require('../local/LocalProgrammaticToolCalling');
|
|
1471
|
+
const registry = new HookRegistry();
|
|
1472
|
+
let seen: string | undefined = 'UNSET';
|
|
1473
|
+
registry.register('PreToolUse', {
|
|
1474
|
+
hooks: [
|
|
1475
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
1476
|
+
async (input) => {
|
|
1477
|
+
seen = input.executingAgentId;
|
|
1478
|
+
return { decision: 'allow' };
|
|
1479
|
+
},
|
|
1480
|
+
],
|
|
1481
|
+
});
|
|
1482
|
+
await ptcMod.applyPreToolUseHooksForBridge(
|
|
1483
|
+
{ registry, runId: 'r1', executingAgentId: 'repo_investigator' },
|
|
1484
|
+
'write_file',
|
|
1485
|
+
'call_1',
|
|
1486
|
+
{ path: '/tmp/x' }
|
|
1487
|
+
);
|
|
1488
|
+
expect(seen).toBe('repo_investigator');
|
|
1489
|
+
});
|
|
1490
|
+
|
|
1467
1491
|
it('passes through when no hook denies (allow path)', async () => {
|
|
1468
1492
|
const { HookRegistry } = await import('@/hooks');
|
|
1469
1493
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describe, it, expect } from '@jest/globals';
|
|
2
|
-
import { Constants } from '@/common';
|
|
3
2
|
import {
|
|
4
3
|
ReadFileToolName,
|
|
5
4
|
ReadFileToolSchema,
|
|
6
5
|
ReadFileToolDescription,
|
|
7
6
|
ReadFileToolDefinition,
|
|
8
7
|
} from '../ReadFile';
|
|
8
|
+
import { Constants } from '@/common';
|
|
9
9
|
|
|
10
10
|
describe('ReadFile', () => {
|
|
11
11
|
describe('schema structure', () => {
|