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

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 (125) hide show
  1. package/LICENSE +106 -0
  2. package/dist/cli-core.js +28 -0
  3. package/dist/runtime-host-cli.js +43 -3
  4. package/dist/runtime-host-handoff-surface.js +10 -8
  5. package/dist/runtime-host-lifecycle-transaction.js +28 -3
  6. package/dist/runtime-host-local-source-retirement.js +1 -1
  7. package/dist/runtime-host-run-command.js +15 -7
  8. package/dist/runtime-host-setup-command.js +29 -6
  9. package/dist/runtime-host-update-command.js +49 -5
  10. package/dist/session-export-command.js +72 -0
  11. package/dist/session-import-command.js +69 -0
  12. package/native/runtime-host-peer/prebuilds/darwin-arm64/maka_runtime_host_peer.node +0 -0
  13. package/native/runtime-host-peer/prebuilds/linux-arm64/maka_runtime_host_peer.node +0 -0
  14. package/native/runtime-host-peer/prebuilds/linux-x64/maka_runtime_host_peer.node +0 -0
  15. package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
  16. package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
  17. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +9 -4
  18. package/node_modules/@maka/core/dist/diagnostic-log.js +18 -7
  19. package/node_modules/@maka/core/dist/text-sanitize.js +8 -2
  20. package/node_modules/@maka/core/dist/usage-stats/types.js +2 -0
  21. package/node_modules/@maka/core/dist/workhub-routing.js +126 -0
  22. package/node_modules/@maka/core/package.json +2 -1
  23. package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +15 -11
  24. package/node_modules/@maka/runtime/dist/archive-read-tool.js +3 -1
  25. package/node_modules/@maka/runtime/dist/bots/bot-test.js +2 -1
  26. package/node_modules/@maka/runtime/dist/bots/feishu-bridge.js +24 -20
  27. package/node_modules/@maka/runtime/dist/bots/slack-bridge.js +5 -3
  28. package/node_modules/@maka/runtime/dist/bots/wechat-bridge.js +87 -29
  29. package/node_modules/@maka/runtime/dist/bots/wecom-bridge.js +40 -36
  30. package/node_modules/@maka/runtime/dist/builtin-tools.js +21 -2
  31. package/node_modules/@maka/runtime/dist/computer-use-tools.js +4 -1
  32. package/node_modules/@maka/runtime/dist/deep-research-tools.js +11 -5
  33. package/node_modules/@maka/runtime/dist/edit-replace.js +2 -2
  34. package/node_modules/@maka/runtime/dist/filesystem-worker/operations.js +5 -6
  35. package/node_modules/@maka/runtime/dist/memory-extraction-evidence.js +7 -1
  36. package/node_modules/@maka/runtime/dist/memory-extraction.js +12 -7
  37. package/node_modules/@maka/runtime/dist/openai-responses-websocket.js +2 -5
  38. package/node_modules/@maka/runtime/dist/plugin-agent-service.js +131 -0
  39. package/node_modules/@maka/runtime/dist/plugin-approval-service.js +33 -0
  40. package/node_modules/@maka/runtime/dist/plugin-attachment-service.js +53 -0
  41. package/node_modules/@maka/runtime/dist/plugin-command-service.js +100 -0
  42. package/node_modules/@maka/runtime/dist/plugin-composition-loader.js +11 -2
  43. package/node_modules/@maka/runtime/dist/plugin-data-services.js +332 -0
  44. package/node_modules/@maka/runtime/dist/plugin-fs-service.js +62 -0
  45. package/node_modules/@maka/runtime/dist/plugin-goal-service.js +61 -0
  46. package/node_modules/@maka/runtime/dist/plugin-invocation-signal.js +24 -0
  47. package/node_modules/@maka/runtime/dist/plugin-llm-service.js +85 -0
  48. package/node_modules/@maka/runtime/dist/plugin-lsp-service.js +94 -0
  49. package/node_modules/@maka/runtime/dist/plugin-scope-registry.js +91 -0
  50. package/node_modules/@maka/runtime/dist/plugin-session-query-service.js +71 -0
  51. package/node_modules/@maka/runtime/dist/plugin-shell-env-service.js +87 -0
  52. package/node_modules/@maka/runtime/dist/plugin-shell-service.js +74 -0
  53. package/node_modules/@maka/runtime/dist/plugin-skill-service.js +93 -0
  54. package/node_modules/@maka/runtime/dist/plugin-system-prompt-service.js +346 -0
  55. package/node_modules/@maka/runtime/dist/plugin-tool-service.js +18 -52
  56. package/node_modules/@maka/runtime/dist/plugin-user-question-service.js +43 -0
  57. package/node_modules/@maka/runtime/dist/plugin-web-service.js +69 -0
  58. package/node_modules/@maka/runtime/dist/request-customization-fetch.js +14 -7
  59. package/node_modules/@maka/runtime/dist/session-export.js +178 -0
  60. package/node_modules/@maka/runtime/dist/session-import.js +100 -0
  61. package/node_modules/@maka/runtime/dist/session-manager.js +6 -1
  62. package/node_modules/@maka/runtime/dist/shell-run-manager.js +9 -6
  63. package/node_modules/@maka/runtime/dist/shell-run-tool-result.js +13 -6
  64. package/node_modules/@maka/runtime/dist/stream-graph-coordinator.js +43 -10
  65. package/node_modules/@maka/runtime/dist/stream-graph-handoff.js +6 -1
  66. package/node_modules/@maka/runtime/dist/subscription-model-fetch.js +1 -4
  67. package/node_modules/@maka/runtime/dist/system-prompt/workspace-instructions.js +11 -6
  68. package/node_modules/@maka/runtime/dist/tavily-search.js +8 -2
  69. package/node_modules/@maka/runtime/dist/text-line-window.js +49 -0
  70. package/node_modules/@maka/runtime/dist/tool-output.js +35 -12
  71. package/node_modules/@maka/runtime/dist/unified-diff.js +40 -10
  72. package/node_modules/@maka/runtime/dist/web-fetch-tool.js +4 -2
  73. package/node_modules/@maka/runtime/dist/workers/filesystem-worker.js +82 -33
  74. package/node_modules/@maka/runtime/dist/workspace-executor.js +2 -6
  75. package/node_modules/@maka/runtime/package.json +20 -1
  76. package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +73 -24
  77. package/node_modules/@maka/runtime-host/dist/client/host-handoff.js +46 -12
  78. package/node_modules/@maka/runtime-host/dist/operator/setup-frame.js +31 -21
  79. package/node_modules/@maka/runtime-host/dist/peer-mesh/node.js +7 -4
  80. package/node_modules/@maka/runtime-host/dist/protocol/artifact.js +2 -2
  81. package/node_modules/@maka/runtime-host/dist/protocol/index.js +10 -1
  82. package/node_modules/@maka/runtime-host/dist/protocol/plugin-platform.js +30 -5
  83. package/node_modules/@maka/runtime-host/dist/protocol/session-transcript.js +3 -2
  84. package/node_modules/@maka/runtime-host/dist/protocol/skill-catalog.js +2 -1
  85. package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +25 -23
  86. package/node_modules/@maka/runtime-host/dist/server/artifact-coordinator.js +2 -0
  87. package/node_modules/@maka/runtime-host/dist/server/client-capability-coordinator.js +62 -4
  88. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +481 -11
  89. package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +74 -0
  90. package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +6 -1
  91. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +2 -2
  92. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-tool-profile.js +30 -0
  93. package/node_modules/@maka/runtime-host/dist/server/interactive-run-composer.js +114 -20
  94. package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +49 -12
  95. package/node_modules/@maka/runtime-host/dist/server/plugin-data-runtime.js +234 -0
  96. package/node_modules/@maka/runtime-host/dist/server/plugin-platform-coordinator.js +6 -0
  97. package/node_modules/@maka/runtime-host/dist/server/plugin-platform.js +12 -0
  98. package/node_modules/@maka/runtime-host/dist/server/root-admission-owner.js +17 -8
  99. package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +189 -92
  100. package/node_modules/@maka/runtime-host/dist/server/runtime-resource-projection.js +3 -9
  101. package/node_modules/@maka/runtime-host/dist/server/session-continuity-coordinator.js +20 -21
  102. package/node_modules/@maka/runtime-host/dist/server/session-transcript-pager.js +24 -2
  103. package/node_modules/@maka/runtime-host/dist/server/skill-catalog-coordinator.js +18 -2
  104. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +44 -35
  105. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +92 -10
  106. package/node_modules/@maka/runtime-host/dist/transport/framed-byte-stream-transport.js +4 -1
  107. package/node_modules/@maka/runtime-host/dist/transport/local-ipc-framing.js +4 -2
  108. package/node_modules/@maka/runtime-host/dist/transport/peer-native.js +9 -8
  109. package/node_modules/@maka/runtime-host/dist/transport/resumable-peer-stream.js +14 -9
  110. package/node_modules/@maka/storage/dist/agent-run-store.js +54 -10
  111. package/node_modules/@maka/storage/dist/context-offload-snapshot.js +32 -10
  112. package/node_modules/@maka/storage/dist/context-value-mutation-gate.js +59 -0
  113. package/node_modules/@maka/storage/dist/execution-stores.js +1 -1
  114. package/node_modules/@maka/storage/dist/session-bundle-policy.js +909 -34
  115. package/node_modules/@maka/storage/dist/session-message-projection.js +8 -4
  116. package/node_modules/@maka/storage/dist/session-store.js +2 -2
  117. package/node_modules/@maka/storage/dist/sqlite-context-offload-store.js +18 -4
  118. package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +12 -5
  119. package/node_modules/@maka/storage/dist/stable-storage.js +2 -1
  120. package/node_modules/@maka/storage/package.json +2 -0
  121. package/node_modules/@modelcontextprotocol/client/dist/src-D_zzAWoS.mjs +22 -5
  122. package/node_modules/@modelcontextprotocol/client/dist/src-NAgB4Mp8.cjs +22 -5
  123. package/node_modules/zod/v4/core/memoizer.cjs +12 -16
  124. package/node_modules/zod/v4/core/memoizer.js +12 -16
  125. package/package.json +1 -1
@@ -18,7 +18,7 @@
18
18
  */
19
19
  import { copyWorkHubAttachmentsToTarget } from './workhub-message-attachments.js';
20
20
  import { createHash, randomUUID } from 'node:crypto';
21
- import { MAX_READ_IMAGE_BYTES } from '@maka/core/attachments';
21
+ import { attachmentKindFromMimeType, MAX_READ_IMAGE_BYTES } from '@maka/core/attachments';
22
22
  import { messageContentDigest, normalizeMessageContent } from '@maka/core/events';
23
23
  import { NO_REAL_CONNECTION_CODE } from '@maka/core/connection-error-copy';
24
24
  import { generalizedErrorMessage } from '@maka/core/redaction';
@@ -26,11 +26,12 @@ import { emptyPlanSessionState } from '@maka/core/plan';
26
26
  import { readLogicalRuntimeExecutionForRun } from '@maka/core/runtime-logical-execution';
27
27
  import { runtimeInvocationOutcome, } from '@maka/core/runtime-invocation';
28
28
  import { isDeepResearchSession, WORKHUB_COORDINATION_SESSION_ID, WORKHUB_COORDINATION_REPLACEMENT_SCHEMA_VERSION, } from '@maka/core/session';
29
- import { AgentGraphCoordinator } from '@maka/runtime/stream-graph-coordinator';
29
+ import { AgentGraphClientOperationError, AgentGraphCoordinator, } from '@maka/runtime/stream-graph-coordinator';
30
30
  import { AgentGraphSupervisorWakeCoordinator } from '@maka/runtime/agent-graph-supervisor-wake';
31
31
  import { BackendRegistry, SessionManager, workHubDirectStopAbortSource, } from '@maka/runtime/session-manager';
32
32
  import { buildToolsForAgentDefinition } from '@maka/runtime/agent-catalog';
33
33
  import { buildHistoryTools } from '@maka/runtime/history-tools';
34
+ import { buildBuiltinTools } from '@maka/runtime/builtin-tools';
34
35
  import { createLocalContinuationSafetyInspector } from '@maka/runtime/continuation-safety';
35
36
  import { createConfiguredSubagentCatalog } from '@maka/runtime/configured-subagent-catalog';
36
37
  import { buildHostCapabilitiesFromBinding } from '@maka/runtime/skills';
@@ -45,8 +46,24 @@ import { SessionActivityRegistry } from '@maka/runtime/goal-turn-lifecycle';
45
46
  import { ShellRunProcessManager } from '@maka/runtime/shell-run-manager';
46
47
  import { resolveShellPlan, resolveTurnShellPlan, validateShellPreference, } from '@maka/runtime/shell-detect';
47
48
  import { Context } from '@maka/runtime/plugin-kernel';
49
+ import { PluginAgentService } from '@maka/runtime/plugin-agent-service';
50
+ import { PluginAttachmentService } from '@maka/runtime/plugin-attachment-service';
51
+ import { PluginApprovalService } from '@maka/runtime/plugin-approval-service';
52
+ import { PluginFilesystemService } from '@maka/runtime/plugin-fs-service';
53
+ import { PluginLlmService } from '@maka/runtime/plugin-llm-service';
54
+ import { PluginShellService } from '@maka/runtime/plugin-shell-service';
55
+ import { PluginUserQuestionService } from '@maka/runtime/plugin-user-question-service';
56
+ import { PluginWebService } from '@maka/runtime/plugin-web-service';
48
57
  import { MakaCompositionLoader } from '@maka/runtime/plugin-composition-loader';
49
58
  import { PluginToolService } from '@maka/runtime/plugin-tool-service';
59
+ import { PluginSystemPromptService } from '@maka/runtime/plugin-system-prompt-service';
60
+ import { PluginCommandService } from '@maka/runtime/plugin-command-service';
61
+ import { PluginAuthorizationService, PluginCredentialService, PluginSettingsService, PluginStorageService, } from '@maka/runtime/plugin-data-services';
62
+ import { PluginGoalService } from '@maka/runtime/plugin-goal-service';
63
+ import { PluginLspService } from '@maka/runtime/plugin-lsp-service';
64
+ import { PluginSessionQueryService } from '@maka/runtime/plugin-session-query-service';
65
+ import { PluginShellEnvService } from '@maka/runtime/plugin-shell-env-service';
66
+ import { PluginSkillService } from '@maka/runtime/plugin-skill-service';
50
67
  import { isHostedExecutionTerminal } from './hosted-execution-authority.js';
51
68
  import { createAgentGraphControlStore } from '@maka/storage/agent-graph-control-store';
52
69
  import { createArtifactAttachmentResourceReader } from '@maka/storage/artifact-stores';
@@ -59,6 +76,7 @@ import { createInteractiveContextOffloadReader } from '@maka/storage/context-off
59
76
  import { openStorageWriterComposition } from '@maka/storage/storage-writer-composition';
60
77
  import { resolveWorkspaceIdentity } from '@maka/storage/workspace-identity';
61
78
  import { CanonicalSessionProjectionReader } from './canonical-session-projection.js';
79
+ import { HostPluginDataRuntime } from './plugin-data-runtime.js';
62
80
  import { bindHostChildAgentBackend, createHostChildAgentToolComposition, } from './child-agent-composition.js';
63
81
  import { HostCanonicalPermissionOutcomeReader } from './canonical-permission-outcome-reader.js';
64
82
  import { HostArtifactCoordinator } from './artifact-coordinator.js';
@@ -75,7 +93,7 @@ import { HostDeepResearchCoordinator } from './deep-research-coordinator.js';
75
93
  import { HostDailyReviewCoordinator } from './daily-review-coordinator.js';
76
94
  import { prepareHostAiSdkBackend } from './execution-model-composition.js';
77
95
  import { createInteractiveRunComposer, createInteractiveRunComposerFactory, routeInteractiveRunToolSurface, } from './interactive-run-composer.js';
78
- import { createHostGoalEvaluator, createHostDailyReviewModel, createHostMemoryExtractionModel, createHostSessionEffectModel, } from './execution-model-authority.js';
96
+ import { createHostGoalEvaluator, createHostDailyReviewModel, createHostMemoryExtractionModel, createHostPluginModel, createHostSessionEffectModel, } from './execution-model-authority.js';
79
97
  import { HostExecutionInspectCoordinator } from './execution-inspect-coordinator.js';
80
98
  import { HostExternalSessionCoordinator } from './external-session-coordinator.js';
81
99
  import { HostGoalCoordinator } from './goal-coordinator.js';
@@ -88,7 +106,7 @@ import { HostInteractionCoordinator } from './interaction-coordinator.js';
88
106
  import { HostInteractiveTurnCoordinator } from './interactive-turn-coordinator.js';
89
107
  import { SessionTurnAccessRequestCoordinator } from './session-turn-access-request-coordinator.js';
90
108
  import { ensureBootstrapRuntimePolicy } from './bootstrap-runtime-policy.js';
91
- import { hostedExecutionRunProfile } from './hosted-execution-tool-profile.js';
109
+ import { bindWorkHubRoutingDecisionPrompt, hostedExecutionRunProfile, } from './hosted-execution-tool-profile.js';
92
110
  import { HostMemoryCoordinator } from './memory-coordinator.js';
93
111
  import { HostMemoryExtractionCoordinator } from './memory-extraction-coordinator.js';
94
112
  import { MemoryExtractionSessionLane } from './memory-extraction-session-lane.js';
@@ -118,7 +136,7 @@ import { HostSessionRevisionCoordinator } from './session-revision-coordinator.j
118
136
  import { HostSessionEffectCoordinator } from './session-effect-coordinator.js';
119
137
  import { SessionContinuityCoordinator } from './session-continuity-coordinator.js';
120
138
  import { createSessionTranscriptReader, } from './session-transcript-reader.js';
121
- import { HostSkillCatalogCoordinator } from './skill-catalog-coordinator.js';
139
+ import { HostSkillCatalogCoordinator, SkillCatalogInvocableContextError, } from './skill-catalog-coordinator.js';
122
140
  import { SkillCatalogRepository } from './skill-catalog-repository.js';
123
141
  import { HostSessionTodoCoordinator } from './session-todo-coordinator.js';
124
142
  import { HostTurnControlCoordinator } from './turn-control-coordinator.js';
@@ -177,10 +195,35 @@ export async function createExecutionRuntimeHostComposition(context, options = {
177
195
  let archiveEvidence;
178
196
  try {
179
197
  const pluginRoot = new Context();
180
- const pluginTools = new PluginToolService(pluginRoot);
198
+ const pluginAgents = new PluginAgentService(pluginRoot);
199
+ const pluginAttachments = new PluginAttachmentService(pluginRoot, pluginAgents);
200
+ new PluginApprovalService(pluginRoot, pluginAgents);
201
+ new PluginUserQuestionService(pluginRoot, pluginAgents);
202
+ const pluginFilesystem = new PluginFilesystemService(pluginRoot, pluginAgents);
203
+ const pluginLlm = new PluginLlmService(pluginRoot, pluginAgents);
204
+ const pluginShellEnv = new PluginShellEnvService(pluginRoot);
205
+ const pluginShell = new PluginShellService(pluginRoot, pluginAgents, pluginShellEnv);
206
+ const pluginWeb = new PluginWebService(pluginRoot, pluginAgents);
207
+ const pluginSessionQuery = new PluginSessionQueryService(pluginRoot, pluginAgents);
208
+ const pluginGoals = new PluginGoalService(pluginRoot, pluginAgents);
209
+ const pluginSkills = new PluginSkillService(pluginRoot);
210
+ const pluginCommands = new PluginCommandService(pluginRoot);
211
+ new PluginLspService(pluginRoot);
212
+ const pluginSettings = new PluginSettingsService(pluginRoot);
213
+ const pluginStorage = new PluginStorageService(pluginRoot);
214
+ const pluginCredentials = new PluginCredentialService(pluginRoot);
215
+ new PluginAuthorizationService(pluginRoot, pluginCredentials);
216
+ const pluginData = new HostPluginDataRuntime(context.owner.controlDirectory);
217
+ pluginSettings.bindRuntime(pluginData);
218
+ pluginStorage.bindRuntime(pluginData);
219
+ pluginCredentials.bindRuntime(pluginData);
220
+ const pluginTools = new PluginToolService(pluginRoot, { agents: pluginAgents });
221
+ const pluginSystemPrompt = new PluginSystemPromptService(pluginRoot);
181
222
  pluginPlatform = new HostPluginPlatform(context.owner.controlDirectory, {
182
223
  composition: new MakaCompositionLoader({ root: pluginRoot }),
183
224
  tools: pluginTools,
225
+ systemPrompt: pluginSystemPrompt,
226
+ commands: pluginCommands,
184
227
  });
185
228
  const pluginPlatformCoordinator = new HostPluginPlatformCoordinator(pluginPlatform);
186
229
  const openedProjectCatalog = storage.projectCatalog;
@@ -323,12 +366,94 @@ export async function createExecutionRuntimeHostComposition(context, options = {
323
366
  ...(sandboxManager ? { sandboxManager } : {}),
324
367
  ...(filesystemWorker ? { filesystemWorker } : {}),
325
368
  };
369
+ const invokeBuiltin = async (name, args, invocation, shellEnvironment) => {
370
+ if (!invocation.toolContext)
371
+ throw new Error(`${name} requires an active Tool invocation`);
372
+ const policy = await runtimePolicyStores.runtimePolicy.getSnapshot();
373
+ const tool = buildBuiltinTools({
374
+ ...builtinTools,
375
+ shell: resolveTurnShellPlan(policy.policy.shell),
376
+ ...(shellEnvironment ? { shellEnvironment } : {}),
377
+ }).find((candidate) => candidate.name === name);
378
+ if (!tool)
379
+ throw new Error(`Builtin capability is unavailable: ${name}`);
380
+ return tool.impl(args, invocation.toolContext);
381
+ };
382
+ pluginFilesystem.bindRuntime({
383
+ execute: (operation, invocation) => {
384
+ switch (operation.kind) {
385
+ case 'read':
386
+ return invokeBuiltin('Read', operation, invocation);
387
+ case 'write':
388
+ return invokeBuiltin('Write', operation, invocation);
389
+ case 'edit':
390
+ return invokeBuiltin('Edit', {
391
+ path: operation.path,
392
+ old_string: operation.oldString,
393
+ new_string: operation.newString,
394
+ }, invocation);
395
+ case 'glob':
396
+ return invokeBuiltin('Glob', { pattern: operation.pattern, cwd: operation.path }, invocation);
397
+ case 'grep':
398
+ return invokeBuiltin('Grep', { pattern: operation.pattern, path: operation.path, glob: operation.glob }, invocation);
399
+ case 'apply_patch':
400
+ return invokeBuiltin('apply_patch', operation.patch, invocation);
401
+ }
402
+ },
403
+ });
404
+ pluginShell.bindRuntime({
405
+ run: (options, invocation) => invokeBuiltin('Bash', {
406
+ command: options.command,
407
+ timeout_ms: options.timeoutMs,
408
+ run_in_background: options.background,
409
+ pty: options.pty,
410
+ }, invocation, options.environment),
411
+ read: (ref, invocation) => runtimeResources.readRuntimeResource(invocation.sessionId, ref, invocation.abortSignal),
412
+ write: (ref, input, invocation) => runtimeResources.writeStdin({
413
+ sessionId: invocation.sessionId,
414
+ ref,
415
+ input,
416
+ abortSignal: invocation.abortSignal,
417
+ caller: 'model',
418
+ }),
419
+ stop: (ref, invocation) => runtimeResources.stopBackgroundTask(invocation.sessionId, ref, invocation.abortSignal),
420
+ });
421
+ pluginAttachments.bindRuntime({
422
+ create: async (input, invocation) => {
423
+ const record = await openedArtifactStore.create({
424
+ sessionId: invocation.sessionId,
425
+ turnId: invocation.turnId,
426
+ name: input.name,
427
+ kind: pluginAttachmentArtifactKind(input.mimeType, input.name),
428
+ content: input.content,
429
+ mimeType: input.mimeType,
430
+ source: 'tool_result',
431
+ ...(input.summary ? { summary: input.summary } : {}),
432
+ });
433
+ return pluginAttachmentRef(record);
434
+ },
435
+ read: async (attachment, invocation) => {
436
+ if (attachment.ref.kind !== 'session_file' ||
437
+ attachment.ref.sessionId !== invocation.sessionId) {
438
+ throw new Error('Attachment is outside the current Session');
439
+ }
440
+ const result = await openedArtifactStore.readBinaryInSession(invocation.sessionId, attachment.ref.relativePath);
441
+ if (!result.ok)
442
+ throw new Error(`Attachment read failed: ${result.reason}`);
443
+ return Uint8Array.from(Buffer.from(result.base64, 'base64'));
444
+ },
445
+ list: async (invocation) => (await openedArtifactStore.listTurnArtifacts(invocation.sessionId, invocation.turnId)).map(pluginAttachmentRef),
446
+ });
326
447
  const webSearchService = createHostWebSearchService({
327
448
  policy: runtimePolicyStores.operations,
328
449
  });
329
450
  const webFetchService = createHostWebFetchService({
330
451
  policy: runtimePolicyStores.operations,
331
452
  });
453
+ pluginWeb.bindRuntime({
454
+ search: ({ query, limit, abortSignal }) => webSearchService.search({ query, limit, ...(abortSignal ? { abortSignal } : {}) }),
455
+ fetch: (input) => webFetchService.fetch(input),
456
+ });
332
457
  const historyTools = buildHistoryTools({
333
458
  listSessions: () => requireSessionManager(manager).listSessions(),
334
459
  readMessages: async (sessionId, abortSignal) => {
@@ -375,8 +500,33 @@ export async function createExecutionRuntimeHostComposition(context, options = {
375
500
  }), workspaceResolver, async (input, connection) => {
376
501
  if (input.target.kind === 'session') {
377
502
  const sessionId = input.target.sessionId;
378
- const header = await stores.sessionStore.readHeaderSnapshot(sessionId);
379
- const preview = await requireClientCapabilities(clientCapabilities).runWithSessionBindingPreview(sessionId, connection.connectionId, () => requireToolNameResolver(resolveAvailableToolNames)(sessionId));
503
+ let header;
504
+ try {
505
+ header = await stores.sessionStore.readHeaderSnapshot(sessionId);
506
+ }
507
+ catch (error) {
508
+ if (isSessionNotFoundError(error)) {
509
+ throw new SkillCatalogInvocableContextError('not_found', 'Session does not exist');
510
+ }
511
+ throw error;
512
+ }
513
+ if (header.isArchived) {
514
+ throw new SkillCatalogInvocableContextError('session_archived', 'Session is archived');
515
+ }
516
+ let preview;
517
+ try {
518
+ preview = await requireClientCapabilities(clientCapabilities).runWithSessionBindingPreview(sessionId, connection.connectionId, () => requireToolNameResolver(resolveAvailableToolNames)(sessionId));
519
+ }
520
+ catch (error) {
521
+ if (isSessionNotFoundError(error)) {
522
+ throw new SkillCatalogInvocableContextError('not_found', 'Session does not exist');
523
+ }
524
+ if (error instanceof AgentGraphClientOperationError &&
525
+ error.code === 'session_archived') {
526
+ throw new SkillCatalogInvocableContextError('session_archived', 'Session is archived');
527
+ }
528
+ throw error;
529
+ }
380
530
  if (!preview.ok)
381
531
  throw new Error(preview.message);
382
532
  return {
@@ -394,6 +544,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
394
544
  publish: (sessionId) => hostChanges.publishSessionCatalog(sessionId),
395
545
  }, projectMembership, context.requestDrain, new HostProjectDirectoryAuthority(options.projectDirectoryRoots));
396
546
  let rootCoordinator;
547
+ let workHubCoordination;
397
548
  let canonicalProjection;
398
549
  let memory;
399
550
  let clientCapabilities;
@@ -473,6 +624,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
473
624
  let recoveryTask;
474
625
  let rootCloseTask;
475
626
  let rootRecoveryCompleted = false;
627
+ let clientBoundRecovery = Promise.resolve();
476
628
  let closeTask;
477
629
  let backendInvalidationPoisoned = false;
478
630
  let domainModules;
@@ -539,6 +691,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
539
691
  oauthCredentials,
540
692
  createRunComposer: createInteractiveRunComposerFactory({
541
693
  skills,
694
+ pluginSkills,
542
695
  memory: requireMemory(memory),
543
696
  sessionTodo,
544
697
  clientCapabilities: requireClientCapabilities(clientCapabilities),
@@ -551,9 +704,29 @@ export async function createExecutionRuntimeHostComposition(context, options = {
551
704
  hostTools,
552
705
  resolveRootTools: (sessionId) => requireGraphCoordinator(graphCoordinator).toolsForSession(sessionId),
553
706
  resolvePluginTools: (sessionId, coreTools) => pluginTools.resolveContributions(sessionId, coreTools),
707
+ resolvePluginSystemPrompt: async (sessionId, promptContext, baseText) => {
708
+ const assembly = await pluginSystemPrompt.assemble({
709
+ sessionId,
710
+ turnId: promptContext.turnId,
711
+ cwd: promptContext.cwd,
712
+ }, baseText);
713
+ return {
714
+ text: assembly.text,
715
+ contexts: assembly.contexts,
716
+ sourceRevisions: assembly.sourceRevision ? [assembly.sourceRevision] : [],
717
+ };
718
+ },
554
719
  parentAgentTools: childAgentTools.parentTools,
555
720
  childTools: childAgentTools.childTools,
556
721
  worktreePatchWriteBackAvailable: true,
722
+ resolveProfileSystemPrompt: async (promptContext, basePrompt) => {
723
+ if (promptContext.sessionId !== WORKHUB_COORDINATION_SESSION_ID)
724
+ return basePrompt;
725
+ const admission = await stores.agentRunStore.readRootTurnAdmission(promptContext.sessionId, promptContext.turnId);
726
+ return bindWorkHubRoutingDecisionPrompt(basePrompt, admission?.execution.kind === 'workhub_coordination'
727
+ ? admission.execution.routingDecision
728
+ : undefined);
729
+ },
557
730
  }),
558
731
  ...(hostedExecutionRunProfile(backendContext.header.toolProfile)?.memoryExtraction === false
559
732
  ? {}
@@ -927,8 +1100,229 @@ export async function createExecutionRuntimeHostComposition(context, options = {
927
1100
  }, {
928
1101
  currentGraphId: (rootSessionId) => requireGraphCoordinator(graphCoordinator).currentGraphId(rootSessionId),
929
1102
  beginNextGraphEpoch: async (rootSessionId) => (await requireGraphCoordinator(graphCoordinator).beginNextGraphEpoch(rootSessionId, (operation) => requireGraphSupervisorWake(graphSupervisorWake).runWithSessionWakesSuppressed(rootSessionId, operation, 'agent_graph_epoch_advanced'))).graphId,
930
- }, (input) => sessionEffectCoordinator.nameSessionFromRootMessage(input), context.owner.capability.rootId);
1103
+ }, (input) => sessionEffectCoordinator.nameSessionFromRootMessage(input), context.owner.capability.rootId, dependencies.workHubRoutingModel
1104
+ ? (input) => workHubCoordination.prepareRoutingDecision(input)
1105
+ : undefined);
931
1106
  const coordinator = rootCoordinator;
1107
+ const pluginModel = createHostPluginModel({
1108
+ runtimePolicy: runtimePolicyStores,
1109
+ oauthCredentials,
1110
+ usage: openedUsageStores,
1111
+ requestDrain: context.requestDrain,
1112
+ readSessionHeader: (sessionId) => stores.sessionStore.readHeaderSnapshot(sessionId),
1113
+ });
1114
+ pluginLlm.bindRuntime({
1115
+ generate: (input, invocation) => pluginModel.generate({
1116
+ sessionId: invocation.sessionId,
1117
+ prompt: input.prompt,
1118
+ ...(input.system ? { system: input.system } : {}),
1119
+ ...(input.maxOutputTokens ? { maxOutputTokens: input.maxOutputTokens } : {}),
1120
+ abortSignal: input.signal ?? invocation.abortSignal,
1121
+ }),
1122
+ });
1123
+ const visibleAgentSessions = async (initiator) => {
1124
+ const sessions = await manager.listSessions();
1125
+ if (!initiator)
1126
+ return [];
1127
+ const visible = new Set([initiator.sessionId]);
1128
+ let changed = true;
1129
+ while (changed) {
1130
+ changed = false;
1131
+ for (const session of sessions) {
1132
+ if (!session.parentSessionId ||
1133
+ !visible.has(session.parentSessionId) ||
1134
+ visible.has(session.id))
1135
+ continue;
1136
+ visible.add(session.id);
1137
+ changed = true;
1138
+ }
1139
+ }
1140
+ return sessions.filter((session) => visible.has(session.id));
1141
+ };
1142
+ const pluginSessionSummary = (session) => Object.freeze({
1143
+ id: session.id,
1144
+ ...(session.name ? { title: session.name } : {}),
1145
+ ...(session.cwd ? { cwd: session.cwd } : {}),
1146
+ ...(session.status ? { status: session.status } : {}),
1147
+ ...(session.parentSessionId ? { parentSessionId: session.parentSessionId } : {}),
1148
+ ...(session.statusUpdatedAt || session.lastMessageAt
1149
+ ? { updatedAt: session.statusUpdatedAt ?? session.lastMessageAt }
1150
+ : {}),
1151
+ });
1152
+ const sessionQueryInitiator = (caller) => caller.invocation ??
1153
+ (caller.scopeSessionId ? Object.freeze({ sessionId: caller.scopeSessionId }) : undefined);
1154
+ pluginSessionQuery.bindRuntime({
1155
+ list: async (caller) => Object.freeze((await visibleAgentSessions(sessionQueryInitiator(caller))).map(pluginSessionSummary)),
1156
+ read: async (sessionId, caller) => {
1157
+ const session = (await visibleAgentSessions(sessionQueryInitiator(caller))).find(({ id }) => id === sessionId);
1158
+ if (!session)
1159
+ return undefined;
1160
+ return Object.freeze({
1161
+ session: pluginSessionSummary(session),
1162
+ messages: Object.freeze([
1163
+ ...(await requireSessionManager(manager).getMessages(sessionId)),
1164
+ ]),
1165
+ });
1166
+ },
1167
+ search: async (request, caller) => {
1168
+ const query = request.query.toLocaleLowerCase();
1169
+ const sessions = await visibleAgentSessions(sessionQueryInitiator(caller));
1170
+ const matches = [];
1171
+ for (const session of sessions) {
1172
+ const headerText = `${session.name}\n${session.cwd ?? ''}`.toLocaleLowerCase();
1173
+ if (headerText.includes(query)) {
1174
+ matches.push(session);
1175
+ continue;
1176
+ }
1177
+ const messages = await requireSessionManager(manager).getMessages(session.id);
1178
+ if (messages.some((message) => JSON.stringify(message).toLocaleLowerCase().includes(query))) {
1179
+ matches.push(session);
1180
+ }
1181
+ }
1182
+ const offset = request.cursor ? Number.parseInt(request.cursor, 10) : 0;
1183
+ if (!Number.isSafeInteger(offset) || offset < 0)
1184
+ throw new TypeError('Invalid Session query cursor');
1185
+ const limit = request.limit ?? 20;
1186
+ const page = matches.slice(offset, offset + limit);
1187
+ return Object.freeze({
1188
+ items: Object.freeze(page.map(pluginSessionSummary)),
1189
+ ...(offset + page.length < matches.length
1190
+ ? { cursor: String(offset + page.length) }
1191
+ : {}),
1192
+ });
1193
+ },
1194
+ });
1195
+ const describeAgent = (session) => ({
1196
+ id: session.id,
1197
+ sessionId: session.id,
1198
+ root: !session.parentSessionId,
1199
+ status: session.runningTurnIds?.length ? 'running' : session.status,
1200
+ ...(session.parentSessionId ? { ownerId: session.parentSessionId } : {}),
1201
+ });
1202
+ const submitAgentMessage = async (id, message, placement, initiator) => {
1203
+ if (!(await visibleAgentSessions(initiator)).some((session) => session.id === id)) {
1204
+ throw new Error('Agent is outside the current ownership tree');
1205
+ }
1206
+ const content = normalizeMessageContent(typeof message === 'string' ? { text: message } : message);
1207
+ const result = await messages.handlers['turn.message.submit']({
1208
+ originHostEpoch: context.hostEpoch,
1209
+ sessionId: id,
1210
+ messageId: randomUUID(),
1211
+ content,
1212
+ placement,
1213
+ }, {
1214
+ hostEpoch: context.hostEpoch,
1215
+ connectionId: 'plugin-agent',
1216
+ principal: 'runtime_host',
1217
+ acquireResidency: () => context.acquireResidency('plugin-agent'),
1218
+ });
1219
+ if (!result.ok)
1220
+ throw new Error(result.error.message);
1221
+ return result.result;
1222
+ };
1223
+ pluginAgents.bindRuntime({
1224
+ create: async (options, initiator) => {
1225
+ const spawn = initiator.toolContext?.spawnChildSession;
1226
+ if (!spawn)
1227
+ throw new Error('Agent creation requires an active Tool invocation');
1228
+ if (!options.prompt?.trim())
1229
+ throw new Error('Agent creation requires a prompt');
1230
+ return new Promise((resolve, reject) => {
1231
+ void spawn({
1232
+ agentProfile: options.agentProfile ?? 'implementation',
1233
+ prompt: options.prompt,
1234
+ ...(options.signal ? { abortSignal: options.signal } : {}),
1235
+ onReady: (ready) => resolve({
1236
+ id: ready.childSessionId,
1237
+ sessionId: ready.childSessionId,
1238
+ root: false,
1239
+ status: 'running',
1240
+ ownerId: initiator.sessionId,
1241
+ }),
1242
+ }).catch(reject);
1243
+ });
1244
+ },
1245
+ resume: async (options, initiator) => {
1246
+ if (options.prompt)
1247
+ await submitAgentMessage(options.sessionId, options.prompt, 'next_turn', initiator);
1248
+ const session = (await visibleAgentSessions(initiator)).find((item) => item.id === options.sessionId);
1249
+ if (!session)
1250
+ throw new Error('Agent was not found');
1251
+ return describeAgent(session);
1252
+ },
1253
+ get: async (id, initiator) => {
1254
+ const session = (await visibleAgentSessions(initiator)).find((item) => item.id === id);
1255
+ return session ? describeAgent(session) : undefined;
1256
+ },
1257
+ list: async (initiator) => (await visibleAgentSessions(initiator)).map(describeAgent),
1258
+ roots: async (initiator) => (await visibleAgentSessions(initiator))
1259
+ .filter((session) => !session.parentSessionId)
1260
+ .map(describeAgent),
1261
+ followup: (id, message, initiator) => submitAgentMessage(id, message, 'next_turn', initiator),
1262
+ steer: (id, message, initiator) => submitAgentMessage(id, message, 'current_turn', initiator),
1263
+ inject: (id, message, initiator) => submitAgentMessage(id, message, 'current_turn', initiator),
1264
+ cancel: async (id, initiator) => {
1265
+ if (!(await visibleAgentSessions(initiator)).some((session) => session.id === id)) {
1266
+ throw new Error('Agent is outside the current ownership tree');
1267
+ }
1268
+ await coordinator.stopSession(id, { source: 'stop_button' });
1269
+ },
1270
+ whenIdle: async (id, signal, initiator) => {
1271
+ if (!(await visibleAgentSessions(initiator)).some((session) => session.id === id)) {
1272
+ throw new Error('Agent is outside the current ownership tree');
1273
+ }
1274
+ const wait = coordinator.whenIdle(id);
1275
+ if (!wait)
1276
+ return;
1277
+ if (!signal)
1278
+ return wait;
1279
+ if (signal.aborted)
1280
+ throw signal.reason;
1281
+ let rejectAbort;
1282
+ const aborted = new Promise((_resolve, reject) => {
1283
+ rejectAbort = reject;
1284
+ });
1285
+ const onAbort = () => rejectAbort?.(signal.reason);
1286
+ signal.addEventListener('abort', onAbort, { once: true });
1287
+ try {
1288
+ await Promise.race([wait, aborted]);
1289
+ }
1290
+ finally {
1291
+ signal.removeEventListener('abort', onAbort);
1292
+ }
1293
+ },
1294
+ snapshot: async (id, initiator) => {
1295
+ const session = (await visibleAgentSessions(initiator)).find((item) => item.id === id);
1296
+ if (!session)
1297
+ throw new Error('Agent was not found');
1298
+ return { agent: describeAgent(session), root: coordinator.readRootState(id) };
1299
+ },
1300
+ inbox: async (id, initiator) => {
1301
+ if (!(await visibleAgentSessions(initiator)).some((session) => session.id === id))
1302
+ throw new Error('Agent was not found');
1303
+ return coordinator.readRootState(id);
1304
+ },
1305
+ result: async (id, initiator) => {
1306
+ if (!(await visibleAgentSessions(initiator)).some((session) => session.id === id))
1307
+ throw new Error('Agent was not found');
1308
+ return (await manager.getMessages(id)).at(-1);
1309
+ },
1310
+ artifacts: async (id, initiator) => {
1311
+ if (!(await visibleAgentSessions(initiator)).some((session) => session.id === id))
1312
+ throw new Error('Agent was not found');
1313
+ return (await openedArtifactStore.listPage(id, { offset: 0, limit: 100 })).records;
1314
+ },
1315
+ transcript: async (id, initiator) => {
1316
+ if (!(await visibleAgentSessions(initiator)).some((session) => session.id === id))
1317
+ throw new Error('Agent was not found');
1318
+ return manager.getMessages(id);
1319
+ },
1320
+ dispose: async (id, initiator) => {
1321
+ if (!(await visibleAgentSessions(initiator)).some((session) => session.id === id))
1322
+ throw new Error('Agent was not found');
1323
+ await coordinator.stopSession(id, { source: 'stop_button' });
1324
+ },
1325
+ });
932
1326
  const contextOperations = new HostContextCoordinator({
933
1327
  runtime: manager,
934
1328
  executions: coordinator,
@@ -1032,6 +1426,34 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1032
1426
  onProjectionChanged: (sessionId) => continuityCoordinator.enqueueCanonicalRefresh(sessionId),
1033
1427
  requestDrain: context.requestDrain,
1034
1428
  });
1429
+ pluginGoals.bindRuntime({
1430
+ execute: async (operation, invocation) => {
1431
+ const coordinator = requireGoal(goal);
1432
+ if (operation.kind === 'get')
1433
+ return coordinator.readProjection(invocation.sessionId);
1434
+ if (!invocation.toolContext)
1435
+ throw new Error('Goal mutation requires an active Tool invocation');
1436
+ const toolName = operation.kind === 'create'
1437
+ ? 'GoalSet'
1438
+ : operation.kind === 'clear'
1439
+ ? 'GoalClear'
1440
+ : operation.kind === 'pause'
1441
+ ? 'GoalPause'
1442
+ : 'GoalResume';
1443
+ const tool = coordinator.tools.find(({ name }) => name === toolName);
1444
+ if (!tool)
1445
+ throw new Error(`Goal capability is unavailable: ${toolName}`);
1446
+ const args = operation.kind === 'create'
1447
+ ? {
1448
+ condition: operation.objective,
1449
+ ...(operation.maxIterations ? { max_iterations: operation.maxIterations } : {}),
1450
+ ...(operation.blockCap ? { block_cap: operation.blockCap } : {}),
1451
+ ...(operation.tokenBudget ? { token_budget: operation.tokenBudget } : {}),
1452
+ }
1453
+ : {};
1454
+ return await tool.impl(args, invocation.toolContext);
1455
+ },
1456
+ });
1035
1457
  async function applyRuntimePolicyMutationEffects() {
1036
1458
  try {
1037
1459
  await requireMemory(memory).refreshAfterPolicyMutation();
@@ -1061,7 +1483,8 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1061
1483
  ? { sessionAccessAuthority: context.sessionAccessAuthority }
1062
1484
  : {}),
1063
1485
  });
1064
- const workHubCoordination = new HostWorkHubCoordinationCoordinator({
1486
+ workHubCoordination = new HostWorkHubCoordinationCoordinator({
1487
+ routingModel: dependencies.workHubRoutingModel,
1065
1488
  configureModel: (input) => sessionCatalog.configureWorkHubModel(input),
1066
1489
  transitionConfiguration: (input) => requireSessionManager(manager).transitionSessionConfiguration(WORKHUB_COORDINATION_SESSION_ID, input),
1067
1490
  stateRoot: context.owner.capability.canonicalPath,
@@ -1556,7 +1979,35 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1556
1979
  }),
1557
1980
  createRuntimeHostDomainModule({
1558
1981
  id: 'client-capability',
1559
- handlers: [clientCapabilities.handlers],
1982
+ handlers: [
1983
+ {
1984
+ ...clientCapabilities.handlers,
1985
+ 'client.capability.replace': async (input, operationContext) => {
1986
+ const outcome = await clientCapabilities.handlers['client.capability.replace'](input, operationContext);
1987
+ if (outcome.ok && rootRecoveryCompleted && !draining) {
1988
+ // Registration completes outside the policy mutation gate before
1989
+ // recovery selects bindings or composes a backend. Serialize
1990
+ // reconnects and retain the task for the shutdown barrier.
1991
+ clientBoundRecovery = clientBoundRecovery.then(async () => {
1992
+ if (draining)
1993
+ return;
1994
+ await coordinator.recover();
1995
+ await messages.consumePendingAdmissions(recoverySessions
1996
+ .filter((session) => session.toolProfile === 'workhub-coordination-v2')
1997
+ .map((session) => session.id));
1998
+ });
1999
+ try {
2000
+ await clientBoundRecovery;
2001
+ }
2002
+ catch (error) {
2003
+ context.requestDrain();
2004
+ throw error;
2005
+ }
2006
+ }
2007
+ return outcome;
2008
+ },
2009
+ },
2010
+ ],
1560
2011
  recovery: {
1561
2012
  resources: async () => {
1562
2013
  await recoverClientCapabilityOutcomes(stores.runtimeEventStore, recoverySessions.map((session) => session.id));
@@ -1630,6 +2081,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
1630
2081
  async () => {
1631
2082
  if (!rootRecoveryCompleted || poisonFailure)
1632
2083
  return;
2084
+ await clientBoundRecovery.catch(() => undefined);
1633
2085
  rootCloseTask ??= coordinator.close();
1634
2086
  await rootCloseTask;
1635
2087
  },
@@ -2028,6 +2480,24 @@ function requireGoal(coordinator) {
2028
2480
  throw new Error('Runtime Host Goal coordinator is not composed');
2029
2481
  return coordinator;
2030
2482
  }
2483
+ function pluginAttachmentArtifactKind(mimeType, name) {
2484
+ const kind = attachmentKindFromMimeType(mimeType, name);
2485
+ return kind === 'image' || kind === 'pdf' ? kind : 'file';
2486
+ }
2487
+ function pluginAttachmentRef(record) {
2488
+ const mimeType = record.mimeType ?? 'application/octet-stream';
2489
+ return {
2490
+ kind: attachmentKindFromMimeType(mimeType, record.name),
2491
+ name: record.name,
2492
+ mimeType,
2493
+ bytes: record.sizeBytes,
2494
+ ref: {
2495
+ kind: 'session_file',
2496
+ sessionId: record.sessionId,
2497
+ relativePath: record.relativePath,
2498
+ },
2499
+ };
2500
+ }
2031
2501
  /** Every run this Session has opened, named by the event spine that defines it. */
2032
2502
  async function sessionRunIds(runtimeEventStore, sessionId) {
2033
2503
  return (await runtimeEventStore.listSessionInvocations(sessionId)).map((invocation) => invocation.runId);