maka-agent 0.2.0-dev.24.20260907 → 0.2.0-dev.26.20260909

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 (154) hide show
  1. package/README.md +38 -19
  2. package/README.zh-CN.md +34 -19
  3. package/dist/mcp-capability-provider.js +4 -1
  4. package/dist/pi-transcript-tools.js +6 -0
  5. package/dist/pi-tui-layout.js +56 -10
  6. package/dist/pi-tui-mcp-status.js +2 -2
  7. package/dist/pi-tui-pickers.js +121 -30
  8. package/dist/pi-tui-runner.js +156 -42
  9. package/dist/pi-tui-todo.js +221 -0
  10. package/dist/pi-tui-transcript-viewer.js +134 -7
  11. package/dist/runtime-host-cli-context.js +70 -13
  12. package/dist/runtime-host-handoff-surface.js +51 -26
  13. package/dist/runtime-host-local-handoff.js +11 -1
  14. package/dist/runtime-host-service-manager.js +0 -3
  15. package/dist/runtime-host-session-channel.js +13 -0
  16. package/dist/runtime-host-session-driver.js +42 -1
  17. package/dist/tui-autocomplete-layout.js +3 -1
  18. package/dist/tui-copy-catalog.js +85 -6
  19. package/dist/tui-editor-render.js +36 -0
  20. package/dist/tui-mcp-control.js +41 -6
  21. package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
  22. package/node_modules/@maka/core/dist/agent-run.js +1 -0
  23. package/node_modules/@maka/core/dist/attachments.js +3 -0
  24. package/node_modules/@maka/core/dist/canonical-json.js +27 -0
  25. package/node_modules/@maka/core/dist/capabilities.js +35 -0
  26. package/node_modules/@maka/core/dist/computer-use.js +0 -1
  27. package/node_modules/@maka/core/dist/display-redaction.js +18 -0
  28. package/node_modules/@maka/core/dist/llm-connections.js +13 -0
  29. package/node_modules/@maka/core/dist/model-call-attempt.js +2 -0
  30. package/node_modules/@maka/core/dist/model-metadata.js +4 -0
  31. package/node_modules/@maka/core/dist/redaction.js +35 -0
  32. package/node_modules/@maka/core/dist/run-composition.js +77 -2
  33. package/node_modules/@maka/core/dist/runtime-event.js +3 -0
  34. package/node_modules/@maka/core/dist/session.js +57 -6
  35. package/node_modules/@maka/core/dist/slash-command-catalog.js +1 -0
  36. package/node_modules/@maka/core/dist/tool-result-record-schema.js +2 -1
  37. package/node_modules/@maka/core/dist/workhub-action-result.js +68 -0
  38. package/node_modules/@maka/core/package.json +3 -3
  39. package/node_modules/@maka/eval/dist/experiment-directory.js +4 -13
  40. package/node_modules/@maka/eval/dist/toolchain-verification.js +1 -1
  41. package/node_modules/@maka/mcp/dist/form-elicitation.js +213 -0
  42. package/node_modules/@maka/mcp/dist/index.js +337 -71
  43. package/node_modules/@maka/runtime/dist/agent-run-inspect.js +0 -13
  44. package/node_modules/@maka/runtime/dist/agent-run.js +90 -2
  45. package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +16 -8
  46. package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +57 -50
  47. package/node_modules/@maka/runtime/dist/archive-read-tool.js +2 -2
  48. package/node_modules/@maka/runtime/dist/context-budget-helpers.js +0 -16
  49. package/node_modules/@maka/runtime/dist/conversation-copy.js +153 -11
  50. package/node_modules/@maka/runtime/dist/github-copilot-oauth-enrollment.js +3 -3
  51. package/node_modules/@maka/runtime/dist/goal-continuation.js +5 -1
  52. package/node_modules/@maka/runtime/dist/ledger-tool-result-archive-reader.js +69 -1
  53. package/node_modules/@maka/runtime/dist/mcp-tools.js +7 -2
  54. package/node_modules/@maka/runtime/dist/model-fetcher.js +42 -2
  55. package/node_modules/@maka/runtime/dist/model-history.js +0 -112
  56. package/node_modules/@maka/runtime/dist/plugin-runtime.js +20 -10
  57. package/node_modules/@maka/runtime/dist/plugin-tool-service.js +205 -0
  58. package/node_modules/@maka/runtime/dist/provider-request-telemetry.js +8 -1
  59. package/node_modules/@maka/runtime/dist/request-shape.js +23 -0
  60. package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +1 -1
  61. package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +24 -1
  62. package/node_modules/@maka/runtime/dist/runtime-kernel.js +127 -13
  63. package/node_modules/@maka/runtime/dist/session-manager.js +20 -36
  64. package/node_modules/@maka/runtime/dist/stream-graph-coordinator.js +21 -0
  65. package/node_modules/@maka/runtime/dist/stream-graph-supervisor-tools.js +0 -5
  66. package/node_modules/@maka/runtime/dist/test-connection.js +0 -1
  67. package/node_modules/@maka/runtime/dist/tool-activation-identity.js +41 -0
  68. package/node_modules/@maka/runtime/dist/tool-availability.js +11 -1
  69. package/node_modules/@maka/runtime/dist/tool-result-archive-resource.js +63 -1
  70. package/node_modules/@maka/runtime/dist/tool-result-archive-transition.js +42 -12
  71. package/node_modules/@maka/runtime/dist/tool-result-archive.js +27 -4
  72. package/node_modules/@maka/runtime/package.json +1 -0
  73. package/node_modules/@maka/runtime-host/dist/client/connection.js +30 -5
  74. package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +52 -13
  75. package/node_modules/@maka/runtime-host/dist/client/host-handoff.js +2 -0
  76. package/node_modules/@maka/runtime-host/dist/client/host-retirement.js +4 -2
  77. package/node_modules/@maka/runtime-host/dist/client/peer-client.js +18 -1
  78. package/node_modules/@maka/runtime-host/dist/client/session-subscription.js +19 -0
  79. package/node_modules/@maka/runtime-host/dist/control/endpoint.js +1 -3
  80. package/node_modules/@maka/runtime-host/dist/node-error.js +22 -0
  81. package/node_modules/@maka/runtime-host/dist/operator/managed-deployment.js +1 -3
  82. package/node_modules/@maka/runtime-host/dist/peer-mesh/limits.js +0 -1
  83. package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +1 -1
  84. package/node_modules/@maka/runtime-host/dist/peer-reachability/publisher.js +1 -3
  85. package/node_modules/@maka/runtime-host/dist/protocol/index.js +9 -1
  86. package/node_modules/@maka/runtime-host/dist/protocol/operations.js +3 -2
  87. package/node_modules/@maka/runtime-host/dist/protocol/plan.js +1 -0
  88. package/node_modules/@maka/runtime-host/dist/protocol/plugin-platform.js +27 -5
  89. package/node_modules/@maka/runtime-host/dist/protocol/project-catalog.js +2 -2
  90. package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +1 -0
  91. package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +86 -157
  92. package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +4 -0
  93. package/node_modules/@maka/runtime-host/dist/server/agent-graph-coordinator.js +0 -3
  94. package/node_modules/@maka/runtime-host/dist/server/canonical-session-projection.js +2 -1
  95. package/node_modules/@maka/runtime-host/dist/server/connection-session.js +28 -8
  96. package/node_modules/@maka/runtime-host/dist/server/daily-review-coordinator.js +112 -56
  97. package/node_modules/@maka/runtime-host/dist/server/execution-artifacts.js +32 -32
  98. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +85 -25
  99. package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +42 -14
  100. package/node_modules/@maka/runtime-host/dist/server/failure-diagnostic.js +24 -0
  101. package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +7 -3
  102. package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +3 -3
  103. package/node_modules/@maka/runtime-host/dist/server/host-session-availability.js +5 -2
  104. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +3 -2
  105. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-tool-profile.js +34 -4
  106. package/node_modules/@maka/runtime-host/dist/server/interactive-run-composer.js +51 -23
  107. package/node_modules/@maka/runtime-host/dist/server/operation-dispatcher.js +2 -7
  108. package/node_modules/@maka/runtime-host/dist/server/plugin-platform-coordinator.js +6 -0
  109. package/node_modules/@maka/runtime-host/dist/server/plugin-platform.js +6 -0
  110. package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +110 -14
  111. package/node_modules/@maka/runtime-host/dist/server/runtime-resource-coordinator.js +11 -8
  112. package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +31 -21
  113. package/node_modules/@maka/runtime-host/dist/server/serial-outbound-writer.js +1 -1
  114. package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +20 -8
  115. package/node_modules/@maka/runtime-host/dist/server/session-retirement-coordinator.js +5 -2
  116. package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +4 -0
  117. package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +15 -104
  118. package/node_modules/@maka/runtime-host/dist/server/shared-session-transcript.js +3 -0
  119. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +59 -82
  120. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +132 -139
  121. package/node_modules/@maka/runtime-host/dist/server/workhub-message-attachments.js +46 -0
  122. package/node_modules/@maka/storage/dist/agent-run-store.js +14 -1
  123. package/node_modules/@maka/storage/dist/artifact-store.js +40 -3
  124. package/node_modules/@maka/storage/dist/atomic-file-write.js +74 -0
  125. package/node_modules/@maka/storage/dist/claude-code-session-adapter.js +0 -1
  126. package/node_modules/@maka/storage/dist/codex-session-adapter.js +284 -196
  127. package/node_modules/@maka/storage/dist/credential-store.js +12 -63
  128. package/node_modules/@maka/storage/dist/execution-stores.js +4 -1
  129. package/node_modules/@maka/storage/dist/git-exec.js +61 -0
  130. package/node_modules/@maka/storage/dist/git-worktree-child-executor.js +8 -35
  131. package/node_modules/@maka/storage/dist/goal-authority.js +2 -2
  132. package/node_modules/@maka/storage/dist/interaction-store.js +2 -2
  133. package/node_modules/@maka/storage/dist/mcp-config-store.js +10 -25
  134. package/node_modules/@maka/storage/dist/project-catalog.js +2 -23
  135. package/node_modules/@maka/storage/dist/runtime-event-invariants.js +2 -2
  136. package/node_modules/@maka/storage/dist/runtime-policy/connection-catalog-document.js +8 -3
  137. package/node_modules/@maka/storage/dist/scheduled-task-store.js +249 -283
  138. package/node_modules/@maka/storage/dist/session-bundle-manifest.js +5 -17
  139. package/node_modules/@maka/storage/dist/session-bundle-policy.js +2 -1
  140. package/node_modules/@maka/storage/dist/session-copy-cleanup.js +2 -1
  141. package/node_modules/@maka/storage/dist/session-store.js +14 -2
  142. package/node_modules/@maka/storage/dist/settings-store.js +8 -4
  143. package/node_modules/@maka/storage/dist/sqlite-artifact-metadata.js +11 -0
  144. package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +1 -2
  145. package/node_modules/@maka/storage/dist/sqlite-session-metadata-schema.js +12 -1
  146. package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +67 -3
  147. package/node_modules/@maka/storage/dist/stable-storage.js +14 -1
  148. package/node_modules/@maka/storage/dist/storage-id.js +28 -0
  149. package/node_modules/@maka/storage/dist/tool-result-archive-evidence.js +31 -4
  150. package/node_modules/@maka/storage/dist/workspace-identity.js +2 -15
  151. package/node_modules/@maka/storage/dist/workspace-version-authority-internal.js +1 -8
  152. package/package.json +1 -1
  153. package/node_modules/@maka/core/dist/workhub-creation-intent.js +0 -990
  154. package/node_modules/@maka/core/dist/workhub-session-resolver.js +0 -50
@@ -52,31 +52,44 @@ export function createInteractiveRunComposer(input) {
52
52
  : input.builtinTools;
53
53
  const inventorySnapshotFor = createTurnSkillInventorySnapshotResolver(input.skills);
54
54
  const inventoryFor = async (context) => (await inventorySnapshotFor(context)).inventory;
55
- const defaultTools = input.boundTools
56
- ? input.boundTools
57
- : buildDefaultHostTools(input.sessionTodo, inventoryFor, builtinTools, input.hostTools, input.scheduledTaskTool, input.goalTools, input.parentAgentTools, input.plan, input.deepResearch?.tools);
58
55
  const hasToolCeiling = input.boundTools !== undefined || input.toolProfile !== undefined;
59
- const clientCapabilityTools = hasToolCeiling ? [] : (input.clientCapabilities?.tools ?? []);
60
- const unscopedCandidateTools = [...defaultTools, ...clientCapabilityTools];
61
- const routedCandidateTools = input.deepResearch
62
- ? unscopedCandidateTools.filter(isDeepResearchToolAllowed)
63
- : unscopedCandidateTools;
64
- const candidateTools = projectHostedExecutionTools(routedCandidateTools, input.toolProfile);
65
56
  const activeExecution = input.plan ? activePlanExecution(input.plan.state) : undefined;
66
- const selectedTools = input.plan
67
- ? selectCollaborationTools({
68
- mode: input.plan.mode,
69
- tools: candidateTools,
70
- hasActiveExecution: activeExecution !== undefined,
71
- fullAccess: input.plan.permissionMode === 'bypass',
72
- })
73
- : candidateTools;
74
- // A bound tool list is an exact child/local activation ceiling. Dynamic
75
- // capabilities must be included by the authority that constructs that
76
- // list. The ceiling is also an exact wire contract: no deferred search
77
- // groups inside it, so the bound tools stay fully visible.
78
- const tools = [...selectedTools];
79
- assertUniqueToolNames(tools);
57
+ // The base Host binding is immutable for this backend. Only scoped plugin
58
+ // contributions are sampled at logical step boundaries.
59
+ const defaultTools = input.boundTools
60
+ ? input.boundTools
61
+ : buildDefaultHostTools(input.sessionTodo, inventoryFor, builtinTools, input.hostTools ?? [], input.scheduledTaskTool, input.goalTools, input.parentAgentTools, input.plan, input.deepResearch?.tools);
62
+ const clientCapabilityTools = input.boundTools !== undefined ||
63
+ (input.toolProfile !== undefined && input.toolProfile !== 'workhub-coordination-v2')
64
+ ? []
65
+ : (input.clientCapabilities?.tools ?? []);
66
+ const resolveTools = () => {
67
+ const stableHostTools = [...defaultTools, ...clientCapabilityTools];
68
+ const additionalTools = hasToolCeiling
69
+ ? []
70
+ : (input.resolveAdditionalTools?.(stableHostTools) ?? []);
71
+ const unscopedCandidateTools = [...stableHostTools, ...additionalTools];
72
+ const routedCandidateTools = input.deepResearch
73
+ ? unscopedCandidateTools.filter(isDeepResearchToolAllowed)
74
+ : unscopedCandidateTools;
75
+ const candidateTools = projectHostedExecutionTools(routedCandidateTools, input.toolProfile);
76
+ const selectedTools = input.plan
77
+ ? selectCollaborationTools({
78
+ mode: input.plan.mode,
79
+ tools: candidateTools,
80
+ hasActiveExecution: activeExecution !== undefined,
81
+ fullAccess: input.plan.permissionMode === 'bypass',
82
+ })
83
+ : candidateTools;
84
+ // A bound tool list is an exact child/local activation ceiling. Dynamic
85
+ // capabilities must be included by the authority that constructs that
86
+ // list. The ceiling is also an exact wire contract: no deferred search
87
+ // groups inside it, so the bound tools stay fully visible.
88
+ const resolved = [...selectedTools];
89
+ assertUniqueToolNames(resolved);
90
+ return Object.freeze(resolved);
91
+ };
92
+ const tools = resolveTools();
80
93
  const hostCapabilities = buildHostCapabilitiesFromBinding(tools.map(({ name }) => name));
81
94
  const toolAvailability = hasToolCeiling
82
95
  ? undefined
@@ -160,6 +173,7 @@ export function createInteractiveRunComposer(input) {
160
173
  composerId: INTERACTIVE_RUN_COMPOSER_ID,
161
174
  composerRevision: INTERACTIVE_RUN_COMPOSER_REVISION,
162
175
  tools,
176
+ resolveTools,
163
177
  toolAvailability,
164
178
  resolveSystemPrompt,
165
179
  });
@@ -248,6 +262,20 @@ export function createInteractiveRunComposerFactory(input) {
248
262
  ...(clientCapabilities ? { clientCapabilities } : {}),
249
263
  ...(input.builtinTools ? { builtinTools: input.builtinTools } : {}),
250
264
  ...(hostTools.length > 0 ? { hostTools } : {}),
265
+ ...(input.resolvePluginTools && !backendContext.tools
266
+ ? {
267
+ resolveAdditionalTools: (hostTools) => {
268
+ return routeInteractiveRunToolSurface({
269
+ runtimePolicy,
270
+ connection,
271
+ modelId,
272
+ hostTools: input.resolvePluginTools(backendContext.sessionId, hostTools).tools,
273
+ worktreePatchWriteBackAvailable: input.worktreePatchWriteBackAvailable,
274
+ tavilyReady,
275
+ }).hostTools;
276
+ },
277
+ }
278
+ : {}),
251
279
  ...(input.scheduledTaskTool ? { scheduledTaskTool: input.scheduledTaskTool } : {}),
252
280
  ...(input.goalTools ? { goalTools: input.goalTools } : {}),
253
281
  ...(parentAgentTools ? { parentAgentTools } : {}),
@@ -16,14 +16,13 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- import { truncateUtf8 } from '@maka/core/diagnostic-log';
20
- import { redactSecrets } from '@maka/core/redaction';
21
19
  import { HOST_OPERATION_SPECS, decodeOperationOutcome, } from '../protocol/index.js';
22
20
  import { HOST_BOOTSTRAP_OPERATION_SPECS } from '../protocol/host-status.js';
23
21
  import { HOST_RESOURCE_OPERATION_SPECS } from '../protocol/host-resources.js';
24
22
  import { ACCESS_AUTHORITY_OPERATION_SPECS } from '../protocol/access-authority.js';
25
23
  import { SESSION_COLLABORATION_OPERATION_SPECS } from '../protocol/session-collaboration.js';
26
24
  import { PEER_MESH_OPERATION_SPECS } from '../protocol/peer-mesh.js';
25
+ import { boundedFailureDiagnostic } from './failure-diagnostic.js';
27
26
  import { createPeerMeshOperationHandlers } from './peer-mesh-authority.js';
28
27
  /**
29
28
  * The spec objects a Runtime Host serves from its own core — operations that
@@ -144,7 +143,7 @@ async function dispatchTypedOperation(request, handlers, context) {
144
143
  outcome = decodeOperationOutcome(request.operation, await handler(request.input, context));
145
144
  }
146
145
  catch (error) {
147
- console.error(`[runtime-host] unexpected ${request.operation} failure: ${boundedUnexpectedFailure(error)}`);
146
+ console.error(`[runtime-host] unexpected ${request.operation} failure: ${boundedFailureDiagnostic(error)}`);
148
147
  return operationFailureResponse(request, 'internal_failure', 'Runtime Host operation failed');
149
148
  }
150
149
  return outcome.ok
@@ -161,7 +160,3 @@ async function dispatchTypedOperation(request, handlers, context) {
161
160
  error: outcome.error,
162
161
  };
163
162
  }
164
- function boundedUnexpectedFailure(error) {
165
- const details = error instanceof Error ? error.stack || `${error.name}: ${error.message}` : String(error);
166
- return truncateUtf8(redactSecrets(details), 8 * 1024, '\n<diagnostic truncated>');
167
- }
@@ -56,6 +56,12 @@ export class HostPluginPlatformCoordinator {
56
56
  const inspections = flattenInspections(this.platform.inspect(input.rootId));
57
57
  return { ok: true, result: boundedPage('entries', inspections, input) };
58
58
  }
59
+ if (input.view === 'tools') {
60
+ return {
61
+ ok: true,
62
+ result: boundedPage('tools', this.platform.inspectTools(input.rootId), input),
63
+ };
64
+ }
59
65
  if (input.view === 'failures') {
60
66
  return { ok: true, result: boundedPage('failures', failures, input) };
61
67
  }
@@ -42,6 +42,7 @@ export class HostPluginPlatform {
42
42
  #packages;
43
43
  #packageLoader;
44
44
  #store;
45
+ #tools;
45
46
  #authority = emptyCompositionAuthority();
46
47
  #desired = emptyCompositionState();
47
48
  #mutation = Promise.resolve();
@@ -62,6 +63,7 @@ export class HostPluginPlatform {
62
63
  this.#packageLoader =
63
64
  options.packageLoader ?? new TrustedPluginPackageLoader(controlDirectory, this.#packages);
64
65
  this.#store = options.store ?? new HostPluginCompositionStore(controlDirectory);
66
+ this.#tools = options.tools;
65
67
  }
66
68
  async recover() {
67
69
  if (this.#recoveryStarted ||
@@ -338,6 +340,10 @@ export class HostPluginPlatform {
338
340
  this.#assertReadable();
339
341
  return this.#composition.inspectTree(rootId);
340
342
  }
343
+ inspectTools(rootId) {
344
+ this.#assertReadable();
345
+ return this.#tools?.inspect(rootId) ?? Object.freeze([]);
346
+ }
341
347
  async status() {
342
348
  this.#assertReadable();
343
349
  return Object.freeze({
@@ -21,7 +21,7 @@ import { isDeepStrictEqual } from 'node:util';
21
21
  import { readLogicalRuntimeExecution, readLogicalRuntimeExecutionForRun, } from '@maka/core/runtime-logical-execution';
22
22
  import { runtimeHandoffPause } from '@maka/core/runtime-handoff';
23
23
  import { INLINE_REFERENCE_MAX_COUNT, messageContentDigest, messageContentsEqual, normalizeMessageContent, } from '@maka/core/events';
24
- import { isWorkHubCoordinationSessionId } from '@maka/core/session';
24
+ import { WORKHUB_COORDINATION_SESSION_ID, isWorkHubCoordinationSessionId, } from '@maka/core/session';
25
25
  import { resolveEffectiveOrchestration } from '@maka/core/orchestration';
26
26
  import { decodeSkillInvocationResult, } from '@maka/core/skill-invocation';
27
27
  import { agentGraphIdForRootSession } from '@maka/runtime/stream-graph-coordinator';
@@ -222,6 +222,10 @@ export class RootTurnCoordinator {
222
222
  throw error;
223
223
  }
224
224
  }
225
+ /** Called under Session admission before changing an execution's authority ceiling. */
226
+ isSessionExecutionIdle(sessionId) {
227
+ return (!this.#recoveryPlansBySession.has(sessionId) && this.readRootState(sessionId).kind === 'idle');
228
+ }
225
229
  readRootState(sessionId) {
226
230
  const active = this.#executions.get(sessionId);
227
231
  if (active) {
@@ -565,7 +569,10 @@ export class RootTurnCoordinator {
565
569
  if (isWorkHubCoordinationSessionId(input.sessionId)) {
566
570
  return Promise.reject(new RuntimeHostedRootUnavailableError(input.sessionId, WORKHUB_COORDINATION_EXECUTION_UNAVAILABLE_REASON));
567
571
  }
568
- return this.runCommand(async () => {
572
+ // Admission is active work even while queued behind a Session gate. Its
573
+ // residency overlaps the execution residency until admission settles.
574
+ const residency = this.acquireRecoveryResidency();
575
+ const admission = this.runCommand(async () => {
569
576
  const activeAtEntry = this.#executions.has(input.sessionId);
570
577
  let reservation = preparedReservation ?? (activeAtEntry ? undefined : this.reserveRootTurn(input.sessionId));
571
578
  if (preparedReservation && this.#admissions.get(input.sessionId) !== preparedReservation) {
@@ -674,6 +681,7 @@ export class RootTurnCoordinator {
674
681
  throw error.cause;
675
682
  throw error;
676
683
  });
684
+ return admission.finally(() => residency.release());
677
685
  }
678
686
  lookup(sessionId, turnId) {
679
687
  return this.runCommand(async () => {
@@ -1090,15 +1098,92 @@ export class RootTurnCoordinator {
1090
1098
  if (!isWorkHubCoordinationSessionId(request.sessionId)) {
1091
1099
  return Promise.resolve(operationUnavailable('WorkHub Coordination execution requires its reserved Session'));
1092
1100
  }
1101
+ if ((request.execution.operation === 'action') !== (request.operation !== undefined)) {
1102
+ return Promise.resolve(operationUnavailable('Coordination execution mode does not match its runner'));
1103
+ }
1093
1104
  return this.startRootMessage(request, context);
1094
1105
  }
1095
- /**
1096
- * Whether a durable root Turn already owns this identity. WorkHub also writes
1097
- * Coordination Turns outside this coordinator, and must not append a second
1098
- * triplet into a Turn this admission ledger already owns.
1099
- */
1100
- async hasRootTurnAdmission(sessionId, turnId) {
1101
- return (await this.stores.agentRunStore.readRootTurnAdmission(sessionId, turnId)) !== undefined;
1106
+ async runWorkHubCoordinationOperation(request, context) {
1107
+ if (request.execution.operation !== 'action' || !request.operation) {
1108
+ return operationUnavailable('Coordination action requires a Host operation');
1109
+ }
1110
+ let turnId = request.turnId;
1111
+ let recoveredReceipt;
1112
+ // A retry preserves the action identity, but never reopens a terminal Run.
1113
+ // The existing admission chain and terminal facts identify prior attempts.
1114
+ for (;;) {
1115
+ const admission = await this.stores.agentRunStore.readRootTurnAdmission(request.sessionId, turnId);
1116
+ if (!admission)
1117
+ break;
1118
+ if (!rootExecutionMatches(admission.execution, request.execution))
1119
+ return operationConflict('Coordination action identity belongs to different content');
1120
+ const run = await this.readRunIfPresent(request.sessionId, admission.runId);
1121
+ if (!run)
1122
+ break;
1123
+ const snapshot = await this.readCanonicalSnapshot(request.sessionId, turnId, admission.runId, run);
1124
+ if (!isTerminalSnapshot(snapshot) || snapshot.status === 'completed')
1125
+ break;
1126
+ // A crash after the receipt does not erase a completed Host effect.
1127
+ const events = await this.stores.runtimeEventStore.readImmutableRuntimeEvents(request.sessionId, admission.runId);
1128
+ recoveredReceipt ??= events.find((event) => event.actions?.coordination)?.actions
1129
+ ?.coordination;
1130
+ turnId = `whretry_${createHash('sha256').update(admission.runId).digest('hex').slice(0, 48)}`;
1131
+ }
1132
+ const receiptToReplay = recoveredReceipt;
1133
+ const started = await this.startWorkHubCoordinationMessage({
1134
+ ...request,
1135
+ turnId,
1136
+ ...(receiptToReplay ? { operation: async () => receiptToReplay } : {}),
1137
+ }, context);
1138
+ if (!started.ok)
1139
+ return started;
1140
+ const active = this.#executions.get(request.sessionId);
1141
+ if (active?.turnId === turnId)
1142
+ await active.done;
1143
+ const snapshot = await this.readCanonicalSnapshot(request.sessionId, turnId, started.result.runId);
1144
+ if (snapshot.status !== 'completed')
1145
+ return operationUnavailable('Coordination operation did not complete');
1146
+ const events = await this.stores.runtimeEventStore.readImmutableRuntimeEvents(request.sessionId, started.result.runId);
1147
+ const receipt = events.find((event) => event.actions?.coordination)?.actions?.coordination;
1148
+ return receipt
1149
+ ? { ok: true, result: receipt }
1150
+ : operationUnavailable('Coordination receipt is unavailable');
1151
+ }
1152
+ coordinationOperation(request, admission) {
1153
+ if (request.execution.kind !== 'workhub_coordination' ||
1154
+ !('operation' in request) ||
1155
+ !request.operation)
1156
+ return undefined;
1157
+ const execute = request.operation;
1158
+ const content = requireHostedExecutionMessageContent(admission);
1159
+ return {
1160
+ sessionId: admission.sessionId,
1161
+ turnId: admission.turnId,
1162
+ runId: admission.runId,
1163
+ userMessageId: admission.userMessageId,
1164
+ execution: admission.execution,
1165
+ content,
1166
+ start: ({ runId, userMessageId, onRunStarted }) => this.manager.runCoordinationOperation(admission.sessionId, { turnId: admission.turnId, ...content }, { runId, userMessageId, onRunStarted }, () => execute(admission.turnId)),
1167
+ };
1168
+ }
1169
+ /** Accepts a model action against the exact live WorkHub root and its durable user input. */
1170
+ readActiveWorkHubRequest(turnId) {
1171
+ const sessionId = WORKHUB_COORDINATION_SESSION_ID;
1172
+ return this.sessionAdmission.run(sessionId, async () => {
1173
+ const active = this.#executions.get(sessionId);
1174
+ if (!active || active.turnId !== turnId)
1175
+ return undefined;
1176
+ const [admission, header] = await Promise.all([
1177
+ this.stores.agentRunStore.readRootTurnAdmission(sessionId, turnId),
1178
+ this.stores.sessionStore.readHeaderSnapshot(sessionId),
1179
+ ]);
1180
+ if (this.#executions.get(sessionId) !== active ||
1181
+ admission?.runId !== active.runId ||
1182
+ admission.execution.kind !== 'workhub_coordination' ||
1183
+ header.toolProfile !== 'workhub-coordination-v2')
1184
+ return undefined;
1185
+ return requireHostedExecutionMessageContent(admission);
1186
+ });
1102
1187
  }
1103
1188
  startRootMessage(request, context) {
1104
1189
  return this.runCommand(async () => {
@@ -1115,7 +1200,7 @@ export class RootTurnCoordinator {
1115
1200
  if (existing.execution.kind !== request.execution.kind) {
1116
1201
  return completedStart(operationConflict('Turn identity belongs to a different execution kind'));
1117
1202
  }
1118
- if (!isDeepStrictEqual(existing.execution, request.execution)) {
1203
+ if (!rootExecutionMatches(existing.execution, request.execution)) {
1119
1204
  return completedStart(operationConflict('Turn identity belongs to a different execution payload'));
1120
1205
  }
1121
1206
  let content;
@@ -1141,7 +1226,7 @@ export class RootTurnCoordinator {
1141
1226
  return completedStart({ ok: true, result: snapshot });
1142
1227
  }
1143
1228
  }
1144
- return this.prepareAdmittedTurn(activationInputForAdmission(existing), existing, context.acquireResidency, lease, undefined, undefined, reservation);
1229
+ return this.prepareAdmittedTurn(activationInputForAdmission(existing), existing, context.acquireResidency, lease, undefined, this.coordinationOperation(request, existing), reservation);
1145
1230
  }
1146
1231
  reservation ??= this.reserveRootTurn(request.sessionId);
1147
1232
  if (!reservation) {
@@ -1186,7 +1271,8 @@ export class RootTurnCoordinator {
1186
1271
  const attachmentError = await this.attachmentValidator?.validateTurnAttachments(request.sessionId, attachments);
1187
1272
  if (attachmentError)
1188
1273
  return completedStart(operationConflict(attachmentError));
1189
- const binding = request.execution.kind === 'workhub_coordination'
1274
+ const binding = request.execution.kind === 'workhub_coordination' &&
1275
+ header.toolProfile === 'workhub-coordination-v1'
1190
1276
  ? undefined
1191
1277
  : prepared.commitCapabilityBinding
1192
1278
  ? await prepared.commitCapabilityBinding()
@@ -1226,7 +1312,7 @@ export class RootTurnCoordinator {
1226
1312
  if (!rootMessageAdmissionMatches(admitted.admission, request, canonicalContent.content, context.turnAdmissionAuthorization)) {
1227
1313
  return completedStart(operationConflict('Turn identity was already admitted with a different payload'));
1228
1314
  }
1229
- return this.prepareAdmittedTurn(activationInputForAdmission(admitted.admission), admitted.admission, context.acquireResidency, lease, undefined, undefined, reservation);
1315
+ return this.prepareAdmittedTurn(activationInputForAdmission(admitted.admission), admitted.admission, context.acquireResidency, lease, undefined, this.coordinationOperation(request, admitted.admission), reservation);
1230
1316
  });
1231
1317
  const disposition = await admissionTask.finally(() => {
1232
1318
  if (reservation)
@@ -2198,8 +2284,18 @@ function throwHostedStopError(sessionId, outcome) {
2198
2284
  throw new RuntimeHostedRootUnavailableError(sessionId, outcome.error.message);
2199
2285
  }
2200
2286
  }
2287
+ /** Compatibility may omit only the action identity absent from an older admission. */
2288
+ function rootExecutionMatches(stored, incoming) {
2289
+ if (stored.kind === 'workhub_coordination' &&
2290
+ incoming.kind === 'workhub_coordination' &&
2291
+ stored.actionId === undefined) {
2292
+ const { actionId: _actionId, ...legacyIncoming } = incoming;
2293
+ return isDeepStrictEqual(stored, legacyIncoming);
2294
+ }
2295
+ return isDeepStrictEqual(stored, incoming);
2296
+ }
2201
2297
  function rootMessageAdmissionMatches(admission, request, content, authorization) {
2202
- return (isDeepStrictEqual(admission.execution, request.execution) &&
2298
+ return (rootExecutionMatches(admission.execution, request.execution) &&
2203
2299
  (request.execution.kind === 'external_message' && request.execution.inputDigest
2204
2300
  ? true
2205
2301
  : messageContentsEqual(requireHostedExecutionMessageContent(admission), content)) &&
@@ -23,6 +23,7 @@ import { ShellRunPtyControlClosedError, isShellRunResourceRef, } from '@maka/run
23
23
  import { defaultShellPlan, ShellPreferenceError } from '@maka/runtime/shell-detect';
24
24
  import { isSessionNotFoundError } from '@maka/storage/execution-stores';
25
25
  import { decodeRuntimeResourceControllerAcquireResult, decodeRuntimeResourceControllerControlResult, decodeRuntimeResourceQueryResult, decodeRuntimeResourceStopResult, decodeRuntimeResourceStartResult, RUNTIME_RESOURCE_CONTROLLER_ACQUIRE_RESULT_MAX_BYTES, RUNTIME_RESOURCE_MAX_CONTROL_SEQUENCE, } from '../protocol/index.js';
26
+ import { boundedFailureDiagnostic } from './failure-diagnostic.js';
26
27
  import { boundedRuntimeResourceSnapshot, canonicalRuntimeResources, createRuntimeResourcePage, runtimeResourceRevision, runtimeResourceSnapshotFromResult, } from './runtime-resource-projection.js';
27
28
  const MAX_CONTROL_REPLAYS = 128;
28
29
  /** Owns Host Shell/PTY tools plus the connection-scoped Client controller fence. */
@@ -186,8 +187,7 @@ export class HostRuntimeResourceCoordinator {
186
187
  if (isSessionNotFoundError(error)) {
187
188
  return queryFailure('not_found', 'Session was not found');
188
189
  }
189
- this.#requestDrain();
190
- return queryFailure('internal_failure', 'Session state is unavailable');
190
+ return this.#canonicalReadFailure(error, 'Session state is unavailable');
191
191
  }
192
192
  if (input.kind === 'get') {
193
193
  try {
@@ -206,9 +206,8 @@ export class HostRuntimeResourceCoordinator {
206
206
  }),
207
207
  };
208
208
  }
209
- catch {
210
- this.#requestDrain();
211
- return queryFailure('internal_failure', 'Runtime Resource state is unavailable');
209
+ catch (error) {
210
+ return this.#canonicalReadFailure(error, 'Runtime Resource state is unavailable');
212
211
  }
213
212
  }
214
213
  let updates;
@@ -218,9 +217,8 @@ export class HostRuntimeResourceCoordinator {
218
217
  updates = updates.filter((update) => update.sessionId === input.sessionId);
219
218
  }
220
219
  }
221
- catch {
222
- this.#requestDrain();
223
- return queryFailure('internal_failure', 'Runtime Resource state is unavailable');
220
+ catch (error) {
221
+ return this.#canonicalReadFailure(error, 'Runtime Resource state is unavailable');
224
222
  }
225
223
  try {
226
224
  const resources = canonicalRuntimeResources(updates);
@@ -251,6 +249,11 @@ export class HostRuntimeResourceCoordinator {
251
249
  ? queryFailure('not_found', 'Session was not found')
252
250
  : outcome;
253
251
  }
252
+ #canonicalReadFailure(error, message) {
253
+ console.error(`[runtime-host] canonical Runtime Resource read failed: ${boundedFailureDiagnostic(error)}`);
254
+ this.#requestDrain();
255
+ return queryFailure('internal_failure', message);
256
+ }
254
257
  #guestObservationGrantId(context, sessionId) {
255
258
  if (context.principalKind !== 'session_guest')
256
259
  return;
@@ -418,28 +418,38 @@ export class HostScheduledTaskCoordinator {
418
418
  }
419
419
  }
420
420
  async #refresh() {
421
- await this.#exclusive(async () => {
422
- if (this.#handoffHeld || this.#draining)
423
- return;
424
- for (const claim of await this.#store.listPendingFires()) {
421
+ if (this.#handoffHeld || this.#draining)
422
+ return;
423
+ // Cover claim admission, native delivery, and persistence, while an idle
424
+ // schedule or a read-only catalog query does not claim active work.
425
+ const residency = this.#acquireResidency();
426
+ try {
427
+ await this.#exclusive(async () => {
425
428
  if (this.#handoffHeld || this.#draining)
426
- break;
427
- if (claim.nativeState === 'waiting_for_provider') {
428
- await this.#fulfill(claim, true);
429
+ return;
430
+ for (const claim of await this.#store.listPendingFires()) {
431
+ if (this.#handoffHeld || this.#draining)
432
+ break;
433
+ if (claim.nativeState === 'waiting_for_provider') {
434
+ await this.#fulfill(claim, true);
435
+ }
429
436
  }
430
- }
431
- while (!this.#draining && !this.#handoffHeld) {
432
- const scan = await this.#store.claimNextDue(this.#now());
433
- for (const expired of scan.expired)
434
- this.#publish('updated', expired.id);
435
- const claim = scan.claim;
436
- if (!claim)
437
- break;
438
- await this.#refreshResidency();
439
- await this.#fulfill(claim, false);
440
- }
441
- await this.#refreshSchedule();
442
- });
437
+ while (!this.#draining && !this.#handoffHeld) {
438
+ const scan = await this.#store.claimNextDue(this.#now());
439
+ for (const expired of scan.expired)
440
+ this.#publish('updated', expired.id);
441
+ const claim = scan.claim;
442
+ if (!claim)
443
+ break;
444
+ await this.#refreshResidency();
445
+ await this.#fulfill(claim, false);
446
+ }
447
+ await this.#refreshSchedule();
448
+ });
449
+ }
450
+ finally {
451
+ residency.release();
452
+ }
443
453
  }
444
454
  async #fulfill(claim, recovering) {
445
455
  const incognito = (await this.#runtimePolicy.runtimePolicy.getSnapshot()).policy.privacy
@@ -680,7 +690,7 @@ export class HostScheduledTaskCoordinator {
680
690
  (claims.length > 0 ||
681
691
  tasks.some((task) => task.status === 'active' && task.nextFireAt !== null));
682
692
  if (shouldHold && !this.#residency)
683
- this.#residency = this.#acquireResidency();
693
+ this.#residency = this.#acquireResidency('idle');
684
694
  if (!shouldHold)
685
695
  this.#releaseResidency();
686
696
  }
@@ -134,7 +134,7 @@ export class BoundedSerialOutboundWriter {
134
134
  if (this.#closed)
135
135
  return;
136
136
  this.close(error);
137
- this.#onFailure();
137
+ this.#onFailure(error);
138
138
  }
139
139
  #nextFrame() {
140
140
  // Close acknowledgements are fences: no lower-priority subscription
@@ -24,7 +24,7 @@ import { thinkingVariantsForConnection } from '@maka/core/model-thinking';
24
24
  import { executionBoundaryDisplayMode, } from '@maka/core/sandbox-boundary';
25
25
  import { DEFAULT_SESSION_NAME, normalizeUserSessionName } from '@maka/core/session-name';
26
26
  import { isSessionStartModeLabel as isExecutionSemanticLabel, sessionStartModeSpec, } from '@maka/core/session-start-mode';
27
- import { isWorkHubCoordinationSessionId, isWorkHubCoordinationSessionTarget, } from '@maka/core/session';
27
+ import { WORKHUB_COORDINATION_SESSION_ID, isWorkHubCoordinationSession, isWorkHubCoordinationSessionId, isWorkHubCoordinationSessionTarget, } from '@maka/core/session';
28
28
  import { isSessionNotFoundError, SessionMetadataConflictError, SessionMetadataVersionConflictError, } from '@maka/storage/execution-stores';
29
29
  import { isVisibleSessionMessage } from '@maka/storage/session-message-projection';
30
30
  import { SessionConfigurationRevisionConflictError, SessionConfigurationTransitionError, } from '@maka/runtime/session-manager';
@@ -438,15 +438,27 @@ export class HostSessionCatalogCoordinator {
438
438
  }
439
439
  });
440
440
  }
441
- async #updateConfiguration(input) {
442
- if (isWorkHubCoordinationSessionId(input.sessionId)) {
441
+ configureWorkHubModel(input) {
442
+ return this.#updateConfiguration({
443
+ sessionId: WORKHUB_COORDINATION_SESSION_ID,
444
+ expectedRevision: input.expectedRevision,
445
+ patch: { modelTarget: input.modelTarget },
446
+ }, 'workhub');
447
+ }
448
+ async #updateConfiguration(input, authority = 'ordinary') {
449
+ if (authority === 'ordinary' && isWorkHubCoordinationSessionId(input.sessionId)) {
443
450
  return configurationFailure('operation_conflict', 'WorkHub Coordination Session configuration requires WorkHub authority');
444
451
  }
445
452
  return this.#admission.run(input.sessionId, async (lease) => {
446
453
  let commitAttempted = false;
447
454
  try {
448
455
  const current = await this.#stores.readHeaderRecordSnapshot(input.sessionId);
449
- if (isWorkHubCoordinationSessionTarget(current.header)) {
456
+ if (authority === 'workhub' &&
457
+ (!isWorkHubCoordinationSessionId(current.header.id) ||
458
+ !isWorkHubCoordinationSession(current.header))) {
459
+ return configurationFailure('operation_conflict', 'WorkHub Coordination Session identity is unavailable');
460
+ }
461
+ if (authority === 'ordinary' && isWorkHubCoordinationSessionTarget(current.header)) {
450
462
  return configurationFailure('operation_conflict', 'WorkHub Coordination Session configuration requires WorkHub authority');
451
463
  }
452
464
  if (current.revision !== input.expectedRevision) {
@@ -461,7 +473,7 @@ export class HostSessionCatalogCoordinator {
461
473
  if (!clearsConnectionBlock && sessionConfigurationMatches(current.header, configuration)) {
462
474
  return configurationSuccess({
463
475
  kind: 'committed',
464
- session: projectSessionCatalogRecord(await this.#stores.readCatalogRecord(input.sessionId)),
476
+ session: projectSessionCatalogRecord(await this.#stores.readCatalogRecord(input.sessionId, authority === 'workhub' ? 'recoverable' : 'ordinary')),
465
477
  });
466
478
  }
467
479
  commitAttempted = true;
@@ -470,7 +482,7 @@ export class HostSessionCatalogCoordinator {
470
482
  clearConnectionBlock: input.patch.modelTarget !== undefined,
471
483
  configuration,
472
484
  });
473
- return configurationSuccess(await this.#committedUpdate(input.sessionId, lease));
485
+ return configurationSuccess(await this.#committedUpdate(input.sessionId, lease, authority === 'workhub' ? 'recoverable' : 'ordinary'));
474
486
  }
475
487
  catch (error) {
476
488
  if (!commitAttempted &&
@@ -597,11 +609,11 @@ export class HostSessionCatalogCoordinator {
597
609
  position = page.nextPosition;
598
610
  }
599
611
  }
600
- async #committedUpdate(sessionId, lease) {
612
+ async #committedUpdate(sessionId, lease, roleScope = 'ordinary') {
601
613
  await this.#continuity.refreshCanonical(sessionId, lease);
602
614
  return {
603
615
  kind: 'committed',
604
- session: projectSessionCatalogRecord(await this.#stores.readCatalogRecord(sessionId)),
616
+ session: projectSessionCatalogRecord(await this.#stores.readCatalogRecord(sessionId, roleScope)),
605
617
  };
606
618
  }
607
619
  #metadataMutationFailure(input, error, unknownMessage) {
@@ -439,8 +439,11 @@ export class HostSessionRetirementCoordinator {
439
439
  throw new SessionRetirementBusyError(`Session ${sessionId} has a live derived effect`);
440
440
  }
441
441
  const header = requireFamilyRecord(family, sessionId).header;
442
- if (!header.subagentParent && (await this.#graph.hasLiveSessionState(sessionId))) {
443
- throw new SessionRetirementBusyError(`Session ${sessionId} has a live Agent Graph`);
442
+ if (!header.subagentParent) {
443
+ const graph = await this.#graph.readRetirementDisposition(sessionId);
444
+ if (graph.kind === 'busy') {
445
+ throw new SessionRetirementBusyError(`Session ${sessionId} has an Agent Graph that is ${graph.status}`);
446
+ }
444
447
  }
445
448
  if (!header.subagentParent && this.#graphWake.hasLiveSessionState(sessionId)) {
446
449
  throw new SessionRetirementBusyError(`Session ${sessionId} has an active Agent Graph supervisor wake`);
@@ -642,6 +642,8 @@ function collectArchivedToolResultPlaceholders(events, messages, copyTurnIds, op
642
642
  return true;
643
643
  if (!isArchivedToolResultPlaceholder(value))
644
644
  return false;
645
+ if (value.rewriteVersion === 2)
646
+ return true;
645
647
  addDescriptor(value);
646
648
  return true;
647
649
  };
@@ -684,6 +686,8 @@ function collectArchivedToolResultPlaceholders(events, messages, copyTurnIds, op
684
686
  continue;
685
687
  }
686
688
  if (message.content.kind === 'archived_tool_result') {
689
+ if (message.content.rewriteVersion === 2 && message.content.resourceRef)
690
+ continue;
687
691
  if (!message.content.artifactId && !message.content.bodySha256)
688
692
  continue;
689
693
  if (!message.content.artifactId || !message.content.bodySha256)