{"version":3,"file":"shell.cjs","names":["z"],"sources":["../../src/tools/shell.ts"],"sourcesContent":["import { z } from \"zod/v4\";\nimport { OpenAI as OpenAIClient } from \"openai\";\nimport { tool, type DynamicStructuredTool } from \"@langchain/core/tools\";\n\n/**\n * Re-export action type from OpenAI SDK for convenience.\n * The action contains command details like commands array, timeout, and max output length.\n */\nexport type ShellAction =\n  OpenAIClient.Responses.ResponseFunctionShellToolCall.Action;\n\n// Zod schema for shell action\nexport const ShellActionSchema = z.object({\n  commands: z.array(z.string()).describe(\"Array of shell commands to execute\"),\n  timeout_ms: z\n    .number()\n    .optional()\n    .describe(\"Optional timeout in milliseconds for the commands\"),\n  max_output_length: z\n    .number()\n    .optional()\n    .describe(\n      \"Optional maximum number of characters to return from each command\"\n    ),\n});\n\n/**\n * Result of a single shell command execution.\n * Contains stdout, stderr, and the outcome (exit code or timeout).\n */\nexport type ShellCommandOutput =\n  OpenAIClient.Responses.ResponseFunctionShellCallOutputContent;\n\n/**\n * Outcome type for shell command execution - either exit with code or timeout.\n */\nexport type ShellCallOutcome = ShellCommandOutput[\"outcome\"];\n\n/**\n * Result of executing shell commands.\n * Contains an array of outputs (one per command) and the max_output_length parameter.\n */\nexport interface ShellResult {\n  /**\n   * Array of command outputs. Each entry corresponds to a command from the action.\n   * The order should match the order of commands in the action.\n   */\n  output: ShellCommandOutput[];\n  /**\n   * The max_output_length from the action, which must be passed back to the API.\n   * If not provided in the action, can be omitted.\n   */\n  maxOutputLength?: number | null;\n}\n\n/**\n * Options for the Shell tool.\n */\nexport interface ShellOptions {\n  /**\n   * Execute function that handles shell command execution.\n   * This function receives the action input containing the commands and limits,\n   * and should return a ShellResult with stdout, stderr, and outcome for each command.\n   *\n   * @example\n   * ```typescript\n   * execute: async (action) => {\n   *   const outputs = await Promise.all(\n   *     action.commands.map(async (cmd) => {\n   *       try {\n   *         const { stdout, stderr } = await exec(cmd, {\n   *           timeout: action.timeout_ms ?? undefined,\n   *         });\n   *         return {\n   *           stdout,\n   *           stderr,\n   *           outcome: { type: \"exit\" as const, exit_code: 0 },\n   *         };\n   *       } catch (error) {\n   *         const timedOut = error.killed && error.signal === \"SIGTERM\";\n   *         return {\n   *           stdout: error.stdout ?? \"\",\n   *           stderr: error.stderr ?? String(error),\n   *           outcome: timedOut\n   *             ? { type: \"timeout\" as const }\n   *             : { type: \"exit\" as const, exit_code: error.code ?? 1 },\n   *         };\n   *       }\n   *     })\n   *   );\n   *   return {\n   *     output: outputs,\n   *     maxOutputLength: action.max_output_length,\n   *   };\n   * }\n   * ```\n   */\n  execute: (action: ShellAction) => ShellResult | Promise<ShellResult>;\n}\n\n/**\n * OpenAI Shell tool type for the Responses API.\n */\nexport type ShellTool = OpenAIClient.Responses.FunctionShellTool;\n\nconst TOOL_NAME = \"shell\";\n\n/**\n * Creates a Shell tool that allows models to run shell commands through your integration.\n *\n * The shell tool allows the model to interact with your local computer through a controlled\n * command-line interface. The model proposes shell commands; your integration executes them\n * and returns the outputs. This creates a simple plan-execute loop that lets models inspect\n * the system, run utilities, and gather data until they can finish the task.\n *\n * **Important**: The shell tool is available through the Responses API for use with `GPT-5.1`.\n * It is not available on other models, or via the Chat Completions API.\n *\n * **When to use**:\n * - **Automating filesystem or process diagnostics** – For example, \"find the largest PDF\n *   under ~/Documents\" or \"show running gunicorn processes.\"\n * - **Extending the model's capabilities** – Using built-in UNIX utilities, python runtime\n *   and other CLIs in your environment.\n * - **Running multi-step build and test flows** – Chaining commands like `pip install` and `pytest`.\n * - **Complex agentic coding workflows** – Using other tools like `apply_patch` to complete\n *   workflows that involve complex file operations.\n *\n * **How it works**:\n * The tool operates in a continuous loop:\n * 1. Model sends shell commands (`shell_call` with `commands` array)\n * 2. Your code executes the commands (can be concurrent)\n * 3. You return stdout, stderr, and outcome for each command\n * 4. Repeat until the task is complete\n *\n * **Security Warning**: Running arbitrary shell commands can be dangerous.\n * Always sandbox execution or add strict allow/deny-lists before forwarding\n * a command to the system shell.\n *\n * @see {@link https://platform.openai.com/docs/guides/tools-shell | OpenAI Shell Documentation}\n * @see {@link https://github.com/openai/codex | Codex CLI} for reference implementation.\n *\n * @param options - Configuration for the Shell tool\n * @returns A Shell tool that can be passed to `bindTools`\n *\n * @example\n * ```typescript\n * import { ChatOpenAI, tools } from \"@langchain/openai\";\n * import { exec } from \"child_process/promises\";\n *\n * const model = new ChatOpenAI({ model: \"gpt-5.1\" });\n *\n * // With execute callback for automatic command handling\n * const shellTool = tools.shell({\n *   execute: async (action) => {\n *     const outputs = await Promise.all(\n *       action.commands.map(async (cmd) => {\n *         try {\n *           const { stdout, stderr } = await exec(cmd, {\n *             timeout: action.timeout_ms ?? undefined,\n *           });\n *           return {\n *             stdout,\n *             stderr,\n *             outcome: { type: \"exit\" as const, exit_code: 0 },\n *           };\n *         } catch (error) {\n *           const timedOut = error.killed && error.signal === \"SIGTERM\";\n *           return {\n *             stdout: error.stdout ?? \"\",\n *             stderr: error.stderr ?? String(error),\n *             outcome: timedOut\n *               ? { type: \"timeout\" as const }\n *               : { type: \"exit\" as const, exit_code: error.code ?? 1 },\n *           };\n *         }\n *       })\n *     );\n *     return {\n *       output: outputs,\n *       maxOutputLength: action.max_output_length,\n *     };\n *   },\n * });\n *\n * const llmWithShell = model.bindTools([shellTool]);\n * const response = await llmWithShell.invoke(\n *   \"Find the largest PDF file in ~/Documents\"\n * );\n * ```\n *\n * @example\n * ```typescript\n * // Full shell loop example\n * async function shellLoop(model, task) {\n *   let response = await model.invoke(task, {\n *     tools: [tools.shell({ execute: myExecutor })],\n *   });\n *\n *   while (true) {\n *     const shellCall = response.additional_kwargs.tool_outputs?.find(\n *       (output) => output.type === \"shell_call\"\n *     );\n *\n *     if (!shellCall) break;\n *\n *     // Execute commands (with proper sandboxing!)\n *     const result = await executeCommands(shellCall.action);\n *\n *     // Send output back to model\n *     response = await model.invoke([\n *       response,\n *       {\n *         type: \"shell_call_output\",\n *         call_id: shellCall.call_id,\n *         output: result.output,\n *         max_output_length: result.maxOutputLength,\n *       },\n *     ], {\n *       tools: [tools.shell({ execute: myExecutor })],\n *     });\n *   }\n *\n *   return response;\n * }\n * ```\n *\n * @remarks\n * - Only available through the Responses API (not Chat Completions)\n * - Designed for use with `gpt-5.1` model\n * - Commands are provided as an array of strings that can be executed concurrently\n * - Action includes: `commands`, `timeout_ms`, `max_output_length`\n * - Always sandbox or validate commands before execution\n * - The `timeout_ms` from the model is only a hint—enforce your own limits\n * - If `max_output_length` exists in the action, always pass it back in the output\n * - Many CLI tools return non-zero exit codes for warnings; still capture stdout/stderr\n */\nexport function shell(options: ShellOptions) {\n  // Wrapper that converts ShellResult to string for LangChain tool compatibility\n  const executeWrapper = async (action: ShellAction): Promise<string> => {\n    const result = await options.execute(action);\n    // Return a JSON string representation for the tool result\n    return JSON.stringify({\n      output: result.output,\n      max_output_length: result.maxOutputLength,\n    });\n  };\n\n  const shellTool = tool(executeWrapper, {\n    name: TOOL_NAME,\n    description:\n      \"Execute shell commands in a managed environment. Commands can be run concurrently.\",\n    schema: ShellActionSchema,\n  });\n\n  shellTool.extras = {\n    ...(shellTool.extras ?? {}),\n    providerToolDefinition: {\n      type: \"shell\",\n    } satisfies ShellTool,\n  };\n\n  return shellTool as DynamicStructuredTool<\n    typeof ShellActionSchema,\n    ShellAction,\n    unknown,\n    string\n  >;\n}\n"],"mappings":";;;AAYA,MAAa,oBAAoBA,OAAAA,EAAE,OAAO;CACxC,UAAUA,OAAAA,EAAE,MAAMA,OAAAA,EAAE,QAAQ,CAAC,CAAC,SAAS,qCAAqC;CAC5E,YAAYA,OAAAA,EACT,QAAQ,CACR,UAAU,CACV,SAAS,oDAAoD;CAChE,mBAAmBA,OAAAA,EAChB,QAAQ,CACR,UAAU,CACV,SACC,oEACD;CACJ,CAAC;AAiFF,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmIlB,SAAgB,MAAM,SAAuB;CAE3C,MAAM,iBAAiB,OAAO,WAAyC;EACrE,MAAM,SAAS,MAAM,QAAQ,QAAQ,OAAO;AAE5C,SAAO,KAAK,UAAU;GACpB,QAAQ,OAAO;GACf,mBAAmB,OAAO;GAC3B,CAAC;;CAGJ,MAAM,aAAA,GAAA,sBAAA,MAAiB,gBAAgB;EACrC,MAAM;EACN,aACE;EACF,QAAQ;EACT,CAAC;AAEF,WAAU,SAAS;EACjB,GAAI,UAAU,UAAU,EAAE;EAC1B,wBAAwB,EACtB,MAAM,SACP;EACF;AAED,QAAO"}