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

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 (105) hide show
  1. package/README.md +38 -19
  2. package/README.zh-CN.md +34 -19
  3. package/dist/pi-transcript-tools.js +6 -0
  4. package/dist/pi-tui-layout.js +56 -10
  5. package/dist/pi-tui-pickers.js +102 -1
  6. package/dist/pi-tui-runner.js +156 -42
  7. package/dist/pi-tui-todo.js +221 -0
  8. package/dist/pi-tui-transcript-viewer.js +134 -7
  9. package/dist/runtime-host-cli-context.js +70 -13
  10. package/dist/runtime-host-handoff-surface.js +51 -26
  11. package/dist/runtime-host-local-handoff.js +11 -1
  12. package/dist/runtime-host-service-manager.js +0 -3
  13. package/dist/runtime-host-session-channel.js +13 -0
  14. package/dist/runtime-host-session-driver.js +42 -1
  15. package/dist/tui-copy-catalog.js +79 -3
  16. package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
  17. package/node_modules/@maka/core/dist/agent-run.js +1 -0
  18. package/node_modules/@maka/core/dist/attachments.js +3 -0
  19. package/node_modules/@maka/core/dist/canonical-json.js +27 -0
  20. package/node_modules/@maka/core/dist/capabilities.js +35 -0
  21. package/node_modules/@maka/core/dist/computer-use.js +0 -1
  22. package/node_modules/@maka/core/dist/display-redaction.js +18 -0
  23. package/node_modules/@maka/core/dist/llm-connections.js +13 -0
  24. package/node_modules/@maka/core/dist/model-call-attempt.js +2 -0
  25. package/node_modules/@maka/core/dist/model-metadata.js +4 -0
  26. package/node_modules/@maka/core/dist/redaction.js +35 -0
  27. package/node_modules/@maka/core/dist/run-composition.js +77 -2
  28. package/node_modules/@maka/core/dist/session.js +30 -4
  29. package/node_modules/@maka/core/dist/slash-command-catalog.js +1 -0
  30. package/node_modules/@maka/core/dist/tool-result-record-schema.js +2 -1
  31. package/node_modules/@maka/core/package.json +1 -0
  32. package/node_modules/@maka/eval/dist/experiment-directory.js +4 -13
  33. package/node_modules/@maka/runtime/dist/agent-run-inspect.js +0 -13
  34. package/node_modules/@maka/runtime/dist/agent-run.js +80 -1
  35. package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +16 -8
  36. package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +57 -50
  37. package/node_modules/@maka/runtime/dist/archive-read-tool.js +2 -2
  38. package/node_modules/@maka/runtime/dist/context-budget-helpers.js +0 -16
  39. package/node_modules/@maka/runtime/dist/conversation-copy.js +153 -11
  40. package/node_modules/@maka/runtime/dist/github-copilot-oauth-enrollment.js +3 -3
  41. package/node_modules/@maka/runtime/dist/ledger-tool-result-archive-reader.js +69 -1
  42. package/node_modules/@maka/runtime/dist/mcp-tools.js +7 -2
  43. package/node_modules/@maka/runtime/dist/model-fetcher.js +42 -2
  44. package/node_modules/@maka/runtime/dist/model-history.js +0 -112
  45. package/node_modules/@maka/runtime/dist/plugin-runtime.js +20 -10
  46. package/node_modules/@maka/runtime/dist/plugin-tool-service.js +205 -0
  47. package/node_modules/@maka/runtime/dist/provider-request-telemetry.js +8 -1
  48. package/node_modules/@maka/runtime/dist/request-shape.js +23 -0
  49. package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +1 -1
  50. package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +4 -0
  51. package/node_modules/@maka/runtime/dist/runtime-kernel.js +7 -0
  52. package/node_modules/@maka/runtime/dist/stream-graph-coordinator.js +21 -0
  53. package/node_modules/@maka/runtime/dist/stream-graph-supervisor-tools.js +0 -5
  54. package/node_modules/@maka/runtime/dist/test-connection.js +0 -1
  55. package/node_modules/@maka/runtime/dist/tool-activation-identity.js +41 -0
  56. package/node_modules/@maka/runtime/dist/tool-availability.js +11 -1
  57. package/node_modules/@maka/runtime/dist/tool-result-archive-resource.js +63 -1
  58. package/node_modules/@maka/runtime/dist/tool-result-archive-transition.js +42 -12
  59. package/node_modules/@maka/runtime/dist/tool-result-archive.js +27 -4
  60. package/node_modules/@maka/runtime/package.json +1 -0
  61. package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +35 -12
  62. package/node_modules/@maka/runtime-host/dist/client/host-handoff.js +2 -0
  63. package/node_modules/@maka/runtime-host/dist/client/session-subscription.js +19 -0
  64. package/node_modules/@maka/runtime-host/dist/control/endpoint.js +1 -3
  65. package/node_modules/@maka/runtime-host/dist/node-error.js +22 -0
  66. package/node_modules/@maka/runtime-host/dist/operator/managed-deployment.js +1 -3
  67. package/node_modules/@maka/runtime-host/dist/peer-mesh/limits.js +0 -1
  68. package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +1 -1
  69. package/node_modules/@maka/runtime-host/dist/peer-reachability/publisher.js +1 -3
  70. package/node_modules/@maka/runtime-host/dist/protocol/index.js +5 -1
  71. package/node_modules/@maka/runtime-host/dist/protocol/plan.js +1 -0
  72. package/node_modules/@maka/runtime-host/dist/protocol/plugin-platform.js +27 -5
  73. package/node_modules/@maka/runtime-host/dist/protocol/project-catalog.js +2 -2
  74. package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +31 -2
  75. package/node_modules/@maka/runtime-host/dist/server/agent-graph-coordinator.js +0 -3
  76. package/node_modules/@maka/runtime-host/dist/server/execution-artifacts.js +32 -32
  77. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +44 -9
  78. package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +42 -14
  79. package/node_modules/@maka/runtime-host/dist/server/interactive-run-composer.js +47 -22
  80. package/node_modules/@maka/runtime-host/dist/server/plugin-platform-coordinator.js +6 -0
  81. package/node_modules/@maka/runtime-host/dist/server/plugin-platform.js +6 -0
  82. package/node_modules/@maka/runtime-host/dist/server/session-retirement-coordinator.js +5 -2
  83. package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +4 -0
  84. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +20 -2
  85. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +13 -3
  86. package/node_modules/@maka/runtime-host/dist/server/workhub-message-attachments.js +46 -0
  87. package/node_modules/@maka/storage/dist/claude-code-session-adapter.js +0 -1
  88. package/node_modules/@maka/storage/dist/codex-session-adapter.js +284 -196
  89. package/node_modules/@maka/storage/dist/git-exec.js +61 -0
  90. package/node_modules/@maka/storage/dist/git-worktree-child-executor.js +8 -35
  91. package/node_modules/@maka/storage/dist/goal-authority.js +2 -2
  92. package/node_modules/@maka/storage/dist/interaction-store.js +2 -2
  93. package/node_modules/@maka/storage/dist/project-catalog.js +2 -23
  94. package/node_modules/@maka/storage/dist/runtime-event-invariants.js +2 -2
  95. package/node_modules/@maka/storage/dist/runtime-policy/connection-catalog-document.js +8 -3
  96. package/node_modules/@maka/storage/dist/scheduled-task-store.js +249 -283
  97. package/node_modules/@maka/storage/dist/session-bundle-manifest.js +5 -17
  98. package/node_modules/@maka/storage/dist/session-bundle-policy.js +2 -1
  99. package/node_modules/@maka/storage/dist/session-copy-cleanup.js +2 -1
  100. package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +1 -2
  101. package/node_modules/@maka/storage/dist/storage-id.js +28 -0
  102. package/node_modules/@maka/storage/dist/tool-result-archive-evidence.js +31 -4
  103. package/node_modules/@maka/storage/dist/workspace-identity.js +2 -15
  104. package/node_modules/@maka/storage/dist/workspace-version-authority-internal.js +1 -8
  105. package/package.json +1 -1
@@ -269,10 +269,9 @@ function registerPluginEffect(ctx, label, register) {
269
269
  }
270
270
  export function registerPluginContribution(ctx, label, register) {
271
271
  if (ctx.makaTransaction) {
272
- ctx.makaTransaction.stage(label, register, ctx);
273
- return;
272
+ return ctx.makaTransaction.stage(label, register, ctx);
274
273
  }
275
- registerPluginEffect(ctx, label, register);
274
+ return registerPluginEffect(ctx, label, register);
276
275
  }
277
276
  export class MakaPluginTransactionBuffer {
278
277
  context;
@@ -283,13 +282,22 @@ export class MakaPluginTransactionBuffer {
283
282
  }
284
283
  stage(label, register, owner = this.context) {
285
284
  if (this.#state === 'committed') {
286
- registerPluginEffect(owner, label, register);
287
- return;
285
+ return registerPluginEffect(owner, label, register);
288
286
  }
289
287
  if (this.#state === 'rolled_back') {
290
288
  throw new MakaPluginRuntimeError('activation_failed', `Cannot stage contribution after transaction is ${this.#state}`);
291
289
  }
292
- this.#registrations.push({ label, register, owner });
290
+ const item = {
291
+ label,
292
+ register,
293
+ owner,
294
+ cancelled: false,
295
+ };
296
+ this.#registrations.push(item);
297
+ return async () => {
298
+ item.cancelled = true;
299
+ await item.release?.();
300
+ };
293
301
  }
294
302
  async commit() {
295
303
  if (this.#state === 'committed')
@@ -300,7 +308,10 @@ export class MakaPluginTransactionBuffer {
300
308
  const registered = [];
301
309
  try {
302
310
  for (const item of this.#registrations) {
303
- registered.push(registerPluginEffect(item.owner, item.label, item.register));
311
+ if (item.cancelled)
312
+ continue;
313
+ item.release = registerPluginEffect(item.owner, item.label, item.register);
314
+ registered.push(item.release);
304
315
  }
305
316
  this.#state = 'committed';
306
317
  this.#registrations.length = 0;
@@ -333,10 +344,9 @@ export class MakaPluginTransactionBuffer {
333
344
  export function fiberStateName(state) {
334
345
  return ['pending', 'loading', 'active', 'failed', 'disposed', 'unloading'][state];
335
346
  }
336
- export function isCanonicalPluginId(value) {
347
+ export function isCanonicalExtensionId(value) {
337
348
  return typeof value === 'string' && value.length <= 128 && ID_PATTERN.test(value);
338
349
  }
339
- export const isCanonicalExtensionId = isCanonicalPluginId;
340
350
  function cloneCompositionEntry(entry) {
341
351
  return {
342
352
  ...entry,
@@ -384,7 +394,7 @@ export function isCanonicalExtensionScopeId(value) {
384
394
  return (typeof value === 'string' && value.length <= 128 && /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u.test(value));
385
395
  }
386
396
  function validatePluginId(value, label) {
387
- if (!isCanonicalPluginId(value)) {
397
+ if (!isCanonicalExtensionId(value)) {
388
398
  throw new MakaPluginRuntimeError('invalid_entry', `Invalid ${label}`);
389
399
  }
390
400
  }
@@ -0,0 +1,205 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+ import { REQUEST_COMPOSITION_MAX_TOOL_DESCRIPTION_LENGTH } from '@maka/core/run-composition';
20
+ import { Service } from './plugin-kernel.js';
21
+ import { MakaPluginRuntimeError, pluginIdentity, registerPluginContribution, } from './plugin-runtime.js';
22
+ import { bindToolActivationIdentity } from './tool-activation-identity.js';
23
+ import { TOOL_SEARCH_NAME, TOOL_SEARCH_PROVIDER_NAME } from './tool-availability.js';
24
+ /**
25
+ * Context-scoped Tool contribution registry for trusted Host plugins.
26
+ *
27
+ * Registration is staged by the Plugin Platform transaction and owned by the
28
+ * registering Fiber. Profile registrations are inherited by Session roots;
29
+ * an exact Session registration shadows the Profile registration. Core tools
30
+ * remain Host-owned and cannot be shadowed.
31
+ */
32
+ export class PluginToolService extends Service {
33
+ layers = new Map();
34
+ onChanged;
35
+ constructor(ctx, options = {}) {
36
+ super(ctx, 'tools');
37
+ this.onChanged = options.onChanged;
38
+ }
39
+ register(definition) {
40
+ const identity = pluginIdentity(this.ctx);
41
+ if (identity.scopeId === 'desktop-ui') {
42
+ throw new MakaPluginRuntimeError('activation_failed', 'desktop-ui plugins cannot register Host tools');
43
+ }
44
+ validateTool(definition);
45
+ return registerPluginContribution(this.ctx, `tools.register(${JSON.stringify(definition.name)})`, () => this.publish(identity, definition));
46
+ }
47
+ resolve(sessionId, coreTools) {
48
+ const contributions = this.resolveContributions(sessionId, coreTools);
49
+ return Object.freeze({
50
+ tools: Object.freeze([...coreTools, ...contributions.tools]),
51
+ });
52
+ }
53
+ /** Resolve only Plugin-owned additions after validating them against the Host binding. */
54
+ resolveContributions(sessionId, coreTools) {
55
+ if (!sessionId || /[\r\n\0]/u.test(sessionId))
56
+ throw new Error('Invalid Tool Session scope');
57
+ const visible = new Map();
58
+ for (const entry of this.layers.get('profile')?.values() ?? []) {
59
+ visible.set(entry.definition.name, entry);
60
+ }
61
+ const sessionRoot = `session:${sessionId}`;
62
+ for (const entry of this.layers.get(sessionRoot)?.values() ?? []) {
63
+ visible.set(entry.definition.name, entry);
64
+ }
65
+ const coreNames = new Set(coreTools.map(({ name }) => name));
66
+ for (const name of visible.keys()) {
67
+ if (coreNames.has(name)) {
68
+ throw new MakaPluginRuntimeError('activation_failed', `Plugin Tool ${JSON.stringify(name)} conflicts with a Host-owned Tool`);
69
+ }
70
+ }
71
+ const entries = [...visible.values()].sort(compareRegistration);
72
+ return Object.freeze({
73
+ tools: Object.freeze(entries.map(({ exposed }) => exposed)),
74
+ });
75
+ }
76
+ inspect(rootId) {
77
+ const layers = rootId
78
+ ? [[rootId, this.layers.get(rootId)]]
79
+ : [...this.layers.entries()];
80
+ return Object.freeze(layers
81
+ .flatMap(([, layer]) => [...(layer?.values() ?? [])])
82
+ .sort(compareRegistration)
83
+ .map((entry) => Object.freeze({
84
+ entryId: entry.entryId,
85
+ scopeId: entry.scopeId,
86
+ extensionId: entry.extensionId,
87
+ generation: entry.generation,
88
+ toolName: entry.definition.name,
89
+ activeCalls: entry.activeCalls,
90
+ retired: entry.retired,
91
+ })));
92
+ }
93
+ publish(identity, definition) {
94
+ const rootId = identity.scopeId;
95
+ let layer = this.layers.get(rootId);
96
+ if (!layer) {
97
+ layer = new Map();
98
+ this.layers.set(rootId, layer);
99
+ }
100
+ const existing = layer.get(definition.name);
101
+ if (existing && existing.entryId !== identity.entryId) {
102
+ throw new MakaPluginRuntimeError('activation_failed', `Plugin Tool ${JSON.stringify(definition.name)} is already registered by ${existing.entryId}`);
103
+ }
104
+ let entry;
105
+ const exposed = bindToolActivationIdentity({
106
+ ...definition,
107
+ impl: async (args, context) => {
108
+ if (entry.retired) {
109
+ throw new Error(`Plugin Tool ${JSON.stringify(definition.name)} is no longer active`);
110
+ }
111
+ entry.activeCalls += 1;
112
+ try {
113
+ return await definition.impl(args, context);
114
+ }
115
+ finally {
116
+ entry.activeCalls -= 1;
117
+ if (entry.activeCalls === 0) {
118
+ for (const resolve of entry.drainWaiters)
119
+ resolve();
120
+ entry.drainWaiters.clear();
121
+ }
122
+ }
123
+ },
124
+ }, {
125
+ kind: 'plugin',
126
+ scopeId: identity.scopeId,
127
+ entryId: identity.entryId,
128
+ extensionId: identity.extensionId,
129
+ generation: identity.generation,
130
+ toolName: definition.name,
131
+ });
132
+ entry = {
133
+ ...identity,
134
+ definition,
135
+ exposed,
136
+ token: Symbol(definition.name),
137
+ activeCalls: 0,
138
+ retired: false,
139
+ drainWaiters: new Set(),
140
+ };
141
+ layer.set(definition.name, entry);
142
+ try {
143
+ this.notifyChanged(rootId);
144
+ }
145
+ catch (error) {
146
+ if (existing)
147
+ layer.set(definition.name, existing);
148
+ else
149
+ layer.delete(definition.name);
150
+ if (layer.size === 0)
151
+ this.layers.delete(rootId);
152
+ throw error;
153
+ }
154
+ return async () => {
155
+ entry.retired = true;
156
+ const currentLayer = this.layers.get(rootId);
157
+ if (currentLayer?.get(definition.name)?.token === entry.token) {
158
+ if (existing && !existing.retired)
159
+ currentLayer.set(definition.name, existing);
160
+ else
161
+ currentLayer.delete(definition.name);
162
+ if (currentLayer.size === 0)
163
+ this.layers.delete(rootId);
164
+ this.notifyChanged(rootId);
165
+ }
166
+ if (entry.activeCalls > 0) {
167
+ await new Promise((resolve) => entry.drainWaiters.add(resolve));
168
+ }
169
+ };
170
+ }
171
+ notifyChanged(rootId) {
172
+ this.ctx.emit('tools/change');
173
+ this.onChanged?.(rootId);
174
+ }
175
+ }
176
+ function validateTool(tool) {
177
+ if (!tool || typeof tool !== 'object')
178
+ throw new TypeError('Tool definition is required');
179
+ if (typeof tool.name !== 'string' ||
180
+ tool.name.length === 0 ||
181
+ tool.name.length > 128 ||
182
+ /[\r\n\0]/u.test(tool.name)) {
183
+ throw new TypeError('Tool requires a valid name');
184
+ }
185
+ if (typeof tool.description !== 'string' ||
186
+ tool.description.length === 0 ||
187
+ tool.description.length > REQUEST_COMPOSITION_MAX_TOOL_DESCRIPTION_LENGTH ||
188
+ typeof tool.impl !== 'function') {
189
+ throw new TypeError(`Tool ${JSON.stringify(tool.name)} requires a description of at most ${REQUEST_COMPOSITION_MAX_TOOL_DESCRIPTION_LENGTH} characters and an implementation`);
190
+ }
191
+ if (tool.parameters === undefined) {
192
+ throw new TypeError(`Tool ${JSON.stringify(tool.name)} requires an input schema`);
193
+ }
194
+ if (tool.providerTool) {
195
+ throw new TypeError(`Plugin Tool ${JSON.stringify(tool.name)} cannot claim a provider protocol`);
196
+ }
197
+ if (tool.name === TOOL_SEARCH_NAME || tool.name === TOOL_SEARCH_PROVIDER_NAME) {
198
+ throw new TypeError(`Plugin Tool name ${JSON.stringify(tool.name)} is reserved by Runtime`);
199
+ }
200
+ }
201
+ function compareRegistration(left, right) {
202
+ return (left.definition.name.localeCompare(right.definition.name) ||
203
+ left.scopeId.localeCompare(right.scopeId) ||
204
+ left.entryId.localeCompare(right.entryId));
205
+ }
@@ -199,14 +199,18 @@ export class ProviderRequestTracker {
199
199
  * that call, not new calls, so they share this id.
200
200
  */
201
201
  logicalCallIdByStep = new Map();
202
+ requestCompositionIdByStep = new Map();
202
203
  constructor(input) {
203
204
  this.input = input;
204
205
  }
205
206
  get traceId() {
206
207
  return this.input.traceId;
207
208
  }
208
- setStep(step) {
209
+ setStep(step, requestCompositionId) {
209
210
  this.step = step;
211
+ if (requestCompositionId !== undefined) {
212
+ this.requestCompositionIdByStep.set(step, requestCompositionId);
213
+ }
210
214
  }
211
215
  async trackStream(input) {
212
216
  throwIfAbortedBeforeDispatch(input.abortSignal);
@@ -356,6 +360,9 @@ export class ProviderRequestTracker {
356
360
  ? { connectionSlug: accounting.connectionSlug }
357
361
  : {}),
358
362
  step: Math.max(0, step),
363
+ ...(this.requestCompositionIdByStep.get(step)
364
+ ? { requestCompositionId: this.requestCompositionIdByStep.get(step) }
365
+ : {}),
359
366
  attempt: Math.max(0, attempt - 1),
360
367
  callKind: accounting.callKind,
361
368
  ...((input.historyCompactRoute ?? accounting.historyCompactRoute) !== undefined
@@ -152,6 +152,29 @@ export function toolCatalogHash(tools) {
152
152
  .sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0))
153
153
  .map(toolShapeForDiagnostics));
154
154
  }
155
+ /** Canonical, JSON-safe schemas for the exact provider-visible tool subset. */
156
+ export function requestCompositionToolSchemas(tools, activeToolNames) {
157
+ const active = new Set(activeToolNames);
158
+ return tools
159
+ .filter((tool) => active.has(tool.name))
160
+ .map((tool) => {
161
+ const inputSchema = JSON.parse(stableStringify(schemaShapeForHash(tool.parameters)));
162
+ if (!isPlainObject(inputSchema)) {
163
+ throw new Error(`Tool ${JSON.stringify(tool.name)} produced a non-object input schema`);
164
+ }
165
+ return {
166
+ name: tool.name,
167
+ description: tool.description,
168
+ inputSchema,
169
+ ...(tool.providerTool
170
+ ? {
171
+ providerTool: JSON.parse(stableStringify(tool.providerTool)),
172
+ }
173
+ : {}),
174
+ };
175
+ })
176
+ .sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0));
177
+ }
155
178
  export function stableStringify(value) {
156
179
  return JSON.stringify(canonicalize(value));
157
180
  }
@@ -18,7 +18,7 @@
18
18
  */
19
19
  import { isRuntimeSystemNoteKind } from '@maka/core/session';
20
20
  import { createRuntimeEventId } from '@maka/core/runtime-event';
21
- export const RUNTIME_EVENT_BACKFILL_STATE_KEY = 'makaRuntimeRecovery';
21
+ const RUNTIME_EVENT_BACKFILL_STATE_KEY = 'makaRuntimeRecovery';
22
22
  export function backfillRuntimeEventsFromStoredMessages(input) {
23
23
  const newId = input.newId ?? (() => createRuntimeEventId('rt-backfill'));
24
24
  const now = input.now ?? (() => Date.now());
@@ -357,6 +357,7 @@ export function applyArchivedToolResultReadModelStatuses(events, archiveStatuses
357
357
  toolCallId: placeholder.toolCallId,
358
358
  toolName: placeholder.toolName,
359
359
  artifactId: placeholder.artifactId,
360
+ ...(placeholder.rewriteVersion === 2 ? { resourceRef: placeholder.resourceRef } : {}),
360
361
  bodySha256: placeholder.bodySha256,
361
362
  originalEstimatedTokens: placeholder.originalEstimatedTokens,
362
363
  originalBytes: placeholder.originalBytes,
@@ -658,6 +659,9 @@ function projectFunctionResponse(event, state, messages) {
658
659
  toolName: archivedPlaceholder.toolName,
659
660
  artifactId: archivedPlaceholder.artifactId,
660
661
  bodySha256: archivedPlaceholder.bodySha256,
662
+ ...(archivedPlaceholder.rewriteVersion === 2
663
+ ? { resourceRef: archivedPlaceholder.resourceRef }
664
+ : {}),
661
665
  originalEstimatedTokens: archivedPlaceholder.originalEstimatedTokens,
662
666
  originalBytes: archivedPlaceholder.originalBytes,
663
667
  rewriteVersion: archivedPlaceholder.rewriteVersion,
@@ -1694,6 +1694,13 @@ export class RuntimeKernel {
1694
1694
  }
1695
1695
  return run.recordRunComposition(snapshot);
1696
1696
  },
1697
+ recordRequestComposition: (runId, snapshot) => {
1698
+ const run = this.active.get(sessionId)?.activeRuns.get(runId);
1699
+ if (!run) {
1700
+ return Promise.reject(new Error('No active AgentRun for Request Composition'));
1701
+ }
1702
+ return run.recordRequestComposition(snapshot);
1703
+ },
1697
1704
  loadHistoryCompactCheckpoint: () => this.historyCompactCoordinator.load(sessionId),
1698
1705
  recordHistoryCompactCheckpoint: (checkpoint, turnId) => this.historyCompactCoordinator.record(sessionId, checkpoint, runFor(turnId)),
1699
1706
  loadModelProjectionTransitions: async () => loadModelProjectionTransitionsFromRunLedger(this.deps.runStore, sessionId, await this.sessionRunIds(sessionId)),
@@ -184,6 +184,27 @@ export class AgentGraphCoordinator {
184
184
  async hasLiveSessionState(rootSessionId) {
185
185
  return (await this.readSessionState(rootSessionId)) === 'live';
186
186
  }
187
+ /**
188
+ * Classify durable graph state for Session retirement without changing the
189
+ * broader live-state semantics used by recovery and graph epoch selection.
190
+ */
191
+ async readRetirementDisposition(rootSessionId) {
192
+ const snapshot = buildAgentGraphClientSnapshot(await this.#readClientModelInputForGraph(rootSessionId, await this.currentGraphId(rootSessionId)));
193
+ if (snapshot.scheduleRevision === 0)
194
+ return { kind: 'clear' };
195
+ switch (snapshot.status) {
196
+ case 'empty':
197
+ case 'completed':
198
+ return { kind: 'clear' };
199
+ case 'stopped':
200
+ case 'failed':
201
+ return { kind: 'quiescent_open' };
202
+ case 'active':
203
+ case 'waiting':
204
+ case 'closing':
205
+ return { kind: 'busy', status: snapshot.status };
206
+ }
207
+ }
187
208
  /**
188
209
  * Reconstruct one stable, reference-only control/data-plane timeline page.
189
210
  *
@@ -22,11 +22,6 @@ import { stableHash } from './request-shape.js';
22
22
  export const VIEW_AGENT_GRAPH_TOOL_NAME = 'view_agent_graph';
23
23
  export const UPDATE_AGENT_GRAPH_TOOL_NAME = 'update_agent_graph';
24
24
  export const YIELD_AGENT_GRAPH_TOOL_NAME = 'yield_agent_graph';
25
- export const AGENT_GRAPH_SUPERVISOR_TOOL_NAMES = [
26
- VIEW_AGENT_GRAPH_TOOL_NAME,
27
- UPDATE_AGENT_GRAPH_TOOL_NAME,
28
- YIELD_AGENT_GRAPH_TOOL_NAME,
29
- ];
30
25
  const TOOL_VIEW_MAX_TERMINAL_WORK = 64;
31
26
  const TOOL_VIEW_MAX_STOPPED_TARGETS = 64;
32
27
  const TOOL_VIEW_MAX_INSTRUCTION_CHARS = 2_000;
@@ -337,7 +337,6 @@ async function httpFailure(r, t0) {
337
337
  await r.cancel();
338
338
  return {
339
339
  ok: false,
340
- errorMessage: 'OAuth 已登录,但当前账号或 provider 正在 rate limit。请稍后重试,或先切换到其它可用模型。',
341
340
  statusCode,
342
341
  errorClass: 'provider_unavailable',
343
342
  latencyMs: Date.now() - t0,
@@ -0,0 +1,41 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+ import { stableHash, toolCatalogHash } from './request-shape.js';
20
+ const TOOL_ACTIVATION_IDENTITY = Symbol('maka.toolActivationIdentity');
21
+ /** Bind a Runtime-owned contribution identity to a Tool without exposing it to providers. */
22
+ export function bindToolActivationIdentity(tool, identity) {
23
+ return Object.freeze({
24
+ ...tool,
25
+ [TOOL_ACTIVATION_IDENTITY]: stableHash({
26
+ identity,
27
+ schemaHash: toolCatalogHash([tool]),
28
+ }),
29
+ });
30
+ }
31
+ /**
32
+ * Stable logical identity used by deferred-tool activation.
33
+ *
34
+ * Host wrappers without explicit contribution metadata fall back to their
35
+ * canonical provider-visible shape, so rebuilding an equivalent wrapper does
36
+ * not revoke activation. Dynamic contributors bind generation-aware metadata.
37
+ */
38
+ export function toolActivationKey(tool) {
39
+ const explicit = tool[TOOL_ACTIVATION_IDENTITY];
40
+ return explicit ?? stableHash({ kind: 'host', schemaHash: toolCatalogHash([tool]) });
41
+ }
@@ -20,6 +20,7 @@ import MiniSearch from 'minisearch';
20
20
  import { z } from 'zod';
21
21
  import { estimateTokens } from './context-budget-helpers.js';
22
22
  import { canonicalizeToolSet, stableHash, toolSchemaCharsForDiagnostics } from './request-shape.js';
23
+ import { toolActivationKey } from './tool-activation-identity.js';
23
24
  /** Canonical name of Maka's provider-independent deferred-tool search connector. */
24
25
  export const TOOL_SEARCH_NAME = 'tool_search';
25
26
  /** Provider-safe alias used because OpenAI Responses reserves `tool_search`. */
@@ -101,6 +102,7 @@ export class ToolAvailabilityRuntime {
101
102
  invalidTool;
102
103
  tools;
103
104
  toolsByName;
105
+ activationKeysByName;
104
106
  groups;
105
107
  searchableNames;
106
108
  directNames;
@@ -115,6 +117,7 @@ export class ToolAvailabilityRuntime {
115
117
  }
116
118
  this.tools = [...tools];
117
119
  this.toolsByName = new Map(tools.map((tool) => [tool.name, tool]));
120
+ this.activationKeysByName = new Map(tools.map((tool) => [tool.name, toolActivationKey(tool)]));
118
121
  const known = new Set(this.toolsByName.keys());
119
122
  const searchable = config === undefined
120
123
  ? new Set()
@@ -240,6 +243,13 @@ export class ToolAvailabilityRuntime {
240
243
  const allTools = [...this.tools, connector];
241
244
  const canonical = canonicalizeToolSet(allTools, this.invalidTool);
242
245
  const knownNames = new Set(canonical.providerTools.map((tool) => tool.name));
246
+ // Activation belongs to a stable logical contribution, not a temporary
247
+ // wrapper object or merely its name. Equivalent Host wrappers survive
248
+ // per-step rebuilding; a replaced Plugin generation does not.
249
+ for (const [name, activatedKey] of activeTools) {
250
+ if (this.activationKeysByName.get(name) !== activatedKey)
251
+ activeTools.delete(name);
252
+ }
243
253
  const requiredNames = [...requiredToolNames].filter((name) => knownNames.has(name));
244
254
  const step = { active: new Set() };
245
255
  const computeActive = () => {
@@ -308,7 +318,7 @@ export class ToolAvailabilityRuntime {
308
318
  schemaChars += chars;
309
319
  }
310
320
  for (const name of activated)
311
- activeTools.set(name, this.toolsByName.get(name));
321
+ activeTools.set(name, this.activationKeysByName.get(name));
312
322
  const result = {
313
323
  activated,
314
324
  ...(blocked ? { blocked } : {}),
@@ -35,12 +35,72 @@ const MAX_SEARCH_SNIPPET_CHARS = 240;
35
35
  const MAX_SEARCH_PATTERN_CHARS = 256;
36
36
  /** Preview length surfaced by inspect for text/object payloads. */
37
37
  const INSPECT_PREVIEW_CHARS = 600;
38
+ export function isLedgerArchiveIdentity(value) {
39
+ if (!isRecord(value))
40
+ return false;
41
+ return (value.storage === 'ledger' &&
42
+ value.artifactId === undefined &&
43
+ ['runtimeEventId', 'toolCallId', 'toolName'].every((key) => typeof value[key] === 'string' &&
44
+ value[key].length > 0 &&
45
+ value[key].length <= 512) &&
46
+ typeof value.sourceProjectionDigest === 'string' &&
47
+ /^sha256:[a-f0-9]{64}$/.test(value.sourceProjectionDigest) &&
48
+ (value.previousTransitionId === undefined ||
49
+ (typeof value.previousTransitionId === 'string' &&
50
+ /^mptransition-[a-f0-9]{32}$/.test(value.previousTransitionId))) &&
51
+ typeof value.bodySha256 === 'string' &&
52
+ /^[a-f0-9]{64}$/.test(value.bodySha256) &&
53
+ Number.isSafeInteger(value.originalBytes) &&
54
+ Number(value.originalBytes) > 0);
55
+ }
38
56
  export function buildToolResultArchiveResourceRef(input) {
57
+ if (input.storage === 'ledger') {
58
+ if (!isLedgerArchiveIdentity(input))
59
+ throw new Error('Invalid ledger archive identity');
60
+ const value = [
61
+ input.runtimeEventId,
62
+ input.toolCallId,
63
+ input.toolName,
64
+ input.sourceProjectionDigest,
65
+ input.previousTransitionId ?? null,
66
+ input.bodySha256,
67
+ input.originalBytes,
68
+ ];
69
+ return `maka://archive-ledger/v1/${encodeURIComponent(JSON.stringify(value))}`;
70
+ }
39
71
  const artifactId = encodeURIComponent(input.artifactId);
40
72
  const sha256 = encodeURIComponent(input.bodySha256);
41
73
  return `maka://archive/${artifactId}/${sha256}/${input.originalBytes}`;
42
74
  }
43
75
  export function parseToolResultArchiveResourceRef(ref) {
76
+ if (ref.startsWith('maka://archive-ledger/')) {
77
+ try {
78
+ const prefix = 'maka://archive-ledger/v1/';
79
+ if (!ref.startsWith(prefix) || ref.length > 16384)
80
+ return null;
81
+ const values = JSON.parse(decodeURIComponent(ref.slice(prefix.length)));
82
+ if (!Array.isArray(values) || values.length !== 7)
83
+ return null;
84
+ const [runtimeEventId, toolCallId, toolName, sourceProjectionDigest, previous, bodySha256, originalBytes,] = values;
85
+ const identity = {
86
+ storage: 'ledger',
87
+ runtimeEventId,
88
+ toolCallId,
89
+ toolName,
90
+ sourceProjectionDigest,
91
+ ...(previous === null ? {} : { previousTransitionId: previous }),
92
+ bodySha256,
93
+ originalBytes,
94
+ };
95
+ return isLedgerArchiveIdentity(identity) &&
96
+ buildToolResultArchiveResourceRef(identity) === ref
97
+ ? identity
98
+ : null;
99
+ }
100
+ catch {
101
+ return null;
102
+ }
103
+ }
44
104
  let url;
45
105
  try {
46
106
  url = new URL(ref);
@@ -162,7 +222,9 @@ function inspectArchive(ref, identity, value, serializedResult) {
162
222
  kind: 'tool_result_archive',
163
223
  operation: 'inspect',
164
224
  ref,
165
- artifactId: identity.artifactId,
225
+ ...(identity.storage === 'ledger'
226
+ ? { storage: 'ledger', runtimeEventId: identity.runtimeEventId }
227
+ : { artifactId: identity.artifactId }),
166
228
  originalBytes: identity.originalBytes,
167
229
  };
168
230
  const readHint = 'Call ArchiveRead with operation "read" (unit "char" or "line"), offset, and limit for bounded pages, or operation "search" with a pattern to locate text.';