@truefoundry/trueforge-core 0.1.0-rc.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/README.md +27 -0
  2. package/dist/agent-session/TurnResourceResolver.d.ts.map +1 -1
  3. package/dist/agent-session/TurnResourceResolver.js +6 -2
  4. package/dist/agent-session/TurnResourceResolver.js.map +1 -1
  5. package/dist/agent-session/TurnResourceResolver.mjs +6 -2
  6. package/dist/agent-session/TurnResourceResolver.mjs.map +1 -1
  7. package/dist/agent-session/schemas/turn.d.ts.map +1 -1
  8. package/dist/agent-session/schemas/turn.js +3 -1
  9. package/dist/agent-session/schemas/turn.js.map +1 -1
  10. package/dist/agent-session/schemas/turn.mjs +3 -1
  11. package/dist/agent-session/schemas/turn.mjs.map +1 -1
  12. package/dist/agent-session/store/InMemorySessionStore.d.ts.map +1 -1
  13. package/dist/agent-session/store/InMemorySessionStore.js +24 -8
  14. package/dist/agent-session/store/InMemorySessionStore.js.map +1 -1
  15. package/dist/agent-session/store/InMemorySessionStore.mjs +24 -8
  16. package/dist/agent-session/store/InMemorySessionStore.mjs.map +1 -1
  17. package/dist/agent-session/store/OffsetPageToken.d.ts.map +1 -1
  18. package/dist/agent-session/store/OffsetPageToken.js +3 -1
  19. package/dist/agent-session/store/OffsetPageToken.js.map +1 -1
  20. package/dist/agent-session/store/OffsetPageToken.mjs +3 -1
  21. package/dist/agent-session/store/OffsetPageToken.mjs.map +1 -1
  22. package/dist/agent-session/store/SessionListPageToken.d.ts.map +1 -1
  23. package/dist/agent-session/store/SessionListPageToken.js +3 -1
  24. package/dist/agent-session/store/SessionListPageToken.js.map +1 -1
  25. package/dist/agent-session/store/SessionListPageToken.mjs +3 -1
  26. package/dist/agent-session/store/SessionListPageToken.mjs.map +1 -1
  27. package/dist/core/InstructionBuilder.d.ts.map +1 -1
  28. package/dist/core/InstructionBuilder.js +12 -4
  29. package/dist/core/InstructionBuilder.js.map +1 -1
  30. package/dist/core/InstructionBuilder.mjs +12 -4
  31. package/dist/core/InstructionBuilder.mjs.map +1 -1
  32. package/dist/core/capabilities/builtins/AskUserQuestion.d.ts.map +1 -1
  33. package/dist/core/capabilities/builtins/AskUserQuestion.js +5 -0
  34. package/dist/core/capabilities/builtins/AskUserQuestion.js.map +1 -1
  35. package/dist/core/capabilities/builtins/AskUserQuestion.mjs +5 -0
  36. package/dist/core/capabilities/builtins/AskUserQuestion.mjs.map +1 -1
  37. package/dist/core/capabilities/builtins/LargeToolResponse.d.ts.map +1 -1
  38. package/dist/core/capabilities/builtins/LargeToolResponse.js +6 -2
  39. package/dist/core/capabilities/builtins/LargeToolResponse.js.map +1 -1
  40. package/dist/core/capabilities/builtins/LargeToolResponse.mjs +6 -2
  41. package/dist/core/capabilities/builtins/LargeToolResponse.mjs.map +1 -1
  42. package/dist/core/index.d.ts +9 -3
  43. package/dist/core/index.d.ts.map +1 -1
  44. package/dist/core/index.js +25 -0
  45. package/dist/core/index.js.map +1 -1
  46. package/dist/core/index.mjs +24 -2
  47. package/dist/core/index.mjs.map +1 -1
  48. package/dist/core/llm/VercelAILLM.d.ts +1 -0
  49. package/dist/core/llm/VercelAILLM.d.ts.map +1 -1
  50. package/dist/core/llm/VercelAILLM.js +13 -14
  51. package/dist/core/llm/VercelAILLM.js.map +1 -1
  52. package/dist/core/llm/VercelAILLM.mjs +13 -15
  53. package/dist/core/llm/VercelAILLM.mjs.map +1 -1
  54. package/dist/core/mcp/RemoteMCP.d.ts.map +1 -1
  55. package/dist/core/mcp/RemoteMCP.js +15 -5
  56. package/dist/core/mcp/RemoteMCP.js.map +1 -1
  57. package/dist/core/mcp/RemoteMCP.mjs +15 -5
  58. package/dist/core/mcp/RemoteMCP.mjs.map +1 -1
  59. package/dist/core/mcp/ToolSelectorPolicy.d.ts.map +1 -1
  60. package/dist/core/mcp/ToolSelectorPolicy.js +3 -1
  61. package/dist/core/mcp/ToolSelectorPolicy.js.map +1 -1
  62. package/dist/core/mcp/ToolSelectorPolicy.mjs +3 -1
  63. package/dist/core/mcp/ToolSelectorPolicy.mjs.map +1 -1
  64. package/dist/core/mcp/ToolSet.d.ts.map +1 -1
  65. package/dist/core/mcp/ToolSet.js +9 -3
  66. package/dist/core/mcp/ToolSet.js.map +1 -1
  67. package/dist/core/mcp/ToolSet.mjs +9 -3
  68. package/dist/core/mcp/ToolSet.mjs.map +1 -1
  69. package/dist/core/mcp/convertMCPServers.d.ts.map +1 -1
  70. package/dist/core/mcp/convertMCPServers.js +6 -2
  71. package/dist/core/mcp/convertMCPServers.js.map +1 -1
  72. package/dist/core/mcp/convertMCPServers.mjs +6 -2
  73. package/dist/core/mcp/convertMCPServers.mjs.map +1 -1
  74. package/dist/core/mcp/remoteMcpClient.d.ts.map +1 -1
  75. package/dist/core/mcp/remoteMcpClient.js +21 -7
  76. package/dist/core/mcp/remoteMcpClient.js.map +1 -1
  77. package/dist/core/mcp/remoteMcpClient.mjs +21 -7
  78. package/dist/core/mcp/remoteMcpClient.mjs.map +1 -1
  79. package/dist/core/mcp/toolSelectors.d.ts.map +1 -1
  80. package/dist/core/mcp/toolSelectors.js +18 -6
  81. package/dist/core/mcp/toolSelectors.js.map +1 -1
  82. package/dist/core/mcp/toolSelectors.mjs +18 -6
  83. package/dist/core/mcp/toolSelectors.mjs.map +1 -1
  84. package/dist/core/runtime/AgentThread.d.ts.map +1 -1
  85. package/dist/core/runtime/AgentThread.js +45 -15
  86. package/dist/core/runtime/AgentThread.js.map +1 -1
  87. package/dist/core/runtime/AgentThread.mjs +45 -15
  88. package/dist/core/runtime/AgentThread.mjs.map +1 -1
  89. package/dist/core/runtime/AgentThreadOrchestrator.d.ts.map +1 -1
  90. package/dist/core/runtime/AgentThreadOrchestrator.js +27 -9
  91. package/dist/core/runtime/AgentThreadOrchestrator.js.map +1 -1
  92. package/dist/core/runtime/AgentThreadOrchestrator.mjs +27 -9
  93. package/dist/core/runtime/AgentThreadOrchestrator.mjs.map +1 -1
  94. package/dist/core/runtime/DeferredTool.d.ts.map +1 -1
  95. package/dist/core/runtime/DeferredTool.js +15 -5
  96. package/dist/core/runtime/DeferredTool.js.map +1 -1
  97. package/dist/core/runtime/DeferredTool.mjs +15 -5
  98. package/dist/core/runtime/DeferredTool.mjs.map +1 -1
  99. package/dist/core/runtime/contextUtils.d.ts.map +1 -1
  100. package/dist/core/runtime/contextUtils.js +3 -1
  101. package/dist/core/runtime/contextUtils.js.map +1 -1
  102. package/dist/core/runtime/contextUtils.mjs +3 -1
  103. package/dist/core/runtime/contextUtils.mjs.map +1 -1
  104. package/dist/core/sandbox/Sandbox.d.ts +7 -9
  105. package/dist/core/sandbox/Sandbox.d.ts.map +1 -1
  106. package/dist/core/sandbox/Sandbox.js +55 -63
  107. package/dist/core/sandbox/Sandbox.js.map +1 -1
  108. package/dist/core/sandbox/Sandbox.mjs +56 -64
  109. package/dist/core/sandbox/Sandbox.mjs.map +1 -1
  110. package/dist/core/sandbox/codeMode/CodeModeDispatcher.d.ts +29 -0
  111. package/dist/core/sandbox/codeMode/CodeModeDispatcher.d.ts.map +1 -0
  112. package/dist/core/sandbox/codeMode/CodeModeDispatcher.js +134 -0
  113. package/dist/core/sandbox/codeMode/CodeModeDispatcher.js.map +1 -0
  114. package/dist/core/sandbox/codeMode/CodeModeDispatcher.mjs +113 -0
  115. package/dist/core/sandbox/codeMode/CodeModeDispatcher.mjs.map +1 -0
  116. package/dist/core/sandbox/codeMode/CodeModeTransport.d.ts +21 -0
  117. package/dist/core/sandbox/codeMode/CodeModeTransport.d.ts.map +1 -0
  118. package/dist/core/sandbox/codeMode/CodeModeTransport.js +19 -0
  119. package/dist/core/sandbox/codeMode/CodeModeTransport.js.map +1 -0
  120. package/dist/core/sandbox/codeMode/CodeModeTransport.mjs +1 -0
  121. package/dist/core/sandbox/codeMode/CodeModeTransport.mjs.map +1 -0
  122. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.d.ts +34 -0
  123. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.d.ts.map +1 -0
  124. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.js +193 -0
  125. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.js.map +1 -0
  126. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.mjs +168 -0
  127. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.mjs.map +1 -0
  128. package/dist/core/sandbox/codeMode/types.d.ts +34 -0
  129. package/dist/core/sandbox/codeMode/types.d.ts.map +1 -0
  130. package/dist/core/sandbox/codeMode/types.js +59 -0
  131. package/dist/core/sandbox/codeMode/types.js.map +1 -0
  132. package/dist/core/sandbox/codeMode/types.mjs +32 -0
  133. package/dist/core/sandbox/codeMode/types.mjs.map +1 -0
  134. package/dist/core/sandbox/provider/DaytonaProvider.d.ts +19 -1
  135. package/dist/core/sandbox/provider/DaytonaProvider.d.ts.map +1 -1
  136. package/dist/core/sandbox/provider/DaytonaProvider.js +96 -23
  137. package/dist/core/sandbox/provider/DaytonaProvider.js.map +1 -1
  138. package/dist/core/sandbox/provider/DaytonaProvider.mjs +96 -23
  139. package/dist/core/sandbox/provider/DaytonaProvider.mjs.map +1 -1
  140. package/dist/core/sandbox/provider/Provider.d.ts +4 -3
  141. package/dist/core/sandbox/provider/Provider.d.ts.map +1 -1
  142. package/dist/core/sandbox/provider/Provider.js.map +1 -1
  143. package/dist/core/sandbox/provider/Provider.mjs.map +1 -1
  144. package/dist/core/sandbox/provider/TFYSandboxProvider.d.ts +2 -1
  145. package/dist/core/sandbox/provider/TFYSandboxProvider.d.ts.map +1 -1
  146. package/dist/core/sandbox/provider/TFYSandboxProvider.js +20 -6
  147. package/dist/core/sandbox/provider/TFYSandboxProvider.js.map +1 -1
  148. package/dist/core/sandbox/provider/TFYSandboxProvider.mjs +20 -6
  149. package/dist/core/sandbox/provider/TFYSandboxProvider.mjs.map +1 -1
  150. package/dist/core/sandbox/sandboxImage.d.ts +1 -1
  151. package/dist/core/sandbox/sandboxImage.d.ts.map +1 -1
  152. package/dist/core/sandbox/sandboxImage.js +1 -1
  153. package/dist/core/sandbox/sandboxImage.js.map +1 -1
  154. package/dist/core/sandbox/sandboxImage.mjs +1 -1
  155. package/dist/core/sandbox/sandboxImage.mjs.map +1 -1
  156. package/dist/core/sandbox/sandboxScripts.gen.d.ts +1 -1
  157. package/dist/core/sandbox/sandboxScripts.gen.d.ts.map +1 -1
  158. package/dist/core/sandbox/sandboxScripts.gen.js +8 -8
  159. package/dist/core/sandbox/sandboxScripts.gen.js.map +1 -1
  160. package/dist/core/sandbox/sandboxScripts.gen.mjs +8 -8
  161. package/dist/core/sandbox/sandboxScripts.gen.mjs.map +1 -1
  162. package/dist/core/sandbox/skills/SkillMounter.d.ts.map +1 -1
  163. package/dist/core/sandbox/skills/SkillMounter.js +3 -1
  164. package/dist/core/sandbox/skills/SkillMounter.js.map +1 -1
  165. package/dist/core/sandbox/skills/SkillMounter.mjs +3 -1
  166. package/dist/core/sandbox/skills/SkillMounter.mjs.map +1 -1
  167. package/dist/core/util/abort.d.ts.map +1 -1
  168. package/dist/core/util/abort.js +3 -1
  169. package/dist/core/util/abort.js.map +1 -1
  170. package/dist/core/util/abort.mjs +3 -1
  171. package/dist/core/util/abort.mjs.map +1 -1
  172. package/dist/core/util/errorLogFields.d.ts +5 -0
  173. package/dist/core/util/errorLogFields.d.ts.map +1 -1
  174. package/dist/core/util/errorLogFields.js +38 -2
  175. package/dist/core/util/errorLogFields.js.map +1 -1
  176. package/dist/core/util/errorLogFields.mjs +37 -2
  177. package/dist/core/util/errorLogFields.mjs.map +1 -1
  178. package/package.json +10 -6
  179. package/dist/core/sandbox/SandboxNatsBridge.d.ts +0 -33
  180. package/dist/core/sandbox/SandboxNatsBridge.d.ts.map +0 -1
  181. package/dist/core/sandbox/SandboxNatsBridge.js +0 -222
  182. package/dist/core/sandbox/SandboxNatsBridge.js.map +0 -1
  183. package/dist/core/sandbox/SandboxNatsBridge.mjs +0 -201
  184. package/dist/core/sandbox/SandboxNatsBridge.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/runtime/contextUtils.ts"],"sourcesContent":["import dedent from 'dedent';\nimport type { ApprovalDecision } from '../events/schema';\nimport {\n EventType,\n type AgentApprovalDecisionMessage,\n type UserToolApprovalMessage,\n type UserToolResponseMessage,\n} from '../events/schema';\nimport type {\n EnrichedToolCall,\n InternalEnrichedToolCall,\n InternalToolCallInfo,\n LLMToolMessage,\n LLMUserMessage,\n ToolInfo,\n} from '../llm/LLMTypes';\nimport { UNKNOWN_TOOL_NAME } from '../llm/LLMTypes';\nimport { estimateTokensForString } from '../llm/usage';\nimport type {\n AgentThreadRuntimeSendInput,\n ContextMessage,\n InternalThreadDoneEvent,\n LLMContextMessage,\n} from './AgentThread.types';\nimport type { CurrentContextUsage } from './contextUsage';\nimport type { AgentInputUserMessage } from './UserInputMessage';\n\nexport const SYSTEM_TAG_START = '<tfy-internal>';\nconst SYSTEM_TAG_END = '</tfy-internal>';\nexport const INTERNAL_SYSTEM_PROMPT = dedent`\nMessages wrapped in tfy-internal tags contain information hidden from the user. The Agent must keep this information in mind when conversing with the user.\nThe Agent must never generate any content with tfy-internal tags.\nThe Agent cannot generate any content with tfy-internal tags.\n`;\n\nexport function internalSystemTag(m: string): string {\n return SYSTEM_TAG_START + m + SYSTEM_TAG_END;\n}\n\nexport function internalSystemMessage(m: string): LLMUserMessage {\n return { role: 'user' as const, content: internalSystemTag(m) };\n}\n\nexport function isLLMContextMessage(msg: ContextMessage): msg is LLMContextMessage {\n return 'role' in msg;\n}\n\nexport function isInternalSystemMessage(m: ContextMessage): boolean {\n if (!isLLMContextMessage(m)) return false;\n return m.role === 'user' && typeof m.content === 'string' && m.content.startsWith(SYSTEM_TAG_START);\n}\n\nexport function isApprovalDecisionMessage(msg: AgentThreadRuntimeSendInput): msg is UserToolApprovalMessage {\n return 'type' in msg && msg.type === EventType.USER_TOOL_APPROVAL;\n}\n\nfunction isUserToolApprovalDecisionMessage(msg: ContextMessage): msg is AgentApprovalDecisionMessage {\n // `'type' in msg` already narrows to AgentApprovalDecisionMessage (literal type).\n return 'type' in msg;\n}\n\nexport function isClientSideToolResponseMessage(msg: AgentThreadRuntimeSendInput): msg is UserToolResponseMessage {\n return 'type' in msg && msg.type === EventType.USER_TOOL_RESPONSE;\n}\n\nexport function isInputUserMessage(msg: AgentThreadRuntimeSendInput): msg is AgentInputUserMessage {\n return 'type' in msg && msg.type === EventType.USER_MESSAGE;\n}\n\nexport function isLLMToolMessage(msg: AgentThreadRuntimeSendInput): msg is LLMToolMessage {\n // `'role' in msg` already narrows to LLMToolMessage among AgentThreadRuntimeSendInput.\n return 'role' in msg;\n}\n\nexport function isInternalThreadDoneError(\n event: InternalThreadDoneEvent,\n): event is InternalThreadDoneEvent & { status: 'error' } {\n return event.status === 'error';\n}\n\nexport function scanApprovalDecisions(context: ContextMessage[]): Map<string, ApprovalDecision> {\n const decisions = new Map<string, ApprovalDecision>();\n for (const msg of context) {\n if (isUserToolApprovalDecisionMessage(msg)) {\n decisions.set(msg.tool_call_id, msg.approval);\n }\n }\n return decisions;\n}\n\nexport function makeUnknownToolInfo(toolName: string): InternalToolCallInfo {\n return {\n type: 'mcp',\n mcp_server_id: UNKNOWN_TOOL_NAME,\n mcp_server_name: UNKNOWN_TOOL_NAME,\n original_tool_name: toolName,\n is_approval_required: false,\n is_client_side: false,\n };\n}\n\nexport function toToolCallInfo(toolInfo: InternalToolCallInfo): ToolInfo {\n if (toolInfo.type === 'mcp') {\n return {\n type: toolInfo.type,\n name: toolInfo.original_tool_name,\n server_id: toolInfo.mcp_server_id,\n server_name: toolInfo.mcp_server_name,\n };\n }\n return {\n type: toolInfo.type,\n name: toolInfo.original_tool_name,\n };\n}\n\nexport function toEnrichedToolCall(toolCall: InternalEnrichedToolCall): EnrichedToolCall {\n const { tool_info, ...rest } = toolCall;\n return { ...rest, tool_info: toToolCallInfo(tool_info) };\n}\n\nexport function assistantMessageContentToStringForSubAgent(\n content: string | ({ type?: string; text?: string } | string)[] | null | undefined,\n errorMessage?: string,\n): string {\n let text = '';\n if (typeof content === 'string') {\n text = content;\n } else if (Array.isArray(content)) {\n text = content.map(item => (typeof item === 'string' ? item : JSON.stringify(item))).join('');\n }\n if (errorMessage) {\n return text ? `${errorMessage}\\n${text}` : errorMessage;\n }\n return text;\n}\n\nexport function getThreadId(): string {\n return crypto.randomUUID();\n}\n\nexport function estimateTokensForContextMessages(messages: ContextMessage[]): CurrentContextUsage {\n let tokenCount = 0;\n\n for (const b of messages) {\n if ('content' in b && b.content) {\n if (typeof b.content === 'string') {\n tokenCount += estimateTokensForString(b.content);\n } else if (Array.isArray(b.content)) {\n for (const part of b.content) {\n if ('text' in part && typeof part.text === 'string') {\n tokenCount += estimateTokensForString(part.text);\n }\n }\n }\n }\n\n if ('tool_calls' in b && b.tool_calls) {\n for (const toolCall of b.tool_calls) {\n tokenCount += estimateTokensForString(toolCall.function.name);\n tokenCount += estimateTokensForString(toolCall.function.arguments);\n }\n }\n\n if ('tool_call_id' in b && b.tool_call_id) {\n tokenCount += estimateTokensForString(b.tool_call_id);\n }\n }\n\n return {\n prompt_tokens: tokenCount,\n completion_tokens: 0,\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/core/runtime/contextUtils.ts"],"sourcesContent":["import dedent from 'dedent';\nimport type { ApprovalDecision } from '../events/schema';\nimport {\n EventType,\n type AgentApprovalDecisionMessage,\n type UserToolApprovalMessage,\n type UserToolResponseMessage,\n} from '../events/schema';\nimport type {\n EnrichedToolCall,\n InternalEnrichedToolCall,\n InternalToolCallInfo,\n LLMToolMessage,\n LLMUserMessage,\n ToolInfo,\n} from '../llm/LLMTypes';\nimport { UNKNOWN_TOOL_NAME } from '../llm/LLMTypes';\nimport { estimateTokensForString } from '../llm/usage';\nimport type {\n AgentThreadRuntimeSendInput,\n ContextMessage,\n InternalThreadDoneEvent,\n LLMContextMessage,\n} from './AgentThread.types';\nimport type { CurrentContextUsage } from './contextUsage';\nimport type { AgentInputUserMessage } from './UserInputMessage';\n\nexport const SYSTEM_TAG_START = '<tfy-internal>';\nconst SYSTEM_TAG_END = '</tfy-internal>';\nexport const INTERNAL_SYSTEM_PROMPT = dedent`\nMessages wrapped in tfy-internal tags contain information hidden from the user. The Agent must keep this information in mind when conversing with the user.\nThe Agent must never generate any content with tfy-internal tags.\nThe Agent cannot generate any content with tfy-internal tags.\n`;\n\nexport function internalSystemTag(m: string): string {\n return SYSTEM_TAG_START + m + SYSTEM_TAG_END;\n}\n\nexport function internalSystemMessage(m: string): LLMUserMessage {\n return { role: 'user' as const, content: internalSystemTag(m) };\n}\n\nexport function isLLMContextMessage(msg: ContextMessage): msg is LLMContextMessage {\n return 'role' in msg;\n}\n\nexport function isInternalSystemMessage(m: ContextMessage): boolean {\n if (!isLLMContextMessage(m)) {\n return false;\n }\n return m.role === 'user' && typeof m.content === 'string' && m.content.startsWith(SYSTEM_TAG_START);\n}\n\nexport function isApprovalDecisionMessage(msg: AgentThreadRuntimeSendInput): msg is UserToolApprovalMessage {\n return 'type' in msg && msg.type === EventType.USER_TOOL_APPROVAL;\n}\n\nfunction isUserToolApprovalDecisionMessage(msg: ContextMessage): msg is AgentApprovalDecisionMessage {\n // `'type' in msg` already narrows to AgentApprovalDecisionMessage (literal type).\n return 'type' in msg;\n}\n\nexport function isClientSideToolResponseMessage(msg: AgentThreadRuntimeSendInput): msg is UserToolResponseMessage {\n return 'type' in msg && msg.type === EventType.USER_TOOL_RESPONSE;\n}\n\nexport function isInputUserMessage(msg: AgentThreadRuntimeSendInput): msg is AgentInputUserMessage {\n return 'type' in msg && msg.type === EventType.USER_MESSAGE;\n}\n\nexport function isLLMToolMessage(msg: AgentThreadRuntimeSendInput): msg is LLMToolMessage {\n // `'role' in msg` already narrows to LLMToolMessage among AgentThreadRuntimeSendInput.\n return 'role' in msg;\n}\n\nexport function isInternalThreadDoneError(\n event: InternalThreadDoneEvent,\n): event is InternalThreadDoneEvent & { status: 'error' } {\n return event.status === 'error';\n}\n\nexport function scanApprovalDecisions(context: ContextMessage[]): Map<string, ApprovalDecision> {\n const decisions = new Map<string, ApprovalDecision>();\n for (const msg of context) {\n if (isUserToolApprovalDecisionMessage(msg)) {\n decisions.set(msg.tool_call_id, msg.approval);\n }\n }\n return decisions;\n}\n\nexport function makeUnknownToolInfo(toolName: string): InternalToolCallInfo {\n return {\n type: 'mcp',\n mcp_server_id: UNKNOWN_TOOL_NAME,\n mcp_server_name: UNKNOWN_TOOL_NAME,\n original_tool_name: toolName,\n is_approval_required: false,\n is_client_side: false,\n };\n}\n\nexport function toToolCallInfo(toolInfo: InternalToolCallInfo): ToolInfo {\n if (toolInfo.type === 'mcp') {\n return {\n type: toolInfo.type,\n name: toolInfo.original_tool_name,\n server_id: toolInfo.mcp_server_id,\n server_name: toolInfo.mcp_server_name,\n };\n }\n return {\n type: toolInfo.type,\n name: toolInfo.original_tool_name,\n };\n}\n\nexport function toEnrichedToolCall(toolCall: InternalEnrichedToolCall): EnrichedToolCall {\n const { tool_info, ...rest } = toolCall;\n return { ...rest, tool_info: toToolCallInfo(tool_info) };\n}\n\nexport function assistantMessageContentToStringForSubAgent(\n content: string | ({ type?: string; text?: string } | string)[] | null | undefined,\n errorMessage?: string,\n): string {\n let text = '';\n if (typeof content === 'string') {\n text = content;\n } else if (Array.isArray(content)) {\n text = content.map(item => (typeof item === 'string' ? item : JSON.stringify(item))).join('');\n }\n if (errorMessage) {\n return text ? `${errorMessage}\\n${text}` : errorMessage;\n }\n return text;\n}\n\nexport function getThreadId(): string {\n return crypto.randomUUID();\n}\n\nexport function estimateTokensForContextMessages(messages: ContextMessage[]): CurrentContextUsage {\n let tokenCount = 0;\n\n for (const b of messages) {\n if ('content' in b && b.content) {\n if (typeof b.content === 'string') {\n tokenCount += estimateTokensForString(b.content);\n } else if (Array.isArray(b.content)) {\n for (const part of b.content) {\n if ('text' in part && typeof part.text === 'string') {\n tokenCount += estimateTokensForString(part.text);\n }\n }\n }\n }\n\n if ('tool_calls' in b && b.tool_calls) {\n for (const toolCall of b.tool_calls) {\n tokenCount += estimateTokensForString(toolCall.function.name);\n tokenCount += estimateTokensForString(toolCall.function.arguments);\n }\n }\n\n if ('tool_call_id' in b && b.tool_call_id) {\n tokenCount += estimateTokensForString(b.tool_call_id);\n }\n }\n\n return {\n prompt_tokens: tokenCount,\n completion_tokens: 0,\n };\n}\n"],"mappings":"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","names":[]}
@@ -54,14 +54,15 @@ export declare class Sandbox extends LocalToolMCP {
54
54
  private sandboxInitPromise?;
55
55
  private codeExecToolSets;
56
56
  private readonly fileDownloadEnabled;
57
- private readonly natsRequestTimeoutSeconds;
57
+ private readonly requestTimeoutSeconds;
58
58
  private readonly execExtraEnv?;
59
59
  private readonly skillMounter?;
60
60
  private cachedSkillsSection?;
61
61
  private readonly mcpClientScriptBase64;
62
62
  private readonly logger;
63
63
  private readonly resolvedGitCredentialsContent;
64
- private natsBridgePromise?;
64
+ private codeModeDispatcher;
65
+ private codeModeTransport;
65
66
  private tools;
66
67
  constructor(options: SandboxOptions);
67
68
  private buildMcpServersEnvelope;
@@ -108,14 +109,11 @@ export declare class Sandbox extends LocalToolMCP {
108
109
  private writeGitCredentials;
109
110
  private initSandboxEnvironment;
110
111
  /**
111
- * Lazily connect the sandbox→gateway NATS bridge. Single-flight and idempotent.
112
- * Skipped when there are no MCP servers exposed to code mode (nothing to bridge). Connect
113
- * failures resolve to `undefined` (no NATS env for that exec); mcp_client then errors at call
114
- * time — there is no HTTPS fallback.
112
+ * Lazily start Code Mode transport. Single-flight and idempotent inside the transport.
113
+ * Skipped when code mode was never configured. Connect failures resolve to `undefined`
114
+ * (no Code Mode env for that exec); mcp_client then errors at call time — no HTTPS fallback.
115
115
  */
116
- private ensureNatsBridgeConnected;
117
- private connectNatsBridge;
118
- private attachBridgeInvalidationOnClose;
116
+ private ensureCodeModeStarted;
119
117
  close(): Promise<void>;
120
118
  }
121
119
  //# sourceMappingURL=Sandbox.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Sandbox.d.ts","sourceRoot":"","sources":["../../../src/core/sandbox/Sandbox.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Sandbox.d.ts","sourceRoot":"","sources":["../../../src/core/sandbox/Sandbox.ts"],"names":[],"mappings":"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"}
@@ -48,10 +48,10 @@ var import_IMCPServer = require("../mcp/IMCPServer.js");
48
48
  var import_LocalToolMCP = require("../mcp/LocalToolMCP.js");
49
49
  var import_DeferredTool = require("../runtime/DeferredTool.js");
50
50
  var import_errorLogFields = require("../util/errorLogFields.js");
51
+ var import_CodeModeDispatcher = require("./codeMode/CodeModeDispatcher.js");
51
52
  var import_constants = require("./constants.js");
52
53
  var import_Provider = require("./provider/Provider.js");
53
54
  var import_SandboxErrors = require("./SandboxErrors.js");
54
- var import_SandboxNatsBridge = require("./SandboxNatsBridge.js");
55
55
  var import_sandboxScripts = require("./sandboxScripts.gen.js");
56
56
  var import_constants2 = require("./skills/constants.js");
57
57
  var SKILL_DOWNLOAD_TIMEOUT_SECONDS = 180;
@@ -92,11 +92,17 @@ function injectTraceContextEnv() {
92
92
  const carrier = {};
93
93
  import_api.propagation.inject(import_api.context.active(), carrier);
94
94
  const env = {};
95
- if (carrier["traceparent"]) env["TFY_TRACEPARENT"] = carrier["traceparent"];
96
- if (carrier["tracestate"]) env["TFY_TRACESTATE"] = carrier["tracestate"];
95
+ if (carrier["traceparent"]) {
96
+ env["TFY_TRACEPARENT"] = carrier["traceparent"];
97
+ }
98
+ if (carrier["tracestate"]) {
99
+ env["TFY_TRACESTATE"] = carrier["tracestate"];
100
+ }
97
101
  return env;
98
102
  }
99
103
  function injectMCPClientEnv(params) {
104
+ const codeModeEnv = params.codeModeEnv ?? {};
105
+ const hasCodeModeTransport = Object.keys(codeModeEnv).length > 0;
100
106
  return {
101
107
  ...params.execExtraEnv ?? {},
102
108
  ...params.env ?? {},
@@ -104,13 +110,10 @@ function injectMCPClientEnv(params) {
104
110
  ...Object.keys(params.mcpServers).length > 0 && {
105
111
  TFY_MCP_SERVERS: Buffer.from(JSON.stringify(params.mcpServers)).toString("base64")
106
112
  },
107
- ...params.natsBridgeSubjectPrefix && {
108
- TFY_NATS_URL: `ws://localhost:${String(import_constants.DEFAULT_SANDBOX_NATS_WS_PORT)}`,
109
- TFY_NATS_SUBJECT_PREFIX: params.natsBridgeSubjectPrefix,
110
- TFY_NATS_REQUEST_TIMEOUT_SECONDS: String(params.natsRequestTimeoutSeconds),
111
- // W3C trace context captured per-exec so each NATS request carries the originating
112
- // Sandbox: exec span as parent. Without this, MCP spans dispatched via the bridge
113
- // inherit whatever ALS context the NATS callback runs under (stale, shared across execs).
113
+ ...codeModeEnv,
114
+ ...hasCodeModeTransport && {
115
+ // W3C trace context captured per-exec so each Code Mode request carries the originating
116
+ // Sandbox: exec span as parent.
114
117
  ...injectTraceContextEnv()
115
118
  },
116
119
  // Approvals are always enabled: destructive tools cannot run in code mode.
@@ -149,7 +152,7 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
149
152
  sandboxInitPromise;
150
153
  codeExecToolSets = [];
151
154
  fileDownloadEnabled;
152
- natsRequestTimeoutSeconds;
155
+ requestTimeoutSeconds;
153
156
  execExtraEnv;
154
157
  skillMounter;
155
158
  cachedSkillsSection;
@@ -157,7 +160,8 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
157
160
  logger;
158
161
  // Pre-resolved credential-store file content (null = clear / no git auth).
159
162
  resolvedGitCredentialsContent;
160
- natsBridgePromise;
163
+ codeModeDispatcher;
164
+ codeModeTransport;
161
165
  tools = [
162
166
  (0, import_LocalToolMCP.defineTool)({
163
167
  name: SANDBOX_EXEC_TOOL_NAME,
@@ -174,7 +178,7 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
174
178
  this.skillMounter = options.skillMounter;
175
179
  this.fileDownloadEnabled = options.fileDownloadEnabled ?? false;
176
180
  const mcpBoundTimeoutMs = options.mcpRequestTimeoutMs + options.mcpConnectTimeoutMs;
177
- this.natsRequestTimeoutSeconds = Math.ceil(mcpBoundTimeoutMs / 1e3) + NATS_REQUEST_TIMEOUT_BUFFER_SECONDS;
181
+ this.requestTimeoutSeconds = Math.ceil(mcpBoundTimeoutMs / 1e3) + NATS_REQUEST_TIMEOUT_BUFFER_SECONDS;
178
182
  this.execExtraEnv = options.execExtraEnv;
179
183
  this.mcpClientScriptBase64 = Buffer.from(import_sandboxScripts.sandboxScripts.mcpClient, "utf-8").toString("base64");
180
184
  this.logger = options.logger.child({ module: "Sandbox" });
@@ -199,7 +203,12 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
199
203
  if (!servers.length) {
200
204
  return;
201
205
  }
206
+ if (this.codeModeDispatcher !== void 0 || this.codeModeTransport !== void 0) {
207
+ throw new Error("Code Mode is already configured for this Sandbox");
208
+ }
202
209
  this.codeExecToolSets = servers;
210
+ this.codeModeDispatcher = new import_CodeModeDispatcher.CodeModeDispatcher({ toolSets: servers, logger: this.logger });
211
+ this.codeModeTransport = this.provider.createCodeModeTransport();
203
212
  }
204
213
  estimateSkillsTokens() {
205
214
  return Math.round((0, import_usage.estimateTokensForString)(this.renderSkillsSection()));
@@ -274,7 +283,9 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
274
283
  }
275
284
  buildMCPSection(builder) {
276
285
  const toolSetNames = this.codeExecToolSets.map((m) => m.name).join(",");
277
- if (!toolSetNames) return;
286
+ if (!toolSetNames) {
287
+ return;
288
+ }
278
289
  builder.addSection(
279
290
  SANDBOX_MCP_REMINDER_TAG,
280
291
  import_dedent.default`
@@ -383,13 +394,12 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
383
394
  overrides: { sandboxCreated: sandboxCreatedFlag, sandboxInfo }
384
395
  });
385
396
  }
386
- const bridge = await this.ensureNatsBridgeConnected(sandboxInfo.sandbox_id);
397
+ const codeModeEnv = await this.ensureCodeModeStarted(sandboxInfo.sandbox_id);
387
398
  const mcpClientEnv = injectMCPClientEnv({
388
399
  env: input.env,
389
400
  mcpServers: this.buildMcpServersEnvelope(),
390
401
  execExtraEnv: this.execExtraEnv,
391
- natsBridgeSubjectPrefix: bridge?.subjectPrefix,
392
- natsRequestTimeoutSeconds: this.natsRequestTimeoutSeconds
402
+ codeModeEnv
393
403
  });
394
404
  const gitAuthEnv = this.resolvedGitCredentialsContent !== null ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(sandboxInfo.sandbox_id)) : {};
395
405
  const env = { ...mcpClientEnv, ...gitAuthEnv };
@@ -499,63 +509,45 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
499
509
  await this.writeGitCredentials();
500
510
  }
501
511
  /**
502
- * Lazily connect the sandbox→gateway NATS bridge. Single-flight and idempotent.
503
- * Skipped when there are no MCP servers exposed to code mode (nothing to bridge). Connect
504
- * failures resolve to `undefined` (no NATS env for that exec); mcp_client then errors at call
505
- * time — there is no HTTPS fallback.
512
+ * Lazily start Code Mode transport. Single-flight and idempotent inside the transport.
513
+ * Skipped when code mode was never configured. Connect failures resolve to `undefined`
514
+ * (no Code Mode env for that exec); mcp_client then errors at call time — no HTTPS fallback.
506
515
  */
507
- async ensureNatsBridgeConnected(sandboxId) {
508
- if (this.codeExecToolSets.length === 0) return void 0;
509
- this.natsBridgePromise ??= this.connectNatsBridge(sandboxId).catch((e) => {
510
- this.logger.error("Sandbox NATS bridge connect failed", {
516
+ async ensureCodeModeStarted(sandboxId) {
517
+ const dispatcher = this.codeModeDispatcher;
518
+ const transport = this.codeModeTransport;
519
+ if (dispatcher === void 0 || transport === void 0) {
520
+ return void 0;
521
+ }
522
+ try {
523
+ const { env } = await transport.start({
524
+ codeModeDispatcher: dispatcher,
525
+ sandboxId,
526
+ requestTimeoutSeconds: this.requestTimeoutSeconds
527
+ });
528
+ return env;
529
+ } catch (e) {
530
+ this.logger.error("Code Mode transport start failed", {
511
531
  ...(0, import_errorLogFields.extractErrorLogFields)(e),
512
532
  sandboxId
513
533
  });
514
- this.natsBridgePromise = void 0;
515
534
  return void 0;
516
- });
517
- return this.natsBridgePromise;
518
- }
519
- async connectNatsBridge(sandboxId) {
520
- const wsUrl = await this.provider.getNatsBridgeUrl(sandboxId);
521
- const toolSets = /* @__PURE__ */ new Map();
522
- for (const server of this.codeExecToolSets) {
523
- toolSets.set(server.name, server);
524
535
  }
525
- const bridge = await import_SandboxNatsBridge.SandboxNatsBridge.connect({ url: wsUrl, toolSets, logger: this.logger });
526
- this.logger.info("Sandbox NATS bridge connected", {
527
- sandboxId,
528
- toolSetCount: toolSets.size
529
- });
530
- this.attachBridgeInvalidationOnClose(bridge, sandboxId);
531
- return bridge;
532
536
  }
533
- attachBridgeInvalidationOnClose(bridge, sandboxId) {
534
- const cachedPromise = this.natsBridgePromise;
535
- void bridge.whenClosed().then(() => {
536
- if (this.natsBridgePromise === cachedPromise) {
537
- this.natsBridgePromise = void 0;
538
- this.logger.info("Sandbox NATS bridge closed; cache invalidated, next exec will reconnect", { sandboxId });
539
- }
540
- });
541
- }
542
- // Tears down per-Sandbox resources. Awaits the in-flight connect (if any) and explicitly
543
- // closes the bridge — dropping the field alone would leak the WS socket and live
544
- // subscriptions, and orphan a bridge that finishes connecting after close() returned.
537
+ // Tears down per-Sandbox Code Mode resources. Dispatcher close first (in-flight requests get
538
+ // source: transport), then transport.stop() — always safe whether start succeeded, failed, or never ran.
545
539
  async close() {
546
- const pendingPromise = this.natsBridgePromise;
547
- this.natsBridgePromise = void 0;
548
- if (!pendingPromise) return;
549
- let bridge;
550
- try {
551
- bridge = await pendingPromise;
552
- } catch {
540
+ this.codeModeDispatcher?.close();
541
+ this.codeModeDispatcher = void 0;
542
+ const transport = this.codeModeTransport;
543
+ this.codeModeTransport = void 0;
544
+ if (transport === void 0) {
545
+ return;
553
546
  }
554
- if (!bridge) return;
555
547
  try {
556
- await bridge.close();
548
+ await transport.stop();
557
549
  } catch (e) {
558
- this.logger.warn("Error closing sandbox NATS bridge", (0, import_errorLogFields.extractErrorLogFields)(e));
550
+ this.logger.warn("Error stopping Code Mode transport", (0, import_errorLogFields.extractErrorLogFields)(e));
559
551
  }
560
552
  }
561
553
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/sandbox/Sandbox.ts"],"sourcesContent":["import { context, propagation } from '@opentelemetry/api';\nimport dedent from 'dedent';\nimport type { Logger } from 'winston';\nimport { z } from 'zod';\nimport { InstructionBuilder } from '../InstructionBuilder';\nimport { estimateTokensForString } from '../llm/usage';\nimport type { MappedMCPTool } from '../mcp/convertMCPServers';\nimport { toolResultResponse, type CallToolResponse, type IToolSet } from '../mcp/IMCPServer';\nimport { defineTool, LocalToolMCP } from '../mcp/LocalToolMCP';\nimport {\n DEFERRED_TOOLS_SERVER_ID,\n GET_TOOL_INFO_NAME,\n GET_TOOL_OUTPUT_SCHEMA_NAME,\n LIST_TOOLS_NAME,\n} from '../runtime/DeferredTool';\nimport type { AgentTracing } from '../tracing/AgentTracing';\nimport { extractErrorLogFields } from '../util/errorLogFields';\nimport { DEFAULT_SANDBOX_NATS_WS_PORT, SANDBOX_FILE_UPLOADS_DIR } from './constants';\nimport { ensureExecSuccess, shellEscape, type SandboxProvider } from './provider/Provider';\nimport { validateNoPathTraversal, validateSandboxOwnedByTenant } from './SandboxErrors';\nimport { SandboxNatsBridge } from './SandboxNatsBridge';\nimport { sandboxScripts } from './sandboxScripts.gen';\n// Import submodules, not the ./skills barrel, to avoid a cycle (the mounters import from Sandbox).\nimport { SKILLS_DIR } from './skills/constants';\nimport type { ISkillMounter } from './skills/ISkillMounter';\n\nexport interface SandboxInfo {\n sandbox_id: string;\n}\n\n// Downloader/setup scripts can run longer than a normal exec.\nexport const SKILL_DOWNLOAD_TIMEOUT_SECONDS = 180;\n\n// Keeps the sandbox-side NATS wait longer than the host's own MCP deadline, so the host\n// surfaces the real MCP error instead of the bridge client giving up first.\nconst NATS_REQUEST_TIMEOUT_BUFFER_SECONDS = 30;\n\n// Write a script (base64-encoded, never interpolated raw) to a path and run it. Skill mounters reuse it.\nexport function buildWriteAndRunScriptCommand(params: { scriptPath: string; scriptContent: string }): string {\n const b64 = Buffer.from(params.scriptContent, 'utf-8').toString('base64');\n return [\n `mkdir -p \"$(dirname ${params.scriptPath})\"`,\n `rm -f ${params.scriptPath}`,\n `echo ${shellEscape(b64)} | base64 -d > ${params.scriptPath}`,\n `chmod a-w ${params.scriptPath}`,\n `python3 ${params.scriptPath}`,\n ].join(' && ');\n}\n\n/** Write or clear the git credential-store file at an absolute path (no global git config mutation). */\nfunction buildSyncGitCredentialsCommand(credentialsContent: string | null, credentialsPath: string): string {\n if (credentialsContent === null) {\n return `rm -f ${credentialsPath}`;\n }\n // Base64 avoids interpolating credentials directly into the shell command.\n const b64 = Buffer.from(credentialsContent, 'utf-8').toString('base64');\n return (\n `mkdir -p \"$(dirname ${credentialsPath})\" && ` +\n `echo '${b64}' | base64 -d > ${credentialsPath} && ` +\n `chmod 600 ${credentialsPath}`\n );\n}\n\n/**\n * Process-scoped credential.helper via GIT_CONFIG_* (avoids shared ~/.gitconfig).\n * Required for TFY sandbox where many logical sandboxes share one pod/HOME.\n */\nfunction buildGitCredentialHelperEnv(credentialsPath: string): Record<string, string> {\n return {\n GIT_CONFIG_COUNT: '1',\n GIT_CONFIG_KEY_0: 'credential.helper',\n GIT_CONFIG_VALUE_0: `store --file ${credentialsPath}`,\n };\n}\n\nexport interface SandboxStoredFile {\n filePath: string;\n sandboxCreated?: SandboxInfo | undefined;\n}\n\nexport interface SandboxOptions {\n provider: SandboxProvider;\n existingSandboxId?: string | undefined;\n skillMounter?: ISkillMounter | undefined;\n fileDownloadEnabled?: boolean | undefined;\n /** Pre-resolved credential-store file content (null = clear / no git auth). */\n resolvedGitCredentialsContent?: string | null | undefined;\n /**\n * Blocks destructive tools in code mode so they go through the approval flow\n * instead. Must be `true` — approvals are always enabled (the kill switch is gone).\n */\n blockDestructiveToolsInCodeMode: true;\n /** Used to derive the Code Mode NATS wait as request + connect. */\n mcpRequestTimeoutMs: number;\n mcpConnectTimeoutMs: number;\n execExtraEnv?: Readonly<Record<string, string>> | undefined;\n tracing: AgentTracing;\n logger: Logger;\n}\n\nexport const SANDBOX_EXEC_TOOL_NAME = 'exec';\nconst SANDBOX_MCP_REMINDER_TAG = 'sandbox-mcp-code-mode';\nconst SANDBOX_FILE_OUTPUT_TAG = 'sandbox-file-output';\nexport const SANDBOX_SCHEMA_INFER_TAG = 'sandbox-schema-infer';\nconst SANDBOX_FILE_UPLOADS_TAG = 'sandbox-file-uploads';\n\n// Stable directory inside the sandbox where the MCP client library is uploaded.\n// MCP client upload dir. Two lookup channels:\n// - Python imports → PYTHONPATH points here (set by injectMCPClientEnv).\n// - Shell `mcp-client` → symlinked into MCP_CLIENT_BIN_SYMLINK (on default PATH);\n// basename drops `.py` so the agent doesn't reflexively prefix with `python`.\nconst MCP_CLIENT_DIR = '/opt/tfy/mcp-client';\nconst MCP_CLIENT_PATH = `${MCP_CLIENT_DIR}/mcp_client.py`;\nconst MCP_CLIENT_BIN_SYMLINK = '/usr/local/bin/mcp-client';\n\n// Per-server config sent to mcp_client.py via TFY_MCP_SERVERS.\ninterface SandboxMcpServerConfig {\n allowed_tools: string[];\n}\n\n// Snapshots the active W3C trace context (`traceparent` + optional `tracestate`) into env\n// vars consumed by mcp_client.py. Read with TFY_TRACEPARENT / TFY_TRACESTATE on the sandbox\n// side and attached as NATS message headers; the bridge extracts them on each message so the\n// resulting MCP spans nest under the originating Sandbox: exec span.\nfunction injectTraceContextEnv(): Record<string, string> {\n const carrier: Record<string, string> = {};\n propagation.inject(context.active(), carrier);\n const env: Record<string, string> = {};\n if (carrier['traceparent']) env['TFY_TRACEPARENT'] = carrier['traceparent'];\n if (carrier['tracestate']) env['TFY_TRACESTATE'] = carrier['tracestate'];\n return env;\n}\n\n/**\n * Injects environment variables required for mcp_client.py into sandbox_exec arguments.\n *\n * `natsBridgeSubjectPrefix` MUST be the prefix the gateway-side bridge subscribed to; the\n * sandbox script publishes to `<prefix>.mcp` (operation in the payload's `op` field) and only\n * this bridge receives them. See SandboxNatsBridge.\n */\nfunction injectMCPClientEnv(params: {\n env?: Record<string, string> | undefined;\n mcpServers: Record<string, SandboxMcpServerConfig>;\n execExtraEnv?: Readonly<Record<string, string>> | undefined;\n natsBridgeSubjectPrefix?: string | undefined;\n natsRequestTimeoutSeconds: number;\n}): Record<string, string> {\n return {\n ...(params.execExtraEnv ?? {}),\n ...(params.env ?? {}),\n PYTHONPATH: MCP_CLIENT_DIR,\n ...(Object.keys(params.mcpServers).length > 0 && {\n TFY_MCP_SERVERS: Buffer.from(JSON.stringify(params.mcpServers)).toString('base64'),\n }),\n ...(params.natsBridgeSubjectPrefix && {\n TFY_NATS_URL: `ws://localhost:${String(DEFAULT_SANDBOX_NATS_WS_PORT)}`,\n TFY_NATS_SUBJECT_PREFIX: params.natsBridgeSubjectPrefix,\n TFY_NATS_REQUEST_TIMEOUT_SECONDS: String(params.natsRequestTimeoutSeconds),\n // W3C trace context captured per-exec so each NATS request carries the originating\n // Sandbox: exec span as parent. Without this, MCP spans dispatched via the bridge\n // inherit whatever ALS context the NATS callback runs under (stale, shared across execs).\n ...injectTraceContextEnv(),\n }),\n // Approvals are always enabled: destructive tools cannot run in code mode.\n TFY_ENABLE_AGENT_APPROVALS: 'true',\n };\n}\n\nconst sandboxExecSchema = z.object({\n intent: z\n .string()\n .describe(\n 'A brief, user-facing explanation of the purpose of this command. Avoid technical jargon and code details.',\n ),\n command: z.string().describe('The shell command to execute in the sandbox.'),\n cwd: z.string().optional().describe('Working directory for command execution.'),\n env: z.record(z.string(), z.string()).optional().describe('Additional environment variables to set.'),\n});\n\nconst SANDBOX_EXEC_DESCRIPTION = `Execute shell commands in a persistent sandbox environment.\nThe sandbox persists across calls within the same session, allowing stateful operations.\nPre-installed: Python 3.13, pydantic, git, curl, helm, jq, ripgrep, genson.\nIMPORTANT: The Agent must never list, print, or expose environment variables as they contain sensitive credentials.\nIMPORTANT: Never read or expose any git credential files or ~/.git-credentials.\n`;\n\nexport function createSandboxLargeToolResponseGuidance(): string {\n return `For use cases where the Agent needs a subset of fields from the MCP response or needs deterministic processing, write code with the provided MCP client and use <${SANDBOX_MCP_REMINDER_TAG}>.`;\n}\n\nexport const SANDBOX_MCP_SERVER_ID = 'sandbox';\ntype SandboxExecInput = z.infer<typeof sandboxExecSchema>;\n\nexport class Sandbox extends LocalToolMCP {\n readonly name = SANDBOX_MCP_SERVER_ID;\n readonly displayName = 'Sandbox';\n override readonly description = 'Persistent sandbox environment for code execution';\n static readonly FILE_UPLOADS_DIR = SANDBOX_FILE_UPLOADS_DIR;\n\n private readonly provider: SandboxProvider;\n private readonly existingSandboxId?: string | undefined;\n private readonly tenantName: string;\n private existingSandboxInfo: SandboxInfo | undefined;\n // Cached promise to prevent concurrent sub-agents from creating duplicate sandboxes.\n private sandboxCreationPromise?: Promise<SandboxInfo> | undefined;\n private sandboxInitPromise?: Promise<void> | undefined;\n private codeExecToolSets: readonly IToolSet[] = [];\n private readonly fileDownloadEnabled: boolean;\n private readonly natsRequestTimeoutSeconds: number;\n private readonly execExtraEnv?: Readonly<Record<string, string>> | undefined;\n private readonly skillMounter?: ISkillMounter | undefined;\n private cachedSkillsSection?: string | undefined;\n private readonly mcpClientScriptBase64: string;\n private readonly logger: Logger;\n // Pre-resolved credential-store file content (null = clear / no git auth).\n private readonly resolvedGitCredentialsContent: string | null;\n private natsBridgePromise?: Promise<SandboxNatsBridge | undefined> | undefined;\n\n private tools = [\n defineTool({\n name: SANDBOX_EXEC_TOOL_NAME,\n description: SANDBOX_EXEC_DESCRIPTION,\n schema: sandboxExecSchema,\n handler: input => this.handleExec(input),\n }),\n ];\n\n constructor(options: SandboxOptions) {\n super({ tracing: options.tracing });\n this.provider = options.provider;\n this.existingSandboxId = options.existingSandboxId;\n this.tenantName = options.execExtraEnv?.['TFY_TENANT_NAME'] ?? '';\n this.skillMounter = options.skillMounter;\n this.fileDownloadEnabled = options.fileDownloadEnabled ?? false;\n const mcpBoundTimeoutMs = options.mcpRequestTimeoutMs + options.mcpConnectTimeoutMs;\n this.natsRequestTimeoutSeconds = Math.ceil(mcpBoundTimeoutMs / 1000) + NATS_REQUEST_TIMEOUT_BUFFER_SECONDS;\n this.execExtraEnv = options.execExtraEnv;\n // Scripts are internal to Sandbox: the upload paths, env contract, and prompt\n // text are all hardcoded here, so injecting different content was never a\n // real extension point. Consumers don't see or provide them.\n this.mcpClientScriptBase64 = Buffer.from(sandboxScripts.mcpClient, 'utf-8').toString('base64');\n this.logger = options.logger.child({ module: 'Sandbox' });\n this.resolvedGitCredentialsContent = options.resolvedGitCredentialsContent ?? null;\n\n if (this.existingSandboxId) {\n validateSandboxOwnedByTenant(this.existingSandboxId, this.tenantName);\n this.existingSandboxInfo = { sandbox_id: this.existingSandboxId };\n }\n }\n\n private buildMcpServersEnvelope(): Record<string, SandboxMcpServerConfig> {\n const out: Record<string, SandboxMcpServerConfig> = {};\n for (const server of this.codeExecToolSets) {\n const allowedTools = server.getAllowedToolNamesForSandbox?.() ?? [];\n out[server.name] = { allowed_tools: allowedTools };\n }\n return out;\n }\n\n protected getTools() {\n return this.tools;\n }\n\n configureCodeMode(servers: readonly IToolSet[]): void {\n if (!servers.length) {\n return;\n }\n this.codeExecToolSets = servers;\n }\n\n estimateSkillsTokens(): number {\n return Math.round(estimateTokensForString(this.renderSkillsSection()));\n }\n\n // Single source for the <skills> section, so the prompt and the token estimate can't drift.\n private renderSkillsSection(): string {\n if (this.cachedSkillsSection === undefined) {\n const skills = new InstructionBuilder('skills');\n this.skillMounter?.instruction(skills);\n this.cachedSkillsSection = skills.build();\n }\n return this.cachedSkillsSection;\n }\n\n buildInstruction(builder: InstructionBuilder): void {\n const providerInstructions = this.provider.getAdditionalInstructions();\n\n const sandboxInstructions = builder.beginSection('sandbox');\n sandboxInstructions.addContent('The Agent has access to a persistent sandbox environment for executing code.');\n sandboxInstructions.addContent('The Agent must NOT read or modify any git credential files.');\n\n this.buildSchemaSection(sandboxInstructions);\n this.buildSkillsSection(sandboxInstructions);\n this.buildMCPSection(sandboxInstructions);\n this.buildFileUploadsSection(sandboxInstructions);\n\n if (this.fileDownloadEnabled) {\n this.buildFileOutputSection(sandboxInstructions);\n }\n\n if (providerInstructions) {\n sandboxInstructions.addContent(providerInstructions);\n }\n }\n\n private buildFileUploadsSection(builder: InstructionBuilder): void {\n builder.addSection(\n SANDBOX_FILE_UPLOADS_TAG,\n `User-uploaded files are placed in ${Sandbox.FILE_UPLOADS_DIR}/. The Agent must not modify files in this directory. Always create a copy at a different location and work on the copy.`,\n );\n }\n\n private buildSchemaSection(builder: InstructionBuilder): void {\n builder.addSection(\n SANDBOX_SCHEMA_INFER_TAG,\n dedent`\n To infer the schema of a file, the Agent MUST execute:\n head -c 200 file_path && echo \"==\" && genson file_path\n This serves two purpose:\n 1. The first 200 characters of the file is printed. Do NOT print more than 200 characters.\n 2. genson infers and returns JSON schema if the file is JSON.\n Even if the file is not JSON, (1) helps to take the next step in less number of turns\n `,\n );\n }\n\n private buildFileOutputSection(builder: InstructionBuilder): void {\n builder.addSection(\n SANDBOX_FILE_OUTPUT_TAG,\n dedent`\n ## File outputs\n\n The user does not have direct access to the sandbox filesystem. When the Agent wants to output a file to the user, it MUST:\n 1. Ensure that the file is present in the sandbox.\n 2. Then emit a fenced sandbox_artifacts block referencing the file.\n\n \\`\\`\\`sandbox_artifacts\n [Human-readable label](/absolute/path/to/file.ext)\n \\`\\`\\`\n\n For large outputs or content that can be generated through code, prefer writing to a file and emitting the sandbox_artifacts block.\n\n Rules:\n - Use absolute paths, not ~/ or relative paths.\n - One link per line. Markdown link syntax: [label](path).`,\n );\n }\n\n private buildSkillsSection(builder: InstructionBuilder): void {\n builder.addContent(this.renderSkillsSection());\n }\n\n private buildMCPSection(builder: InstructionBuilder): void {\n const toolSetNames = this.codeExecToolSets.map(m => m.name).join(',');\n if (!toolSetNames) return;\n\n builder.addSection(\n SANDBOX_MCP_REMINDER_TAG,\n dedent`\n The following MCP servers are accessible for Code Mode from ${SANDBOX_EXEC_TOOL_NAME} via the pre-installed mcp_client module: ${toolSetNames}\n Tool and functions are same.\n Tool and MCP tools are same.\n\n Use \\`from mcp_client import call_tool\\` in code, or \\`mcp-client\\` in shell — both work from any directory with no setup.\n\n For deferred MCP servers, the Agent MUST:\n 1. Discover tools via ${LIST_TOOLS_NAME} from ${DEFERRED_TOOLS_SERVER_ID}. Never call ${GET_TOOL_OUTPUT_SCHEMA_NAME}.\n 2. Discover inputSchema, outputSchema via ${GET_TOOL_INFO_NAME} for the selected tools.\n\n For non-deferred MCP servers, the Agent MUST:\n 1. Discover outputSchema via ${GET_TOOL_OUTPUT_SCHEMA_NAME} for the selected tools.\n\n For both deferred and non-deferred if outputSchema is absent,\n the Agent MUST say: \"Given the MCP Server does not define an outputSchema let me figure it out first before entering Code Mode.\"\n mcp-client call-tool {server} {tool} '{\"param\":\"value\"}' > file && ${SANDBOX_SCHEMA_INFER_TAG}.\n the Agent MUST execute a single command for above.\n If the Agent does not get the outputSchema, the Agent will encounters scenarios like:\n Agent: \"Let me fix the code - it seems the x might be a string rather than an object in some cases:\"\n The Agent MUST not face the above scenario.\n \n Only after the Agent has the above details, it can enter Code Mode.\n Agent: Now I know the inputSchema and outputSchema of tool_a, let me enter Code Mode.\n\n CLI: mcp-client call-tool {server} {tool_a} '{\"param\":\"value\"}'\n # The output of the above command MUST be passed through tools like jq or head -c\n # or should be written to a file. Goal is to reduce content that the Agent prints.\n\n Code: from mcp_client import call_tool\n async def main():\n result = await call_tool(\"{server}\", \"{tool_a}\", body={\"param1\": \"value1\"})\n # In most cases, it is safe to assume response is a dict.\n # To know the dict keys, the Agent still needs to figure out the outputSchema.\n # The Agent MUST write the code to a file first before executing it.\n\n Code Mode MUST be used in following scenarios:\n\n 1. Reduce structured tool output by executing logic on top of it. Never present raw output.\n Agent: Now I know the inputSchema and outputSchema of tool_a, let me enter Code Mode.\n\n from mcp_client import call_tool\n from collections import Counter\n result = await call_tool(\"{server}\", \"{tool_a}\", body={\"param1\": \"value1\"})\n print(Counter(r[\"a\"] for r in result[\"b\"] if r[\"c\"])) # Here we need outputSchema to know a, b and c exists.\n\n 2. Piping result of one tool call to another tool request. Never present raw output.\n Agent: Now I know the inputSchema and outputSchema of tool1, let me enter Code Mode.\n\n from mcp_client import call_tool\n result1 = await call_tool(\"{server}\", \"{tool1}\", body={\"param1\": \"value1\"})\n result2 = await call_tool(\"{server}\", \"{tool2}\", body={\"param2\": result1[\"value1\"]}) # Here we need outputSchema to know value1 exists.\n print(result2) # Note in this case, we do not need outputSchema of result2 as we are not using any fields.\n\n The Agent MUST NOT use Code Mode just to print the full raw response of a tool. The Agent MUST call the tool directly in this case, there are other mechanisms in place to ensure\n large tool call outputs are not loaded in context.\n \n The Agent must not use Code Mode in the following patterns:\n from mcp_client import call_tool\n import json\n result = await call_tool(\"{server}\", \"{tool}\", body={\"param1\": \"value1\"})\n print(result) # Never do this. Call tool without Code Mode.\n print(json.dumps(result, ...)) # Never do this. Call tool without Code Mode.\n print(result[\"a\"][:100]) # Never do this. Call tool without Code Mode.\n\n mcp-client call-tool {server} {tool} '{\"param\":\"value\"}' > data && cat data # Never do this. Call tool without Code Mode.\n `,\n );\n }\n\n private get requiredSandboxInfo(): SandboxInfo {\n if (!this.existingSandboxInfo) {\n throw new Error('Sandbox info not available');\n }\n return this.existingSandboxInfo;\n }\n\n private async ensureSandboxCreated(): Promise<{\n sandboxInfo: SandboxInfo;\n sandboxCreated: SandboxInfo | undefined;\n }> {\n if (this.existingSandboxInfo) {\n return { sandboxInfo: this.existingSandboxInfo, sandboxCreated: undefined };\n }\n // Provider returns camelCase `{ sandboxId }`; rename to the snake_case\n // `SandboxInfo` shape used everywhere downstream (Redis JSON, wire event,\n // in-memory state).\n this.sandboxCreationPromise ??= this.provider\n .createSandbox()\n .then(({ sandboxId }) => {\n validateSandboxOwnedByTenant(sandboxId, this.tenantName);\n return { sandbox_id: sandboxId };\n })\n .catch((e: unknown) => {\n this.sandboxCreationPromise = undefined;\n throw e;\n });\n\n const sandboxInfo = await this.sandboxCreationPromise;\n // Concurrent callers may both await the same creation promise; only the first\n // should report sandboxCreated. Read via a local to avoid control-flow narrowing\n // that treats existingSandboxInfo as always undefined after the early return above.\n const prior = this.existingSandboxInfo as SandboxInfo | undefined;\n const isNew = prior === undefined;\n this.existingSandboxInfo = sandboxInfo;\n return { sandboxInfo, sandboxCreated: isNew ? sandboxInfo : undefined };\n }\n\n private async handleExec(input: SandboxExecInput): Promise<CallToolResponse> {\n const { sandboxInfo, sandboxCreated } = await this.ensureSandboxCreated();\n const sandboxCreatedFlag = Boolean(sandboxCreated);\n try {\n await this.ensureSandboxInitialized();\n } catch (e) {\n this.logger.error('Sandbox initialization failed', extractErrorLogFields(e));\n const message = e instanceof Error ? e.message : 'Sandbox initialization failed';\n return toolResultResponse({\n text: `Sandbox initialization failed: ${message}`,\n isError: true,\n overrides: { sandboxCreated: sandboxCreatedFlag, sandboxInfo },\n });\n }\n const bridge = await this.ensureNatsBridgeConnected(sandboxInfo.sandbox_id);\n const mcpClientEnv = injectMCPClientEnv({\n env: input.env,\n mcpServers: this.buildMcpServersEnvelope(),\n execExtraEnv: this.execExtraEnv,\n natsBridgeSubjectPrefix: bridge?.subjectPrefix,\n natsRequestTimeoutSeconds: this.natsRequestTimeoutSeconds,\n });\n const gitAuthEnv =\n this.resolvedGitCredentialsContent !== null\n ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(sandboxInfo.sandbox_id))\n : {};\n const env = { ...mcpClientEnv, ...gitAuthEnv };\n\n const result = await this.provider.exec({\n sandboxId: sandboxInfo.sandbox_id,\n command: input.command,\n cwd: input.cwd,\n env,\n });\n\n return {\n result: {\n content: [{ type: 'text', text: JSON.stringify(result) }],\n isError: !result.success,\n },\n wasInitialized: undefined,\n sandboxCreated: sandboxCreatedFlag,\n sandboxInfo,\n };\n }\n\n async getToolResultDumpDir(): Promise<{ dir: string; sandboxCreated: SandboxInfo | undefined }> {\n const { sandboxCreated } = await this.ensureSandboxCreated();\n const dir = this.provider.getToolResultDumpDir(this.requiredSandboxInfo.sandbox_id).replace(/\\/+$/, '');\n return { dir, sandboxCreated };\n }\n\n async uploadFile(params: {\n targetDir: string;\n fileName: string;\n content: Buffer;\n }): Promise<{ filePath: string; sandboxCreated: SandboxInfo | undefined }> {\n const { sandboxCreated } = await this.ensureSandboxCreated();\n await this.ensureSandboxInitialized();\n const { sandbox_id: sandboxId } = this.requiredSandboxInfo;\n const fileName = params.fileName.replace(/^\\/+/, '');\n const targetDir = params.targetDir.replace(/\\/+$/, '');\n const filePath = `${targetDir}/${fileName}`;\n await this.provider.uploadFile({ sandboxId, remotePath: filePath, content: params.content });\n return { filePath, sandboxCreated };\n }\n\n async uploadUserFile(input: { fileName: string; content: Buffer; mime: string }): Promise<SandboxStoredFile> {\n validateNoPathTraversal(input.fileName);\n const result = await this.uploadFile({\n targetDir: Sandbox.FILE_UPLOADS_DIR,\n fileName: input.fileName,\n content: input.content,\n });\n return {\n filePath: result.filePath,\n ...(result.sandboxCreated && { sandboxCreated: result.sandboxCreated }),\n };\n }\n\n async writeArtifact(input: {\n fileName: string;\n content: Buffer;\n sourceTool?: MappedMCPTool | undefined;\n }): Promise<SandboxStoredFile> {\n validateNoPathTraversal(input.fileName);\n const { dir, sandboxCreated: dumpDirCreated } = await this.getToolResultDumpDir();\n const result = await this.uploadFile({\n targetDir: dir,\n fileName: input.fileName,\n content: input.content,\n });\n const sandboxCreated = dumpDirCreated ?? result.sandboxCreated;\n return {\n filePath: result.filePath,\n ...(sandboxCreated && { sandboxCreated }),\n };\n }\n\n /**\n * Upload the MCP client Python script to the sandbox on the first tool call.\n * The sandbox filesystem is persistent within a session, so this only needs to run once.\n */\n private async ensureSandboxInitialized(): Promise<void> {\n this.sandboxInitPromise ??= this.initSandboxEnvironment().catch((e: unknown) => {\n this.sandboxInitPromise = undefined;\n throw e;\n });\n await this.sandboxInitPromise;\n }\n\n private async writeGitCredentials(): Promise<void> {\n const sandboxId = this.requiredSandboxInfo.sandbox_id;\n const credentialsPath = this.provider.getGitCredentialsPath(sandboxId);\n const result = await this.provider.exec({\n sandboxId,\n command: buildSyncGitCredentialsCommand(this.resolvedGitCredentialsContent, credentialsPath),\n });\n ensureExecSuccess(result);\n }\n\n private async initSandboxEnvironment(): Promise<void> {\n const toolResultDumpDir = this.provider.getToolResultDumpDir(this.requiredSandboxInfo.sandbox_id);\n\n this.logger.info('Uploading MCP client script and preparing skills directory in sandbox');\n\n const initSteps = [\n `mkdir -p ${MCP_CLIENT_DIR} ${Sandbox.FILE_UPLOADS_DIR} ${toolResultDumpDir} ${SKILLS_DIR}`,\n `rm -f ${MCP_CLIENT_PATH}`,\n `echo '${this.mcpClientScriptBase64}' | base64 -d > ${MCP_CLIENT_PATH}`,\n // Make executable + symlink onto PATH so `mcp-client` runs by name.\n `chmod 0555 ${MCP_CLIENT_PATH}`,\n `ln -sf ${MCP_CLIENT_PATH} ${MCP_CLIENT_BIN_SYMLINK}`,\n ];\n\n // Fold skill installation into this single init exec. The mounter returns a declarative\n // command + env + timeout; runs even when empty so its downloader can prune a reused sandbox.\n const skillInit = this.skillMounter?.getSandboxInit();\n if (skillInit) {\n initSteps.push(skillInit.command);\n }\n\n const script = initSteps.join(' && ');\n const result = await this.provider.exec({\n sandboxId: this.requiredSandboxInfo.sandbox_id,\n command: script,\n env: skillInit?.env,\n timeoutSeconds: skillInit?.timeoutSeconds,\n });\n ensureExecSuccess(result);\n this.logger.info(\n `Sandbox initialized: MCP client at ${MCP_CLIENT_PATH} (symlinked to ${MCP_CLIENT_BIN_SYMLINK}); skills dir ${SKILLS_DIR}`,\n );\n\n await this.writeGitCredentials();\n }\n\n /**\n * Lazily connect the sandbox→gateway NATS bridge. Single-flight and idempotent.\n * Skipped when there are no MCP servers exposed to code mode (nothing to bridge). Connect\n * failures resolve to `undefined` (no NATS env for that exec); mcp_client then errors at call\n * time — there is no HTTPS fallback.\n */\n private async ensureNatsBridgeConnected(sandboxId: string): Promise<SandboxNatsBridge | undefined> {\n // No MCP servers means the bridge has nothing to dispatch to. Avoid the connect cost.\n if (this.codeExecToolSets.length === 0) return undefined;\n this.natsBridgePromise ??= this.connectNatsBridge(sandboxId).catch((e: unknown) => {\n // Connect-level errors (network, timeout, broker not up) are not sticky: a later exec\n // may succeed (e.g. after sandbox warmup). Wipe the cached promise so retries happen.\n this.logger.error('Sandbox NATS bridge connect failed', {\n ...extractErrorLogFields(e),\n sandboxId,\n });\n this.natsBridgePromise = undefined;\n return undefined;\n });\n return this.natsBridgePromise;\n }\n\n private async connectNatsBridge(sandboxId: string): Promise<SandboxNatsBridge> {\n const wsUrl = await this.provider.getNatsBridgeUrl(sandboxId);\n const toolSets = new Map<string, IToolSet>();\n for (const server of this.codeExecToolSets) {\n toolSets.set(server.name, server);\n }\n const bridge = await SandboxNatsBridge.connect({ url: wsUrl, toolSets, logger: this.logger });\n this.logger.info('Sandbox NATS bridge connected', {\n sandboxId,\n toolSetCount: toolSets.size,\n });\n this.attachBridgeInvalidationOnClose(bridge, sandboxId);\n return bridge;\n }\n\n private attachBridgeInvalidationOnClose(bridge: SandboxNatsBridge, sandboxId: string): void {\n const cachedPromise = this.natsBridgePromise;\n // fire and forget\n void bridge.whenClosed().then(() => {\n if (this.natsBridgePromise === cachedPromise) {\n this.natsBridgePromise = undefined;\n this.logger.info('Sandbox NATS bridge closed; cache invalidated, next exec will reconnect', { sandboxId });\n }\n });\n }\n\n // Tears down per-Sandbox resources. Awaits the in-flight connect (if any) and explicitly\n // closes the bridge — dropping the field alone would leak the WS socket and live\n // subscriptions, and orphan a bridge that finishes connecting after close() returned.\n async close(): Promise<void> {\n const pendingPromise = this.natsBridgePromise;\n this.natsBridgePromise = undefined;\n if (!pendingPromise) return;\n let bridge: SandboxNatsBridge | undefined;\n try {\n bridge = await pendingPromise;\n } catch {\n // Connect-error path already logged inside ensureNatsBridgeConnected's .catch.\n }\n if (!bridge) return;\n try {\n await bridge.close();\n } catch (e) {\n this.logger.warn('Error closing sandbox NATS bridge', extractErrorLogFields(e));\n }\n }\n}\n"],"mappings":"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","names":["import_constants","dedent"]}
1
+ {"version":3,"sources":["../../../src/core/sandbox/Sandbox.ts"],"sourcesContent":["import { context, propagation } from '@opentelemetry/api';\nimport dedent from 'dedent';\nimport type { Logger } from 'winston';\nimport { z } from 'zod';\nimport { InstructionBuilder } from '../InstructionBuilder';\nimport { estimateTokensForString } from '../llm/usage';\nimport type { MappedMCPTool } from '../mcp/convertMCPServers';\nimport { toolResultResponse, type CallToolResponse, type IToolSet } from '../mcp/IMCPServer';\nimport { defineTool, LocalToolMCP } from '../mcp/LocalToolMCP';\nimport {\n DEFERRED_TOOLS_SERVER_ID,\n GET_TOOL_INFO_NAME,\n GET_TOOL_OUTPUT_SCHEMA_NAME,\n LIST_TOOLS_NAME,\n} from '../runtime/DeferredTool';\nimport type { AgentTracing } from '../tracing/AgentTracing';\nimport { extractErrorLogFields } from '../util/errorLogFields';\nimport { CodeModeDispatcher } from './codeMode/CodeModeDispatcher';\nimport type { CodeModeTransport } from './codeMode/CodeModeTransport';\nimport { SANDBOX_FILE_UPLOADS_DIR } from './constants';\nimport { ensureExecSuccess, shellEscape, type SandboxProvider } from './provider/Provider';\nimport { validateNoPathTraversal, validateSandboxOwnedByTenant } from './SandboxErrors';\nimport { sandboxScripts } from './sandboxScripts.gen';\n// Import submodules, not the ./skills barrel, to avoid a cycle (the mounters import from Sandbox).\nimport { SKILLS_DIR } from './skills/constants';\nimport type { ISkillMounter } from './skills/ISkillMounter';\n\nexport interface SandboxInfo {\n sandbox_id: string;\n}\n\n// Downloader/setup scripts can run longer than a normal exec.\nexport const SKILL_DOWNLOAD_TIMEOUT_SECONDS = 180;\n\n// Keeps the sandbox-side NATS wait longer than the host's own MCP deadline, so the host\n// surfaces the real MCP error instead of the bridge client giving up first.\nconst NATS_REQUEST_TIMEOUT_BUFFER_SECONDS = 30;\n\n// Write a script (base64-encoded, never interpolated raw) to a path and run it. Skill mounters reuse it.\nexport function buildWriteAndRunScriptCommand(params: { scriptPath: string; scriptContent: string }): string {\n const b64 = Buffer.from(params.scriptContent, 'utf-8').toString('base64');\n return [\n `mkdir -p \"$(dirname ${params.scriptPath})\"`,\n `rm -f ${params.scriptPath}`,\n `echo ${shellEscape(b64)} | base64 -d > ${params.scriptPath}`,\n `chmod a-w ${params.scriptPath}`,\n `python3 ${params.scriptPath}`,\n ].join(' && ');\n}\n\n/** Write or clear the git credential-store file at an absolute path (no global git config mutation). */\nfunction buildSyncGitCredentialsCommand(credentialsContent: string | null, credentialsPath: string): string {\n if (credentialsContent === null) {\n return `rm -f ${credentialsPath}`;\n }\n // Base64 avoids interpolating credentials directly into the shell command.\n const b64 = Buffer.from(credentialsContent, 'utf-8').toString('base64');\n return (\n `mkdir -p \"$(dirname ${credentialsPath})\" && ` +\n `echo '${b64}' | base64 -d > ${credentialsPath} && ` +\n `chmod 600 ${credentialsPath}`\n );\n}\n\n/**\n * Process-scoped credential.helper via GIT_CONFIG_* (avoids shared ~/.gitconfig).\n * Required for TFY sandbox where many logical sandboxes share one pod/HOME.\n */\nfunction buildGitCredentialHelperEnv(credentialsPath: string): Record<string, string> {\n return {\n GIT_CONFIG_COUNT: '1',\n GIT_CONFIG_KEY_0: 'credential.helper',\n GIT_CONFIG_VALUE_0: `store --file ${credentialsPath}`,\n };\n}\n\nexport interface SandboxStoredFile {\n filePath: string;\n sandboxCreated?: SandboxInfo | undefined;\n}\n\nexport interface SandboxOptions {\n provider: SandboxProvider;\n existingSandboxId?: string | undefined;\n skillMounter?: ISkillMounter | undefined;\n fileDownloadEnabled?: boolean | undefined;\n /** Pre-resolved credential-store file content (null = clear / no git auth). */\n resolvedGitCredentialsContent?: string | null | undefined;\n /**\n * Blocks destructive tools in code mode so they go through the approval flow\n * instead. Must be `true` — approvals are always enabled (the kill switch is gone).\n */\n blockDestructiveToolsInCodeMode: true;\n /** Used to derive the Code Mode NATS wait as request + connect. */\n mcpRequestTimeoutMs: number;\n mcpConnectTimeoutMs: number;\n execExtraEnv?: Readonly<Record<string, string>> | undefined;\n tracing: AgentTracing;\n logger: Logger;\n}\n\nexport const SANDBOX_EXEC_TOOL_NAME = 'exec';\nconst SANDBOX_MCP_REMINDER_TAG = 'sandbox-mcp-code-mode';\nconst SANDBOX_FILE_OUTPUT_TAG = 'sandbox-file-output';\nexport const SANDBOX_SCHEMA_INFER_TAG = 'sandbox-schema-infer';\nconst SANDBOX_FILE_UPLOADS_TAG = 'sandbox-file-uploads';\n\n// Stable directory inside the sandbox where the MCP client library is uploaded.\n// MCP client upload dir. Two lookup channels:\n// - Python imports → PYTHONPATH points here (set by injectMCPClientEnv).\n// - Shell `mcp-client` → symlinked into MCP_CLIENT_BIN_SYMLINK (on default PATH);\n// basename drops `.py` so the agent doesn't reflexively prefix with `python`.\nconst MCP_CLIENT_DIR = '/opt/tfy/mcp-client';\nconst MCP_CLIENT_PATH = `${MCP_CLIENT_DIR}/mcp_client.py`;\nconst MCP_CLIENT_BIN_SYMLINK = '/usr/local/bin/mcp-client';\n\n// Per-server config sent to mcp_client.py via TFY_MCP_SERVERS.\ninterface SandboxMcpServerConfig {\n allowed_tools: string[];\n}\n\n// Snapshots the active W3C trace context (`traceparent` + optional `tracestate`) into env\n// vars consumed by mcp_client.py. Read with TFY_TRACEPARENT / TFY_TRACESTATE on the sandbox\n// side and attached as NATS message headers; the bridge extracts them on each message so the\n// resulting MCP spans nest under the originating Sandbox: exec span.\nfunction injectTraceContextEnv(): Record<string, string> {\n const carrier: Record<string, string> = {};\n propagation.inject(context.active(), carrier);\n const env: Record<string, string> = {};\n if (carrier['traceparent']) {\n env['TFY_TRACEPARENT'] = carrier['traceparent'];\n }\n if (carrier['tracestate']) {\n env['TFY_TRACESTATE'] = carrier['tracestate'];\n }\n return env;\n}\n\n/**\n * Injects environment variables required for mcp_client.py into sandbox_exec arguments.\n * Transport-specific vars (NATS URL/prefix/timeout) come from `codeModeEnv` via transport.start().\n */\nfunction injectMCPClientEnv(params: {\n env?: Record<string, string> | undefined;\n mcpServers: Record<string, SandboxMcpServerConfig>;\n execExtraEnv?: Readonly<Record<string, string>> | undefined;\n codeModeEnv?: Record<string, string> | undefined;\n}): Record<string, string> {\n const codeModeEnv = params.codeModeEnv ?? {};\n const hasCodeModeTransport = Object.keys(codeModeEnv).length > 0;\n return {\n ...(params.execExtraEnv ?? {}),\n ...(params.env ?? {}),\n PYTHONPATH: MCP_CLIENT_DIR,\n ...(Object.keys(params.mcpServers).length > 0 && {\n TFY_MCP_SERVERS: Buffer.from(JSON.stringify(params.mcpServers)).toString('base64'),\n }),\n ...codeModeEnv,\n ...(hasCodeModeTransport && {\n // W3C trace context captured per-exec so each Code Mode request carries the originating\n // Sandbox: exec span as parent.\n ...injectTraceContextEnv(),\n }),\n // Approvals are always enabled: destructive tools cannot run in code mode.\n TFY_ENABLE_AGENT_APPROVALS: 'true',\n };\n}\n\nconst sandboxExecSchema = z.object({\n intent: z\n .string()\n .describe(\n 'A brief, user-facing explanation of the purpose of this command. Avoid technical jargon and code details.',\n ),\n command: z.string().describe('The shell command to execute in the sandbox.'),\n cwd: z.string().optional().describe('Working directory for command execution.'),\n env: z.record(z.string(), z.string()).optional().describe('Additional environment variables to set.'),\n});\n\nconst SANDBOX_EXEC_DESCRIPTION = `Execute shell commands in a persistent sandbox environment.\nThe sandbox persists across calls within the same session, allowing stateful operations.\nPre-installed: Python 3.13, pydantic, git, curl, helm, jq, ripgrep, genson.\nIMPORTANT: The Agent must never list, print, or expose environment variables as they contain sensitive credentials.\nIMPORTANT: Never read or expose any git credential files or ~/.git-credentials.\n`;\n\nexport function createSandboxLargeToolResponseGuidance(): string {\n return `For use cases where the Agent needs a subset of fields from the MCP response or needs deterministic processing, write code with the provided MCP client and use <${SANDBOX_MCP_REMINDER_TAG}>.`;\n}\n\nexport const SANDBOX_MCP_SERVER_ID = 'sandbox';\ntype SandboxExecInput = z.infer<typeof sandboxExecSchema>;\n\nexport class Sandbox extends LocalToolMCP {\n readonly name = SANDBOX_MCP_SERVER_ID;\n readonly displayName = 'Sandbox';\n override readonly description = 'Persistent sandbox environment for code execution';\n static readonly FILE_UPLOADS_DIR = SANDBOX_FILE_UPLOADS_DIR;\n\n private readonly provider: SandboxProvider;\n private readonly existingSandboxId?: string | undefined;\n private readonly tenantName: string;\n private existingSandboxInfo: SandboxInfo | undefined;\n // Cached promise to prevent concurrent sub-agents from creating duplicate sandboxes.\n private sandboxCreationPromise?: Promise<SandboxInfo> | undefined;\n private sandboxInitPromise?: Promise<void> | undefined;\n private codeExecToolSets: readonly IToolSet[] = [];\n private readonly fileDownloadEnabled: boolean;\n private readonly requestTimeoutSeconds: number;\n private readonly execExtraEnv?: Readonly<Record<string, string>> | undefined;\n private readonly skillMounter?: ISkillMounter | undefined;\n private cachedSkillsSection?: string | undefined;\n private readonly mcpClientScriptBase64: string;\n private readonly logger: Logger;\n // Pre-resolved credential-store file content (null = clear / no git auth).\n private readonly resolvedGitCredentialsContent: string | null;\n private codeModeDispatcher: CodeModeDispatcher | undefined;\n private codeModeTransport: CodeModeTransport | undefined;\n\n private tools = [\n defineTool({\n name: SANDBOX_EXEC_TOOL_NAME,\n description: SANDBOX_EXEC_DESCRIPTION,\n schema: sandboxExecSchema,\n handler: input => this.handleExec(input),\n }),\n ];\n\n constructor(options: SandboxOptions) {\n super({ tracing: options.tracing });\n this.provider = options.provider;\n this.existingSandboxId = options.existingSandboxId;\n this.tenantName = options.execExtraEnv?.['TFY_TENANT_NAME'] ?? '';\n this.skillMounter = options.skillMounter;\n this.fileDownloadEnabled = options.fileDownloadEnabled ?? false;\n const mcpBoundTimeoutMs = options.mcpRequestTimeoutMs + options.mcpConnectTimeoutMs;\n this.requestTimeoutSeconds = Math.ceil(mcpBoundTimeoutMs / 1000) + NATS_REQUEST_TIMEOUT_BUFFER_SECONDS;\n this.execExtraEnv = options.execExtraEnv;\n // Scripts are internal to Sandbox: the upload paths, env contract, and prompt\n // text are all hardcoded here, so injecting different content was never a\n // real extension point. Consumers don't see or provide them.\n this.mcpClientScriptBase64 = Buffer.from(sandboxScripts.mcpClient, 'utf-8').toString('base64');\n this.logger = options.logger.child({ module: 'Sandbox' });\n this.resolvedGitCredentialsContent = options.resolvedGitCredentialsContent ?? null;\n\n if (this.existingSandboxId) {\n validateSandboxOwnedByTenant(this.existingSandboxId, this.tenantName);\n this.existingSandboxInfo = { sandbox_id: this.existingSandboxId };\n }\n }\n\n private buildMcpServersEnvelope(): Record<string, SandboxMcpServerConfig> {\n const out: Record<string, SandboxMcpServerConfig> = {};\n for (const server of this.codeExecToolSets) {\n const allowedTools = server.getAllowedToolNamesForSandbox?.() ?? [];\n out[server.name] = { allowed_tools: allowedTools };\n }\n return out;\n }\n\n protected getTools() {\n return this.tools;\n }\n\n configureCodeMode(servers: readonly IToolSet[]): void {\n if (!servers.length) {\n return;\n }\n if (this.codeModeDispatcher !== undefined || this.codeModeTransport !== undefined) {\n throw new Error('Code Mode is already configured for this Sandbox');\n }\n this.codeExecToolSets = servers;\n this.codeModeDispatcher = new CodeModeDispatcher({ toolSets: servers, logger: this.logger });\n this.codeModeTransport = this.provider.createCodeModeTransport();\n }\n\n estimateSkillsTokens(): number {\n return Math.round(estimateTokensForString(this.renderSkillsSection()));\n }\n\n // Single source for the <skills> section, so the prompt and the token estimate can't drift.\n private renderSkillsSection(): string {\n if (this.cachedSkillsSection === undefined) {\n const skills = new InstructionBuilder('skills');\n this.skillMounter?.instruction(skills);\n this.cachedSkillsSection = skills.build();\n }\n return this.cachedSkillsSection;\n }\n\n buildInstruction(builder: InstructionBuilder): void {\n const providerInstructions = this.provider.getAdditionalInstructions();\n\n const sandboxInstructions = builder.beginSection('sandbox');\n sandboxInstructions.addContent('The Agent has access to a persistent sandbox environment for executing code.');\n sandboxInstructions.addContent('The Agent must NOT read or modify any git credential files.');\n\n this.buildSchemaSection(sandboxInstructions);\n this.buildSkillsSection(sandboxInstructions);\n this.buildMCPSection(sandboxInstructions);\n this.buildFileUploadsSection(sandboxInstructions);\n\n if (this.fileDownloadEnabled) {\n this.buildFileOutputSection(sandboxInstructions);\n }\n\n if (providerInstructions) {\n sandboxInstructions.addContent(providerInstructions);\n }\n }\n\n private buildFileUploadsSection(builder: InstructionBuilder): void {\n builder.addSection(\n SANDBOX_FILE_UPLOADS_TAG,\n `User-uploaded files are placed in ${Sandbox.FILE_UPLOADS_DIR}/. The Agent must not modify files in this directory. Always create a copy at a different location and work on the copy.`,\n );\n }\n\n private buildSchemaSection(builder: InstructionBuilder): void {\n builder.addSection(\n SANDBOX_SCHEMA_INFER_TAG,\n dedent`\n To infer the schema of a file, the Agent MUST execute:\n head -c 200 file_path && echo \"==\" && genson file_path\n This serves two purpose:\n 1. The first 200 characters of the file is printed. Do NOT print more than 200 characters.\n 2. genson infers and returns JSON schema if the file is JSON.\n Even if the file is not JSON, (1) helps to take the next step in less number of turns\n `,\n );\n }\n\n private buildFileOutputSection(builder: InstructionBuilder): void {\n builder.addSection(\n SANDBOX_FILE_OUTPUT_TAG,\n dedent`\n ## File outputs\n\n The user does not have direct access to the sandbox filesystem. When the Agent wants to output a file to the user, it MUST:\n 1. Ensure that the file is present in the sandbox.\n 2. Then emit a fenced sandbox_artifacts block referencing the file.\n\n \\`\\`\\`sandbox_artifacts\n [Human-readable label](/absolute/path/to/file.ext)\n \\`\\`\\`\n\n For large outputs or content that can be generated through code, prefer writing to a file and emitting the sandbox_artifacts block.\n\n Rules:\n - Use absolute paths, not ~/ or relative paths.\n - One link per line. Markdown link syntax: [label](path).`,\n );\n }\n\n private buildSkillsSection(builder: InstructionBuilder): void {\n builder.addContent(this.renderSkillsSection());\n }\n\n private buildMCPSection(builder: InstructionBuilder): void {\n const toolSetNames = this.codeExecToolSets.map(m => m.name).join(',');\n if (!toolSetNames) {\n return;\n }\n\n builder.addSection(\n SANDBOX_MCP_REMINDER_TAG,\n dedent`\n The following MCP servers are accessible for Code Mode from ${SANDBOX_EXEC_TOOL_NAME} via the pre-installed mcp_client module: ${toolSetNames}\n Tool and functions are same.\n Tool and MCP tools are same.\n\n Use \\`from mcp_client import call_tool\\` in code, or \\`mcp-client\\` in shell — both work from any directory with no setup.\n\n For deferred MCP servers, the Agent MUST:\n 1. Discover tools via ${LIST_TOOLS_NAME} from ${DEFERRED_TOOLS_SERVER_ID}. Never call ${GET_TOOL_OUTPUT_SCHEMA_NAME}.\n 2. Discover inputSchema, outputSchema via ${GET_TOOL_INFO_NAME} for the selected tools.\n\n For non-deferred MCP servers, the Agent MUST:\n 1. Discover outputSchema via ${GET_TOOL_OUTPUT_SCHEMA_NAME} for the selected tools.\n\n For both deferred and non-deferred if outputSchema is absent,\n the Agent MUST say: \"Given the MCP Server does not define an outputSchema let me figure it out first before entering Code Mode.\"\n mcp-client call-tool {server} {tool} '{\"param\":\"value\"}' > file && ${SANDBOX_SCHEMA_INFER_TAG}.\n the Agent MUST execute a single command for above.\n If the Agent does not get the outputSchema, the Agent will encounters scenarios like:\n Agent: \"Let me fix the code - it seems the x might be a string rather than an object in some cases:\"\n The Agent MUST not face the above scenario.\n \n Only after the Agent has the above details, it can enter Code Mode.\n Agent: Now I know the inputSchema and outputSchema of tool_a, let me enter Code Mode.\n\n CLI: mcp-client call-tool {server} {tool_a} '{\"param\":\"value\"}'\n # The output of the above command MUST be passed through tools like jq or head -c\n # or should be written to a file. Goal is to reduce content that the Agent prints.\n\n Code: from mcp_client import call_tool\n async def main():\n result = await call_tool(\"{server}\", \"{tool_a}\", body={\"param1\": \"value1\"})\n # In most cases, it is safe to assume response is a dict.\n # To know the dict keys, the Agent still needs to figure out the outputSchema.\n # The Agent MUST write the code to a file first before executing it.\n\n Code Mode MUST be used in following scenarios:\n\n 1. Reduce structured tool output by executing logic on top of it. Never present raw output.\n Agent: Now I know the inputSchema and outputSchema of tool_a, let me enter Code Mode.\n\n from mcp_client import call_tool\n from collections import Counter\n result = await call_tool(\"{server}\", \"{tool_a}\", body={\"param1\": \"value1\"})\n print(Counter(r[\"a\"] for r in result[\"b\"] if r[\"c\"])) # Here we need outputSchema to know a, b and c exists.\n\n 2. Piping result of one tool call to another tool request. Never present raw output.\n Agent: Now I know the inputSchema and outputSchema of tool1, let me enter Code Mode.\n\n from mcp_client import call_tool\n result1 = await call_tool(\"{server}\", \"{tool1}\", body={\"param1\": \"value1\"})\n result2 = await call_tool(\"{server}\", \"{tool2}\", body={\"param2\": result1[\"value1\"]}) # Here we need outputSchema to know value1 exists.\n print(result2) # Note in this case, we do not need outputSchema of result2 as we are not using any fields.\n\n The Agent MUST NOT use Code Mode just to print the full raw response of a tool. The Agent MUST call the tool directly in this case, there are other mechanisms in place to ensure\n large tool call outputs are not loaded in context.\n \n The Agent must not use Code Mode in the following patterns:\n from mcp_client import call_tool\n import json\n result = await call_tool(\"{server}\", \"{tool}\", body={\"param1\": \"value1\"})\n print(result) # Never do this. Call tool without Code Mode.\n print(json.dumps(result, ...)) # Never do this. Call tool without Code Mode.\n print(result[\"a\"][:100]) # Never do this. Call tool without Code Mode.\n\n mcp-client call-tool {server} {tool} '{\"param\":\"value\"}' > data && cat data # Never do this. Call tool without Code Mode.\n `,\n );\n }\n\n private get requiredSandboxInfo(): SandboxInfo {\n if (!this.existingSandboxInfo) {\n throw new Error('Sandbox info not available');\n }\n return this.existingSandboxInfo;\n }\n\n private async ensureSandboxCreated(): Promise<{\n sandboxInfo: SandboxInfo;\n sandboxCreated: SandboxInfo | undefined;\n }> {\n if (this.existingSandboxInfo) {\n return { sandboxInfo: this.existingSandboxInfo, sandboxCreated: undefined };\n }\n // Provider returns camelCase `{ sandboxId }`; rename to the snake_case\n // `SandboxInfo` shape used everywhere downstream (Redis JSON, wire event,\n // in-memory state).\n this.sandboxCreationPromise ??= this.provider\n .createSandbox()\n .then(({ sandboxId }) => {\n validateSandboxOwnedByTenant(sandboxId, this.tenantName);\n return { sandbox_id: sandboxId };\n })\n .catch((e: unknown) => {\n this.sandboxCreationPromise = undefined;\n throw e;\n });\n\n const sandboxInfo = await this.sandboxCreationPromise;\n // Concurrent callers may both await the same creation promise; only the first\n // should report sandboxCreated. Read via a local to avoid control-flow narrowing\n // that treats existingSandboxInfo as always undefined after the early return above.\n const prior = this.existingSandboxInfo as SandboxInfo | undefined;\n const isNew = prior === undefined;\n this.existingSandboxInfo = sandboxInfo;\n return { sandboxInfo, sandboxCreated: isNew ? sandboxInfo : undefined };\n }\n\n private async handleExec(input: SandboxExecInput): Promise<CallToolResponse> {\n const { sandboxInfo, sandboxCreated } = await this.ensureSandboxCreated();\n const sandboxCreatedFlag = Boolean(sandboxCreated);\n try {\n await this.ensureSandboxInitialized();\n } catch (e) {\n this.logger.error('Sandbox initialization failed', extractErrorLogFields(e));\n const message = e instanceof Error ? e.message : 'Sandbox initialization failed';\n return toolResultResponse({\n text: `Sandbox initialization failed: ${message}`,\n isError: true,\n overrides: { sandboxCreated: sandboxCreatedFlag, sandboxInfo },\n });\n }\n const codeModeEnv = await this.ensureCodeModeStarted(sandboxInfo.sandbox_id);\n const mcpClientEnv = injectMCPClientEnv({\n env: input.env,\n mcpServers: this.buildMcpServersEnvelope(),\n execExtraEnv: this.execExtraEnv,\n codeModeEnv,\n });\n const gitAuthEnv =\n this.resolvedGitCredentialsContent !== null\n ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(sandboxInfo.sandbox_id))\n : {};\n const env = { ...mcpClientEnv, ...gitAuthEnv };\n\n const result = await this.provider.exec({\n sandboxId: sandboxInfo.sandbox_id,\n command: input.command,\n cwd: input.cwd,\n env,\n });\n\n return {\n result: {\n content: [{ type: 'text', text: JSON.stringify(result) }],\n isError: !result.success,\n },\n wasInitialized: undefined,\n sandboxCreated: sandboxCreatedFlag,\n sandboxInfo,\n };\n }\n\n async getToolResultDumpDir(): Promise<{ dir: string; sandboxCreated: SandboxInfo | undefined }> {\n const { sandboxCreated } = await this.ensureSandboxCreated();\n const dir = this.provider.getToolResultDumpDir(this.requiredSandboxInfo.sandbox_id).replace(/\\/+$/, '');\n return { dir, sandboxCreated };\n }\n\n async uploadFile(params: {\n targetDir: string;\n fileName: string;\n content: Buffer;\n }): Promise<{ filePath: string; sandboxCreated: SandboxInfo | undefined }> {\n const { sandboxCreated } = await this.ensureSandboxCreated();\n await this.ensureSandboxInitialized();\n const { sandbox_id: sandboxId } = this.requiredSandboxInfo;\n const fileName = params.fileName.replace(/^\\/+/, '');\n const targetDir = params.targetDir.replace(/\\/+$/, '');\n const filePath = `${targetDir}/${fileName}`;\n await this.provider.uploadFile({ sandboxId, remotePath: filePath, content: params.content });\n return { filePath, sandboxCreated };\n }\n\n async uploadUserFile(input: { fileName: string; content: Buffer; mime: string }): Promise<SandboxStoredFile> {\n validateNoPathTraversal(input.fileName);\n const result = await this.uploadFile({\n targetDir: Sandbox.FILE_UPLOADS_DIR,\n fileName: input.fileName,\n content: input.content,\n });\n return {\n filePath: result.filePath,\n ...(result.sandboxCreated && { sandboxCreated: result.sandboxCreated }),\n };\n }\n\n async writeArtifact(input: {\n fileName: string;\n content: Buffer;\n sourceTool?: MappedMCPTool | undefined;\n }): Promise<SandboxStoredFile> {\n validateNoPathTraversal(input.fileName);\n const { dir, sandboxCreated: dumpDirCreated } = await this.getToolResultDumpDir();\n const result = await this.uploadFile({\n targetDir: dir,\n fileName: input.fileName,\n content: input.content,\n });\n const sandboxCreated = dumpDirCreated ?? result.sandboxCreated;\n return {\n filePath: result.filePath,\n ...(sandboxCreated && { sandboxCreated }),\n };\n }\n\n /**\n * Upload the MCP client Python script to the sandbox on the first tool call.\n * The sandbox filesystem is persistent within a session, so this only needs to run once.\n */\n private async ensureSandboxInitialized(): Promise<void> {\n this.sandboxInitPromise ??= this.initSandboxEnvironment().catch((e: unknown) => {\n this.sandboxInitPromise = undefined;\n throw e;\n });\n await this.sandboxInitPromise;\n }\n\n private async writeGitCredentials(): Promise<void> {\n const sandboxId = this.requiredSandboxInfo.sandbox_id;\n const credentialsPath = this.provider.getGitCredentialsPath(sandboxId);\n const result = await this.provider.exec({\n sandboxId,\n command: buildSyncGitCredentialsCommand(this.resolvedGitCredentialsContent, credentialsPath),\n });\n ensureExecSuccess(result);\n }\n\n private async initSandboxEnvironment(): Promise<void> {\n const toolResultDumpDir = this.provider.getToolResultDumpDir(this.requiredSandboxInfo.sandbox_id);\n\n this.logger.info('Uploading MCP client script and preparing skills directory in sandbox');\n\n const initSteps = [\n `mkdir -p ${MCP_CLIENT_DIR} ${Sandbox.FILE_UPLOADS_DIR} ${toolResultDumpDir} ${SKILLS_DIR}`,\n `rm -f ${MCP_CLIENT_PATH}`,\n `echo '${this.mcpClientScriptBase64}' | base64 -d > ${MCP_CLIENT_PATH}`,\n // Make executable + symlink onto PATH so `mcp-client` runs by name.\n `chmod 0555 ${MCP_CLIENT_PATH}`,\n `ln -sf ${MCP_CLIENT_PATH} ${MCP_CLIENT_BIN_SYMLINK}`,\n ];\n\n // Fold skill installation into this single init exec. The mounter returns a declarative\n // command + env + timeout; runs even when empty so its downloader can prune a reused sandbox.\n const skillInit = this.skillMounter?.getSandboxInit();\n if (skillInit) {\n initSteps.push(skillInit.command);\n }\n\n const script = initSteps.join(' && ');\n const result = await this.provider.exec({\n sandboxId: this.requiredSandboxInfo.sandbox_id,\n command: script,\n env: skillInit?.env,\n timeoutSeconds: skillInit?.timeoutSeconds,\n });\n ensureExecSuccess(result);\n this.logger.info(\n `Sandbox initialized: MCP client at ${MCP_CLIENT_PATH} (symlinked to ${MCP_CLIENT_BIN_SYMLINK}); skills dir ${SKILLS_DIR}`,\n );\n\n await this.writeGitCredentials();\n }\n\n /**\n * Lazily start Code Mode transport. Single-flight and idempotent inside the transport.\n * Skipped when code mode was never configured. Connect failures resolve to `undefined`\n * (no Code Mode env for that exec); mcp_client then errors at call time — no HTTPS fallback.\n */\n private async ensureCodeModeStarted(sandboxId: string): Promise<Record<string, string> | undefined> {\n const dispatcher = this.codeModeDispatcher;\n const transport = this.codeModeTransport;\n if (dispatcher === undefined || transport === undefined) {\n return undefined;\n }\n try {\n const { env } = await transport.start({\n codeModeDispatcher: dispatcher,\n sandboxId,\n requestTimeoutSeconds: this.requestTimeoutSeconds,\n });\n return env;\n } catch (e) {\n // Connect-level errors are not sticky: transport clears its session so a later exec may retry.\n this.logger.error('Code Mode transport start failed', {\n ...extractErrorLogFields(e),\n sandboxId,\n });\n return undefined;\n }\n }\n\n // Tears down per-Sandbox Code Mode resources. Dispatcher close first (in-flight requests get\n // source: transport), then transport.stop() — always safe whether start succeeded, failed, or never ran.\n async close(): Promise<void> {\n this.codeModeDispatcher?.close();\n this.codeModeDispatcher = undefined;\n const transport = this.codeModeTransport;\n this.codeModeTransport = undefined;\n if (transport === undefined) {\n return;\n }\n try {\n await transport.stop();\n } catch (e) {\n this.logger.warn('Error stopping Code Mode transport', extractErrorLogFields(e));\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAqC;AACrC,oBAAmB;AAEnB,iBAAkB;AAClB,gCAAmC;AACnC,mBAAwC;AAExC,wBAAyE;AACzE,0BAAyC;AACzC,0BAKO;AAEP,4BAAsC;AACtC,gCAAmC;AAEnC,uBAAyC;AACzC,sBAAqE;AACrE,2BAAsE;AACtE,4BAA+B;AAE/B,IAAAA,oBAA2B;AAQpB,IAAM,iCAAiC;AAI9C,IAAM,sCAAsC;AAGrC,SAAS,8BAA8B,QAA+D;AAC3G,QAAM,MAAM,OAAO,KAAK,OAAO,eAAe,OAAO,EAAE,SAAS,QAAQ;AACxE,SAAO;AAAA,IACL,uBAAuB,OAAO,UAAU;AAAA,IACxC,SAAS,OAAO,UAAU;AAAA,IAC1B,YAAQ,6BAAY,GAAG,CAAC,kBAAkB,OAAO,UAAU;AAAA,IAC3D,aAAa,OAAO,UAAU;AAAA,IAC9B,WAAW,OAAO,UAAU;AAAA,EAC9B,EAAE,KAAK,MAAM;AACf;AAGA,SAAS,+BAA+B,oBAAmC,iBAAiC;AAC1G,MAAI,uBAAuB,MAAM;AAC/B,WAAO,SAAS,eAAe;AAAA,EACjC;AAEA,QAAM,MAAM,OAAO,KAAK,oBAAoB,OAAO,EAAE,SAAS,QAAQ;AACtE,SACE,uBAAuB,eAAe,eAC7B,GAAG,mBAAmB,eAAe,iBACjC,eAAe;AAEhC;AAMA,SAAS,4BAA4B,iBAAiD;AACpF,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,kBAAkB;AAAA,IAClB,oBAAoB,gBAAgB,eAAe;AAAA,EACrD;AACF;AA2BO,IAAM,yBAAyB;AACtC,IAAM,2BAA2B;AACjC,IAAM,0BAA0B;AACzB,IAAM,2BAA2B;AACxC,IAAM,2BAA2B;AAOjC,IAAM,iBAAiB;AACvB,IAAM,kBAAkB,GAAG,cAAc;AACzC,IAAM,yBAAyB;AAW/B,SAAS,wBAAgD;AACvD,QAAM,UAAkC,CAAC;AACzC,yBAAY,OAAO,mBAAQ,OAAO,GAAG,OAAO;AAC5C,QAAM,MAA8B,CAAC;AACrC,MAAI,QAAQ,aAAa,GAAG;AAC1B,QAAI,iBAAiB,IAAI,QAAQ,aAAa;AAAA,EAChD;AACA,MAAI,QAAQ,YAAY,GAAG;AACzB,QAAI,gBAAgB,IAAI,QAAQ,YAAY;AAAA,EAC9C;AACA,SAAO;AACT;AAMA,SAAS,mBAAmB,QAKD;AACzB,QAAM,cAAc,OAAO,eAAe,CAAC;AAC3C,QAAM,uBAAuB,OAAO,KAAK,WAAW,EAAE,SAAS;AAC/D,SAAO;AAAA,IACL,GAAI,OAAO,gBAAgB,CAAC;AAAA,IAC5B,GAAI,OAAO,OAAO,CAAC;AAAA,IACnB,YAAY;AAAA,IACZ,GAAI,OAAO,KAAK,OAAO,UAAU,EAAE,SAAS,KAAK;AAAA,MAC/C,iBAAiB,OAAO,KAAK,KAAK,UAAU,OAAO,UAAU,CAAC,EAAE,SAAS,QAAQ;AAAA,IACnF;AAAA,IACA,GAAG;AAAA,IACH,GAAI,wBAAwB;AAAA;AAAA;AAAA,MAG1B,GAAG,sBAAsB;AAAA,IAC3B;AAAA;AAAA,IAEA,4BAA4B;AAAA,EAC9B;AACF;AAEA,IAAM,oBAAoB,aAAE,OAAO;AAAA,EACjC,QAAQ,aACL,OAAO,EACP;AAAA,IACC;AAAA,EACF;AAAA,EACF,SAAS,aAAE,OAAO,EAAE,SAAS,8CAA8C;AAAA,EAC3E,KAAK,aAAE,OAAO,EAAE,SAAS,EAAE,SAAS,0CAA0C;AAAA,EAC9E,KAAK,aAAE,OAAO,aAAE,OAAO,GAAG,aAAE,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS,0CAA0C;AACtG,CAAC;AAED,IAAM,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAO1B,SAAS,yCAAiD;AAC/D,SAAO,oKAAoK,wBAAwB;AACrM;AAEO,IAAM,wBAAwB;AAG9B,IAAM,UAAN,MAAM,iBAAgB,iCAAa;AAAA,EAC/B,OAAO;AAAA,EACP,cAAc;AAAA,EACL,cAAc;AAAA,EAChC,OAAgB,mBAAmB;AAAA,EAElB;AAAA,EACA;AAAA,EACA;AAAA,EACT;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA,mBAAwC,CAAC;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT;AAAA,EACS;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACT;AAAA,EACA;AAAA,EAEA,QAAQ;AAAA,QACd,gCAAW;AAAA,MACT,MAAM;AAAA,MACN,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,SAAS,WAAS,KAAK,WAAW,KAAK;AAAA,IACzC,CAAC;AAAA,EACH;AAAA,EAEA,YAAY,SAAyB;AACnC,UAAM,EAAE,SAAS,QAAQ,QAAQ,CAAC;AAClC,SAAK,WAAW,QAAQ;AACxB,SAAK,oBAAoB,QAAQ;AACjC,SAAK,aAAa,QAAQ,eAAe,iBAAiB,KAAK;AAC/D,SAAK,eAAe,QAAQ;AAC5B,SAAK,sBAAsB,QAAQ,uBAAuB;AAC1D,UAAM,oBAAoB,QAAQ,sBAAsB,QAAQ;AAChE,SAAK,wBAAwB,KAAK,KAAK,oBAAoB,GAAI,IAAI;AACnE,SAAK,eAAe,QAAQ;AAI5B,SAAK,wBAAwB,OAAO,KAAK,qCAAe,WAAW,OAAO,EAAE,SAAS,QAAQ;AAC7F,SAAK,SAAS,QAAQ,OAAO,MAAM,EAAE,QAAQ,UAAU,CAAC;AACxD,SAAK,gCAAgC,QAAQ,iCAAiC;AAE9E,QAAI,KAAK,mBAAmB;AAC1B,6DAA6B,KAAK,mBAAmB,KAAK,UAAU;AACpE,WAAK,sBAAsB,EAAE,YAAY,KAAK,kBAAkB;AAAA,IAClE;AAAA,EACF;AAAA,EAEQ,0BAAkE;AACxE,UAAM,MAA8C,CAAC;AACrD,eAAW,UAAU,KAAK,kBAAkB;AAC1C,YAAM,eAAe,OAAO,gCAAgC,KAAK,CAAC;AAClE,UAAI,OAAO,IAAI,IAAI,EAAE,eAAe,aAAa;AAAA,IACnD;AACA,WAAO;AAAA,EACT;AAAA,EAEU,WAAW;AACnB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,kBAAkB,SAAoC;AACpD,QAAI,CAAC,QAAQ,QAAQ;AACnB;AAAA,IACF;AACA,QAAI,KAAK,uBAAuB,UAAa,KAAK,sBAAsB,QAAW;AACjF,YAAM,IAAI,MAAM,kDAAkD;AAAA,IACpE;AACA,SAAK,mBAAmB;AACxB,SAAK,qBAAqB,IAAI,6CAAmB,EAAE,UAAU,SAAS,QAAQ,KAAK,OAAO,CAAC;AAC3F,SAAK,oBAAoB,KAAK,SAAS,wBAAwB;AAAA,EACjE;AAAA,EAEA,uBAA+B;AAC7B,WAAO,KAAK,UAAM,sCAAwB,KAAK,oBAAoB,CAAC,CAAC;AAAA,EACvE;AAAA;AAAA,EAGQ,sBAA8B;AACpC,QAAI,KAAK,wBAAwB,QAAW;AAC1C,YAAM,SAAS,IAAI,6CAAmB,QAAQ;AAC9C,WAAK,cAAc,YAAY,MAAM;AACrC,WAAK,sBAAsB,OAAO,MAAM;AAAA,IAC1C;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,iBAAiB,SAAmC;AAClD,UAAM,uBAAuB,KAAK,SAAS,0BAA0B;AAErE,UAAM,sBAAsB,QAAQ,aAAa,SAAS;AAC1D,wBAAoB,WAAW,8EAA8E;AAC7G,wBAAoB,WAAW,6DAA6D;AAE5F,SAAK,mBAAmB,mBAAmB;AAC3C,SAAK,mBAAmB,mBAAmB;AAC3C,SAAK,gBAAgB,mBAAmB;AACxC,SAAK,wBAAwB,mBAAmB;AAEhD,QAAI,KAAK,qBAAqB;AAC5B,WAAK,uBAAuB,mBAAmB;AAAA,IACjD;AAEA,QAAI,sBAAsB;AACxB,0BAAoB,WAAW,oBAAoB;AAAA,IACrD;AAAA,EACF;AAAA,EAEQ,wBAAwB,SAAmC;AACjE,YAAQ;AAAA,MACN;AAAA,MACA,qCAAqC,SAAQ,gBAAgB;AAAA,IAC/D;AAAA,EACF;AAAA,EAEQ,mBAAmB,SAAmC;AAC5D,YAAQ;AAAA,MACN;AAAA,MACA,cAAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQF;AAAA,EACF;AAAA,EAEQ,uBAAuB,SAAmC;AAChE,YAAQ;AAAA,MACN;AAAA,MACA,cAAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgBF;AAAA,EACF;AAAA,EAEQ,mBAAmB,SAAmC;AAC5D,YAAQ,WAAW,KAAK,oBAAoB,CAAC;AAAA,EAC/C;AAAA,EAEQ,gBAAgB,SAAmC;AACzD,UAAM,eAAe,KAAK,iBAAiB,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,GAAG;AACpE,QAAI,CAAC,cAAc;AACjB;AAAA,IACF;AAEA,YAAQ;AAAA,MACN;AAAA,MACA,cAAAA;AAAA,sEACgE,sBAAsB,6CAA6C,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gCAOrH,mCAAe,SAAS,4CAAwB,gBAAgB,+CAA2B;AAAA,oDACvE,sCAAkB;AAAA;AAAA;AAAA,uCAG/B,+CAA2B;AAAA;AAAA;AAAA;AAAA,6EAIW,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAmDjG;AAAA,EACF;AAAA,EAEA,IAAY,sBAAmC;AAC7C,QAAI,CAAC,KAAK,qBAAqB;AAC7B,YAAM,IAAI,MAAM,4BAA4B;AAAA,IAC9C;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,uBAGX;AACD,QAAI,KAAK,qBAAqB;AAC5B,aAAO,EAAE,aAAa,KAAK,qBAAqB,gBAAgB,OAAU;AAAA,IAC5E;AAIA,SAAK,2BAA2B,KAAK,SAClC,cAAc,EACd,KAAK,CAAC,EAAE,UAAU,MAAM;AACvB,6DAA6B,WAAW,KAAK,UAAU;AACvD,aAAO,EAAE,YAAY,UAAU;AAAA,IACjC,CAAC,EACA,MAAM,CAAC,MAAe;AACrB,WAAK,yBAAyB;AAC9B,YAAM;AAAA,IACR,CAAC;AAEH,UAAM,cAAc,MAAM,KAAK;AAI/B,UAAM,QAAQ,KAAK;AACnB,UAAM,QAAQ,UAAU;AACxB,SAAK,sBAAsB;AAC3B,WAAO,EAAE,aAAa,gBAAgB,QAAQ,cAAc,OAAU;AAAA,EACxE;AAAA,EAEA,MAAc,WAAW,OAAoD;AAC3E,UAAM,EAAE,aAAa,eAAe,IAAI,MAAM,KAAK,qBAAqB;AACxE,UAAM,qBAAqB,QAAQ,cAAc;AACjD,QAAI;AACF,YAAM,KAAK,yBAAyB;AAAA,IACtC,SAAS,GAAG;AACV,WAAK,OAAO,MAAM,qCAAiC,6CAAsB,CAAC,CAAC;AAC3E,YAAM,UAAU,aAAa,QAAQ,EAAE,UAAU;AACjD,iBAAO,sCAAmB;AAAA,QACxB,MAAM,kCAAkC,OAAO;AAAA,QAC/C,SAAS;AAAA,QACT,WAAW,EAAE,gBAAgB,oBAAoB,YAAY;AAAA,MAC/D,CAAC;AAAA,IACH;AACA,UAAM,cAAc,MAAM,KAAK,sBAAsB,YAAY,UAAU;AAC3E,UAAM,eAAe,mBAAmB;AAAA,MACtC,KAAK,MAAM;AAAA,MACX,YAAY,KAAK,wBAAwB;AAAA,MACzC,cAAc,KAAK;AAAA,MACnB;AAAA,IACF,CAAC;AACD,UAAM,aACJ,KAAK,kCAAkC,OACnC,4BAA4B,KAAK,SAAS,sBAAsB,YAAY,UAAU,CAAC,IACvF,CAAC;AACP,UAAM,MAAM,EAAE,GAAG,cAAc,GAAG,WAAW;AAE7C,UAAM,SAAS,MAAM,KAAK,SAAS,KAAK;AAAA,MACtC,WAAW,YAAY;AAAA,MACvB,SAAS,MAAM;AAAA,MACf,KAAK,MAAM;AAAA,MACX;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,QAAQ;AAAA,QACN,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,MAAM,EAAE,CAAC;AAAA,QACxD,SAAS,CAAC,OAAO;AAAA,MACnB;AAAA,MACA,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,uBAA0F;AAC9F,UAAM,EAAE,eAAe,IAAI,MAAM,KAAK,qBAAqB;AAC3D,UAAM,MAAM,KAAK,SAAS,qBAAqB,KAAK,oBAAoB,UAAU,EAAE,QAAQ,QAAQ,EAAE;AACtG,WAAO,EAAE,KAAK,eAAe;AAAA,EAC/B;AAAA,EAEA,MAAM,WAAW,QAI0D;AACzE,UAAM,EAAE,eAAe,IAAI,MAAM,KAAK,qBAAqB;AAC3D,UAAM,KAAK,yBAAyB;AACpC,UAAM,EAAE,YAAY,UAAU,IAAI,KAAK;AACvC,UAAM,WAAW,OAAO,SAAS,QAAQ,QAAQ,EAAE;AACnD,UAAM,YAAY,OAAO,UAAU,QAAQ,QAAQ,EAAE;AACrD,UAAM,WAAW,GAAG,SAAS,IAAI,QAAQ;AACzC,UAAM,KAAK,SAAS,WAAW,EAAE,WAAW,YAAY,UAAU,SAAS,OAAO,QAAQ,CAAC;AAC3F,WAAO,EAAE,UAAU,eAAe;AAAA,EACpC;AAAA,EAEA,MAAM,eAAe,OAAwF;AAC3G,sDAAwB,MAAM,QAAQ;AACtC,UAAM,SAAS,MAAM,KAAK,WAAW;AAAA,MACnC,WAAW,SAAQ;AAAA,MACnB,UAAU,MAAM;AAAA,MAChB,SAAS,MAAM;AAAA,IACjB,CAAC;AACD,WAAO;AAAA,MACL,UAAU,OAAO;AAAA,MACjB,GAAI,OAAO,kBAAkB,EAAE,gBAAgB,OAAO,eAAe;AAAA,IACvE;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,OAIW;AAC7B,sDAAwB,MAAM,QAAQ;AACtC,UAAM,EAAE,KAAK,gBAAgB,eAAe,IAAI,MAAM,KAAK,qBAAqB;AAChF,UAAM,SAAS,MAAM,KAAK,WAAW;AAAA,MACnC,WAAW;AAAA,MACX,UAAU,MAAM;AAAA,MAChB,SAAS,MAAM;AAAA,IACjB,CAAC;AACD,UAAM,iBAAiB,kBAAkB,OAAO;AAChD,WAAO;AAAA,MACL,UAAU,OAAO;AAAA,MACjB,GAAI,kBAAkB,EAAE,eAAe;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,2BAA0C;AACtD,SAAK,uBAAuB,KAAK,uBAAuB,EAAE,MAAM,CAAC,MAAe;AAC9E,WAAK,qBAAqB;AAC1B,YAAM;AAAA,IACR,CAAC;AACD,UAAM,KAAK;AAAA,EACb;AAAA,EAEA,MAAc,sBAAqC;AACjD,UAAM,YAAY,KAAK,oBAAoB;AAC3C,UAAM,kBAAkB,KAAK,SAAS,sBAAsB,SAAS;AACrE,UAAM,SAAS,MAAM,KAAK,SAAS,KAAK;AAAA,MACtC;AAAA,MACA,SAAS,+BAA+B,KAAK,+BAA+B,eAAe;AAAA,IAC7F,CAAC;AACD,2CAAkB,MAAM;AAAA,EAC1B;AAAA,EAEA,MAAc,yBAAwC;AACpD,UAAM,oBAAoB,KAAK,SAAS,qBAAqB,KAAK,oBAAoB,UAAU;AAEhG,SAAK,OAAO,KAAK,uEAAuE;AAExF,UAAM,YAAY;AAAA,MAChB,YAAY,cAAc,IAAI,SAAQ,gBAAgB,IAAI,iBAAiB,IAAI,4BAAU;AAAA,MACzF,SAAS,eAAe;AAAA,MACxB,SAAS,KAAK,qBAAqB,mBAAmB,eAAe;AAAA;AAAA,MAErE,cAAc,eAAe;AAAA,MAC7B,UAAU,eAAe,IAAI,sBAAsB;AAAA,IACrD;AAIA,UAAM,YAAY,KAAK,cAAc,eAAe;AACpD,QAAI,WAAW;AACb,gBAAU,KAAK,UAAU,OAAO;AAAA,IAClC;AAEA,UAAM,SAAS,UAAU,KAAK,MAAM;AACpC,UAAM,SAAS,MAAM,KAAK,SAAS,KAAK;AAAA,MACtC,WAAW,KAAK,oBAAoB;AAAA,MACpC,SAAS;AAAA,MACT,KAAK,WAAW;AAAA,MAChB,gBAAgB,WAAW;AAAA,IAC7B,CAAC;AACD,2CAAkB,MAAM;AACxB,SAAK,OAAO;AAAA,MACV,sCAAsC,eAAe,kBAAkB,sBAAsB,iBAAiB,4BAAU;AAAA,IAC1H;AAEA,UAAM,KAAK,oBAAoB;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,sBAAsB,WAAgE;AAClG,UAAM,aAAa,KAAK;AACxB,UAAM,YAAY,KAAK;AACvB,QAAI,eAAe,UAAa,cAAc,QAAW;AACvD,aAAO;AAAA,IACT;AACA,QAAI;AACF,YAAM,EAAE,IAAI,IAAI,MAAM,UAAU,MAAM;AAAA,QACpC,oBAAoB;AAAA,QACpB;AAAA,QACA,uBAAuB,KAAK;AAAA,MAC9B,CAAC;AACD,aAAO;AAAA,IACT,SAAS,GAAG;AAEV,WAAK,OAAO,MAAM,oCAAoC;AAAA,QACpD,OAAG,6CAAsB,CAAC;AAAA,QAC1B;AAAA,MACF,CAAC;AACD,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,MAAM,QAAuB;AAC3B,SAAK,oBAAoB,MAAM;AAC/B,SAAK,qBAAqB;AAC1B,UAAM,YAAY,KAAK;AACvB,SAAK,oBAAoB;AACzB,QAAI,cAAc,QAAW;AAC3B;AAAA,IACF;AACA,QAAI;AACF,YAAM,UAAU,KAAK;AAAA,IACvB,SAAS,GAAG;AACV,WAAK,OAAO,KAAK,0CAAsC,6CAAsB,CAAC,CAAC;AAAA,IACjF;AAAA,EACF;AACF;","names":["import_constants","dedent"]}