@mcoda/codali 0.1.134 → 0.1.135-codali.4

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 (230) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/ORCHESTRATION.md +387 -0
  3. package/README.md +103 -1
  4. package/config/alternate-local.example.json +49 -0
  5. package/config/docdex-runtime.json +21 -0
  6. package/config/orchestration.schema.json +548 -0
  7. package/config/raijin-suku.example.json +172 -0
  8. package/config/terminal-long-scenarios.v1.json +70 -0
  9. package/dist/agents/RoleResolution.d.ts.map +1 -1
  10. package/dist/agents/RoleResolution.js +4 -4
  11. package/dist/api/CodaliApi.d.ts +16 -0
  12. package/dist/api/CodaliApi.d.ts.map +1 -1
  13. package/dist/api/CodaliApi.js +39 -10
  14. package/dist/cli/AskCommand.d.ts +3 -0
  15. package/dist/cli/AskCommand.d.ts.map +1 -1
  16. package/dist/cli/AskCommand.js +76 -13
  17. package/dist/cli/RunCommand.d.ts +4 -0
  18. package/dist/cli/RunCommand.d.ts.map +1 -1
  19. package/dist/cli/RunCommand.js +110 -24
  20. package/dist/cli/TerminalCommand.d.ts +35 -0
  21. package/dist/cli/TerminalCommand.d.ts.map +1 -0
  22. package/dist/cli/TerminalCommand.js +616 -0
  23. package/dist/cli/TerminalCredentials.d.ts +3 -0
  24. package/dist/cli/TerminalCredentials.d.ts.map +1 -0
  25. package/dist/cli/TerminalCredentials.js +89 -0
  26. package/dist/cli/TerminalInput.d.ts +24 -0
  27. package/dist/cli/TerminalInput.d.ts.map +1 -0
  28. package/dist/cli/TerminalInput.js +98 -0
  29. package/dist/cli/TerminalText.d.ts +10 -0
  30. package/dist/cli/TerminalText.d.ts.map +1 -0
  31. package/dist/cli/TerminalText.js +53 -0
  32. package/dist/cli.d.ts.map +1 -1
  33. package/dist/cli.js +33 -4
  34. package/dist/cognitive/ConfiguredPipeline.d.ts +34 -0
  35. package/dist/cognitive/ConfiguredPipeline.d.ts.map +1 -0
  36. package/dist/cognitive/ConfiguredPipeline.js +50 -0
  37. package/dist/cognitive/ValidationRunner.d.ts +4 -0
  38. package/dist/cognitive/ValidationRunner.d.ts.map +1 -1
  39. package/dist/cognitive/ValidationRunner.js +18 -41
  40. package/dist/config/NodeOrchestration.d.ts +21 -0
  41. package/dist/config/NodeOrchestration.d.ts.map +1 -0
  42. package/dist/config/NodeOrchestration.js +54 -0
  43. package/dist/config/OrchestrationConfig.d.ts +100 -0
  44. package/dist/config/OrchestrationConfig.d.ts.map +1 -0
  45. package/dist/config/OrchestrationConfig.js +245 -0
  46. package/dist/connectors/mcp/McpClient.d.ts +3 -1
  47. package/dist/connectors/mcp/McpClient.d.ts.map +1 -1
  48. package/dist/connectors/mcp/McpClient.js +3 -2
  49. package/dist/connectors/mcp/McpServerRegistry.d.ts +2 -2
  50. package/dist/connectors/mcp/McpServerRegistry.d.ts.map +1 -1
  51. package/dist/connectors/mcp/McpServerRegistry.js +39 -16
  52. package/dist/connectors/mcp/McpToolAdapter.js +2 -2
  53. package/dist/connectors/media/ConfiguredMediaTools.d.ts +6 -0
  54. package/dist/connectors/media/ConfiguredMediaTools.d.ts.map +1 -0
  55. package/dist/connectors/media/ConfiguredMediaTools.js +41 -0
  56. package/dist/connectors/media/ImageGenerationTool.js +3 -3
  57. package/dist/connectors/media/MediaArtifactReceipt.d.ts +5 -0
  58. package/dist/connectors/media/MediaArtifactReceipt.d.ts.map +1 -0
  59. package/dist/connectors/media/MediaArtifactReceipt.js +65 -0
  60. package/dist/connectors/media/MediaJobStore.d.ts +68 -0
  61. package/dist/connectors/media/MediaJobStore.d.ts.map +1 -0
  62. package/dist/connectors/media/MediaJobStore.js +199 -0
  63. package/dist/connectors/media/MediaJobWorker.d.ts +2 -0
  64. package/dist/connectors/media/MediaJobWorker.d.ts.map +1 -0
  65. package/dist/connectors/media/MediaJobWorker.js +65 -0
  66. package/dist/connectors/media/RemoteMediaJob.d.ts +6 -0
  67. package/dist/connectors/media/RemoteMediaJob.d.ts.map +1 -0
  68. package/dist/connectors/media/RemoteMediaJob.js +80 -0
  69. package/dist/docdex/DocdexClient.d.ts +18 -1
  70. package/dist/docdex/DocdexClient.d.ts.map +1 -1
  71. package/dist/docdex/DocdexClient.js +135 -19
  72. package/dist/docdex/ManagedDocdex.d.ts +29 -0
  73. package/dist/docdex/ManagedDocdex.d.ts.map +1 -0
  74. package/dist/docdex/ManagedDocdex.js +215 -0
  75. package/dist/docdex/ManagedRuntime.d.ts +28 -0
  76. package/dist/docdex/ManagedRuntime.d.ts.map +1 -0
  77. package/dist/docdex/ManagedRuntime.js +212 -0
  78. package/dist/eval/EvaluationProcess.d.ts +13 -0
  79. package/dist/eval/EvaluationProcess.d.ts.map +1 -0
  80. package/dist/eval/EvaluationProcess.js +76 -0
  81. package/dist/eval/LongWorkflowJourney.d.ts +34 -0
  82. package/dist/eval/LongWorkflowJourney.d.ts.map +1 -0
  83. package/dist/eval/LongWorkflowJourney.js +243 -0
  84. package/dist/eval/PlanningCorpus.d.ts +45 -0
  85. package/dist/eval/PlanningCorpus.d.ts.map +1 -0
  86. package/dist/eval/PlanningCorpus.js +189 -0
  87. package/dist/eval/PlanningCorpusRunner.d.ts +13 -0
  88. package/dist/eval/PlanningCorpusRunner.d.ts.map +1 -0
  89. package/dist/eval/PlanningCorpusRunner.js +89 -0
  90. package/dist/eval/TerminalCorpusRunner.d.ts +36 -0
  91. package/dist/eval/TerminalCorpusRunner.d.ts.map +1 -0
  92. package/dist/eval/TerminalCorpusRunner.js +222 -0
  93. package/dist/eval/TerminalTaskCorpus.d.ts +26 -0
  94. package/dist/eval/TerminalTaskCorpus.d.ts.map +1 -0
  95. package/dist/eval/TerminalTaskCorpus.js +105 -0
  96. package/dist/eval/TerminalWorkflowCorpus.d.ts +11 -0
  97. package/dist/eval/TerminalWorkflowCorpus.d.ts.map +1 -0
  98. package/dist/eval/TerminalWorkflowCorpus.js +116 -0
  99. package/dist/eval/fixtures/TerminalRecoveryJourney.d.ts +4 -0
  100. package/dist/eval/fixtures/TerminalRecoveryJourney.d.ts.map +1 -0
  101. package/dist/eval/fixtures/TerminalRecoveryJourney.js +132 -0
  102. package/dist/gateway/CodaliGateway.d.ts +2 -0
  103. package/dist/gateway/CodaliGateway.d.ts.map +1 -1
  104. package/dist/gateway/CodaliGateway.js +11 -1
  105. package/dist/gateway/ConfiguredGateway.d.ts +23 -0
  106. package/dist/gateway/ConfiguredGateway.d.ts.map +1 -0
  107. package/dist/gateway/ConfiguredGateway.js +44 -0
  108. package/dist/gateway/GatewayTracer.d.ts +1 -1
  109. package/dist/gateway/GatewayTracer.d.ts.map +1 -1
  110. package/dist/gateway/GatewayTracer.js +2 -27
  111. package/dist/index.d.ts +23 -0
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +12 -0
  114. package/dist/permissions/PermissionGate.d.ts +44 -0
  115. package/dist/permissions/PermissionGate.d.ts.map +1 -0
  116. package/dist/permissions/PermissionGate.js +97 -0
  117. package/dist/providers/ConfiguredEmbeddings.d.ts +43 -0
  118. package/dist/providers/ConfiguredEmbeddings.d.ts.map +1 -0
  119. package/dist/providers/ConfiguredEmbeddings.js +87 -0
  120. package/dist/providers/ConfiguredModelScope.d.ts +69 -0
  121. package/dist/providers/ConfiguredModelScope.d.ts.map +1 -0
  122. package/dist/providers/ConfiguredModelScope.js +113 -0
  123. package/dist/providers/ConfiguredProvider.d.ts +79 -0
  124. package/dist/providers/ConfiguredProvider.d.ts.map +1 -0
  125. package/dist/providers/ConfiguredProvider.js +238 -0
  126. package/dist/providers/ModelServiceError.d.ts +10 -0
  127. package/dist/providers/ModelServiceError.d.ts.map +1 -0
  128. package/dist/providers/ModelServiceError.js +45 -0
  129. package/dist/providers/MswarmWorkerProvider.d.ts.map +1 -1
  130. package/dist/providers/MswarmWorkerProvider.js +4 -0
  131. package/dist/providers/OpenAiCompatibleProvider.d.ts.map +1 -1
  132. package/dist/providers/OpenAiCompatibleProvider.js +91 -50
  133. package/dist/providers/ProviderTypes.d.ts +12 -0
  134. package/dist/providers/ProviderTypes.d.ts.map +1 -1
  135. package/dist/runtime/CodaliJobRuntime.d.ts +6 -0
  136. package/dist/runtime/CodaliJobRuntime.d.ts.map +1 -1
  137. package/dist/runtime/CodaliJobRuntime.js +36 -1
  138. package/dist/runtime/CodaliRuntime.d.ts +28 -0
  139. package/dist/runtime/CodaliRuntime.d.ts.map +1 -1
  140. package/dist/runtime/CodaliRuntime.js +69 -1
  141. package/dist/runtime/CompletionReport.d.ts +5 -0
  142. package/dist/runtime/CompletionReport.d.ts.map +1 -0
  143. package/dist/runtime/CompletionReport.js +12 -0
  144. package/dist/runtime/ProgressTracker.d.ts +17 -0
  145. package/dist/runtime/ProgressTracker.d.ts.map +1 -0
  146. package/dist/runtime/ProgressTracker.js +27 -0
  147. package/dist/runtime/RequestedTestEvidence.d.ts +12 -0
  148. package/dist/runtime/RequestedTestEvidence.d.ts.map +1 -0
  149. package/dist/runtime/RequestedTestEvidence.js +16 -0
  150. package/dist/runtime/RequiredRetrieval.d.ts +13 -0
  151. package/dist/runtime/RequiredRetrieval.d.ts.map +1 -0
  152. package/dist/runtime/RequiredRetrieval.js +25 -0
  153. package/dist/runtime/ReviewSource.d.ts +6 -0
  154. package/dist/runtime/ReviewSource.d.ts.map +1 -0
  155. package/dist/runtime/ReviewSource.js +38 -0
  156. package/dist/runtime/Runner.d.ts +7 -0
  157. package/dist/runtime/Runner.d.ts.map +1 -1
  158. package/dist/runtime/Runner.js +215 -171
  159. package/dist/runtime/SecretRedaction.d.ts +11 -0
  160. package/dist/runtime/SecretRedaction.d.ts.map +1 -0
  161. package/dist/runtime/SecretRedaction.js +85 -0
  162. package/dist/runtime/SessionController.d.ts +148 -0
  163. package/dist/runtime/SessionController.d.ts.map +1 -0
  164. package/dist/runtime/SessionController.js +1357 -0
  165. package/dist/runtime/StructuralEvidence.d.ts +22 -0
  166. package/dist/runtime/StructuralEvidence.d.ts.map +1 -0
  167. package/dist/runtime/StructuralEvidence.js +87 -0
  168. package/dist/runtime/TaskReviewContext.d.ts +34 -0
  169. package/dist/runtime/TaskReviewContext.d.ts.map +1 -0
  170. package/dist/runtime/TaskReviewContext.js +34 -0
  171. package/dist/runtime/ValidationOutput.d.ts +5 -0
  172. package/dist/runtime/ValidationOutput.d.ts.map +1 -0
  173. package/dist/runtime/ValidationOutput.js +32 -0
  174. package/dist/runtime/VerificationCommand.d.ts +5 -0
  175. package/dist/runtime/VerificationCommand.d.ts.map +1 -0
  176. package/dist/runtime/VerificationCommand.js +76 -0
  177. package/dist/runtime/WorkStatusPage.d.ts +15 -0
  178. package/dist/runtime/WorkStatusPage.d.ts.map +1 -0
  179. package/dist/runtime/WorkStatusPage.js +58 -0
  180. package/dist/runtime/WorkspaceLedger.d.ts +13 -0
  181. package/dist/runtime/WorkspaceLedger.d.ts.map +1 -0
  182. package/dist/runtime/WorkspaceLedger.js +145 -0
  183. package/dist/runtime/WorkspaceLock.d.ts.map +1 -1
  184. package/dist/runtime/WorkspaceLock.js +20 -17
  185. package/dist/runtime/WorkspaceSnapshot.d.ts +13 -0
  186. package/dist/runtime/WorkspaceSnapshot.d.ts.map +1 -0
  187. package/dist/runtime/WorkspaceSnapshot.js +88 -0
  188. package/dist/session/AtomicState.d.ts +13 -0
  189. package/dist/session/AtomicState.d.ts.map +1 -0
  190. package/dist/session/AtomicState.js +123 -0
  191. package/dist/session/SessionStoragePath.d.ts +15 -0
  192. package/dist/session/SessionStoragePath.d.ts.map +1 -0
  193. package/dist/session/SessionStoragePath.js +89 -0
  194. package/dist/session/SessionStore.d.ts +9 -0
  195. package/dist/session/SessionStore.d.ts.map +1 -1
  196. package/dist/session/SessionStore.js +181 -47
  197. package/dist/session/WorkState.d.ts +23 -0
  198. package/dist/session/WorkState.d.ts.map +1 -0
  199. package/dist/session/WorkState.js +367 -0
  200. package/dist/session/WorkTypes.d.ts +94 -0
  201. package/dist/session/WorkTypes.d.ts.map +1 -0
  202. package/dist/session/WorkTypes.js +1 -0
  203. package/dist/tools/ToolRegistry.d.ts +2 -0
  204. package/dist/tools/ToolRegistry.d.ts.map +1 -1
  205. package/dist/tools/ToolRegistry.js +12 -2
  206. package/dist/tools/ToolTypes.d.ts +16 -0
  207. package/dist/tools/ToolTypes.d.ts.map +1 -1
  208. package/dist/tools/docdex/DocdexTools.d.ts +2 -0
  209. package/dist/tools/docdex/DocdexTools.d.ts.map +1 -1
  210. package/dist/tools/docdex/DocdexTools.js +17 -2
  211. package/dist/tools/filesystem/FileTools.d.ts.map +1 -1
  212. package/dist/tools/filesystem/FileTools.js +30 -10
  213. package/dist/tools/shell/AsyncProcess.d.ts +19 -0
  214. package/dist/tools/shell/AsyncProcess.d.ts.map +1 -0
  215. package/dist/tools/shell/AsyncProcess.js +94 -0
  216. package/dist/tools/shell/DarwinRuntimeLibraries.d.ts +13 -0
  217. package/dist/tools/shell/DarwinRuntimeLibraries.d.ts.map +1 -0
  218. package/dist/tools/shell/DarwinRuntimeLibraries.js +130 -0
  219. package/dist/tools/shell/HostToolchain.d.ts +19 -0
  220. package/dist/tools/shell/HostToolchain.d.ts.map +1 -0
  221. package/dist/tools/shell/HostToolchain.js +266 -0
  222. package/dist/tools/shell/IsolatedExecutor.d.ts +15 -0
  223. package/dist/tools/shell/IsolatedExecutor.d.ts.map +1 -0
  224. package/dist/tools/shell/IsolatedExecutor.js +138 -0
  225. package/dist/tools/shell/ShellTool.d.ts.map +1 -1
  226. package/dist/tools/shell/ShellTool.js +9 -29
  227. package/dist/tools/shell/ShellWorkingDirectory.d.ts +3 -0
  228. package/dist/tools/shell/ShellWorkingDirectory.d.ts.map +1 -0
  229. package/dist/tools/shell/ShellWorkingDirectory.js +30 -0
  230. package/package.json +27 -24
@@ -38,196 +38,240 @@ export class Runner {
38
38
  this.onToken = options.onToken;
39
39
  this.streamFlushMs = options.streamFlushMs;
40
40
  this.timeoutMs = options.timeoutMs;
41
+ this.continueAfterFinal = options.continueAfterFinal;
42
+ this.onMessages = options.onMessages;
41
43
  this.logger = options.logger;
44
+ this.signal = options.signal ?? options.context.signal;
42
45
  }
43
46
  async run(initialMessages) {
44
- const messages = [...initialMessages];
45
- let toolCallsExecuted = 0;
46
- let usageTotals;
47
- const deadline = this.timeoutMs ? Date.now() + this.timeoutMs : undefined;
48
- const emitEvent = (event) => {
49
- if (this.onEvent) {
50
- this.onEvent(event);
51
- return;
52
- }
53
- if (event.type === "token") {
54
- this.onToken?.(event.content);
55
- }
56
- };
57
- const emitStatus = (phase, message) => {
58
- this.onEvent?.({ type: "status", phase, message });
59
- };
60
- const recordUsage = (usage) => {
61
- if (!usage)
62
- return;
63
- if (!usageTotals)
64
- usageTotals = {};
65
- if (usage.inputTokens !== undefined) {
66
- usageTotals.inputTokens = (usageTotals.inputTokens ?? 0) + usage.inputTokens;
67
- }
68
- if (usage.outputTokens !== undefined) {
69
- usageTotals.outputTokens = (usageTotals.outputTokens ?? 0) + usage.outputTokens;
70
- }
71
- if (usage.totalTokens !== undefined) {
72
- usageTotals.totalTokens = (usageTotals.totalTokens ?? 0) + usage.totalTokens;
73
- }
74
- };
75
- const timeRemaining = () => {
76
- if (!deadline)
77
- return undefined;
78
- return deadline - Date.now();
79
- };
80
- const throwBudgetError = async (code, step) => {
81
- const error = new RunnerBudgetError(code, {
82
- step,
83
- tool_calls_executed: toolCallsExecuted,
84
- max_steps: this.maxSteps,
85
- max_tool_calls: this.maxToolCalls,
86
- timeout_ms: this.timeoutMs,
87
- });
88
- if (this.logger) {
89
- await this.logger.log("runner_budget_failure", error.metadata);
90
- }
91
- throw error;
92
- };
93
- const withTimeout = async (promise, label) => {
94
- const remaining = timeRemaining();
95
- if (remaining === undefined)
96
- return promise;
97
- if (remaining <= 0) {
98
- await throwBudgetError("runner_timeout_exceeded", -1);
99
- }
100
- let timeoutId;
101
- const timeoutPromise = new Promise((_, reject) => {
102
- timeoutId = setTimeout(() => reject(new Error("Runner timeout exceeded")), remaining);
103
- });
104
- try {
105
- return await Promise.race([promise, timeoutPromise]);
106
- }
107
- catch (error) {
108
- if (error instanceof Error && /Runner timeout exceeded/i.test(error.message)) {
109
- await throwBudgetError("runner_timeout_exceeded", -1);
47
+ this.signal?.throwIfAborted();
48
+ const abortController = new AbortController();
49
+ const onAbort = () => abortController.abort(this.signal?.reason);
50
+ this.signal?.addEventListener("abort", onAbort, { once: true });
51
+ const timeout = this.timeoutMs ? setTimeout(() => abortController.abort(new Error("Runner timeout exceeded")), this.timeoutMs) : undefined;
52
+ const signal = abortController.signal;
53
+ try {
54
+ const messages = [...initialMessages];
55
+ let toolCallsExecuted = 0;
56
+ let usageTotals;
57
+ const deadline = this.timeoutMs ? Date.now() + this.timeoutMs : undefined;
58
+ const emitEvent = (event) => {
59
+ if (signal.aborted)
60
+ return;
61
+ if (this.onEvent) {
62
+ this.onEvent(event);
63
+ return;
64
+ }
65
+ if (event.type === "token") {
66
+ this.onToken?.(event.content);
67
+ }
68
+ };
69
+ const emitStatus = (phase, message) => {
70
+ this.onEvent?.({ type: "status", phase, message });
71
+ };
72
+ const recordUsage = (usage) => {
73
+ if (!usage)
74
+ return;
75
+ if (!usageTotals)
76
+ usageTotals = {};
77
+ if (usage.inputTokens !== undefined) {
78
+ usageTotals.inputTokens = (usageTotals.inputTokens ?? 0) + usage.inputTokens;
79
+ }
80
+ if (usage.outputTokens !== undefined) {
81
+ usageTotals.outputTokens = (usageTotals.outputTokens ?? 0) + usage.outputTokens;
82
+ }
83
+ if (usage.totalTokens !== undefined) {
84
+ usageTotals.totalTokens = (usageTotals.totalTokens ?? 0) + usage.totalTokens;
85
+ }
86
+ };
87
+ const timeRemaining = () => {
88
+ if (!deadline)
89
+ return undefined;
90
+ return deadline - Date.now();
91
+ };
92
+ const throwBudgetError = async (code, step) => {
93
+ const error = new RunnerBudgetError(code, {
94
+ step,
95
+ tool_calls_executed: toolCallsExecuted,
96
+ max_steps: this.maxSteps,
97
+ max_tool_calls: this.maxToolCalls,
98
+ timeout_ms: this.timeoutMs,
99
+ });
100
+ if (this.logger) {
101
+ await this.logger.log("runner_budget_failure", error.metadata);
110
102
  }
111
103
  throw error;
112
- }
113
- finally {
114
- if (timeoutId)
115
- clearTimeout(timeoutId);
116
- }
117
- };
118
- for (let step = 0; step < this.maxSteps; step += 1) {
119
- if (deadline && timeRemaining() <= 0) {
120
- await throwBudgetError("runner_timeout_exceeded", step);
121
- }
122
- const toolSpecs = this.tools.describe().map((tool) => ({
123
- name: tool.name,
124
- description: tool.description,
125
- inputSchema: tool.inputSchema,
126
- }));
127
- const finalSummaryStep = this.finalStepWithoutTools && step > 0 && step === this.maxSteps - 1;
128
- const allowTools = toolSpecs.length > 0 && this.toolChoice !== "none" && !finalSummaryStep;
129
- emitStatus("thinking");
130
- if (this.logger) {
131
- await this.logger.log("provider_request", {
132
- provider: this.provider.name,
133
- messages,
134
- tools: allowTools ? toolSpecs : [],
135
- toolChoice: allowTools ? this.toolChoice ?? "auto" : "none",
136
- responseFormat: this.responseFormat,
137
- temperature: this.temperature,
138
- maxTokens: this.maxTokens,
139
- stream: this.stream ?? false,
104
+ };
105
+ const withTimeout = async (promise, label) => {
106
+ const remaining = timeRemaining();
107
+ if (remaining !== undefined && remaining <= 0) {
108
+ await throwBudgetError("runner_timeout_exceeded", -1);
109
+ }
110
+ let timeoutId;
111
+ const timeoutPromise = new Promise((_, reject) => {
112
+ if (remaining !== undefined)
113
+ timeoutId = setTimeout(() => reject(new Error("Runner timeout exceeded")), remaining);
140
114
  });
141
- }
142
- const response = await withTimeout(this.provider.generate({
143
- messages,
144
- tools: allowTools ? toolSpecs : undefined,
145
- toolChoice: allowTools ? this.toolChoice ?? "auto" : finalSummaryStep ? "none" : undefined,
146
- maxTokens: this.maxTokens,
147
- temperature: this.temperature,
148
- responseFormat: this.responseFormat,
149
- stream: this.stream,
150
- onEvent: emitEvent,
151
- onToken: (token) => emitEvent({ type: "token", content: token }),
152
- streamFlushMs: this.streamFlushMs,
153
- }), "provider");
154
- recordUsage(response.usage);
155
- messages.push({
156
- ...response.message,
157
- ...(response.toolCalls?.length ? { toolCalls: response.toolCalls } : {}),
158
- });
159
- if (this.logger) {
160
- await this.logger.log("provider_response", {
161
- message: response.message,
162
- toolCalls: response.toolCalls,
163
- usage: response.usage,
115
+ let onCancel;
116
+ const cancelled = new Promise((_, reject) => {
117
+ // Provider streams may not honor AbortSignal; never accept their late reply.
118
+ // Tools are allowed to finish their cancellation cleanup before unlocking.
119
+ if (label === "provider") {
120
+ onCancel = () => reject(signal.reason ?? new Error("Cancelled"));
121
+ signal.addEventListener("abort", onCancel, { once: true });
122
+ if (signal.aborted)
123
+ onCancel();
124
+ }
164
125
  });
165
- }
166
- if (!response.toolCalls || response.toolCalls.length === 0) {
167
- return {
168
- finalMessage: response.message,
169
- messages,
170
- toolCallsExecuted,
171
- usage: usageTotals,
172
- };
173
- }
174
- for (const call of response.toolCalls) {
175
- if (toolCallsExecuted >= this.maxToolCalls) {
176
- await throwBudgetError("runner_tool_call_limit_exceeded", step);
126
+ try {
127
+ return await Promise.race([promise, timeoutPromise, cancelled]);
177
128
  }
178
- toolCallsExecuted += 1;
179
- emitStatus("executing", call.name);
180
- this.onEvent?.({ type: "tool_call", name: call.name, args: call.args });
181
- const result = await withTimeout(this.tools.execute(call.name, call.args, this.context), "tool");
182
- const toolError = result.error;
183
- let content = result.ok
184
- ? result.output
185
- : `ERROR[${toolError?.code ?? "tool_execution_failed"}]: ${toolError?.message ?? "tool failed"}`;
186
- if (result.ok && this.maxToolResultChars && this.maxToolResultChars > 0) {
187
- const limit = Math.max(1, Math.floor(this.maxToolResultChars / response.toolCalls.length));
188
- let structured = result.data;
189
- if (structured === undefined) {
190
- try {
191
- structured = JSON.parse(content);
192
- }
193
- catch { /* Plain-text tool output. */ }
129
+ catch (error) {
130
+ if (error instanceof Error && /Runner timeout exceeded/i.test(error.message)) {
131
+ await throwBudgetError("runner_timeout_exceeded", -1);
194
132
  }
195
- content = truncateToolResult(structured, content, limit).text;
133
+ throw error;
134
+ }
135
+ finally {
136
+ if (timeoutId)
137
+ clearTimeout(timeoutId);
138
+ if (onCancel)
139
+ signal.removeEventListener("abort", onCancel);
140
+ }
141
+ };
142
+ for (let step = 0; step < this.maxSteps; step += 1) {
143
+ signal.throwIfAborted();
144
+ if (deadline && timeRemaining() <= 0) {
145
+ await throwBudgetError("runner_timeout_exceeded", step);
146
+ }
147
+ const toolSpecs = this.tools.describe().map((tool) => ({
148
+ name: tool.name,
149
+ description: tool.description,
150
+ inputSchema: tool.inputSchema,
151
+ }));
152
+ const finalSummaryStep = this.finalStepWithoutTools && step > 0 && step === this.maxSteps - 1;
153
+ const allowTools = toolSpecs.length > 0 && this.toolChoice !== "none" && !finalSummaryStep;
154
+ emitStatus("thinking");
155
+ if (this.logger) {
156
+ await this.logger.log("provider_request", {
157
+ provider: this.provider.name,
158
+ messages,
159
+ tools: allowTools ? toolSpecs : [],
160
+ toolChoice: allowTools ? this.toolChoice ?? "auto" : "none",
161
+ responseFormat: this.responseFormat,
162
+ temperature: this.temperature,
163
+ maxTokens: this.maxTokens,
164
+ stream: this.stream ?? false,
165
+ });
196
166
  }
197
- messages.push(buildToolMessage(call, content));
198
- this.onEvent?.({
199
- type: "tool_result",
200
- name: call.name,
201
- output: content,
202
- ok: result.ok,
203
- errorCode: toolError?.code,
204
- retryable: toolError?.retryable,
167
+ const response = await withTimeout(this.provider.generate({
168
+ signal,
169
+ messages,
170
+ tools: allowTools ? toolSpecs : undefined,
171
+ toolChoice: allowTools ? this.toolChoice ?? "auto" : finalSummaryStep ? "none" : undefined,
172
+ maxTokens: this.maxTokens,
173
+ temperature: this.temperature,
174
+ responseFormat: this.responseFormat,
175
+ stream: this.stream,
176
+ onEvent: emitEvent,
177
+ onToken: (token) => emitEvent({ type: "token", content: token }),
178
+ streamFlushMs: this.streamFlushMs,
179
+ }), "provider");
180
+ recordUsage(response.usage);
181
+ signal.throwIfAborted();
182
+ messages.push({
183
+ ...response.message,
184
+ ...(response.toolCalls?.length ? { toolCalls: response.toolCalls } : {}),
205
185
  });
186
+ await this.onMessages?.([...messages]);
206
187
  if (this.logger) {
207
- await this.logger.log("tool_call", {
188
+ await this.logger.log("provider_response", {
189
+ message: response.message,
190
+ toolCalls: response.toolCalls,
191
+ usage: response.usage,
192
+ });
193
+ }
194
+ if (!response.toolCalls || response.toolCalls.length === 0) {
195
+ const continuation = await this.continueAfterFinal?.(response.message);
196
+ if (continuation) {
197
+ messages.push({ role: "user", content: continuation });
198
+ continue;
199
+ }
200
+ return {
201
+ finalMessage: response.message,
202
+ messages,
203
+ toolCallsExecuted,
204
+ usage: usageTotals,
205
+ };
206
+ }
207
+ for (const call of response.toolCalls) {
208
+ signal.throwIfAborted();
209
+ if (toolCallsExecuted >= this.maxToolCalls) {
210
+ await throwBudgetError("runner_tool_call_limit_exceeded", step);
211
+ }
212
+ toolCallsExecuted += 1;
213
+ emitStatus("executing", call.name);
214
+ this.onEvent?.({ type: "tool_call", name: call.name, args: call.args });
215
+ const result = await withTimeout(this.tools.execute(call.name, call.args, { ...this.context, signal }), "tool");
216
+ const toolError = result.error;
217
+ let content = result.ok
218
+ ? result.output
219
+ : `ERROR[${toolError?.code ?? "tool_execution_failed"}]: ${toolError?.message ?? "tool failed"}`;
220
+ if (result.ok && this.maxToolResultChars && this.maxToolResultChars > 0) {
221
+ const limit = Math.max(1, Math.floor(this.maxToolResultChars / response.toolCalls.length));
222
+ let structured = result.data;
223
+ if (structured === undefined) {
224
+ try {
225
+ structured = JSON.parse(content);
226
+ }
227
+ catch { /* Plain-text tool output. */ }
228
+ }
229
+ content = truncateToolResult(structured, content, limit).text;
230
+ }
231
+ if (result.invocationReceipt) {
232
+ content += `\n\n[Tool metadata: invocation receipt ID ${result.invocationReceipt.id}; receiptRef=${result.invocationReceipt.reference}]`;
233
+ }
234
+ messages.push(buildToolMessage(call, content));
235
+ await this.onMessages?.([...messages]);
236
+ this.onEvent?.({
237
+ type: "tool_result",
208
238
  name: call.name,
239
+ output: content,
209
240
  ok: result.ok,
210
- error: toolError?.message,
211
- error_code: toolError?.code,
212
- error_category: toolError?.category,
213
- error_retryable: toolError?.retryable,
214
- error_details: toolError?.details,
241
+ errorCode: toolError?.code,
242
+ retryable: toolError?.retryable,
215
243
  });
216
- if (toolError) {
217
- await this.logger.logSafetyEvent({
218
- phase: "act",
219
- category: "tool",
220
- code: toolError.code,
221
- disposition: toolError.retryable ? "retryable" : "non_retryable",
222
- tool: call.name,
223
- message: toolError.message,
224
- details: toolError.details,
244
+ if (this.logger) {
245
+ await this.logger.log("tool_call", {
246
+ name: call.name,
247
+ ok: result.ok,
248
+ error: toolError?.message,
249
+ error_code: toolError?.code,
250
+ error_category: toolError?.category,
251
+ error_retryable: toolError?.retryable,
252
+ error_details: toolError?.details,
225
253
  });
254
+ if (toolError) {
255
+ await this.logger.logSafetyEvent({
256
+ phase: "act",
257
+ category: "tool",
258
+ code: toolError.code,
259
+ disposition: toolError.retryable ? "retryable" : "non_retryable",
260
+ tool: call.name,
261
+ message: toolError.message,
262
+ details: toolError.details,
263
+ });
264
+ }
226
265
  }
227
266
  }
228
267
  }
268
+ await throwBudgetError("runner_step_limit_exceeded", this.maxSteps);
269
+ throw new Error("unreachable_runner_budget_path");
270
+ }
271
+ finally {
272
+ if (timeout)
273
+ clearTimeout(timeout);
274
+ this.signal?.removeEventListener("abort", onAbort);
229
275
  }
230
- await throwBudgetError("runner_step_limit_exceeded", this.maxSteps);
231
- throw new Error("unreachable_runner_budget_path");
232
276
  }
233
277
  }
@@ -0,0 +1,11 @@
1
+ /** Register credentials when resolved; do not scan or expose unrelated environment values. */
2
+ export declare const registerSecretValue: (value: string) => void;
3
+ export declare const redactSecretValues: (value: string) => string;
4
+ /** Hold incomplete credential-shaped words so split chunks cannot expose a prefix or tail. */
5
+ export declare class StreamingSecretRedactor {
6
+ private pending;
7
+ private droppingWord;
8
+ write(chunk: string): string;
9
+ finish(): string;
10
+ }
11
+ //# sourceMappingURL=SecretRedaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SecretRedaction.d.ts","sourceRoot":"","sources":["../../src/runtime/SecretRedaction.ts"],"names":[],"mappings":"AAaA,8FAA8F;AAC9F,eAAO,MAAM,mBAAmB,GAAI,OAAO,MAAM,KAAG,IAEnD,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,KAAG,MAKlD,CAAC;AAEF,8FAA8F;AAC9F,qBAAa,uBAAuB;IAClC,OAAO,CAAC,OAAO,CAAM;IACrB,OAAO,CAAC,YAAY,CAAS;IAC7B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IA4B5B,MAAM,IAAI,MAAM;CAUjB"}
@@ -0,0 +1,85 @@
1
+ const knownSecrets = new Set();
2
+ const patterns = [
3
+ /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}/gi,
4
+ /\bsk-[A-Za-z0-9_-]{16,}\b/g,
5
+ /\bsk_[A-Za-z0-9]+_[A-Za-z0-9_]{8,}\b/g,
6
+ /\bgh[pousr]_[A-Za-z0-9_]{20,}\b/g,
7
+ /\bglpat-[A-Za-z0-9_-]{16,}\b/g,
8
+ /\bxox[abprs]-[A-Za-z0-9-]{10,}\b/g,
9
+ /\bAKIA[0-9A-Z]{16}\b/g,
10
+ /\bAIza[0-9A-Za-z_-]{30,}\b/g,
11
+ /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,
12
+ ];
13
+ /** Register credentials when resolved; do not scan or expose unrelated environment values. */
14
+ export const registerSecretValue = (value) => {
15
+ if (value.length >= 4) {
16
+ knownSecrets.add(value);
17
+ knownSecrets.add(JSON.stringify(value).slice(1, -1));
18
+ }
19
+ };
20
+ export const redactSecretValues = (value) => {
21
+ let output = value;
22
+ for (const secret of [...knownSecrets].sort((a, b) => b.length - a.length))
23
+ output = output.split(secret).join("[redacted]");
24
+ for (const pattern of patterns)
25
+ output = output.replace(pattern, "[redacted]");
26
+ return output;
27
+ };
28
+ /** Hold incomplete credential-shaped words so split chunks cannot expose a prefix or tail. */
29
+ export class StreamingSecretRedactor {
30
+ constructor() {
31
+ this.pending = "";
32
+ this.droppingWord = false;
33
+ }
34
+ write(chunk) {
35
+ if (this.droppingWord) {
36
+ const boundary = chunk.search(/[^A-Za-z0-9._~+/=-]/);
37
+ if (boundary < 0)
38
+ return "";
39
+ chunk = chunk.slice(boundary);
40
+ this.droppingWord = false;
41
+ }
42
+ this.pending += chunk;
43
+ let cutoff = this.pending.search(/[A-Za-z0-9._~+/=-]*$/);
44
+ const bearer = /\bBearer\s+[A-Za-z0-9._~+/=-]*$/i.exec(this.pending);
45
+ if (bearer)
46
+ cutoff = Math.min(cutoff, bearer.index);
47
+ for (const secret of knownSecrets) {
48
+ // An exact credential may contain spaces/punctuation, unlike a bearer word.
49
+ for (let at = this.pending.indexOf(secret); at >= 0; at = this.pending.indexOf(secret, at + 1)) {
50
+ if (at < cutoff && at + secret.length > cutoff)
51
+ cutoff = at;
52
+ }
53
+ for (let size = Math.min(secret.length - 1, this.pending.length); size > 0; size--) {
54
+ if (this.pending.endsWith(secret.slice(0, size))) {
55
+ cutoff = Math.min(cutoff, this.pending.length - size);
56
+ break;
57
+ }
58
+ }
59
+ }
60
+ let output = redactSecretValues(this.pending.slice(0, cutoff));
61
+ this.pending = this.pending.slice(cutoff);
62
+ // Never release a truncated prefix; discard an oversized unbroken token.
63
+ const longestCredential = Math.max(0, ...[...knownSecrets].map(secret => secret.length));
64
+ if (this.pending.length > Math.max(65536, longestCredential)) {
65
+ output += "[redacted oversized token]";
66
+ this.pending = "";
67
+ this.droppingWord = true;
68
+ }
69
+ return output;
70
+ }
71
+ finish() {
72
+ let output = redactSecretValues(this.pending);
73
+ for (const secret of knownSecrets) {
74
+ for (let size = Math.min(secret.length - 1, output.length); size >= 4; size--) {
75
+ if (output.endsWith(secret.slice(0, size))) {
76
+ output = `${output.slice(0, -size)}[redacted]`;
77
+ break;
78
+ }
79
+ }
80
+ }
81
+ this.pending = "";
82
+ this.droppingWord = false;
83
+ return output;
84
+ }
85
+ }
@@ -0,0 +1,148 @@
1
+ import { SessionStore } from "../session/SessionStore.js";
2
+ import type { WorkState } from "../session/WorkTypes.js";
3
+ import type { Provider } from "../providers/ProviderTypes.js";
4
+ import { type EffortLevel, type ResolvedOrchestrationConfig } from "../config/OrchestrationConfig.js";
5
+ import { PermissionGate, type PermissionProfile, type PermissionPrompt } from "../permissions/PermissionGate.js";
6
+ import { ToolRegistry } from "../tools/ToolRegistry.js";
7
+ import { type ToolDefinition } from "../tools/ToolTypes.js";
8
+ import { MediaJobStore } from "../connectors/media/MediaJobStore.js";
9
+ import { type RunContext } from "../runcontext/RunContextResolver.js";
10
+ import type { ProjectTaskAuthority } from "@mcoda/shared";
11
+ export interface SessionEvent {
12
+ schemaVersion: 1;
13
+ id: string;
14
+ sessionId: string;
15
+ sequence: number;
16
+ at: string;
17
+ type: string;
18
+ data: Record<string, unknown>;
19
+ }
20
+ export interface SessionControllerOptions {
21
+ workspaceRoot: string;
22
+ resolved: ResolvedOrchestrationConfig;
23
+ effort?: EffortLevel;
24
+ permissions?: PermissionProfile;
25
+ approve?: PermissionPrompt;
26
+ onEvent?: (event: SessionEvent) => void;
27
+ storageRoot?: string;
28
+ provider?: Provider;
29
+ tools?: ToolDefinition[];
30
+ docdexUrl?: string;
31
+ docdex?: boolean;
32
+ allowWeb?: boolean;
33
+ allowMemory?: boolean;
34
+ allowMedia?: boolean;
35
+ allowNetwork?: boolean;
36
+ /** Authenticated host context; repository settings can only narrow tools. */
37
+ runContext?: RunContext;
38
+ projectTaskAuthority?: ProjectTaskAuthority;
39
+ projectTaskKey?: string;
40
+ }
41
+ interface SessionUsage {
42
+ modelCalls: number;
43
+ toolCalls: number;
44
+ tokens: number;
45
+ inputTokens: number;
46
+ outputTokens: number;
47
+ estimated: boolean;
48
+ embeddingCalls?: number;
49
+ embeddingTokens?: number;
50
+ }
51
+ export declare class SessionController {
52
+ private readonly options;
53
+ private projectHandoff;
54
+ readonly store: SessionStore;
55
+ readonly gate: PermissionGate;
56
+ readonly registry: ToolRegistry;
57
+ readonly isolation: import("../tools/shell/IsolatedExecutor.js").ExecutorStatus;
58
+ readonly workspaceRoot: string;
59
+ sessionId?: string;
60
+ state?: WorkState;
61
+ effort: EffortLevel;
62
+ private active?;
63
+ private sequence;
64
+ private messages;
65
+ private receipts;
66
+ private observed;
67
+ private touched;
68
+ private currentReceipt?;
69
+ private persistence;
70
+ private persistenceError?;
71
+ private usage;
72
+ private reservations;
73
+ private modelSettlements;
74
+ private closingModelTurn?;
75
+ private baseline?;
76
+ private previousSnapshot?;
77
+ private instructions;
78
+ private finalAttempts;
79
+ private docdex?;
80
+ private managedDocdex?;
81
+ private docdexNames;
82
+ private docdexReady;
83
+ private memoryContext;
84
+ private lastRequestEstimate;
85
+ private repeatedFailures;
86
+ private progressTracker;
87
+ private connectorRegistry?;
88
+ private connectorNames;
89
+ private connectorHealth;
90
+ private outputStreams;
91
+ private runContext?;
92
+ private enabledTools;
93
+ private get fencePath();
94
+ private resetSessionState;
95
+ private attachConnectors;
96
+ private closeConnectors;
97
+ private clearFence;
98
+ constructor(options: SessionControllerOptions);
99
+ private usesManagedDocdex;
100
+ private attachDocdexTools;
101
+ private startManagedDocdex;
102
+ get busy(): boolean;
103
+ status(): Record<string, unknown>;
104
+ usageSnapshot(): SessionUsage;
105
+ mediaStore(): MediaJobStore;
106
+ private workspaceLedger;
107
+ artifacts(): Promise<Record<string, unknown>[]>;
108
+ private flushOutputStreams;
109
+ private emit;
110
+ private update;
111
+ private checkProjectTask;
112
+ private completionInputs;
113
+ private completeGoal;
114
+ private reconcileProjectHandoff;
115
+ start(objective: string): Promise<void>;
116
+ resume(id: string): Promise<void>;
117
+ cancel(): void;
118
+ steer(instruction: string): Promise<void>;
119
+ checkpoint(note?: string): Promise<void>;
120
+ private compactMessages;
121
+ compact(): Promise<void>;
122
+ clearPermissionGrants(): Promise<void>;
123
+ fork(): Promise<string>;
124
+ reloadConfiguration(resolved: ResolvedOrchestrationConfig): Promise<void>;
125
+ deleteSession(id: string): Promise<void>;
126
+ reconcile(invocationId: string, outcome: "success" | "failed", note: string): Promise<void>;
127
+ diff(): Promise<string>;
128
+ private hashes;
129
+ private assertEditEvidence;
130
+ private shellWritePaths;
131
+ private validationReserve;
132
+ private validationContext;
133
+ private provider;
134
+ private beforeTool;
135
+ private afterTool;
136
+ private prepareEditTool;
137
+ private receiptRef;
138
+ private resolveReceipt;
139
+ private workTools;
140
+ private helperTool;
141
+ private verify;
142
+ run(prompt?: string): Promise<{
143
+ content: string;
144
+ completed: boolean;
145
+ }>;
146
+ }
147
+ export {};
148
+ //# sourceMappingURL=SessionController.d.ts.map