maka-agent 0.2.0-dev.46.20260922 → 0.2.0-dev.48.20260923

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 (131) hide show
  1. package/DISCLAIMER-WIP +6 -1
  2. package/README.md +6 -1
  3. package/dist/acp/maka-acp-agent.js +1 -1
  4. package/dist/acp/session-mcp.js +212 -0
  5. package/dist/acp/session-registry.js +52 -8
  6. package/dist/acp/stdio-server.js +3 -0
  7. package/dist/cli-core.js +1 -1
  8. package/dist/mcp-capability-provider.js +6 -1
  9. package/dist/mcp-capability-publication.js +139 -0
  10. package/dist/pi-tui-layout.js +46 -17
  11. package/dist/pi-tui-pickers.js +25 -14
  12. package/dist/pi-tui-runner.js +24 -15
  13. package/dist/runtime-host-capability-provider-command.js +25 -6
  14. package/dist/runtime-host-service-manager.js +26 -2
  15. package/dist/tui-context-refresh.js +15 -26
  16. package/dist/tui-mcp-control.js +66 -112
  17. package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
  18. package/node_modules/@maka/acp-executor-plugin/dist/acp-errors.js +26 -0
  19. package/node_modules/@maka/acp-executor-plugin/dist/acp-filesystem.js +103 -0
  20. package/node_modules/@maka/acp-executor-plugin/dist/acp-process.js +119 -0
  21. package/node_modules/@maka/acp-executor-plugin/dist/acp-projection.js +146 -0
  22. package/node_modules/@maka/acp-executor-plugin/dist/index.js +653 -0
  23. package/node_modules/@maka/acp-executor-plugin/dist/plugin.mjs +24446 -0
  24. package/node_modules/@maka/acp-executor-plugin/package.json +15 -0
  25. package/node_modules/@maka/antigravity-acp-plugin/dist/index.js +88 -0
  26. package/node_modules/@maka/antigravity-acp-plugin/dist/model-presentation.js +53 -0
  27. package/node_modules/@maka/antigravity-acp-plugin/dist/plugin.mjs +115 -0
  28. package/node_modules/@maka/antigravity-acp-plugin/package.json +15 -0
  29. package/node_modules/@maka/core/dist/client-capability-grant.js +2 -2
  30. package/node_modules/@maka/core/dist/executor-catalog.js +106 -0
  31. package/node_modules/@maka/core/dist/mcp.js +4 -1
  32. package/node_modules/@maka/core/dist/model-metadata.js +28 -1
  33. package/node_modules/@maka/core/dist/model-thinking.js +36 -1
  34. package/node_modules/@maka/core/dist/provider-registry.js +0 -1
  35. package/node_modules/@maka/core/dist/refresh-read-coordinator.js +62 -0
  36. package/node_modules/@maka/core/dist/runtime-event-store.js +25 -0
  37. package/node_modules/@maka/core/dist/runtime-invocation.js +5 -0
  38. package/node_modules/@maka/core/dist/runtime-policy/connection-catalog-codec.js +4 -0
  39. package/node_modules/@maka/core/dist/runtime-policy/credential-vault-codec.js +6 -0
  40. package/node_modules/@maka/core/dist/runtime-policy/policy-codec.js +21 -0
  41. package/node_modules/@maka/core/dist/session.js +19 -1
  42. package/node_modules/@maka/core/dist/settings.js +3 -0
  43. package/node_modules/@maka/core/dist/tool-ledger-scanner.js +365 -104
  44. package/node_modules/@maka/core/dist/turn-origin.js +14 -0
  45. package/node_modules/@maka/core/package.json +3 -0
  46. package/node_modules/@maka/mcp/dist/credential-coordinator.js +6 -1
  47. package/node_modules/@maka/mcp/dist/index.js +31 -5
  48. package/node_modules/@maka/mcp/dist/oauth.js +54 -6
  49. package/node_modules/@maka/runtime/dist/agent-run-inspect.js +1 -1
  50. package/node_modules/@maka/runtime/dist/ai-sdk-message-projection.js +15 -60
  51. package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +18 -0
  52. package/node_modules/@maka/runtime/dist/apply-patch-profile.js +64 -14
  53. package/node_modules/@maka/runtime/dist/builtin-tools.js +3 -2
  54. package/node_modules/@maka/runtime/dist/codex-v4a-patch.js +18 -0
  55. package/node_modules/@maka/runtime/dist/conversation-copy.js +56 -1
  56. package/node_modules/@maka/runtime/dist/mcp-tools.js +9 -2
  57. package/node_modules/@maka/runtime/dist/model-adapter.js +80 -3
  58. package/node_modules/@maka/runtime/dist/model-runtime.js +6 -0
  59. package/node_modules/@maka/runtime/dist/openai-apply-patch.js +5 -0
  60. package/node_modules/@maka/runtime/dist/plugin-executor-backend.js +122 -3
  61. package/node_modules/@maka/runtime/dist/plugin-executor-service.js +212 -16
  62. package/node_modules/@maka/runtime/dist/runtime-ledger-repair.js +2 -2
  63. package/node_modules/@maka/runtime/dist/session-event-runtime-mapper.js +3 -0
  64. package/node_modules/@maka/runtime/dist/session-manager.js +184 -126
  65. package/node_modules/@maka/runtime/dist/shell-run-manager.js +3 -0
  66. package/node_modules/@maka/runtime/dist/stream-graph-coordinator.js +29 -4
  67. package/node_modules/@maka/runtime-host/dist/candidate-entry.js +8 -5
  68. package/node_modules/@maka/runtime-host/dist/client/capability-provider-service.js +2 -0
  69. package/node_modules/@maka/runtime-host/dist/client/client-capability-channel.js +59 -20
  70. package/node_modules/@maka/runtime-host/dist/client/connection.js +6 -4
  71. package/node_modules/@maka/runtime-host/dist/client/index.js +1 -1
  72. package/node_modules/@maka/runtime-host/dist/client/reconnect-lifecycle.js +8 -1
  73. package/node_modules/@maka/runtime-host/dist/client/reconnecting-connection.js +4 -4
  74. package/node_modules/@maka/runtime-host/dist/client/session-catalog-summary.js +6 -1
  75. package/node_modules/@maka/runtime-host/dist/composition-identity.js +19 -0
  76. package/node_modules/@maka/runtime-host/dist/protocol/client-capability.js +20 -3
  77. package/node_modules/@maka/runtime-host/dist/protocol/external-session.js +8 -5
  78. package/node_modules/@maka/runtime-host/dist/protocol/index.js +20 -2
  79. package/node_modules/@maka/runtime-host/dist/protocol/plugin-platform.js +34 -0
  80. package/node_modules/@maka/runtime-host/dist/protocol/session-catalog.js +75 -5
  81. package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +1 -5
  82. package/node_modules/@maka/runtime-host/dist/server/builtin-external-agent-plugins.js +188 -0
  83. package/node_modules/@maka/runtime-host/dist/server/candidate.js +12 -7
  84. package/node_modules/@maka/runtime-host/dist/server/client-capability-coordinator.js +234 -70
  85. package/node_modules/@maka/runtime-host/dist/server/client-capability-invocation-broker.js +14 -8
  86. package/node_modules/@maka/runtime-host/dist/server/client-capability-recovery.js +44 -46
  87. package/node_modules/@maka/runtime-host/dist/server/context-coordinator.js +2 -0
  88. package/node_modules/@maka/runtime-host/dist/server/execution-composition-factory.js +1 -1
  89. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +188 -21
  90. package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +6 -0
  91. package/node_modules/@maka/runtime-host/dist/server/extension-bundle.js +4 -0
  92. package/node_modules/@maka/runtime-host/dist/server/external-session-coordinator.js +29 -7
  93. package/node_modules/@maka/runtime-host/dist/server/host-composition-source.js +47 -0
  94. package/node_modules/@maka/runtime-host/dist/server/host-composition.js +1 -29
  95. package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +2 -9
  96. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +75 -9
  97. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-tool-profile.js +5 -1
  98. package/node_modules/@maka/runtime-host/dist/server/interaction-coordinator.js +45 -0
  99. package/node_modules/@maka/runtime-host/dist/server/jev-routing-model.js +157 -0
  100. package/node_modules/@maka/runtime-host/dist/server/listener-set.js +2 -2
  101. package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +4 -0
  102. package/node_modules/@maka/runtime-host/dist/server/plugin-platform-coordinator.js +11 -1
  103. package/node_modules/@maka/runtime-host/dist/server/process-lifecycle.js +1 -1
  104. package/node_modules/@maka/runtime-host/dist/server/process-termination-error.js +27 -0
  105. package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +91 -12
  106. package/node_modules/@maka/runtime-host/dist/server/runtime-policy-coordinator.js +2 -0
  107. package/node_modules/@maka/runtime-host/dist/server/session-bundle-coordinator.js +4 -1
  108. package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +128 -13
  109. package/node_modules/@maka/runtime-host/dist/server/session-effect-coordinator.js +12 -6
  110. package/node_modules/@maka/runtime-host/dist/server/session-retirement-coordinator.js +2 -2
  111. package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +33 -0
  112. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +4 -0
  113. package/node_modules/@maka/runtime-host/dist/server/workhub-result-coordinator.js +173 -0
  114. package/node_modules/@maka/runtime-host/dist/server/workhub-result-runtime.js +293 -0
  115. package/node_modules/@maka/runtime-host/package.json +2 -0
  116. package/node_modules/@maka/storage/dist/agent-run-store-contract.js +8 -0
  117. package/node_modules/@maka/storage/dist/execution-stores.js +15 -3
  118. package/node_modules/@maka/storage/dist/mcp-config-store.js +91 -2
  119. package/node_modules/@maka/storage/dist/operational-state-store.js +15 -1
  120. package/node_modules/@maka/storage/dist/plan-authority.js +2 -0
  121. package/node_modules/@maka/storage/dist/plan-store.js +30 -0
  122. package/node_modules/@maka/storage/dist/runtime-event-persistence.js +1 -0
  123. package/node_modules/@maka/storage/dist/runtime-policy/credential-vault-document.js +4 -1
  124. package/node_modules/@maka/storage/dist/runtime-policy/policy-document.js +2 -0
  125. package/node_modules/@maka/storage/dist/session-store-values.js +16 -4
  126. package/node_modules/@maka/storage/dist/shell-run-authority.js +1 -0
  127. package/node_modules/@maka/storage/dist/shell-run-store.js +15 -0
  128. package/node_modules/@maka/storage/dist/sqlite-runtime-schema.js +74 -1
  129. package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +724 -84
  130. package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +16 -0
  131. package/package.json +1 -1
@@ -82,7 +82,7 @@ export class ClientCapabilityInvocationBroker {
82
82
  }));
83
83
  }
84
84
  #prepare(registration, signal, timeoutMs, onProgress, requestInteraction, frameFor) {
85
- const sender = this.#senderFor(registration.connectionId);
85
+ const sender = this.#senderFor(registration);
86
86
  if (!sender) {
87
87
  throw new ClientCapabilityInvocationError('capability_lost', 'Client Capability provider is unavailable');
88
88
  }
@@ -162,7 +162,7 @@ export class ClientCapabilityInvocationBroker {
162
162
  invocation.requestInteraction = requestInteraction ?? invocation.requestInteraction;
163
163
  invocation.phase = 'admitted';
164
164
  this.#armTimer(invocation);
165
- const currentSender = this.#senderFor(invocation.registration.connectionId);
165
+ const currentSender = this.#senderFor(invocation.registration);
166
166
  if (!currentSender) {
167
167
  this.#settle(invocation, undefined, new ClientCapabilityInvocationError('capability_lost', 'Client Capability provider disappeared before admission'), false);
168
168
  }
@@ -183,7 +183,7 @@ export class ClientCapabilityInvocationBroker {
183
183
  const invocation = this.#invocations.get(invocationId);
184
184
  if (!invocation)
185
185
  return;
186
- const currentSender = this.#senderFor(invocation.registration.connectionId);
186
+ const currentSender = this.#senderFor(invocation.registration);
187
187
  void currentSender
188
188
  ?.send({ kind: 'client.capability.cancel', invocationId })
189
189
  .catch(() => { });
@@ -279,10 +279,16 @@ export class ClientCapabilityInvocationBroker {
279
279
  this.#acceptChunk(invocation, frame.index, frame.data);
280
280
  }
281
281
  }
282
- async releaseConnection(connectionId) {
282
+ releaseConnection(connectionId) {
283
+ return this.#releaseWhere((registration) => registration.connectionId === connectionId);
284
+ }
285
+ releaseRegistration(registration) {
286
+ return this.#releaseWhere((candidate) => candidate === registration);
287
+ }
288
+ async #releaseWhere(matches) {
283
289
  const interactions = [];
284
290
  for (const invocation of [...this.#invocations.values()]) {
285
- if (invocation.registration.connectionId !== connectionId)
291
+ if (!matches(invocation.registration))
286
292
  continue;
287
293
  if (invocation.phase === 'dispatched' || invocation.phase === 'accepted') {
288
294
  invocation.providerAvailability.abort(new ClientCapabilityInvocationError('capability_lost', 'Client Capability provider disconnected before admission'));
@@ -379,7 +385,7 @@ export class ClientCapabilityInvocationBroker {
379
385
  this.#settle(invocation, undefined, terminalBeforeSend.error, terminalBeforeSend.releaseRemote);
380
386
  return;
381
387
  }
382
- const sender = this.#senderFor(invocation.registration.connectionId);
388
+ const sender = this.#senderFor(invocation.registration);
383
389
  if (!sender) {
384
390
  this.#settle(invocation, undefined, new ToolOutcomeUnknownError('Client Capability provider disappeared before receiving an interaction result'), false);
385
391
  return;
@@ -433,7 +439,7 @@ export class ClientCapabilityInvocationBroker {
433
439
  const current = this.#invocations.get(invocation.invocationId);
434
440
  if (current !== invocation)
435
441
  return;
436
- const sender = this.#senderFor(current.registration.connectionId);
442
+ const sender = this.#senderFor(current.registration);
437
443
  void sender
438
444
  ?.send({ kind: 'client.capability.cancel', invocationId: current.invocationId })
439
445
  .catch(() => { });
@@ -456,7 +462,7 @@ export class ClientCapabilityInvocationBroker {
456
462
  }
457
463
  this.#rememberRetired(invocation.invocationId);
458
464
  if (releaseRemote) {
459
- const sender = this.#senderFor(invocation.registration.connectionId);
465
+ const sender = this.#senderFor(invocation.registration);
460
466
  void sender
461
467
  ?.send({
462
468
  kind: 'client.capability.release',
@@ -20,53 +20,51 @@ import { compatibilityToolResultProjection } from '@maka/runtime/durable-tool-re
20
20
  const OUTCOME_UNKNOWN_TEXT = 'outcome_unknown: the Host restarted after dispatching this Client Capability call. The client-side effect may have happened; do not retry it automatically.';
21
21
  export async function recoverClientCapabilityOutcomes(store, sessionIds, now = Date.now) {
22
22
  let recovered = 0;
23
- for (const sessionId of sessionIds) {
24
- const operations = await store.listUnsettledToolOperations(sessionId);
25
- for (const operation of operations) {
26
- if (operation.recoveryMode !== 'outcome_unknown')
27
- continue;
28
- const ts = now();
29
- const result = {
30
- kind: 'text',
31
- text: OUTCOME_UNKNOWN_TEXT,
32
- uncertainOutcome: {
33
- code: 'outcome_unknown',
34
- retrySafe: false,
35
- },
36
- };
37
- const responseContent = {
38
- kind: 'function_response',
39
- id: operation.providerToolCallId,
40
- name: operation.toolName,
41
- result,
42
- isError: true,
43
- };
44
- const modelProjection = compatibilityToolResultProjection(responseContent, sessionId);
45
- const runtimeEvent = {
46
- id: `${operation.operationId}_response`,
47
- invocationId: operation.invocationId,
48
- runId: operation.runId,
49
- sessionId,
50
- turnId: operation.turnId,
51
- ts,
52
- partial: false,
53
- role: 'tool',
54
- author: 'tool',
55
- content: { ...responseContent, ...(modelProjection ? { modelProjection } : {}) },
56
- refs: {
57
- operationId: operation.operationId,
58
- toolCallId: operation.providerToolCallId,
59
- },
60
- };
61
- const committed = await store.commitToolOutcome({
23
+ const operations = await store.listUnsettledToolOperations(sessionIds);
24
+ for (const operation of operations) {
25
+ if (operation.recoveryMode !== 'outcome_unknown')
26
+ continue;
27
+ const ts = now();
28
+ const result = {
29
+ kind: 'text',
30
+ text: OUTCOME_UNKNOWN_TEXT,
31
+ uncertainOutcome: {
32
+ code: 'outcome_unknown',
33
+ retrySafe: false,
34
+ },
35
+ };
36
+ const responseContent = {
37
+ kind: 'function_response',
38
+ id: operation.providerToolCallId,
39
+ name: operation.toolName,
40
+ result,
41
+ isError: true,
42
+ };
43
+ const modelProjection = compatibilityToolResultProjection(responseContent, operation.sessionId);
44
+ const runtimeEvent = {
45
+ id: `${operation.operationId}_response`,
46
+ invocationId: operation.invocationId,
47
+ runId: operation.runId,
48
+ sessionId: operation.sessionId,
49
+ turnId: operation.turnId,
50
+ ts,
51
+ partial: false,
52
+ role: 'tool',
53
+ author: 'tool',
54
+ content: { ...responseContent, ...(modelProjection ? { modelProjection } : {}) },
55
+ refs: {
62
56
  operationId: operation.operationId,
63
- journalEventId: `${operation.operationId}_outcome`,
64
- runtimeEvent,
65
- committedAt: ts,
66
- });
67
- if (committed.created)
68
- recovered += 1;
69
- }
57
+ toolCallId: operation.providerToolCallId,
58
+ },
59
+ };
60
+ const committed = await store.commitToolOutcome({
61
+ operationId: operation.operationId,
62
+ journalEventId: `${operation.operationId}_outcome`,
63
+ runtimeEvent,
64
+ committedAt: ts,
65
+ });
66
+ if (committed.created)
67
+ recovered += 1;
70
68
  }
71
69
  return recovered;
72
70
  }
@@ -150,6 +150,8 @@ export class HostContextCoordinator {
150
150
  return notFound('Session does not exist');
151
151
  throw error;
152
152
  }
153
+ if (header.backend === 'plugin-executor')
154
+ return operationUnavailable('External executors own their context. Start a new task instead of compacting.');
153
155
  if (header.isArchived) {
154
156
  return sessionArchived('Cannot compact an archived Session');
155
157
  }
@@ -16,7 +16,7 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- import { defineInteractiveRuntimeHostComposition, } from './host-composition.js';
19
+ import { defineInteractiveRuntimeHostComposition, } from './host-composition-source.js';
20
20
  export async function createExecutionRuntimeHostCompositionSource(options, dependencies = {}) {
21
21
  const compositionOptions = {
22
22
  ...(options.initialization ? { initialization: options.initialization } : {}),
@@ -16,6 +16,8 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
+ import { createWorkHubResultRuntime } from './workhub-result-runtime.js';
20
+ import { createJevRoutingModel } from './jev-routing-model.js';
19
21
  import { copyWorkHubAttachmentsToTarget } from './workhub-message-attachments.js';
20
22
  import { createHash, randomUUID } from 'node:crypto';
21
23
  import { attachmentKindFromMimeType, MAX_READ_IMAGE_BYTES } from '@maka/core/attachments';
@@ -99,9 +101,10 @@ import { HostClientCapabilityCoordinator } from './client-capability-coordinator
99
101
  import { HostDailyReviewCoordinator } from './daily-review-coordinator.js';
100
102
  import { prepareHostAiSdkBackend } from './execution-model-composition.js';
101
103
  import { createInteractiveRunComposer, createInteractiveRunComposerFactory, routeInteractiveRunToolSurface, } from './interactive-run-composer.js';
102
- import { createHostGoalEvaluator, createHostDailyReviewModel, createHostMemoryExtractionModel, createHostPluginModel, createHostSessionEffectModel, } from './execution-model-authority.js';
104
+ import { readDuringBackendCreation, createHostGoalEvaluator, createHostDailyReviewModel, createHostMemoryExtractionModel, createHostPluginModel, createHostSessionEffectModel, } from './execution-model-authority.js';
103
105
  import { HostExecutionInspectCoordinator } from './execution-inspect-coordinator.js';
104
106
  import { HostExternalSessionCoordinator } from './external-session-coordinator.js';
107
+ import { boundedFailureDiagnostic } from './failure-diagnostic.js';
105
108
  import { HostSessionBundleCoordinator } from './session-bundle-coordinator.js';
106
109
  import { HostGoalCoordinator } from './goal-coordinator.js';
107
110
  import { HostGoalExecutionCoordinator } from './goal-execution-coordinator.js';
@@ -132,6 +135,7 @@ import { HostPlanCoordinator } from './plan-coordinator.js';
132
135
  import { HostProjectDirectoryAuthority, } from './project-directory-authority.js';
133
136
  import { HostProjectCatalogCoordinator } from './project-catalog-coordinator.js';
134
137
  import { HostProjectMembershipGate } from './project-membership-gate.js';
138
+ import { HostBuiltinExternalAgentPluginCoordinator, withBuiltinExternalAgentCatalog, } from './builtin-external-agent-plugins.js';
135
139
  import { HostPluginPlatformCoordinator } from './plugin-platform-coordinator.js';
136
140
  import { HostPluginPlatform } from './plugin-platform.js';
137
141
  import { RootAdmissionOwner } from './root-admission-owner.js';
@@ -149,7 +153,7 @@ import { HostStorageMaintenance } from './storage-maintenance.js';
149
153
  import { HostSessionRevisionCoordinator } from './session-revision-coordinator.js';
150
154
  import { HostSessionEffectCoordinator } from './session-effect-coordinator.js';
151
155
  import { SessionContinuityCoordinator } from './session-continuity-coordinator.js';
152
- import { createSessionTranscriptReader, } from './session-transcript-reader.js';
156
+ import { createSessionTranscriptReader, createTurnResultReader, } from './session-transcript-reader.js';
153
157
  import { HostSkillCatalogCoordinator, SkillCatalogInvocableContextError, } from './skill-catalog-coordinator.js';
154
158
  import { SkillCatalogRepository } from './skill-catalog-repository.js';
155
159
  import { HostSessionTodoCoordinator } from './session-todo-coordinator.js';
@@ -252,9 +256,28 @@ export async function createExecutionRuntimeHostComposition(context, options = {
252
256
  executors: pluginExecutors,
253
257
  clientBridge: pluginClientBridge,
254
258
  });
255
- const pluginPlatformCoordinator = new HostPluginPlatformCoordinator(pluginPlatform);
259
+ const pluginPlatformCoordinator = new HostPluginPlatformCoordinator(pluginPlatform, async (input) => {
260
+ if (input.kind === 'conversation') {
261
+ const header = await stores.sessionStore.readHeaderSnapshot(input.sessionId);
262
+ if (!header.executorId)
263
+ return [];
264
+ return pluginExecutors.catalog({
265
+ sessionId: input.sessionId,
266
+ executorId: header.executorId,
267
+ cwd: header.cwd,
268
+ ...(header.executorConfig ? { configuration: header.executorConfig } : {}),
269
+ });
270
+ }
271
+ const catalog = await pluginExecutors.catalog({ cwd: input.cwd });
272
+ return withBuiltinExternalAgentCatalog(catalog);
273
+ });
256
274
  const openedProjectCatalog = storage.projectCatalog;
257
275
  const runtimePolicyStores = storage.runtimePolicy;
276
+ const builtinExternalAgentPlugins = new HostBuiltinExternalAgentPluginCoordinator({
277
+ platform: pluginPlatform,
278
+ controlDirectory: context.owner.controlDirectory,
279
+ readPolicy: () => runtimePolicyStores.runtimePolicy.getSnapshot(),
280
+ });
258
281
  const oauthCredentials = new HostOAuthExecutionAuthority(runtimePolicyStores);
259
282
  const openedScheduledTaskStore = storage.scheduledTasks;
260
283
  const openedPlanStore = storage.plan;
@@ -622,6 +645,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
622
645
  }, projectMembership, context.requestDrain, new HostProjectDirectoryAuthority(options.projectDirectoryRoots));
623
646
  let rootCoordinator;
624
647
  let workHubCoordination;
648
+ let workHubResults;
625
649
  let canonicalProjection;
626
650
  let memory;
627
651
  let clientCapabilities;
@@ -633,7 +657,32 @@ export async function createExecutionRuntimeHostComposition(context, options = {
633
657
  let dailyReview;
634
658
  const rootPort = {
635
659
  readLatestRootTurnLineage: (identity) => requireRootCoordinator(rootCoordinator).readLatestRootTurnLineage(identity),
636
- readSessionHeader: (sessionId) => requireRootCoordinator(rootCoordinator).readSessionHeader(sessionId),
660
+ readSessionHeader: async (sessionId) => {
661
+ const projected = await requireRootCoordinator(rootCoordinator).readSessionHeader(sessionId);
662
+ if (!projected || projected.unavailableReason)
663
+ return projected;
664
+ const header = await stores.sessionStore.readHeaderSnapshot(sessionId);
665
+ if (!header.executorId)
666
+ return projected;
667
+ const [entry] = await pluginExecutors.catalog({
668
+ sessionId,
669
+ executorId: header.executorId,
670
+ cwd: header.cwd,
671
+ ...(header.executorConfig ? { configuration: header.executorConfig } : {}),
672
+ });
673
+ return {
674
+ ...projected,
675
+ idleOnly: true,
676
+ supportsAttachments: entry?.supportsAttachments ?? false,
677
+ ...(entry?.readiness === 'ready'
678
+ ? {}
679
+ : {
680
+ unavailableReason: entry?.readiness === 'history_only'
681
+ ? 'External conversation is history-only. Start a new task.'
682
+ : 'Executor is unavailable. Check External Agents settings.',
683
+ }),
684
+ };
685
+ },
637
686
  readRootState: (sessionId) => requireRootCoordinator(rootCoordinator).readRootState(sessionId),
638
687
  claimStopFence: (input, commitQueueFence, admission) => requireRootCoordinator(rootCoordinator).claimStopFence(input, commitQueueFence, admission),
639
688
  startFromMessage: (input, admission, commitAdmission) => requireRootCoordinator(rootCoordinator).startFromMessage(input, admission, commitAdmission),
@@ -675,8 +724,14 @@ export async function createExecutionRuntimeHostComposition(context, options = {
675
724
  continuity = new SessionContinuityCoordinator(context.hostEpoch, (sessionId) => canonicalProjectionReader.read(sessionId), sessionAdmission, context.requestDrain, transcriptReader, (sessionId) => hostChanges.publishSessionCatalog(sessionId), context.sessionAccessAuthority);
676
725
  const continuityCoordinator = continuity;
677
726
  const planStore = observeInteractivePlanStoreWriter(openedPlanStore, (sessionId) => continuityCoordinator.enqueueSessionDomainChanged(sessionId, 'plan'), context.requestDrain);
678
- unsubscribeTranscriptChanges = stores.sessionStore.subscribeTranscriptChanges((sessionId) => continuityCoordinator.enqueueCanonicalRefresh(sessionId));
679
- unsubscribeRuntimeEventCommits = stores.runtimeEventStore.subscribeRuntimeEventCommits((sessionId) => continuityCoordinator.enqueueTranscriptAdvanced(sessionId));
727
+ unsubscribeTranscriptChanges = stores.sessionStore.subscribeTranscriptChanges((sessionId) => {
728
+ continuityCoordinator.enqueueCanonicalRefresh(sessionId);
729
+ sessionAdmission.detach(() => workHubResults?.notify(sessionId));
730
+ });
731
+ unsubscribeRuntimeEventCommits = stores.runtimeEventStore.subscribeRuntimeEventCommits((sessionId) => {
732
+ continuityCoordinator.enqueueTranscriptAdvanced(sessionId);
733
+ sessionAdmission.detach(() => workHubResults?.notify(sessionId));
734
+ });
680
735
  unsubscribeUsageChanges = openedUsageStores.subscribeSessionUsageChanges((sessionId) => continuityCoordinator.enqueueSessionDomainChanged(sessionId, 'usage'));
681
736
  dailyReview = new HostDailyReviewCoordinator({
682
737
  store: openedDailyReviewStore,
@@ -716,7 +771,10 @@ export async function createExecutionRuntimeHostComposition(context, options = {
716
771
  preflightSessionSnapshot: (sessionId, interactionProjection) => canonicalProjectionReader.fitsCandidate(sessionId, {
717
772
  interactions: interactionProjection,
718
773
  }),
719
- refreshCanonicalContinuity: (sessionId, admission) => continuityCoordinator.refreshCanonical(sessionId, admission),
774
+ refreshCanonicalContinuity: async (sessionId, admission) => {
775
+ await continuityCoordinator.refreshCanonical(sessionId, admission);
776
+ sessionAdmission.detach(() => workHubResults?.notify(sessionId));
777
+ },
720
778
  onPoison: (error) => {
721
779
  if (poisonFailure)
722
780
  return;
@@ -783,7 +841,9 @@ export async function createExecutionRuntimeHostComposition(context, options = {
783
841
  goalTools: requireGoal(goal).tools,
784
842
  builtinTools,
785
843
  hostTools,
786
- resolveRootTools: (sessionId) => requireGraphCoordinator(graphCoordinator).toolsForSession(sessionId),
844
+ resolveRootTools: (sessionId) => sessionId === WORKHUB_COORDINATION_SESSION_ID && workHubResults
845
+ ? Promise.resolve([workHubResults.tool])
846
+ : requireGraphCoordinator(graphCoordinator).toolsForSession(sessionId),
787
847
  resolvePluginTools: (sessionId, coreTools) => pluginTools.resolveContributions(sessionId, coreTools),
788
848
  resolvePluginSystemPrompt: async (sessionId, promptContext, baseText) => {
789
849
  const assembly = await pluginSystemPrompt.assemble({
@@ -835,6 +895,15 @@ export async function createExecutionRuntimeHostComposition(context, options = {
835
895
  build: (factoryContext) => new PluginExecutorBackend({
836
896
  sessionId: factoryContext.sessionId,
837
897
  cwd: factoryContext.header.cwd,
898
+ ...(factoryContext.header.model === executorId
899
+ ? {}
900
+ : { model: factoryContext.header.model }),
901
+ ...(factoryContext.header.thinkingLevel
902
+ ? { thinkingLevel: factoryContext.header.thinkingLevel }
903
+ : {}),
904
+ ...(factoryContext.header.executorConfig
905
+ ? { configuration: factoryContext.header.executorConfig }
906
+ : {}),
838
907
  ...(factoryContext.systemPrompt ? { instructions: factoryContext.systemPrompt } : {}),
839
908
  binding,
840
909
  }),
@@ -911,7 +980,9 @@ export async function createExecutionRuntimeHostComposition(context, options = {
911
980
  const capabilitySnapshot = requireClientCapabilities(clientCapabilities).snapshotForSession(sessionId);
912
981
  try {
913
982
  const [graphTools, planState] = await Promise.all([
914
- requireGraphCoordinator(graphCoordinator).toolsForSession(sessionId),
983
+ sessionId === WORKHUB_COORDINATION_SESSION_ID && workHubResults
984
+ ? Promise.resolve([workHubResults.tool])
985
+ : requireGraphCoordinator(graphCoordinator).toolsForSession(sessionId),
915
986
  planStore.readState(sessionId),
916
987
  ]);
917
988
  const { runtimePolicy, surface } = await resolveInteractiveToolSurface({
@@ -1160,6 +1231,10 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1160
1231
  };
1161
1232
  clientCapabilities = new HostClientCapabilityCoordinator({
1162
1233
  activation: runtimePolicyActivation,
1234
+ isSessionRetired: async (sessionId) => {
1235
+ const state = await stores.sessionStore.probeSessionRemoval(sessionId);
1236
+ return (state.kind === 'removed' || (state.kind === 'present' && state.record.header.isArchived));
1237
+ },
1163
1238
  onModelToolsChanged: registerBackendInvalidation,
1164
1239
  interactions,
1165
1240
  grants: stores.interactionStore,
@@ -1235,9 +1310,32 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1235
1310
  }, {
1236
1311
  currentGraphId: (rootSessionId) => requireGraphCoordinator(graphCoordinator).currentGraphId(rootSessionId),
1237
1312
  beginNextGraphEpoch: async (rootSessionId) => (await requireGraphCoordinator(graphCoordinator).beginNextGraphEpoch(rootSessionId, (operation) => requireGraphSupervisorWake(graphSupervisorWake).runWithSessionWakesSuppressed(rootSessionId, operation, 'agent_graph_epoch_advanced'))).graphId,
1238
- }, (input) => sessionEffectCoordinator.nameSessionFromRootMessage(input), context.owner.capability.rootId, dependencies.workHubRoutingModel
1239
- ? (input) => workHubCoordination.prepareRoutingDecision(input)
1240
- : undefined);
1313
+ }, (input) => sessionEffectCoordinator.nameSessionFromRootMessage(input), context.owner.capability.rootId, async (input) => {
1314
+ // Explicit injection remains an experiment seam. Injected models own
1315
+ // policy/egress checks and cancellation; this bypasses the production
1316
+ // Jev preparation deadline (including its transcript-read protection).
1317
+ if (dependencies.workHubRoutingModel)
1318
+ return workHubCoordination.prepareRoutingDecision(input);
1319
+ // One admission budget covers policy/transcript reads, both Jev asks,
1320
+ // candidate resolution and transport cleanup; it is not per request.
1321
+ const signal = AbortSignal.any([
1322
+ ...(input.inputClosedSignal ? [input.inputClosedSignal] : []),
1323
+ AbortSignal.timeout(8_000),
1324
+ ]);
1325
+ try {
1326
+ const { policy } = await readDuringBackendCreation(() => runtimePolicyStores.runtimePolicy.getSnapshot(), signal);
1327
+ if (!policy.jev?.enabled || policy.privacy.incognitoActive)
1328
+ return undefined;
1329
+ return await readDuringBackendCreation(() => workHubCoordination.prepareRoutingDecision({ ...input, inputClosedSignal: signal }), signal);
1330
+ }
1331
+ catch {
1332
+ if (!input.inputClosedSignal?.aborted) {
1333
+ const failure = signal.aborted ? 'timeout' : 'preparation_unavailable';
1334
+ console.warn(`[runtime-host] Jev routing fallback: ${failure}`);
1335
+ }
1336
+ return undefined;
1337
+ }
1338
+ });
1241
1339
  const coordinator = rootCoordinator;
1242
1340
  const pluginModel = createHostPluginModel({
1243
1341
  runtimePolicy: runtimePolicyStores,
@@ -1590,6 +1688,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1590
1688
  });
1591
1689
  async function applyRuntimePolicyMutationEffects() {
1592
1690
  try {
1691
+ await builtinExternalAgentPlugins.reconcile();
1593
1692
  await requireMemory(memory).refreshAfterPolicyMutation();
1594
1693
  }
1595
1694
  catch (error) {
@@ -1613,8 +1712,33 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1613
1712
  continuity: continuityCoordinator,
1614
1713
  workspaceResolver,
1615
1714
  requestDrain: context.requestDrain,
1616
- assertExecutorAvailable: (sessionId, executorId) => {
1715
+ configureExecutor: async (header, configuration) => {
1716
+ if (!header.executorId)
1717
+ throw new Error('Session has no executor');
1718
+ await pluginExecutors.configureConversation(header.id, header.executorId, {
1719
+ conversationKey: header.id,
1720
+ cwd: header.cwd,
1721
+ configuration,
1722
+ });
1723
+ },
1724
+ retireExecutor: (sessionId) => pluginExecutors.retireConversation(sessionId),
1725
+ assertExecutorAvailable: async (sessionId, executorId, configuration, cwd) => {
1617
1726
  pluginExecutors.identity(sessionId, executorId);
1727
+ const [entry] = await pluginExecutors.catalog({
1728
+ cwd,
1729
+ executorId,
1730
+ discoverySessionId: sessionId,
1731
+ });
1732
+ if (!entry || entry.readiness !== 'ready')
1733
+ throw new Error('Executor is not ready');
1734
+ // Catalog-managed executors pin their confirmed configuration on every create path.
1735
+ // Providers without model discovery retain main's executor-specific model contract.
1736
+ if (entry.supportsModelChange || entry.models.length > 0) {
1737
+ if (configuration?.model &&
1738
+ !entry.models.some((model) => model.id === configuration.model))
1739
+ throw new Error('Executor model is unavailable');
1740
+ return configuration ?? {};
1741
+ }
1618
1742
  },
1619
1743
  ...(context.sessionAccessAuthority
1620
1744
  ? { sessionAccessAuthority: context.sessionAccessAuthority }
@@ -1640,7 +1764,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1640
1764
  },
1641
1765
  });
1642
1766
  workHubCoordination = new HostWorkHubCoordinationCoordinator({
1643
- routingModel: dependencies.workHubRoutingModel,
1767
+ routingModel: dependencies.workHubRoutingModel ?? createJevRoutingModel({ stores: runtimePolicyStores }),
1644
1768
  requestForm: (input) => interactions.requestForm(input),
1645
1769
  targetExecution: workHubTargetExecution,
1646
1770
  configureModel: (input) => sessionCatalog.configureWorkHubModel(input),
@@ -1789,7 +1913,12 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1789
1913
  workspace: input.create.workspace,
1790
1914
  name: input.create.title,
1791
1915
  ...(input.create.defaults?.executorId
1792
- ? { executorId: input.create.defaults.executorId }
1916
+ ? {
1917
+ executorId: input.create.defaults.executorId,
1918
+ ...(input.create.defaults.executorModel
1919
+ ? { executorModel: input.create.defaults.executorModel }
1920
+ : {}),
1921
+ }
1793
1922
  : {
1794
1923
  modelTarget: input.create.defaults?.model
1795
1924
  ? {
@@ -1803,6 +1932,9 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1803
1932
  ...(input.create.defaults?.permissionMode
1804
1933
  ? { permissionMode: input.create.defaults.permissionMode }
1805
1934
  : {}),
1935
+ ...(input.create.defaults?.thinkingLevel
1936
+ ? { thinkingLevel: input.create.defaults.thinkingLevel }
1937
+ : {}),
1806
1938
  collaborationMode: 'agent',
1807
1939
  orchestrationMode: 'default',
1808
1940
  })
@@ -1862,6 +1994,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1862
1994
  ? WORKHUB_COORDINATION_REPLACEMENT_SCHEMA_VERSION
1863
1995
  : 1,
1864
1996
  kind: 'delegation_assigned',
1997
+ returnResults: true,
1865
1998
  actionId: input.actionId,
1866
1999
  actionFingerprint: input.actionFingerprint,
1867
2000
  coordinationTurnId: input.coordinationTurnId ?? input.actionId,
@@ -1928,6 +2061,20 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1928
2061
  },
1929
2062
  requestDrain: context.requestDrain,
1930
2063
  });
2064
+ workHubResults = createWorkHubResultRuntime({
2065
+ stores,
2066
+ executions: coordinator,
2067
+ messages,
2068
+ interactions,
2069
+ admission: sessionAdmission,
2070
+ readTurnResult: createTurnResultReader({
2071
+ stores,
2072
+ canonicalPermissionOutcomes,
2073
+ ensureTranscriptLedger: (sessionId) => requireSessionManager(manager).ensureTranscriptLedgerForRead(sessionId),
2074
+ }),
2075
+ acquireResidency: () => context.acquireResidency('hosted-execution'),
2076
+ onError: (error) => console.error(`[runtime-host] WorkHub result reconciliation failed: ${boundedFailureDiagnostic(error)}`),
2077
+ });
1931
2078
  scheduledTasks = new HostScheduledTaskCoordinator({
1932
2079
  store: openedScheduledTaskStore,
1933
2080
  sessions: stores.sessionStore,
@@ -1950,6 +2097,9 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1950
2097
  const sessionBundles = new HostSessionBundleCoordinator({
1951
2098
  lease: context.owner.lease,
1952
2099
  fenceSubtree: (sessionId, operation) => requireSessionManager(manager).runSessionSubtreeQuiescentMutation(sessionId, operation),
2100
+ recoverInterruptedSessions: (sessionIds) => requireSessionManager(manager)
2101
+ .recoverInterruptedSessionsForSessions(sessionIds)
2102
+ .then(() => undefined),
1953
2103
  onImported: (sessionId) => hostChanges.publishSessionCatalog(sessionId),
1954
2104
  });
1955
2105
  const externalSessions = new HostExternalSessionCoordinator({
@@ -2007,7 +2157,13 @@ export async function createExecutionRuntimeHostComposition(context, options = {
2007
2157
  sessionEffects: sessionEffectCoordinator,
2008
2158
  graph: requireGraphCoordinator(graphCoordinator),
2009
2159
  graphWake: requireGraphSupervisorWake(graphSupervisorWake),
2010
- manager,
2160
+ manager: {
2161
+ finalizeChildWorkspacePatches: (sessionId) => requireSessionManager(manager).finalizeChildWorkspacePatches(sessionId),
2162
+ disposeSessionBackend: async (sessionId) => {
2163
+ await requireSessionManager(manager).disposeSessionBackend(sessionId);
2164
+ await pluginExecutors.retireConversation(sessionId);
2165
+ },
2166
+ },
2011
2167
  capabilities: clientCapabilities,
2012
2168
  continuity: continuityCoordinator,
2013
2169
  artifacts: openedArtifactStore,
@@ -2081,6 +2237,10 @@ export async function createExecutionRuntimeHostComposition(context, options = {
2081
2237
  (connectionId) => pluginPlatformCoordinator.releaseConnection(connectionId),
2082
2238
  ],
2083
2239
  }),
2240
+ createRuntimeHostDomainModule({
2241
+ id: 'builtin-external-agent-plugins',
2242
+ recovery: { state: () => builtinExternalAgentPlugins.recover() },
2243
+ }),
2084
2244
  createRuntimeHostDomainModule({
2085
2245
  id: 'memory',
2086
2246
  handlers: [requireMemory(memory).handlers],
@@ -2115,9 +2275,6 @@ export async function createExecutionRuntimeHostComposition(context, options = {
2115
2275
  recoverySessions = await stores.sessionStore.listForRecovery();
2116
2276
  await worktreeChildExecutor.recover(recoverySessions.flatMap((session) => session.subagentWorkspace ? [session.subagentWorkspace] : []));
2117
2277
  await sessionRevisions.recover();
2118
- for (const session of recoverySessions) {
2119
- await stores.runtimeEventStore.repairImmutableSteeringMessageProofsForRecovery(session.id);
2120
- }
2121
2278
  },
2122
2279
  },
2123
2280
  }),
@@ -2194,8 +2351,13 @@ export async function createExecutionRuntimeHostComposition(context, options = {
2194
2351
  await clientBoundRecovery;
2195
2352
  }
2196
2353
  catch (error) {
2354
+ // The registration mutation has already committed. Returning a
2355
+ // failure now would make the Client discard its new registration
2356
+ // identity and mistake the old registration's release for
2357
+ // authoritative Session retirement. Drain the unhealthy Host, but
2358
+ // acknowledge the committed mutation so reconnect can republish it.
2359
+ console.error(`[runtime-host] post-commit Client Capability recovery failed: ${boundedFailureDiagnostic(error)}`);
2197
2360
  context.requestDrain();
2198
- throw error;
2199
2361
  }
2200
2362
  }
2201
2363
  return outcome;
@@ -2258,6 +2420,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
2258
2420
  },
2259
2421
  },
2260
2422
  drain: [
2423
+ () => workHubResults?.coordinator.beginDrain(),
2261
2424
  () => turnAccessRequests?.beginDrain(),
2262
2425
  () => rootCoordinator?.beginDrain(),
2263
2426
  () => workspaceExecution?.beginDrain(),
@@ -2274,6 +2437,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
2274
2437
  rootCloseTask ??= coordinator.close();
2275
2438
  await rootCloseTask;
2276
2439
  },
2440
+ () => workHubResults?.coordinator.close(),
2277
2441
  () => runtimeResources?.close(),
2278
2442
  () => workspaceExecution?.close(),
2279
2443
  () => sessionEffects?.close(),
@@ -2330,7 +2494,10 @@ export async function createExecutionRuntimeHostComposition(context, options = {
2330
2494
  beginDrain();
2331
2495
  const handlers = composeRuntimeHostDomainHandlers(domainModules);
2332
2496
  const recover = () => {
2333
- recoveryTask ??= recoverRuntimeHostDomainModules(domainModules);
2497
+ recoveryTask ??= recoverRuntimeHostDomainModules(domainModules).then(() => {
2498
+ if (!draining)
2499
+ workHubResults?.coordinator.start();
2500
+ });
2334
2501
  return recoveryTask;
2335
2502
  };
2336
2503
  const close = () => {
@@ -305,6 +305,9 @@ function createAuxiliaryModelCallAuthority(input) {
305
305
  };
306
306
  }
307
307
  async function runHostAuxiliaryModelCall(authority, input) {
308
+ if (input.header.backend === 'plugin-executor') {
309
+ throw new AuxiliaryModelCallConfigurationError('Plugin executor Sessions do not provide a native auxiliary model');
310
+ }
308
311
  const target = await readAuxiliaryPreflight(authority, input.abortSignal, () => readDuringBackendCreation(() => resolveExecutionTarget(input.header, authority.runtimePolicy, authority.oauthCredentials, authority.createFetchTransport), input.abortSignal));
309
312
  const pricingSnapshot = await readAuxiliaryPreflight(authority, input.abortSignal, () => readDuringBackendCreation(() => authority.usage.pricing.snapshot(), input.abortSignal));
310
313
  const request = input.buildRequest(target);
@@ -589,6 +592,9 @@ function parseDailyReviewModelKey(modelKey) {
589
592
  return connectionSlug && modelId ? { connectionSlug, modelId } : undefined;
590
593
  }
591
594
  export async function resolveExecutionTarget(header, runtimePolicy, oauthCredentials, createFetchTransport) {
595
+ if (header.backend === 'plugin-executor') {
596
+ throw new AuxiliaryModelCallConfigurationError('Plugin Executor Sessions do not expose the native auxiliary model authority');
597
+ }
592
598
  const resolved = await runtimePolicy.operations.resolveExecutionConnection(executionConnectionRef(header));
593
599
  if (resolved.kind !== 'ready') {
594
600
  throw new AuxiliaryModelCallConfigurationError(`Runtime Host model connection is not ready: ${resolved.kind}`);
@@ -233,6 +233,10 @@ export function extensionPackageContentDigest(files) {
233
233
  }
234
234
  return `sha256-${hash.digest('hex')}`;
235
235
  }
236
+ /** Computes the canonical digest used by PluginPackageStore without installing the package. */
237
+ export async function extensionPackageDirectoryContentDigest(root) {
238
+ return extensionPackageContentDigest(await readDirectory(root));
239
+ }
236
240
  function safePath(value) {
237
241
  if (!value ||
238
242
  value.length > 512 ||