@librechat/agents 3.1.79 → 3.1.80-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/tools/BashExecutor.cjs +10 -2
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +2 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +16 -5
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +9 -4
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +63 -40
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalExecutionTools.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +10 -2
- package/dist/esm/tools/BashExecutor.mjs.map +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +2 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +16 -5
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +9 -4
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +63 -40
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/local/LocalExecutionTools.mjs.map +1 -1
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
- package/dist/types/types/tools.d.ts +82 -17
- package/package.json +1 -1
- package/src/scripts/code_exec_multi_session.ts +4 -4
- package/src/tools/BashExecutor.ts +11 -3
- package/src/tools/BashProgrammaticToolCalling.ts +6 -6
- package/src/tools/CodeExecutor.ts +17 -6
- package/src/tools/ProgrammaticToolCalling.ts +14 -10
- package/src/tools/ToolNode.ts +85 -48
- package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +9 -2
- package/src/tools/__tests__/ToolNode.session.test.ts +131 -50
- package/src/tools/local/LocalExecutionTools.ts +2 -2
- package/src/tools/local/LocalProgrammaticToolCalling.ts +23 -6
- package/src/types/tools.ts +79 -17
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocalExecutionTools.mjs","sources":["../../../../src/tools/local/LocalExecutionTools.ts"],"sourcesContent":["import { tool } from '@langchain/core/tools';\nimport type { DynamicStructuredTool } from '@langchain/core/tools';\nimport type * as t from '@/types';\nimport {\n CodeExecutionToolName,\n CodeExecutionToolSchema,\n} from '@/tools/CodeExecutor';\nimport {\n BashExecutionToolName,\n BashExecutionToolSchema,\n BashToolOutputReferencesGuide,\n} from '@/tools/BashExecutor';\nimport {\n executeLocalBash,\n executeLocalBashWithArgs,\n executeLocalCode,\n getLocalCwd,\n getLocalSessionId,\n} from './LocalExecutionEngine';\nimport { Constants } from '@/common';\n\nconst emptyOutputMessage =\n 'stdout: Empty. Ensure you\\'re writing output explicitly.\\n';\n\nexport const LocalCodeExecutionToolDescription = `\nRuns code on the local machine in the configured working directory. Unlike the remote Code API sandbox, this tool can see the local repository, installed runtimes, environment variables, and filesystem available to the host process.\n\nUsage:\n- The remote sandbox API remains the default; this description applies only when local execution mode is enabled.\n- Local commands can use the Anthropic sandbox runtime when local.sandbox.enabled=true and @anthropic-ai/sandbox-runtime is installed.\n- Commands execute in the local working directory and may modify local files.\n- Input code is already displayed to the user, so do not repeat it unless asked.\n- Output is not displayed unless you print it explicitly.\n`.trim();\n\nexport const LocalBashExecutionToolDescription = `\nRuns bash commands on the local machine in the configured working directory. Unlike the remote Code API sandbox, this tool can see the local repository, installed tools, environment variables, and filesystem available to the host process.\n\nUsage:\n- The remote sandbox API remains the default; this description applies only when local execution mode is enabled.\n- Local commands can use the Anthropic sandbox runtime when local.sandbox.enabled=true and @anthropic-ai/sandbox-runtime is installed.\n- Commands execute in the local working directory and may modify local files.\n- Output is not displayed unless you print it explicitly.\n- Prefer project-native commands and inspect files before changing them.\n`.trim();\n\nfunction formatLocalOutput(\n result: {\n stdout: string;\n stderr: string;\n exitCode: number | null;\n timedOut: boolean;\n overflowKilled?: boolean;\n signal?: string;\n fullOutputPath?: string;\n },\n cwd: string\n): string {\n let formatted = '';\n if (result.stdout !== '') {\n formatted += `stdout:\\n${result.stdout}\\n`;\n } else {\n formatted += emptyOutputMessage;\n }\n\n if (result.stderr !== '') {\n formatted += `stderr:\\n${result.stderr}\\n`;\n }\n\n if (result.exitCode != null && result.exitCode !== 0) {\n formatted += `exit_code: ${result.exitCode}\\n`;\n }\n\n if (result.timedOut) {\n formatted += 'timed_out: true\\n';\n }\n\n if (result.overflowKilled === true) {\n // Surface the force-kill explicitly so the model treats this as a\n // failure rather than misreading \"exit_code: 137 + truncated\n // stdout\" as a normal completion. (Codex P1 — pre-fix the close\n // handler swallowed the overflow flag and exitCode was null on\n // signal-killed processes.)\n formatted +=\n 'killed: true (output exceeded local.maxSpawnedBytes; process tree was terminated)\\n';\n } else if (result.signal != null) {\n // Generic signal kill: `kill -9 $$` from inside the script,\n // native crash, OS OOM killer, etc. Codex P2 generalization of\n // the overflow case.\n formatted += `killed: true (signal=${result.signal})\\n`;\n }\n\n if (result.fullOutputPath != null) {\n formatted += `full_output_path: ${result.fullOutputPath} (output exceeded the configured cap; use bash to inspect — the file holds the complete stdout/stderr)\\n`;\n }\n\n formatted += `working_directory: ${cwd}`;\n return formatted.trim();\n}\n\nexport function createLocalCodeExecutionTool(\n config: t.LocalExecutionConfig = {}\n): DynamicStructuredTool {\n return tool(\n async (rawInput) => {\n const input = rawInput as {\n lang: string;\n code: string;\n args?: string[];\n };\n const cwd = getLocalCwd(config);\n const result = await executeLocalCode(input, config);\n return [\n formatLocalOutput(result, cwd),\n {\n session_id: getLocalSessionId(config),\n files: [],\n },\n ];\n },\n {\n name: CodeExecutionToolName,\n description: LocalCodeExecutionToolDescription,\n schema: CodeExecutionToolSchema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n\nexport function createLocalBashExecutionTool(options?: {\n config?: t.LocalExecutionConfig;\n enableToolOutputReferences?: boolean;\n}): DynamicStructuredTool {\n const config = options?.config ?? {};\n return tool(\n async (rawInput) => {\n const input = rawInput as { command: string; args?: string[] };\n const cwd = getLocalCwd(config);\n // Use the standard `bash -lc <command> -- <args...>` form so\n // `$1`, `$2`, … resolve correctly inside `command`. The\n // previous implementation appended args literally to the\n // command string (`${command} ${args.join(' ')}`), which\n // doesn't populate positional parameters and silently broke\n // shell snippets like `command: 'echo \"$1\"'`.\n const result =\n input.args != null && input.args.length > 0\n ? await executeLocalBashWithArgs(input.command, input.args, config)\n : await executeLocalBash(input.command, config);\n return [\n formatLocalOutput(result, cwd),\n {\n session_id: getLocalSessionId(config),\n files: [],\n },\n ];\n },\n {\n name: BashExecutionToolName,\n description:\n options?.enableToolOutputReferences === true\n ? `${LocalBashExecutionToolDescription}\\n\\n${BashToolOutputReferencesGuide}`\n : LocalBashExecutionToolDescription,\n schema: BashExecutionToolSchema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n"],"names":[],"mappings":";;;;;;AAqBA,MAAM,kBAAkB,GACtB,4DAA4D;AAEvD,MAAM,iCAAiC,GAAG;;;;;;;;;CAShD,CAAC,IAAI;AAEC,MAAM,iCAAiC,GAAG;;;;;;;;;CAShD,CAAC,IAAI;AAEN,SAAS,iBAAiB,CACxB,MAQC,EACD,GAAW,EAAA;IAEX,IAAI,SAAS,GAAG,EAAE;AAClB,IAAA,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE;AACxB,QAAA,SAAS,IAAI,CAAA,SAAA,EAAY,MAAM,CAAC,MAAM,IAAI;IAC5C;SAAO;QACL,SAAS,IAAI,kBAAkB;IACjC;AAEA,IAAA,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE;AACxB,QAAA,SAAS,IAAI,CAAA,SAAA,EAAY,MAAM,CAAC,MAAM,IAAI;IAC5C;AAEA,IAAA,IAAI,MAAM,CAAC,QAAQ,IAAI,IAAI,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE;AACpD,QAAA,SAAS,IAAI,CAAA,WAAA,EAAc,MAAM,CAAC,QAAQ,IAAI;IAChD;AAEA,IAAA,IAAI,MAAM,CAAC,QAAQ,EAAE;QACnB,SAAS,IAAI,mBAAmB;IAClC;AAEA,IAAA,IAAI,MAAM,CAAC,cAAc,KAAK,IAAI,EAAE;;;;;;QAMlC,SAAS;AACP,YAAA,qFAAqF;IACzF;AAAO,SAAA,IAAI,MAAM,CAAC,MAAM,IAAI,IAAI,EAAE;;;;AAIhC,QAAA,SAAS,IAAI,CAAA,qBAAA,EAAwB,MAAM,CAAC,MAAM,KAAK;IACzD;AAEA,IAAA,IAAI,MAAM,CAAC,cAAc,IAAI,IAAI,EAAE;AACjC,QAAA,SAAS,IAAI,CAAA,kBAAA,EAAqB,MAAM,CAAC,cAAc,0GAA0G;IACnK;AAEA,IAAA,SAAS,IAAI,CAAA,mBAAA,EAAsB,GAAG,CAAA,CAAE;AACxC,IAAA,OAAO,SAAS,CAAC,IAAI,EAAE;AACzB;AAEM,SAAU,4BAA4B,CAC1C,MAAA,GAAiC,EAAE,EAAA;AAEnC,IAAA,OAAO,IAAI,CACT,OAAO,QAAQ,KAAI;QACjB,MAAM,KAAK,GAAG,QAIb;AACD,QAAA,MAAM,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC;QACpD,OAAO;AACL,YAAA,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC;AAC9B,YAAA;AACE,gBAAA,UAAU,EAAE,iBAAiB,CAAC,MAAM,CAAC;AACrC,gBAAA,KAAK,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"LocalExecutionTools.mjs","sources":["../../../../src/tools/local/LocalExecutionTools.ts"],"sourcesContent":["import { tool } from '@langchain/core/tools';\nimport type { DynamicStructuredTool } from '@langchain/core/tools';\nimport type * as t from '@/types';\nimport {\n CodeExecutionToolName,\n CodeExecutionToolSchema,\n} from '@/tools/CodeExecutor';\nimport {\n BashExecutionToolName,\n BashExecutionToolSchema,\n BashToolOutputReferencesGuide,\n} from '@/tools/BashExecutor';\nimport {\n executeLocalBash,\n executeLocalBashWithArgs,\n executeLocalCode,\n getLocalCwd,\n getLocalSessionId,\n} from './LocalExecutionEngine';\nimport { Constants } from '@/common';\n\nconst emptyOutputMessage =\n 'stdout: Empty. Ensure you\\'re writing output explicitly.\\n';\n\nexport const LocalCodeExecutionToolDescription = `\nRuns code on the local machine in the configured working directory. Unlike the remote Code API sandbox, this tool can see the local repository, installed runtimes, environment variables, and filesystem available to the host process.\n\nUsage:\n- The remote sandbox API remains the default; this description applies only when local execution mode is enabled.\n- Local commands can use the Anthropic sandbox runtime when local.sandbox.enabled=true and @anthropic-ai/sandbox-runtime is installed.\n- Commands execute in the local working directory and may modify local files.\n- Input code is already displayed to the user, so do not repeat it unless asked.\n- Output is not displayed unless you print it explicitly.\n`.trim();\n\nexport const LocalBashExecutionToolDescription = `\nRuns bash commands on the local machine in the configured working directory. Unlike the remote Code API sandbox, this tool can see the local repository, installed tools, environment variables, and filesystem available to the host process.\n\nUsage:\n- The remote sandbox API remains the default; this description applies only when local execution mode is enabled.\n- Local commands can use the Anthropic sandbox runtime when local.sandbox.enabled=true and @anthropic-ai/sandbox-runtime is installed.\n- Commands execute in the local working directory and may modify local files.\n- Output is not displayed unless you print it explicitly.\n- Prefer project-native commands and inspect files before changing them.\n`.trim();\n\nfunction formatLocalOutput(\n result: {\n stdout: string;\n stderr: string;\n exitCode: number | null;\n timedOut: boolean;\n overflowKilled?: boolean;\n signal?: string;\n fullOutputPath?: string;\n },\n cwd: string\n): string {\n let formatted = '';\n if (result.stdout !== '') {\n formatted += `stdout:\\n${result.stdout}\\n`;\n } else {\n formatted += emptyOutputMessage;\n }\n\n if (result.stderr !== '') {\n formatted += `stderr:\\n${result.stderr}\\n`;\n }\n\n if (result.exitCode != null && result.exitCode !== 0) {\n formatted += `exit_code: ${result.exitCode}\\n`;\n }\n\n if (result.timedOut) {\n formatted += 'timed_out: true\\n';\n }\n\n if (result.overflowKilled === true) {\n // Surface the force-kill explicitly so the model treats this as a\n // failure rather than misreading \"exit_code: 137 + truncated\n // stdout\" as a normal completion. (Codex P1 — pre-fix the close\n // handler swallowed the overflow flag and exitCode was null on\n // signal-killed processes.)\n formatted +=\n 'killed: true (output exceeded local.maxSpawnedBytes; process tree was terminated)\\n';\n } else if (result.signal != null) {\n // Generic signal kill: `kill -9 $$` from inside the script,\n // native crash, OS OOM killer, etc. Codex P2 generalization of\n // the overflow case.\n formatted += `killed: true (signal=${result.signal})\\n`;\n }\n\n if (result.fullOutputPath != null) {\n formatted += `full_output_path: ${result.fullOutputPath} (output exceeded the configured cap; use bash to inspect — the file holds the complete stdout/stderr)\\n`;\n }\n\n formatted += `working_directory: ${cwd}`;\n return formatted.trim();\n}\n\nexport function createLocalCodeExecutionTool(\n config: t.LocalExecutionConfig = {}\n): DynamicStructuredTool {\n return tool(\n async (rawInput) => {\n const input = rawInput as {\n lang: string;\n code: string;\n args?: string[];\n };\n const cwd = getLocalCwd(config);\n const result = await executeLocalCode(input, config);\n return [\n formatLocalOutput(result, cwd),\n {\n session_id: getLocalSessionId(config),\n files: [],\n } satisfies t.CodeExecutionArtifact,\n ];\n },\n {\n name: CodeExecutionToolName,\n description: LocalCodeExecutionToolDescription,\n schema: CodeExecutionToolSchema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n\nexport function createLocalBashExecutionTool(options?: {\n config?: t.LocalExecutionConfig;\n enableToolOutputReferences?: boolean;\n}): DynamicStructuredTool {\n const config = options?.config ?? {};\n return tool(\n async (rawInput) => {\n const input = rawInput as { command: string; args?: string[] };\n const cwd = getLocalCwd(config);\n // Use the standard `bash -lc <command> -- <args...>` form so\n // `$1`, `$2`, … resolve correctly inside `command`. The\n // previous implementation appended args literally to the\n // command string (`${command} ${args.join(' ')}`), which\n // doesn't populate positional parameters and silently broke\n // shell snippets like `command: 'echo \"$1\"'`.\n const result =\n input.args != null && input.args.length > 0\n ? await executeLocalBashWithArgs(input.command, input.args, config)\n : await executeLocalBash(input.command, config);\n return [\n formatLocalOutput(result, cwd),\n {\n session_id: getLocalSessionId(config),\n files: [],\n } satisfies t.CodeExecutionArtifact,\n ];\n },\n {\n name: BashExecutionToolName,\n description:\n options?.enableToolOutputReferences === true\n ? `${LocalBashExecutionToolDescription}\\n\\n${BashToolOutputReferencesGuide}`\n : LocalBashExecutionToolDescription,\n schema: BashExecutionToolSchema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n"],"names":[],"mappings":";;;;;;AAqBA,MAAM,kBAAkB,GACtB,4DAA4D;AAEvD,MAAM,iCAAiC,GAAG;;;;;;;;;CAShD,CAAC,IAAI;AAEC,MAAM,iCAAiC,GAAG;;;;;;;;;CAShD,CAAC,IAAI;AAEN,SAAS,iBAAiB,CACxB,MAQC,EACD,GAAW,EAAA;IAEX,IAAI,SAAS,GAAG,EAAE;AAClB,IAAA,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE;AACxB,QAAA,SAAS,IAAI,CAAA,SAAA,EAAY,MAAM,CAAC,MAAM,IAAI;IAC5C;SAAO;QACL,SAAS,IAAI,kBAAkB;IACjC;AAEA,IAAA,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE;AACxB,QAAA,SAAS,IAAI,CAAA,SAAA,EAAY,MAAM,CAAC,MAAM,IAAI;IAC5C;AAEA,IAAA,IAAI,MAAM,CAAC,QAAQ,IAAI,IAAI,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE;AACpD,QAAA,SAAS,IAAI,CAAA,WAAA,EAAc,MAAM,CAAC,QAAQ,IAAI;IAChD;AAEA,IAAA,IAAI,MAAM,CAAC,QAAQ,EAAE;QACnB,SAAS,IAAI,mBAAmB;IAClC;AAEA,IAAA,IAAI,MAAM,CAAC,cAAc,KAAK,IAAI,EAAE;;;;;;QAMlC,SAAS;AACP,YAAA,qFAAqF;IACzF;AAAO,SAAA,IAAI,MAAM,CAAC,MAAM,IAAI,IAAI,EAAE;;;;AAIhC,QAAA,SAAS,IAAI,CAAA,qBAAA,EAAwB,MAAM,CAAC,MAAM,KAAK;IACzD;AAEA,IAAA,IAAI,MAAM,CAAC,cAAc,IAAI,IAAI,EAAE;AACjC,QAAA,SAAS,IAAI,CAAA,kBAAA,EAAqB,MAAM,CAAC,cAAc,0GAA0G;IACnK;AAEA,IAAA,SAAS,IAAI,CAAA,mBAAA,EAAsB,GAAG,CAAA,CAAE;AACxC,IAAA,OAAO,SAAS,CAAC,IAAI,EAAE;AACzB;AAEM,SAAU,4BAA4B,CAC1C,MAAA,GAAiC,EAAE,EAAA;AAEnC,IAAA,OAAO,IAAI,CACT,OAAO,QAAQ,KAAI;QACjB,MAAM,KAAK,GAAG,QAIb;AACD,QAAA,MAAM,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC;QACpD,OAAO;AACL,YAAA,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC;AAC9B,YAAA;AACE,gBAAA,UAAU,EAAE,iBAAiB,CAAC,MAAM,CAAC;AACrC,gBAAA,KAAK,EAAE,EAAE;AACwB,aAAA;SACpC;AACH,IAAA,CAAC,EACD;AACE,QAAA,IAAI,EAAE,qBAAqB;AAC3B,QAAA,WAAW,EAAE,iCAAiC;AAC9C,QAAA,MAAM,EAAE,uBAAuB;QAC/B,cAAc,EAAE,SAAS,CAAC,oBAAoB;AAC/C,KAAA,CACF;AACH;AAEM,SAAU,4BAA4B,CAAC,OAG5C,EAAA;AACC,IAAA,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,EAAE;AACpC,IAAA,OAAO,IAAI,CACT,OAAO,QAAQ,KAAI;QACjB,MAAM,KAAK,GAAG,QAAgD;AAC9D,QAAA,MAAM,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC;;;;;;;AAO/B,QAAA,MAAM,MAAM,GACV,KAAK,CAAC,IAAI,IAAI,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG;AACxC,cAAE,MAAM,wBAAwB,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM;cAChE,MAAM,gBAAgB,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC;QACnD,OAAO;AACL,YAAA,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC;AAC9B,YAAA;AACE,gBAAA,UAAU,EAAE,iBAAiB,CAAC,MAAM,CAAC;AACrC,gBAAA,KAAK,EAAE,EAAE;AACwB,aAAA;SACpC;AACH,IAAA,CAAC,EACD;AACE,QAAA,IAAI,EAAE,qBAAqB;AAC3B,QAAA,WAAW,EACT,OAAO,EAAE,0BAA0B,KAAK;AACtC,cAAE,CAAA,EAAG,iCAAiC,CAAA,IAAA,EAAO,6BAA6B,CAAA;AAC1E,cAAE,iCAAiC;AACvC,QAAA,MAAM,EAAE,uBAAuB;QAC/B,cAAc,EAAE,SAAS,CAAC,oBAAoB;AAC/C,KAAA,CACF;AACH;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocalProgrammaticToolCalling.mjs","sources":["../../../../src/tools/local/LocalProgrammaticToolCalling.ts"],"sourcesContent":["import { randomBytes, randomUUID, timingSafeEqual } from 'crypto';\nimport { createServer } from 'http';\nimport { tool } from '@langchain/core/tools';\nimport type { AddressInfo } from 'net';\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { DynamicStructuredTool } from '@langchain/core/tools';\nimport type * as t from '@/types';\nimport { executeHooks } from '@/hooks';\nimport {\n executeTools,\n filterToolsByUsage,\n formatCompletedResponse,\n normalizeToPythonIdentifier,\n ProgrammaticToolCallingName,\n ProgrammaticToolCallingSchema,\n ProgrammaticToolCallingDescription,\n} from '@/tools/ProgrammaticToolCalling';\nimport {\n BashProgrammaticToolCallingSchema,\n BashProgrammaticToolCallingDescription,\n filterBashToolsByUsage,\n normalizeToBashIdentifier,\n} from '@/tools/BashProgrammaticToolCalling';\nimport {\n executeLocalBash,\n executeLocalCode,\n getLocalSessionId,\n shellQuote,\n} from './LocalExecutionEngine';\nimport { Constants } from '@/common';\n\nconst DEFAULT_TIMEOUT = 60000;\nconst LocalProgrammaticToolCallingSchema = {\n ...ProgrammaticToolCallingSchema,\n properties: {\n ...ProgrammaticToolCallingSchema.properties,\n lang: {\n type: 'string',\n enum: ['py', 'python', 'bash', 'sh'],\n default: 'bash',\n description:\n 'Local engine runtime for orchestration code. Defaults to bash; use py/python for Python orchestration.',\n },\n },\n} as const;\n\ntype ToolBridge = {\n url: string;\n token: string;\n close: () => Promise<void>;\n};\n\ntype ToolRequest = {\n id?: string;\n name?: string;\n input?: Record<string, unknown>;\n};\n\nconst BRIDGE_AUTH_HEADER = 'x-librechat-bridge-token';\n\nfunction constantTimeEquals(a: string, b: string): boolean {\n const aBuf = Buffer.from(a, 'utf8');\n const bBuf = Buffer.from(b, 'utf8');\n if (aBuf.length !== bBuf.length) {\n return false;\n }\n return timingSafeEqual(aBuf, bBuf);\n}\n\ntype LocalProgrammaticRuntime = 'python' | 'bash';\n\ntype LocalProgrammaticParams = {\n code: string;\n timeout?: number;\n lang?: string;\n runtime?: string;\n language?: string;\n};\n\ntype ToolFilter = (toolDefs: t.LCTool[], code: string) => t.LCTool[];\n\nfunction resolveRuntime(params: LocalProgrammaticParams): LocalProgrammaticRuntime {\n const rawRuntime = params.lang ?? params.runtime ?? params.language ?? 'bash';\n return rawRuntime === 'py' || rawRuntime === 'python' ? 'python' : 'bash';\n}\n\nfunction toSerializable(value: unknown): unknown {\n if (value === undefined) {\n return null;\n }\n return value;\n}\n\nasync function readRequestBody(req: IncomingMessage): Promise<ToolRequest> {\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n const raw = Buffer.concat(chunks).toString('utf8');\n if (raw === '') {\n return {};\n }\n return JSON.parse(raw) as ToolRequest;\n}\n\nfunction writeJson(res: ServerResponse, status: number, value: unknown): void {\n res.writeHead(status, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(value));\n}\n\n/**\n * Run the host's `PreToolUse` hook chain for a single bridge call.\n * Returns the (possibly rewritten) input and a `denyReason` if any\n * matcher returned `decision: 'deny'` or `'ask'`. `'ask'` collapses\n * to deny because the bridge can't raise a LangGraph interrupt from\n * inside an HTTP handler — fail-closed matches the rest of the SDK\n * when HITL is unavailable.\n *\n * @internal Exported for tests so the deny / allow / updatedInput /\n * ask branches can be exercised without standing up the full HTTP\n * bridge.\n */\nexport async function applyPreToolUseHooksForBridge(\n hookContext: t.ProgrammaticHookContext,\n toolName: string,\n toolUseId: string,\n toolInput: Record<string, unknown>\n): Promise<{ input: Record<string, unknown>; denyReason?: string }> {\n if (hookContext.registry == null) {\n return { input: toolInput };\n }\n const result = await executeHooks({\n registry: hookContext.registry,\n input: {\n hook_event_name: 'PreToolUse',\n runId: hookContext.runId,\n threadId: hookContext.threadId,\n agentId: hookContext.agentId,\n toolName,\n toolInput,\n toolUseId,\n stepId: '',\n turn: 0,\n },\n sessionId: hookContext.runId,\n matchQuery: toolName,\n }).catch(() => undefined);\n if (result == null) {\n return { input: toolInput };\n }\n const nextInput =\n result.updatedInput != null\n ? (result.updatedInput as Record<string, unknown>)\n : toolInput;\n if (result.decision === 'deny' || result.decision === 'ask') {\n return {\n input: nextInput,\n denyReason:\n result.reason ??\n (result.decision === 'ask'\n ? `Tool \"${toolName}\" requires human approval; bridge cannot raise an interrupt — denying.`\n : `Tool \"${toolName}\" denied by PreToolUse hook.`),\n };\n }\n return { input: nextInput };\n}\n\nasync function createToolBridge(\n toolMap: t.ToolMap,\n hookContext?: t.ProgrammaticHookContext\n): Promise<ToolBridge> {\n const token = randomBytes(32).toString('hex');\n const server = createServer((req, res) => {\n // `?mode=text` returns the already-serialized result as the body\n // (or the error message at non-2xx). Python/Node callers stay on\n // JSON; bash callers using curl can avoid pulling in a JSON\n // parser dependency (Codex P2 #19 — `python3` was a hard\n // requirement for the bash bridge, breaking minimal containers).\n const url = new URL(req.url ?? '/', 'http://127.0.0.1');\n const isTextMode = url.searchParams.get('mode') === 'text';\n if (req.method !== 'POST' || url.pathname !== '/tool') {\n if (isTextMode) {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not found');\n } else {\n writeJson(res, 404, { error: 'Not found' });\n }\n return;\n }\n\n const presented = req.headers[BRIDGE_AUTH_HEADER];\n const presentedToken = Array.isArray(presented) ? presented[0] : presented;\n if (\n typeof presentedToken !== 'string' ||\n !constantTimeEquals(presentedToken, token)\n ) {\n if (isTextMode) {\n res.writeHead(401, { 'Content-Type': 'text/plain' });\n res.end('Unauthorized');\n } else {\n writeJson(res, 401, { error: 'Unauthorized' });\n }\n return;\n }\n\n readRequestBody(req)\n .then(async (body) => {\n if (typeof body.name !== 'string' || body.name === '') {\n const message = 'Tool request is missing a tool name.';\n if (isTextMode) {\n res.writeHead(400, { 'Content-Type': 'text/plain' });\n res.end(message);\n } else {\n writeJson(res, 400, {\n call_id: body.id ?? 'invalid',\n result: null,\n is_error: true,\n error_message: message,\n });\n }\n return;\n }\n\n const callId = body.id ?? `local_call_${randomUUID()}`;\n let effectiveInput: Record<string, unknown> = body.input ?? {};\n if (hookContext != null) {\n const gate = await applyPreToolUseHooksForBridge(\n hookContext,\n body.name,\n callId,\n effectiveInput\n );\n if (gate.denyReason != null) {\n const denyMsg = gate.denyReason;\n if (isTextMode) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(denyMsg);\n } else {\n writeJson(res, 500, {\n call_id: callId,\n result: null,\n is_error: true,\n error_message: denyMsg,\n });\n }\n return;\n }\n effectiveInput = gate.input;\n }\n\n const [result] = await executeTools(\n [\n {\n id: callId,\n name: body.name,\n input: effectiveInput,\n },\n ],\n toolMap\n );\n\n if (isTextMode) {\n if (result.is_error === true) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(result.error_message ?? `Tool ${body.name} failed`);\n } else {\n const value = toSerializable(result.result);\n const text =\n typeof value === 'string' ? value : JSON.stringify(value);\n res.writeHead(200, { 'Content-Type': 'text/plain' });\n res.end(text);\n }\n return;\n }\n\n writeJson(res, 200, {\n ...result,\n result: toSerializable(result.result),\n });\n })\n .catch((error: Error) => {\n if (isTextMode) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(error.message);\n } else {\n writeJson(res, 500, {\n call_id: 'error',\n result: null,\n is_error: true,\n error_message: error.message,\n });\n }\n });\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(0, '127.0.0.1', resolve);\n });\n\n const address = server.address() as AddressInfo;\n return {\n url: `http://127.0.0.1:${address.port}/tool`,\n token,\n close: () =>\n new Promise((resolve, reject) => {\n server.close((error) => (error ? reject(error) : resolve()));\n }),\n };\n}\n\nfunction indent(code: string): string {\n return code\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n}\n\nfunction createPythonProgram(\n code: string,\n toolDefs: t.LCTool[],\n bridgeUrl: string,\n bridgeToken: string\n): string {\n const functionDefs = toolDefs\n .map((def) => {\n const pythonName = normalizeToPythonIdentifier(def.name);\n return [\n `async def ${pythonName}(**kwargs):`,\n ` return await __librechat_call_tool(${JSON.stringify(def.name)}, kwargs)`,\n ].join('\\n');\n })\n .join('\\n\\n');\n\n return `\nimport asyncio\nimport json\nimport urllib.request\n\n__LIBRECHAT_TOOL_BRIDGE = ${JSON.stringify(bridgeUrl)}\n__LIBRECHAT_TOOL_TOKEN = ${JSON.stringify(bridgeToken)}\n\nasync def __librechat_call_tool(name, payload):\n body = json.dumps({\"name\": name, \"input\": payload}).encode(\"utf-8\")\n headers = {\n \"Content-Type\": \"application/json\",\n ${JSON.stringify(BRIDGE_AUTH_HEADER)}: __LIBRECHAT_TOOL_TOKEN,\n }\n\n def request():\n req = urllib.request.Request(__LIBRECHAT_TOOL_BRIDGE, data=body, headers=headers, method=\"POST\")\n with urllib.request.urlopen(req, timeout=300) as response:\n return response.read().decode(\"utf-8\")\n\n raw = await asyncio.to_thread(request)\n result = json.loads(raw)\n if result.get(\"is_error\"):\n raise RuntimeError(result.get(\"error_message\") or f\"Tool {name} failed\")\n return result.get(\"result\")\n\n${functionDefs}\n\nasync def __librechat_main():\n${indent(code)}\n\nasyncio.run(__librechat_main())\n`.trimStart();\n}\n\nexport function _createBashProgramForTests(\n code: string,\n toolDefs: t.LCTool[],\n bridgeUrl: string,\n bridgeToken: string\n): string {\n return createBashProgram(code, toolDefs, bridgeUrl, bridgeToken);\n}\n\nfunction createBashProgram(\n code: string,\n toolDefs: t.LCTool[],\n bridgeUrl: string,\n bridgeToken: string\n): string {\n const functions = toolDefs\n .map((def) => {\n const bashName = normalizeToBashIdentifier(def.name);\n return [\n `${bashName}() {`,\n ' local payload=\"${1:-}\"',\n ' if [ -z \"$payload\" ]; then payload=\\'{}\\'; fi',\n ` __librechat_call_tool ${shellQuote(def.name)} \"$payload\"`,\n '}',\n ].join('\\n');\n })\n .join('\\n\\n');\n\n return `\n__LIBRECHAT_TOOL_BRIDGE=${shellQuote(bridgeUrl)}\n__LIBRECHAT_TOOL_HEADER=${shellQuote(BRIDGE_AUTH_HEADER)}\n__LIBRECHAT_TOOL_TOKEN=${shellQuote(bridgeToken)}\n\n# Bridge call helper. Tries curl first (universally available, no\n# JSON parser needed thanks to the bridge's ?mode=text endpoint),\n# falls back to python3 for environments without curl. Codex P2 #19\n# flagged that the prior python3-only path broke minimal containers\n# (and Windows hosts without a python3 binary on PATH). Tool names\n# come from Constants.* and are always safe identifiers, so we can\n# splice them into JSON without an escape pass.\n__librechat_call_tool() {\n local tool_name=\"$1\"\n local payload=\"$2\"\n if command -v curl >/dev/null 2>&1; then\n local body=\"{\\\\\"name\\\\\":\\\\\"$tool_name\\\\\",\\\\\"input\\\\\":$payload}\"\n local response\n local http_code\n response=$(curl -sS -X POST \\\n -H \"Content-Type: application/json\" \\\n -H \"$__LIBRECHAT_TOOL_HEADER: $__LIBRECHAT_TOOL_TOKEN\" \\\n --data-binary \"$body\" \\\n -w '\\\\n__LIBRECHAT_HTTP_CODE_%{http_code}__' \\\n \"$__LIBRECHAT_TOOL_BRIDGE?mode=text\")\n http_code=$(printf '%s' \"$response\" | sed -n 's/.*__LIBRECHAT_HTTP_CODE_\\\\([0-9][0-9]*\\\\)__$/\\\\1/p')\n local body_only\n body_only=$(printf '%s' \"$response\" | sed 's/__LIBRECHAT_HTTP_CODE_[0-9][0-9]*__$//')\n if [ \"$http_code\" = \"200\" ]; then\n printf '%s' \"$body_only\"\n return 0\n fi\n printf '%s\\\\n' \"$body_only\" >&2\n return 1\n elif command -v python3 >/dev/null 2>&1; then\n python3 - \"$__LIBRECHAT_TOOL_BRIDGE\" \"$tool_name\" \"$payload\" \"$__LIBRECHAT_TOOL_HEADER\" \"$__LIBRECHAT_TOOL_TOKEN\" <<'PY'\nimport json\nimport sys\nimport urllib.request\n\nurl, name, payload, header, token = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]\nbody = json.dumps({\"name\": name, \"input\": json.loads(payload)}).encode(\"utf-8\")\nreq = urllib.request.Request(url, data=body, headers={\"Content-Type\": \"application/json\", header: token}, method=\"POST\")\nwith urllib.request.urlopen(req, timeout=300) as response:\n result = json.loads(response.read().decode(\"utf-8\"))\nif result.get(\"is_error\"):\n print(result.get(\"error_message\") or f\"Tool {name} failed\", file=sys.stderr)\n sys.exit(1)\nvalue = result.get(\"result\")\nif isinstance(value, str):\n print(value)\nelse:\n print(json.dumps(value))\nPY\n else\n printf 'librechat: tool bridge needs either curl or python3 on PATH\\\\n' >&2\n return 1\n fi\n}\n\n${functions}\n\n${code}\n`.trimStart();\n}\n\nfunction getProgrammaticContext(config?: {\n toolCall?: unknown;\n}): Partial<t.ProgrammaticCache> {\n return (config?.toolCall ?? {}) as Partial<t.ProgrammaticCache>;\n}\n\nfunction createEffectiveToolMap(\n toolMap: t.ToolMap,\n toolDefs: t.LCTool[],\n code: string,\n filterTools: ToolFilter\n): { effectiveTools: t.LCTool[]; effectiveMap: t.ToolMap } {\n const effectiveTools = filterTools(toolDefs, code);\n const effectiveMap = new Map<string, t.GenericTool>(\n effectiveTools\n .map((def) => {\n const executable = toolMap.get(def.name);\n return executable == null\n ? undefined\n : ([def.name, executable] as [string, t.GenericTool]);\n })\n .filter((entry): entry is [string, t.GenericTool] => entry != null)\n );\n\n return { effectiveTools, effectiveMap };\n}\n\nasync function runLocalProgrammaticTool(args: {\n params: LocalProgrammaticParams;\n config?: { toolCall?: unknown };\n localConfig: t.LocalExecutionConfig;\n runtime: LocalProgrammaticRuntime;\n}): Promise<[string, t.ProgrammaticExecutionArtifact]> {\n const { toolMap, toolDefs, hookContext } = getProgrammaticContext(args.config);\n\n if (toolMap == null || toolMap.size === 0) {\n throw new Error('No toolMap provided for local programmatic execution.');\n }\n if (toolDefs == null || toolDefs.length === 0) {\n throw new Error('No tool definitions provided for local programmatic execution.');\n }\n\n const { effectiveTools, effectiveMap } = createEffectiveToolMap(\n toolMap,\n toolDefs,\n args.params.code,\n args.runtime === 'bash' ? filterBashToolsByUsage : filterToolsByUsage\n );\n const bridge = await createToolBridge(effectiveMap, hookContext);\n\n try {\n const timeoutMs = args.params.timeout ?? args.localConfig.timeoutMs ?? DEFAULT_TIMEOUT;\n const result =\n args.runtime === 'bash'\n ? await executeLocalBash(\n createBashProgram(args.params.code, effectiveTools, bridge.url, bridge.token),\n { ...args.localConfig, timeoutMs }\n )\n : await executeLocalCode(\n {\n lang: 'py',\n code: createPythonProgram(args.params.code, effectiveTools, bridge.url, bridge.token),\n },\n { ...args.localConfig, timeoutMs }\n );\n\n if (result.exitCode !== 0 || result.timedOut) {\n throw new Error(\n result.stderr !== ''\n ? result.stderr\n : `Local ${args.runtime} programmatic execution exited with code ${\n result.exitCode ?? 'unknown'\n }`\n );\n }\n\n return formatCompletedResponse({\n status: 'completed',\n session_id: getLocalSessionId(args.localConfig),\n stdout: result.stdout,\n stderr: result.stderr,\n files: [],\n });\n } finally {\n await bridge.close();\n }\n}\n\nexport function createLocalProgrammaticToolCallingTool(\n localConfig: t.LocalExecutionConfig = {}\n): DynamicStructuredTool {\n return tool(\n async (rawParams, config) => {\n const params = rawParams as LocalProgrammaticParams;\n return runLocalProgrammaticTool({\n params,\n config,\n localConfig,\n runtime: resolveRuntime(params),\n });\n },\n {\n name: ProgrammaticToolCallingName,\n description: `${ProgrammaticToolCallingDescription}\\n\\nLocal engine: runs bash by default, or Python when \\`lang\\` is \\`py\\` or \\`python\\`, on the host machine and calls tools through an in-process localhost bridge.`,\n schema: LocalProgrammaticToolCallingSchema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n\nexport function createLocalBashProgrammaticToolCallingTool(\n localConfig: t.LocalExecutionConfig = {}\n): DynamicStructuredTool {\n return tool(\n async (rawParams, config) => {\n const params = rawParams as LocalProgrammaticParams;\n return runLocalProgrammaticTool({\n params,\n config,\n localConfig,\n runtime: 'bash',\n });\n },\n {\n name: Constants.BASH_PROGRAMMATIC_TOOL_CALLING,\n description: `${BashProgrammaticToolCallingDescription}\\n\\nLocal engine: runs this bash orchestration code on the host machine and calls tools through an in-process localhost bridge.`,\n schema: BashProgrammaticToolCallingSchema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LocalProgrammaticToolCalling.mjs","sources":["../../../../src/tools/local/LocalProgrammaticToolCalling.ts"],"sourcesContent":["import { randomBytes, randomUUID, timingSafeEqual } from 'crypto';\nimport { createServer } from 'http';\nimport { tool } from '@langchain/core/tools';\nimport type { AddressInfo } from 'net';\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { DynamicStructuredTool } from '@langchain/core/tools';\nimport type * as t from '@/types';\nimport { executeHooks } from '@/hooks';\nimport {\n executeTools,\n filterToolsByUsage,\n formatCompletedResponse,\n normalizeToPythonIdentifier,\n ProgrammaticToolCallingName,\n ProgrammaticToolCallingSchema,\n ProgrammaticToolCallingDescription,\n} from '@/tools/ProgrammaticToolCalling';\nimport {\n BashProgrammaticToolCallingSchema,\n BashProgrammaticToolCallingDescription,\n filterBashToolsByUsage,\n normalizeToBashIdentifier,\n} from '@/tools/BashProgrammaticToolCalling';\nimport {\n executeLocalBash,\n executeLocalCode,\n getLocalSessionId,\n shellQuote,\n} from './LocalExecutionEngine';\nimport { Constants } from '@/common';\n\nconst DEFAULT_TIMEOUT = 60000;\nconst LocalProgrammaticToolCallingSchema = {\n ...ProgrammaticToolCallingSchema,\n properties: {\n ...ProgrammaticToolCallingSchema.properties,\n lang: {\n type: 'string',\n enum: ['py', 'python', 'bash', 'sh'],\n default: 'bash',\n description:\n 'Local engine runtime for orchestration code. Defaults to bash; use py/python for Python orchestration.',\n },\n },\n} as const;\n\ntype ToolBridge = {\n url: string;\n token: string;\n close: () => Promise<void>;\n};\n\ntype ToolRequest = {\n id?: string;\n name?: string;\n input?: Record<string, unknown>;\n};\n\nconst BRIDGE_AUTH_HEADER = 'x-librechat-bridge-token';\n\nfunction constantTimeEquals(a: string, b: string): boolean {\n const aBuf = Buffer.from(a, 'utf8');\n const bBuf = Buffer.from(b, 'utf8');\n if (aBuf.length !== bBuf.length) {\n return false;\n }\n return timingSafeEqual(aBuf, bBuf);\n}\n\ntype LocalProgrammaticRuntime = 'python' | 'bash';\n\ntype LocalProgrammaticParams = {\n code: string;\n timeout?: number;\n lang?: string;\n runtime?: string;\n language?: string;\n};\n\ntype ToolFilter = (toolDefs: t.LCTool[], code: string) => t.LCTool[];\n\nfunction resolveRuntime(\n params: LocalProgrammaticParams\n): LocalProgrammaticRuntime {\n const rawRuntime = params.lang ?? params.runtime ?? params.language ?? 'bash';\n return rawRuntime === 'py' || rawRuntime === 'python' ? 'python' : 'bash';\n}\n\nfunction toSerializable(value: unknown): unknown {\n if (value === undefined) {\n return null;\n }\n return value;\n}\n\nasync function readRequestBody(req: IncomingMessage): Promise<ToolRequest> {\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n const raw = Buffer.concat(chunks).toString('utf8');\n if (raw === '') {\n return {};\n }\n return JSON.parse(raw) as ToolRequest;\n}\n\nfunction writeJson(res: ServerResponse, status: number, value: unknown): void {\n res.writeHead(status, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(value));\n}\n\n/**\n * Run the host's `PreToolUse` hook chain for a single bridge call.\n * Returns the (possibly rewritten) input and a `denyReason` if any\n * matcher returned `decision: 'deny'` or `'ask'`. `'ask'` collapses\n * to deny because the bridge can't raise a LangGraph interrupt from\n * inside an HTTP handler — fail-closed matches the rest of the SDK\n * when HITL is unavailable.\n *\n * @internal Exported for tests so the deny / allow / updatedInput /\n * ask branches can be exercised without standing up the full HTTP\n * bridge.\n */\nexport async function applyPreToolUseHooksForBridge(\n hookContext: t.ProgrammaticHookContext,\n toolName: string,\n toolUseId: string,\n toolInput: Record<string, unknown>\n): Promise<{ input: Record<string, unknown>; denyReason?: string }> {\n if (hookContext.registry == null) {\n return { input: toolInput };\n }\n const result = await executeHooks({\n registry: hookContext.registry,\n input: {\n hook_event_name: 'PreToolUse',\n runId: hookContext.runId,\n threadId: hookContext.threadId,\n agentId: hookContext.agentId,\n toolName,\n toolInput,\n toolUseId,\n stepId: '',\n turn: 0,\n },\n sessionId: hookContext.runId,\n matchQuery: toolName,\n }).catch(() => undefined);\n if (result == null) {\n return { input: toolInput };\n }\n const nextInput =\n result.updatedInput != null\n ? (result.updatedInput as Record<string, unknown>)\n : toolInput;\n if (result.decision === 'deny' || result.decision === 'ask') {\n return {\n input: nextInput,\n denyReason:\n result.reason ??\n (result.decision === 'ask'\n ? `Tool \"${toolName}\" requires human approval; bridge cannot raise an interrupt — denying.`\n : `Tool \"${toolName}\" denied by PreToolUse hook.`),\n };\n }\n return { input: nextInput };\n}\n\nasync function createToolBridge(\n toolMap: t.ToolMap,\n hookContext?: t.ProgrammaticHookContext\n): Promise<ToolBridge> {\n const token = randomBytes(32).toString('hex');\n const server = createServer((req, res) => {\n // `?mode=text` returns the already-serialized result as the body\n // (or the error message at non-2xx). Python/Node callers stay on\n // JSON; bash callers using curl can avoid pulling in a JSON\n // parser dependency (Codex P2 #19 — `python3` was a hard\n // requirement for the bash bridge, breaking minimal containers).\n const url = new URL(req.url ?? '/', 'http://127.0.0.1');\n const isTextMode = url.searchParams.get('mode') === 'text';\n if (req.method !== 'POST' || url.pathname !== '/tool') {\n if (isTextMode) {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not found');\n } else {\n writeJson(res, 404, { error: 'Not found' });\n }\n return;\n }\n\n const presented = req.headers[BRIDGE_AUTH_HEADER];\n const presentedToken = Array.isArray(presented) ? presented[0] : presented;\n if (\n typeof presentedToken !== 'string' ||\n !constantTimeEquals(presentedToken, token)\n ) {\n if (isTextMode) {\n res.writeHead(401, { 'Content-Type': 'text/plain' });\n res.end('Unauthorized');\n } else {\n writeJson(res, 401, { error: 'Unauthorized' });\n }\n return;\n }\n\n readRequestBody(req)\n .then(async (body) => {\n if (typeof body.name !== 'string' || body.name === '') {\n const message = 'Tool request is missing a tool name.';\n if (isTextMode) {\n res.writeHead(400, { 'Content-Type': 'text/plain' });\n res.end(message);\n } else {\n writeJson(res, 400, {\n call_id: body.id ?? 'invalid',\n result: null,\n is_error: true,\n error_message: message,\n });\n }\n return;\n }\n\n const callId = body.id ?? `local_call_${randomUUID()}`;\n let effectiveInput: Record<string, unknown> = body.input ?? {};\n if (hookContext != null) {\n const gate = await applyPreToolUseHooksForBridge(\n hookContext,\n body.name,\n callId,\n effectiveInput\n );\n if (gate.denyReason != null) {\n const denyMsg = gate.denyReason;\n if (isTextMode) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(denyMsg);\n } else {\n writeJson(res, 500, {\n call_id: callId,\n result: null,\n is_error: true,\n error_message: denyMsg,\n });\n }\n return;\n }\n effectiveInput = gate.input;\n }\n\n const [result] = await executeTools(\n [\n {\n id: callId,\n name: body.name,\n input: effectiveInput,\n },\n ],\n toolMap\n );\n\n if (isTextMode) {\n if (result.is_error === true) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(result.error_message ?? `Tool ${body.name} failed`);\n } else {\n const value = toSerializable(result.result);\n const text =\n typeof value === 'string' ? value : JSON.stringify(value);\n res.writeHead(200, { 'Content-Type': 'text/plain' });\n res.end(text);\n }\n return;\n }\n\n writeJson(res, 200, {\n ...result,\n result: toSerializable(result.result),\n });\n })\n .catch((error: Error) => {\n if (isTextMode) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(error.message);\n } else {\n writeJson(res, 500, {\n call_id: 'error',\n result: null,\n is_error: true,\n error_message: error.message,\n });\n }\n });\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(0, '127.0.0.1', resolve);\n });\n\n const address = server.address() as AddressInfo;\n return {\n url: `http://127.0.0.1:${address.port}/tool`,\n token,\n close: () =>\n new Promise((resolve, reject) => {\n server.close((error) => (error ? reject(error) : resolve()));\n }),\n };\n}\n\nfunction indent(code: string): string {\n return code\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n}\n\nfunction createPythonProgram(\n code: string,\n toolDefs: t.LCTool[],\n bridgeUrl: string,\n bridgeToken: string\n): string {\n const functionDefs = toolDefs\n .map((def) => {\n const pythonName = normalizeToPythonIdentifier(def.name);\n return [\n `async def ${pythonName}(**kwargs):`,\n ` return await __librechat_call_tool(${JSON.stringify(def.name)}, kwargs)`,\n ].join('\\n');\n })\n .join('\\n\\n');\n\n return `\nimport asyncio\nimport json\nimport urllib.request\n\n__LIBRECHAT_TOOL_BRIDGE = ${JSON.stringify(bridgeUrl)}\n__LIBRECHAT_TOOL_TOKEN = ${JSON.stringify(bridgeToken)}\n\nasync def __librechat_call_tool(name, payload):\n body = json.dumps({\"name\": name, \"input\": payload}).encode(\"utf-8\")\n headers = {\n \"Content-Type\": \"application/json\",\n ${JSON.stringify(BRIDGE_AUTH_HEADER)}: __LIBRECHAT_TOOL_TOKEN,\n }\n\n def request():\n req = urllib.request.Request(__LIBRECHAT_TOOL_BRIDGE, data=body, headers=headers, method=\"POST\")\n with urllib.request.urlopen(req, timeout=300) as response:\n return response.read().decode(\"utf-8\")\n\n raw = await asyncio.to_thread(request)\n result = json.loads(raw)\n if result.get(\"is_error\"):\n raise RuntimeError(result.get(\"error_message\") or f\"Tool {name} failed\")\n return result.get(\"result\")\n\n${functionDefs}\n\nasync def __librechat_main():\n${indent(code)}\n\nasyncio.run(__librechat_main())\n`.trimStart();\n}\n\nexport function _createBashProgramForTests(\n code: string,\n toolDefs: t.LCTool[],\n bridgeUrl: string,\n bridgeToken: string\n): string {\n return createBashProgram(code, toolDefs, bridgeUrl, bridgeToken);\n}\n\nfunction createBashProgram(\n code: string,\n toolDefs: t.LCTool[],\n bridgeUrl: string,\n bridgeToken: string\n): string {\n const functions = toolDefs\n .map((def) => {\n const bashName = normalizeToBashIdentifier(def.name);\n return [\n `${bashName}() {`,\n ' local payload=\"${1:-}\"',\n ' if [ -z \"$payload\" ]; then payload=\\'{}\\'; fi',\n ` __librechat_call_tool ${shellQuote(def.name)} \"$payload\"`,\n '}',\n ].join('\\n');\n })\n .join('\\n\\n');\n\n return `\n__LIBRECHAT_TOOL_BRIDGE=${shellQuote(bridgeUrl)}\n__LIBRECHAT_TOOL_HEADER=${shellQuote(BRIDGE_AUTH_HEADER)}\n__LIBRECHAT_TOOL_TOKEN=${shellQuote(bridgeToken)}\n\n# Bridge call helper. Tries curl first (universally available, no\n# JSON parser needed thanks to the bridge's ?mode=text endpoint),\n# falls back to python3 for environments without curl. Codex P2 #19\n# flagged that the prior python3-only path broke minimal containers\n# (and Windows hosts without a python3 binary on PATH). Tool names\n# come from Constants.* and are always safe identifiers, so we can\n# splice them into JSON without an escape pass.\n__librechat_call_tool() {\n local tool_name=\"$1\"\n local payload=\"$2\"\n if command -v curl >/dev/null 2>&1; then\n local body=\"{\\\\\"name\\\\\":\\\\\"$tool_name\\\\\",\\\\\"input\\\\\":$payload}\"\n local response\n local http_code\n response=$(curl -sS -X POST \\\n -H \"Content-Type: application/json\" \\\n -H \"$__LIBRECHAT_TOOL_HEADER: $__LIBRECHAT_TOOL_TOKEN\" \\\n --data-binary \"$body\" \\\n -w '\\\\n__LIBRECHAT_HTTP_CODE_%{http_code}__' \\\n \"$__LIBRECHAT_TOOL_BRIDGE?mode=text\")\n http_code=$(printf '%s' \"$response\" | sed -n 's/.*__LIBRECHAT_HTTP_CODE_\\\\([0-9][0-9]*\\\\)__$/\\\\1/p')\n local body_only\n body_only=$(printf '%s' \"$response\" | sed 's/__LIBRECHAT_HTTP_CODE_[0-9][0-9]*__$//')\n if [ \"$http_code\" = \"200\" ]; then\n printf '%s' \"$body_only\"\n return 0\n fi\n printf '%s\\\\n' \"$body_only\" >&2\n return 1\n elif command -v python3 >/dev/null 2>&1; then\n python3 - \"$__LIBRECHAT_TOOL_BRIDGE\" \"$tool_name\" \"$payload\" \"$__LIBRECHAT_TOOL_HEADER\" \"$__LIBRECHAT_TOOL_TOKEN\" <<'PY'\nimport json\nimport sys\nimport urllib.request\n\nurl, name, payload, header, token = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]\nbody = json.dumps({\"name\": name, \"input\": json.loads(payload)}).encode(\"utf-8\")\nreq = urllib.request.Request(url, data=body, headers={\"Content-Type\": \"application/json\", header: token}, method=\"POST\")\nwith urllib.request.urlopen(req, timeout=300) as response:\n result = json.loads(response.read().decode(\"utf-8\"))\nif result.get(\"is_error\"):\n print(result.get(\"error_message\") or f\"Tool {name} failed\", file=sys.stderr)\n sys.exit(1)\nvalue = result.get(\"result\")\nif isinstance(value, str):\n print(value)\nelse:\n print(json.dumps(value))\nPY\n else\n printf 'librechat: tool bridge needs either curl or python3 on PATH\\\\n' >&2\n return 1\n fi\n}\n\n${functions}\n\n${code}\n`.trimStart();\n}\n\nfunction getProgrammaticContext(config?: {\n toolCall?: unknown;\n}): Partial<t.ProgrammaticCache> {\n return (config?.toolCall ?? {}) as Partial<t.ProgrammaticCache>;\n}\n\nfunction createEffectiveToolMap(\n toolMap: t.ToolMap,\n toolDefs: t.LCTool[],\n code: string,\n filterTools: ToolFilter\n): { effectiveTools: t.LCTool[]; effectiveMap: t.ToolMap } {\n const effectiveTools = filterTools(toolDefs, code);\n const effectiveMap = new Map<string, t.GenericTool>(\n effectiveTools\n .map((def) => {\n const executable = toolMap.get(def.name);\n return executable == null\n ? undefined\n : ([def.name, executable] as [string, t.GenericTool]);\n })\n .filter((entry): entry is [string, t.GenericTool] => entry != null)\n );\n\n return { effectiveTools, effectiveMap };\n}\n\nasync function runLocalProgrammaticTool(args: {\n params: LocalProgrammaticParams;\n config?: { toolCall?: unknown };\n localConfig: t.LocalExecutionConfig;\n runtime: LocalProgrammaticRuntime;\n}): Promise<[string, t.ProgrammaticExecutionArtifact]> {\n const { toolMap, toolDefs, hookContext } = getProgrammaticContext(\n args.config\n );\n\n if (toolMap == null || toolMap.size === 0) {\n throw new Error('No toolMap provided for local programmatic execution.');\n }\n if (toolDefs == null || toolDefs.length === 0) {\n throw new Error(\n 'No tool definitions provided for local programmatic execution.'\n );\n }\n\n const { effectiveTools, effectiveMap } = createEffectiveToolMap(\n toolMap,\n toolDefs,\n args.params.code,\n args.runtime === 'bash' ? filterBashToolsByUsage : filterToolsByUsage\n );\n const bridge = await createToolBridge(effectiveMap, hookContext);\n\n try {\n const timeoutMs =\n args.params.timeout ?? args.localConfig.timeoutMs ?? DEFAULT_TIMEOUT;\n const result =\n args.runtime === 'bash'\n ? await executeLocalBash(\n createBashProgram(\n args.params.code,\n effectiveTools,\n bridge.url,\n bridge.token\n ),\n { ...args.localConfig, timeoutMs }\n )\n : await executeLocalCode(\n {\n lang: 'py',\n code: createPythonProgram(\n args.params.code,\n effectiveTools,\n bridge.url,\n bridge.token\n ),\n },\n { ...args.localConfig, timeoutMs }\n );\n\n if (result.exitCode !== 0 || result.timedOut) {\n throw new Error(\n result.stderr !== ''\n ? result.stderr\n : `Local ${args.runtime} programmatic execution exited with code ${\n result.exitCode ?? 'unknown'\n }`\n );\n }\n\n return formatCompletedResponse({\n status: 'completed',\n session_id: getLocalSessionId(args.localConfig),\n stdout: result.stdout,\n stderr: result.stderr,\n files: [],\n });\n } finally {\n await bridge.close();\n }\n}\n\nexport function createLocalProgrammaticToolCallingTool(\n localConfig: t.LocalExecutionConfig = {}\n): DynamicStructuredTool {\n return tool(\n async (rawParams, config) => {\n const params = rawParams as LocalProgrammaticParams;\n return runLocalProgrammaticTool({\n params,\n config,\n localConfig,\n runtime: resolveRuntime(params),\n });\n },\n {\n name: ProgrammaticToolCallingName,\n description: `${ProgrammaticToolCallingDescription}\\n\\nLocal engine: runs bash by default, or Python when \\`lang\\` is \\`py\\` or \\`python\\`, on the host machine and calls tools through an in-process localhost bridge.`,\n schema: LocalProgrammaticToolCallingSchema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n\nexport function createLocalBashProgrammaticToolCallingTool(\n localConfig: t.LocalExecutionConfig = {}\n): DynamicStructuredTool {\n return tool(\n async (rawParams, config) => {\n const params = rawParams as LocalProgrammaticParams;\n return runLocalProgrammaticTool({\n params,\n config,\n localConfig,\n runtime: 'bash',\n });\n },\n {\n name: Constants.BASH_PROGRAMMATIC_TOOL_CALLING,\n description: `${BashProgrammaticToolCallingDescription}\\n\\nLocal engine: runs this bash orchestration code on the host machine and calls tools through an in-process localhost bridge.`,\n schema: BashProgrammaticToolCallingSchema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -125,38 +125,88 @@ export type ToolEndEvent = {
|
|
|
125
125
|
index: number;
|
|
126
126
|
type?: 'tool_call';
|
|
127
127
|
};
|
|
128
|
-
|
|
128
|
+
/**
|
|
129
|
+
* Closed set of resource kinds for sandbox file caching. Defined as a
|
|
130
|
+
* `as const` tuple so the runtime list and the TypeScript union can't
|
|
131
|
+
* drift on future additions — adding a new kind to the tuple updates
|
|
132
|
+
* both at once.
|
|
133
|
+
*
|
|
134
|
+
* - `skill`: shared per skill identity. Cross-user-within-tenant
|
|
135
|
+
* sharing. Codeapi sessionKey omits the user dimension. `version`
|
|
136
|
+
* is required (skill's monotonic counter scopes cache per revision).
|
|
137
|
+
* - `agent`: shared per agent identity. Same sharing semantic as
|
|
138
|
+
* skills.
|
|
139
|
+
* - `user`: user-private. Codeapi sessionKey is keyed by the
|
|
140
|
+
* requesting user from auth context. Used for chat attachments
|
|
141
|
+
* and code-output files.
|
|
142
|
+
*/
|
|
143
|
+
export declare const CODE_ENV_KINDS: readonly ["skill", "agent", "user"];
|
|
144
|
+
export type CodeEnvKind = (typeof CODE_ENV_KINDS)[number];
|
|
145
|
+
type CodeEnvFileBase = {
|
|
146
|
+
/**
|
|
147
|
+
* Resource identity. Semantics depend on `kind`:
|
|
148
|
+
* - `skill`: skill `_id` (sessionKey-meaningful, cross-user shared).
|
|
149
|
+
* - `agent`: agent id (sessionKey-meaningful, cross-user shared).
|
|
150
|
+
* - `user`: informational only — codeapi derives sessionKey from
|
|
151
|
+
* the auth-context user. Kept on the type for shape uniformity;
|
|
152
|
+
* do not rely on it for routing.
|
|
153
|
+
*/
|
|
129
154
|
id: string;
|
|
130
155
|
name: string;
|
|
131
|
-
session_id: string;
|
|
132
156
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* file plus a user attachment in the same call).
|
|
157
|
+
* Storage session — the long-lived bucket where this file's bytes
|
|
158
|
+
* live in object storage. Distinct from the (transient) execution
|
|
159
|
+
* session id that appears at the top level of an execute response;
|
|
160
|
+
* the two used to share the field name `session_id` and the
|
|
161
|
+
* conflation caused real bugs. See codeapi #1455 / agents #148.
|
|
139
162
|
*/
|
|
140
|
-
|
|
163
|
+
storage_session_id: string;
|
|
141
164
|
};
|
|
165
|
+
/**
|
|
166
|
+
* `CodeEnvFile` is a discriminated union on `kind`. `version` is
|
|
167
|
+
* statically required for `kind: 'skill'` and statically forbidden
|
|
168
|
+
* for `agent` / `user` — the constraint holds at compile time on
|
|
169
|
+
* every consumer, not just on codeapi's runtime validator.
|
|
170
|
+
*
|
|
171
|
+
* Codeapi switches on `kind` to derive the sessionKey for cache
|
|
172
|
+
* scoping (`<tenant>:<kind>:<id>[:v:<version>]`). Cross-user sharing
|
|
173
|
+
* for `kind: 'skill'` / `'agent'` is a designed property of the
|
|
174
|
+
* kind switch.
|
|
175
|
+
*/
|
|
176
|
+
export type CodeEnvFile = (CodeEnvFileBase & {
|
|
177
|
+
kind: 'skill';
|
|
178
|
+
version: number;
|
|
179
|
+
}) | (CodeEnvFileBase & {
|
|
180
|
+
kind: 'agent';
|
|
181
|
+
}) | (CodeEnvFileBase & {
|
|
182
|
+
kind: 'user';
|
|
183
|
+
});
|
|
142
184
|
export type CodeExecutionToolParams = undefined | {
|
|
185
|
+
/** Execution session — see `CodeSessionContext.session_id`. */
|
|
143
186
|
session_id?: string;
|
|
144
187
|
user_id?: string;
|
|
145
188
|
files?: CodeEnvFile[];
|
|
146
189
|
};
|
|
147
190
|
export type FileRef = {
|
|
191
|
+
/**
|
|
192
|
+
* Resource identity. Semantics depend on `kind` (when present):
|
|
193
|
+
* - `skill` / `agent`: shared resource id (sessionKey-meaningful).
|
|
194
|
+
* - `user`: informational only — codeapi derives sessionKey from
|
|
195
|
+
* the auth-context user. Do not rely on it for routing.
|
|
196
|
+
*/
|
|
148
197
|
id: string;
|
|
149
198
|
name: string;
|
|
150
199
|
path?: string;
|
|
151
|
-
/** Session ID this file belongs to (for multi-session file tracking) */
|
|
152
|
-
session_id?: string;
|
|
153
200
|
/**
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
* `_injected_files` when a subsequent execute references a mix of
|
|
157
|
-
* files uploaded under different entities.
|
|
201
|
+
* Storage session this file lives in. See `CodeEnvFile.storage_session_id`
|
|
202
|
+
* for the full motivation.
|
|
158
203
|
*/
|
|
159
|
-
|
|
204
|
+
storage_session_id?: string;
|
|
205
|
+
/** Resource kind — see `CodeEnvFile.kind`. */
|
|
206
|
+
kind?: CodeEnvKind;
|
|
207
|
+
/** Resource version — see `CodeEnvFile.version`. Only meaningful when
|
|
208
|
+
* `kind === 'skill'`. */
|
|
209
|
+
version?: number;
|
|
160
210
|
/**
|
|
161
211
|
* `true` when the codeapi sandbox echoed this entry as an unchanged
|
|
162
212
|
* passthrough of an input the caller already owns (skill files,
|
|
@@ -169,6 +219,11 @@ export type FileRef = {
|
|
|
169
219
|
};
|
|
170
220
|
export type FileRefs = FileRef[];
|
|
171
221
|
export type ExecuteResult = {
|
|
222
|
+
/**
|
|
223
|
+
* Execution session id — the (transient) sandbox run that produced
|
|
224
|
+
* this output. Distinct from per-file `storage_session_id` on the
|
|
225
|
+
* files array.
|
|
226
|
+
*/
|
|
172
227
|
session_id: string;
|
|
173
228
|
stdout: string;
|
|
174
229
|
stderr: string;
|
|
@@ -224,6 +279,7 @@ export type ToolCallRequest = {
|
|
|
224
279
|
turn?: number;
|
|
225
280
|
/** Code execution session context for session continuity in event-driven mode */
|
|
226
281
|
codeSessionContext?: {
|
|
282
|
+
/** Execution session — see `CodeSessionContext.session_id`. */
|
|
227
283
|
session_id: string;
|
|
228
284
|
files?: CodeEnvFile[];
|
|
229
285
|
};
|
|
@@ -709,6 +765,7 @@ export type PTCToolResult = {
|
|
|
709
765
|
*/
|
|
710
766
|
export type ProgrammaticExecutionResponse = {
|
|
711
767
|
status: 'tool_call_required' | 'completed' | 'error' | unknown;
|
|
768
|
+
/** Execution session — see `CodeSessionContext.session_id`. */
|
|
712
769
|
session_id?: string;
|
|
713
770
|
/** Present when status='tool_call_required' */
|
|
714
771
|
continuation_token?: string;
|
|
@@ -724,6 +781,7 @@ export type ProgrammaticExecutionResponse = {
|
|
|
724
781
|
* Artifact returned by the PTC tool
|
|
725
782
|
*/
|
|
726
783
|
export type ProgrammaticExecutionArtifact = {
|
|
784
|
+
/** Execution session — see `CodeSessionContext.session_id`. */
|
|
727
785
|
session_id?: string;
|
|
728
786
|
files?: FileRefs;
|
|
729
787
|
};
|
|
@@ -749,7 +807,12 @@ export type ProgrammaticToolCallingParams = {
|
|
|
749
807
|
* Stored in Graph.sessions and injected into subsequent tool invocations.
|
|
750
808
|
*/
|
|
751
809
|
export type CodeSessionContext = {
|
|
752
|
-
/**
|
|
810
|
+
/**
|
|
811
|
+
* Execution session id — the (transient) sandbox run id. Used by
|
|
812
|
+
* ToolNode to thread session continuity into the next code-execution
|
|
813
|
+
* tool call. Distinct from per-file `storage_session_id` carried on
|
|
814
|
+
* `files`.
|
|
815
|
+
*/
|
|
753
816
|
session_id: string;
|
|
754
817
|
/** Files generated in this session (for context/tracking) */
|
|
755
818
|
files?: FileRefs;
|
|
@@ -761,6 +824,7 @@ export type CodeSessionContext = {
|
|
|
761
824
|
* Used to extract session context after tool completion.
|
|
762
825
|
*/
|
|
763
826
|
export type CodeExecutionArtifact = {
|
|
827
|
+
/** Execution session — see `CodeSessionContext.session_id`. */
|
|
764
828
|
session_id?: string;
|
|
765
829
|
files?: FileRefs;
|
|
766
830
|
};
|
|
@@ -774,3 +838,4 @@ export type ToolSessionContext = CodeSessionContext;
|
|
|
774
838
|
* Keys are tool constants (e.g., Constants.EXECUTE_CODE, Constants.PROGRAMMATIC_TOOL_CALLING).
|
|
775
839
|
*/
|
|
776
840
|
export type ToolSessionMap = Map<string, ToolSessionContext>;
|
|
841
|
+
export {};
|
package/package.json
CHANGED
|
@@ -46,7 +46,7 @@ function printSessionContext(run: Run<t.IState>, label: string): void {
|
|
|
46
46
|
console.log(` Latest session_id: ${session.session_id}`);
|
|
47
47
|
console.log(` Files tracked: ${session.files?.length ?? 0}`);
|
|
48
48
|
for (const file of session.files ?? []) {
|
|
49
|
-
console.log(` - ${file.name} (
|
|
49
|
+
console.log(` - ${file.name} (storage: ${file.storage_session_id})`);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -200,13 +200,13 @@ Tell me what version it shows.
|
|
|
200
200
|
|
|
201
201
|
if (finalSession) {
|
|
202
202
|
const files = finalSession.files ?? [];
|
|
203
|
-
const uniqueSessionIds = new Set(files.map((f) => f.
|
|
203
|
+
const uniqueSessionIds = new Set(files.map((f) => f.storage_session_id));
|
|
204
204
|
console.log(`\nTotal files tracked: ${files.length}`);
|
|
205
|
-
console.log(`Unique
|
|
205
|
+
console.log(`Unique storage_session_ids: ${uniqueSessionIds.size}`);
|
|
206
206
|
console.log('\nFiles:');
|
|
207
207
|
for (const file of files) {
|
|
208
208
|
console.log(
|
|
209
|
-
` - ${file.name} (
|
|
209
|
+
` - ${file.name} (storage: ${file.storage_session_id?.slice(0, 20)}...)`
|
|
210
210
|
);
|
|
211
211
|
}
|
|
212
212
|
|
|
@@ -163,7 +163,10 @@ function createBashExecutionTool(
|
|
|
163
163
|
const id = nameParts.length > 1 ? nameParts[1].split('.')[0] : '';
|
|
164
164
|
|
|
165
165
|
return {
|
|
166
|
-
session_id,
|
|
166
|
+
storage_session_id: session_id,
|
|
167
|
+
/* `/files` fallback returns code-output files belonging
|
|
168
|
+
* to the user; tag them user-private. */
|
|
169
|
+
kind: 'user' as const,
|
|
167
170
|
id,
|
|
168
171
|
name: file.metadata['original-filename'],
|
|
169
172
|
};
|
|
@@ -241,11 +244,16 @@ function createBashExecutionTool(
|
|
|
241
244
|
{
|
|
242
245
|
session_id: result.session_id,
|
|
243
246
|
files: result.files,
|
|
244
|
-
},
|
|
247
|
+
} satisfies t.CodeExecutionArtifact,
|
|
245
248
|
];
|
|
246
249
|
}
|
|
247
250
|
|
|
248
|
-
return [
|
|
251
|
+
return [
|
|
252
|
+
formattedOutput.trim(),
|
|
253
|
+
{
|
|
254
|
+
session_id: result.session_id,
|
|
255
|
+
} satisfies t.CodeExecutionArtifact,
|
|
256
|
+
];
|
|
249
257
|
} catch (error) {
|
|
250
258
|
throw new Error(
|
|
251
259
|
`Execution error:\n\n${(error as Error | undefined)?.message}`
|
|
@@ -252,12 +252,12 @@ export function createBashProgrammaticToolCallingTool(
|
|
|
252
252
|
const params = rawParams as { code: string; timeout?: number };
|
|
253
253
|
const { code, timeout = DEFAULT_TIMEOUT } = params;
|
|
254
254
|
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
255
|
+
const toolCall = (config.toolCall ?? {}) as ToolCall &
|
|
256
|
+
Partial<t.ProgrammaticCache> & {
|
|
257
|
+
session_id?: string;
|
|
258
|
+
_injected_files?: t.CodeEnvFile[];
|
|
259
|
+
};
|
|
260
|
+
const { toolMap, toolDefs, session_id, _injected_files } = toolCall;
|
|
261
261
|
|
|
262
262
|
if (toolMap == null || toolMap.size === 0) {
|
|
263
263
|
throw new Error(
|
|
@@ -135,8 +135,8 @@ function createCodeExecutionTool(
|
|
|
135
135
|
};
|
|
136
136
|
/**
|
|
137
137
|
* Extract session context from config.toolCall (injected by ToolNode).
|
|
138
|
-
* - session_id:
|
|
139
|
-
* - _injected_files: File refs to pass directly (avoids /files endpoint race condition)
|
|
138
|
+
* - session_id: associates with the previous run.
|
|
139
|
+
* - _injected_files: File refs to pass directly (avoids /files endpoint race condition).
|
|
140
140
|
*/
|
|
141
141
|
const { session_id, _injected_files } = (config.toolCall ?? {}) as {
|
|
142
142
|
session_id?: string;
|
|
@@ -153,7 +153,10 @@ function createCodeExecutionTool(
|
|
|
153
153
|
/**
|
|
154
154
|
* File injection priority:
|
|
155
155
|
* 1. Use _injected_files from ToolNode (avoids /files endpoint race condition)
|
|
156
|
-
* 2. Fall back to fetching from /files endpoint if session_id
|
|
156
|
+
* 2. Fall back to fetching from /files endpoint if session_id
|
|
157
|
+
* provided but no injected files. The /files lookup still uses the
|
|
158
|
+
* same id value — codeapi stores output files under the exec id as
|
|
159
|
+
* their storage prefix, so the two values coincide here.
|
|
157
160
|
*/
|
|
158
161
|
if (_injected_files && _injected_files.length > 0) {
|
|
159
162
|
postData.files = _injected_files;
|
|
@@ -186,7 +189,10 @@ function createCodeExecutionTool(
|
|
|
186
189
|
const id = nameParts.length > 1 ? nameParts[1].split('.')[0] : '';
|
|
187
190
|
|
|
188
191
|
return {
|
|
189
|
-
session_id,
|
|
192
|
+
storage_session_id: session_id,
|
|
193
|
+
/* `/files` fallback returns code-output files belonging
|
|
194
|
+
* to the user; tag them user-private. */
|
|
195
|
+
kind: 'user' as const,
|
|
190
196
|
id,
|
|
191
197
|
name: file.metadata['original-filename'],
|
|
192
198
|
};
|
|
@@ -259,11 +265,16 @@ function createCodeExecutionTool(
|
|
|
259
265
|
{
|
|
260
266
|
session_id: result.session_id,
|
|
261
267
|
files: result.files,
|
|
262
|
-
},
|
|
268
|
+
} satisfies t.CodeExecutionArtifact,
|
|
263
269
|
];
|
|
264
270
|
}
|
|
265
271
|
|
|
266
|
-
return [
|
|
272
|
+
return [
|
|
273
|
+
formattedOutput.trim(),
|
|
274
|
+
{
|
|
275
|
+
session_id: result.session_id,
|
|
276
|
+
} satisfies t.CodeExecutionArtifact,
|
|
277
|
+
];
|
|
267
278
|
} catch (error) {
|
|
268
279
|
throw new Error(
|
|
269
280
|
`Execution error:\n\n${(error as Error | undefined)?.message}`
|
|
@@ -304,7 +304,10 @@ export async function fetchSessionFiles(
|
|
|
304
304
|
const id = nameParts.length > 1 ? nameParts[1].split('.')[0] : '';
|
|
305
305
|
|
|
306
306
|
return {
|
|
307
|
-
|
|
307
|
+
storage_session_id: sessionId,
|
|
308
|
+
/* `/files` fallback returns code-output files belonging to
|
|
309
|
+
* the user; tag them user-private. */
|
|
310
|
+
kind: 'user' as const,
|
|
308
311
|
id,
|
|
309
312
|
name: (file.metadata as Record<string, unknown>)[
|
|
310
313
|
'original-filename'
|
|
@@ -588,7 +591,7 @@ export function formatCompletedResponse(
|
|
|
588
591
|
{
|
|
589
592
|
session_id: response.session_id,
|
|
590
593
|
files: response.files,
|
|
591
|
-
},
|
|
594
|
+
} satisfies t.ProgrammaticExecutionArtifact,
|
|
592
595
|
];
|
|
593
596
|
}
|
|
594
597
|
|
|
@@ -629,13 +632,13 @@ export function createProgrammaticToolCallingTool(
|
|
|
629
632
|
const params = rawParams as { code: string; timeout?: number };
|
|
630
633
|
const { code, timeout = DEFAULT_TIMEOUT } = params;
|
|
631
634
|
|
|
632
|
-
// Extra params injected by ToolNode (follows web_search pattern)
|
|
633
|
-
const
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
635
|
+
// Extra params injected by ToolNode (follows web_search pattern).
|
|
636
|
+
const toolCall = (config.toolCall ?? {}) as ToolCall &
|
|
637
|
+
Partial<t.ProgrammaticCache> & {
|
|
638
|
+
session_id?: string;
|
|
639
|
+
_injected_files?: t.CodeEnvFile[];
|
|
640
|
+
};
|
|
641
|
+
const { toolMap, toolDefs, session_id, _injected_files } = toolCall;
|
|
639
642
|
|
|
640
643
|
if (toolMap == null || toolMap.size === 0) {
|
|
641
644
|
throw new Error(
|
|
@@ -671,7 +674,8 @@ export function createProgrammaticToolCallingTool(
|
|
|
671
674
|
/**
|
|
672
675
|
* File injection priority:
|
|
673
676
|
* 1. Use _injected_files from ToolNode (avoids /files endpoint race condition)
|
|
674
|
-
* 2. Fall back to fetching from /files endpoint if session_id
|
|
677
|
+
* 2. Fall back to fetching from /files endpoint if session_id
|
|
678
|
+
* provided but no injected files.
|
|
675
679
|
*/
|
|
676
680
|
let files: t.CodeEnvFile[] | undefined;
|
|
677
681
|
if (_injected_files && _injected_files.length > 0) {
|