maka-agent 0.2.0-dev.46.20260922 → 0.2.0-dev.48.20260923
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DISCLAIMER-WIP +6 -1
- package/README.md +6 -1
- package/dist/acp/maka-acp-agent.js +1 -1
- package/dist/acp/session-mcp.js +212 -0
- package/dist/acp/session-registry.js +52 -8
- package/dist/acp/stdio-server.js +3 -0
- package/dist/cli-core.js +1 -1
- package/dist/mcp-capability-provider.js +6 -1
- package/dist/mcp-capability-publication.js +139 -0
- package/dist/pi-tui-layout.js +46 -17
- package/dist/pi-tui-pickers.js +25 -14
- package/dist/pi-tui-runner.js +24 -15
- package/dist/runtime-host-capability-provider-command.js +25 -6
- package/dist/runtime-host-service-manager.js +26 -2
- package/dist/tui-context-refresh.js +15 -26
- package/dist/tui-mcp-control.js +66 -112
- package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
- package/node_modules/@maka/acp-executor-plugin/dist/acp-errors.js +26 -0
- package/node_modules/@maka/acp-executor-plugin/dist/acp-filesystem.js +103 -0
- package/node_modules/@maka/acp-executor-plugin/dist/acp-process.js +119 -0
- package/node_modules/@maka/acp-executor-plugin/dist/acp-projection.js +146 -0
- package/node_modules/@maka/acp-executor-plugin/dist/index.js +653 -0
- package/node_modules/@maka/acp-executor-plugin/dist/plugin.mjs +24446 -0
- package/node_modules/@maka/acp-executor-plugin/package.json +15 -0
- package/node_modules/@maka/antigravity-acp-plugin/dist/index.js +88 -0
- package/node_modules/@maka/antigravity-acp-plugin/dist/model-presentation.js +53 -0
- package/node_modules/@maka/antigravity-acp-plugin/dist/plugin.mjs +115 -0
- package/node_modules/@maka/antigravity-acp-plugin/package.json +15 -0
- package/node_modules/@maka/core/dist/client-capability-grant.js +2 -2
- package/node_modules/@maka/core/dist/executor-catalog.js +106 -0
- package/node_modules/@maka/core/dist/mcp.js +4 -1
- package/node_modules/@maka/core/dist/model-metadata.js +28 -1
- package/node_modules/@maka/core/dist/model-thinking.js +36 -1
- package/node_modules/@maka/core/dist/provider-registry.js +0 -1
- package/node_modules/@maka/core/dist/refresh-read-coordinator.js +62 -0
- package/node_modules/@maka/core/dist/runtime-event-store.js +25 -0
- package/node_modules/@maka/core/dist/runtime-invocation.js +5 -0
- package/node_modules/@maka/core/dist/runtime-policy/connection-catalog-codec.js +4 -0
- package/node_modules/@maka/core/dist/runtime-policy/credential-vault-codec.js +6 -0
- package/node_modules/@maka/core/dist/runtime-policy/policy-codec.js +21 -0
- package/node_modules/@maka/core/dist/session.js +19 -1
- package/node_modules/@maka/core/dist/settings.js +3 -0
- package/node_modules/@maka/core/dist/tool-ledger-scanner.js +365 -104
- package/node_modules/@maka/core/dist/turn-origin.js +14 -0
- package/node_modules/@maka/core/package.json +3 -0
- package/node_modules/@maka/mcp/dist/credential-coordinator.js +6 -1
- package/node_modules/@maka/mcp/dist/index.js +31 -5
- package/node_modules/@maka/mcp/dist/oauth.js +54 -6
- package/node_modules/@maka/runtime/dist/agent-run-inspect.js +1 -1
- package/node_modules/@maka/runtime/dist/ai-sdk-message-projection.js +15 -60
- package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +18 -0
- package/node_modules/@maka/runtime/dist/apply-patch-profile.js +64 -14
- package/node_modules/@maka/runtime/dist/builtin-tools.js +3 -2
- package/node_modules/@maka/runtime/dist/codex-v4a-patch.js +18 -0
- package/node_modules/@maka/runtime/dist/conversation-copy.js +56 -1
- package/node_modules/@maka/runtime/dist/mcp-tools.js +9 -2
- package/node_modules/@maka/runtime/dist/model-adapter.js +80 -3
- package/node_modules/@maka/runtime/dist/model-runtime.js +6 -0
- package/node_modules/@maka/runtime/dist/openai-apply-patch.js +5 -0
- package/node_modules/@maka/runtime/dist/plugin-executor-backend.js +122 -3
- package/node_modules/@maka/runtime/dist/plugin-executor-service.js +212 -16
- package/node_modules/@maka/runtime/dist/runtime-ledger-repair.js +2 -2
- package/node_modules/@maka/runtime/dist/session-event-runtime-mapper.js +3 -0
- package/node_modules/@maka/runtime/dist/session-manager.js +184 -126
- package/node_modules/@maka/runtime/dist/shell-run-manager.js +3 -0
- package/node_modules/@maka/runtime/dist/stream-graph-coordinator.js +29 -4
- package/node_modules/@maka/runtime-host/dist/candidate-entry.js +8 -5
- package/node_modules/@maka/runtime-host/dist/client/capability-provider-service.js +2 -0
- package/node_modules/@maka/runtime-host/dist/client/client-capability-channel.js +59 -20
- package/node_modules/@maka/runtime-host/dist/client/connection.js +6 -4
- package/node_modules/@maka/runtime-host/dist/client/index.js +1 -1
- package/node_modules/@maka/runtime-host/dist/client/reconnect-lifecycle.js +8 -1
- package/node_modules/@maka/runtime-host/dist/client/reconnecting-connection.js +4 -4
- package/node_modules/@maka/runtime-host/dist/client/session-catalog-summary.js +6 -1
- package/node_modules/@maka/runtime-host/dist/composition-identity.js +19 -0
- package/node_modules/@maka/runtime-host/dist/protocol/client-capability.js +20 -3
- package/node_modules/@maka/runtime-host/dist/protocol/external-session.js +8 -5
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +20 -2
- package/node_modules/@maka/runtime-host/dist/protocol/plugin-platform.js +34 -0
- package/node_modules/@maka/runtime-host/dist/protocol/session-catalog.js +75 -5
- package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +1 -5
- package/node_modules/@maka/runtime-host/dist/server/builtin-external-agent-plugins.js +188 -0
- package/node_modules/@maka/runtime-host/dist/server/candidate.js +12 -7
- package/node_modules/@maka/runtime-host/dist/server/client-capability-coordinator.js +234 -70
- package/node_modules/@maka/runtime-host/dist/server/client-capability-invocation-broker.js +14 -8
- package/node_modules/@maka/runtime-host/dist/server/client-capability-recovery.js +44 -46
- package/node_modules/@maka/runtime-host/dist/server/context-coordinator.js +2 -0
- package/node_modules/@maka/runtime-host/dist/server/execution-composition-factory.js +1 -1
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +188 -21
- package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +6 -0
- package/node_modules/@maka/runtime-host/dist/server/extension-bundle.js +4 -0
- package/node_modules/@maka/runtime-host/dist/server/external-session-coordinator.js +29 -7
- package/node_modules/@maka/runtime-host/dist/server/host-composition-source.js +47 -0
- package/node_modules/@maka/runtime-host/dist/server/host-composition.js +1 -29
- package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +2 -9
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +75 -9
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-tool-profile.js +5 -1
- package/node_modules/@maka/runtime-host/dist/server/interaction-coordinator.js +45 -0
- package/node_modules/@maka/runtime-host/dist/server/jev-routing-model.js +157 -0
- package/node_modules/@maka/runtime-host/dist/server/listener-set.js +2 -2
- package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +4 -0
- package/node_modules/@maka/runtime-host/dist/server/plugin-platform-coordinator.js +11 -1
- package/node_modules/@maka/runtime-host/dist/server/process-lifecycle.js +1 -1
- package/node_modules/@maka/runtime-host/dist/server/process-termination-error.js +27 -0
- package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +91 -12
- package/node_modules/@maka/runtime-host/dist/server/runtime-policy-coordinator.js +2 -0
- package/node_modules/@maka/runtime-host/dist/server/session-bundle-coordinator.js +4 -1
- package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +128 -13
- package/node_modules/@maka/runtime-host/dist/server/session-effect-coordinator.js +12 -6
- package/node_modules/@maka/runtime-host/dist/server/session-retirement-coordinator.js +2 -2
- package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +33 -0
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +4 -0
- package/node_modules/@maka/runtime-host/dist/server/workhub-result-coordinator.js +173 -0
- package/node_modules/@maka/runtime-host/dist/server/workhub-result-runtime.js +293 -0
- package/node_modules/@maka/runtime-host/package.json +2 -0
- package/node_modules/@maka/storage/dist/agent-run-store-contract.js +8 -0
- package/node_modules/@maka/storage/dist/execution-stores.js +15 -3
- package/node_modules/@maka/storage/dist/mcp-config-store.js +91 -2
- package/node_modules/@maka/storage/dist/operational-state-store.js +15 -1
- package/node_modules/@maka/storage/dist/plan-authority.js +2 -0
- package/node_modules/@maka/storage/dist/plan-store.js +30 -0
- package/node_modules/@maka/storage/dist/runtime-event-persistence.js +1 -0
- package/node_modules/@maka/storage/dist/runtime-policy/credential-vault-document.js +4 -1
- package/node_modules/@maka/storage/dist/runtime-policy/policy-document.js +2 -0
- package/node_modules/@maka/storage/dist/session-store-values.js +16 -4
- package/node_modules/@maka/storage/dist/shell-run-authority.js +1 -0
- package/node_modules/@maka/storage/dist/shell-run-store.js +15 -0
- package/node_modules/@maka/storage/dist/sqlite-runtime-schema.js +74 -1
- package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +724 -84
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +16 -0
- package/package.json +1 -1
|
@@ -27,11 +27,11 @@ import { canonicalToolArgsHash } from './tool-args-identity.js';
|
|
|
27
27
|
* at `running` with no terminal event at all (#2234). This error is always a
|
|
28
28
|
* producer bug: something emitted a fact the ledger's invariants forbid.
|
|
29
29
|
*
|
|
30
|
-
* It deliberately does NOT cover a ledger that is already
|
|
31
|
-
* rejects well-formed candidates because of damage
|
|
32
|
-
* so "the store is healthy" is false and
|
|
33
|
-
*
|
|
34
|
-
* classified as one.
|
|
30
|
+
* It deliberately does NOT cover a ledger dependency closure that is already
|
|
31
|
+
* corrupt. That refusal rejects well-formed candidates because of damage in
|
|
32
|
+
* the facts they depend on, so "the store is healthy for this run" is false and
|
|
33
|
+
* the run must keep failing closed — see `ToolLedgerCorruptionError`, which is
|
|
34
|
+
* a plain durability failure and is classified as one.
|
|
35
35
|
*/
|
|
36
36
|
export class ToolLedgerRejectionError extends Error {
|
|
37
37
|
code;
|
|
@@ -44,10 +44,11 @@ export class ToolLedgerRejectionError extends Error {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
|
-
* The
|
|
48
|
-
* nothing wrong with
|
|
49
|
-
*
|
|
50
|
-
*
|
|
47
|
+
* The selected tool dependency closure is already corrupt, so it refuses a
|
|
48
|
+
* candidate that has nothing wrong with it. Unlike `ToolLedgerRejectionError`
|
|
49
|
+
* this is not a producer bug. The affected run stays on the fail-closed path;
|
|
50
|
+
* unrelated closures remain writable and explicit full-ledger audit owns
|
|
51
|
+
* discovery outside the active closure.
|
|
51
52
|
*/
|
|
52
53
|
export class ToolLedgerCorruptionError extends Error {
|
|
53
54
|
code;
|
|
@@ -59,6 +60,23 @@ export class ToolLedgerCorruptionError extends Error {
|
|
|
59
60
|
this.eventId = eventId;
|
|
60
61
|
}
|
|
61
62
|
}
|
|
63
|
+
/** Operation identities whose invocation closure must accompany these facts. */
|
|
64
|
+
export function referencedToolOperationIds(events) {
|
|
65
|
+
const operationIds = new Set();
|
|
66
|
+
for (const event of events) {
|
|
67
|
+
const dispatchOperationId = event.actions?.toolDispatch?.operationId;
|
|
68
|
+
const recoveryOperationId = event.actions?.toolRecovery?.payload.operationId;
|
|
69
|
+
if (dispatchOperationId)
|
|
70
|
+
operationIds.add(dispatchOperationId);
|
|
71
|
+
if (recoveryOperationId)
|
|
72
|
+
operationIds.add(recoveryOperationId);
|
|
73
|
+
if (event.refs?.operationId)
|
|
74
|
+
operationIds.add(event.refs.operationId);
|
|
75
|
+
if (event.refs?.parentOperationId)
|
|
76
|
+
operationIds.add(event.refs.parentOperationId);
|
|
77
|
+
}
|
|
78
|
+
return operationIds;
|
|
79
|
+
}
|
|
62
80
|
/**
|
|
63
81
|
* Enforces the semantic boundary for durable tool-ledger facts.
|
|
64
82
|
*
|
|
@@ -113,95 +131,153 @@ export function validateGenericToolLedgerAppend(event) {
|
|
|
113
131
|
* before committing its candidate events.
|
|
114
132
|
*/
|
|
115
133
|
export function validateToolLedgerTransition(input) {
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
if (!nodeUtil.isDeepStrictEqual(prior, candidate)) {
|
|
128
|
-
return { ok: false, code: 'duplicate_event_id', eventId: candidate.id };
|
|
129
|
-
}
|
|
134
|
+
const reducer = new ToolLedgerReducer(input.existingEvents);
|
|
135
|
+
const validation = validateIncrementalToolLedgerTransition({
|
|
136
|
+
reducer,
|
|
137
|
+
candidateEvents: input.candidateEvents,
|
|
138
|
+
expectedTransition: input.expectedTransition,
|
|
139
|
+
});
|
|
140
|
+
if (validation.ok) {
|
|
141
|
+
reducer.commit(validation.checkpoint);
|
|
142
|
+
return { ok: true };
|
|
130
143
|
}
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
return shape;
|
|
134
|
-
const prospective = scanToolLedger([...input.existingEvents, ...candidates]);
|
|
135
|
-
if (prospective.hasCorruption)
|
|
136
|
-
return issueValidation(prospective.issues[0]);
|
|
137
|
-
return { ok: true };
|
|
144
|
+
const { source: _source, ...failure } = validation;
|
|
145
|
+
return failure;
|
|
138
146
|
}
|
|
139
147
|
/**
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
148
|
+
* Stateful interpretation of an immutable RuntimeEvent prefix.
|
|
149
|
+
*
|
|
150
|
+
* Candidate appends mutate the reducer behind a checkpoint. The caller either
|
|
151
|
+
* commits that checkpoint after durable transaction commit or rolls it back.
|
|
152
|
+
* Rollback records only the fields touched by the candidate batch, so a small
|
|
153
|
+
* append does not clone maps proportional to the full checked prefix.
|
|
143
154
|
*/
|
|
144
|
-
export
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
155
|
+
export class ToolLedgerReducer {
|
|
156
|
+
operations = [];
|
|
157
|
+
issues = [];
|
|
158
|
+
eventsById = new Map();
|
|
159
|
+
byToolCall = new Map();
|
|
160
|
+
byOperation = new Map();
|
|
161
|
+
invocationSpines = new Map();
|
|
162
|
+
undoLog = [];
|
|
163
|
+
recordUndo = false;
|
|
164
|
+
constructor(events = []) {
|
|
165
|
+
this.consume(events, false);
|
|
166
|
+
}
|
|
167
|
+
scan() {
|
|
168
|
+
const dependencyIssues = this.toolDependencyIssues();
|
|
169
|
+
if (dependencyIssues.length === 0) {
|
|
170
|
+
return {
|
|
171
|
+
operations: this.operations,
|
|
172
|
+
issues: this.issues,
|
|
173
|
+
hasCorruption: this.issues.length > 0,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const issuesByOperation = new Map();
|
|
177
|
+
for (const { operation, issue } of dependencyIssues) {
|
|
178
|
+
const issues = issuesByOperation.get(operation);
|
|
179
|
+
if (issues)
|
|
180
|
+
issues.push(issue);
|
|
181
|
+
else
|
|
182
|
+
issuesByOperation.set(operation, [issue]);
|
|
159
183
|
}
|
|
160
|
-
|
|
184
|
+
return {
|
|
185
|
+
operations: this.operations.map((operation) => {
|
|
186
|
+
const dependency = issuesByOperation.get(operation);
|
|
187
|
+
return dependency
|
|
188
|
+
? { ...operation, issues: [...operation.issues, ...dependency] }
|
|
189
|
+
: operation;
|
|
190
|
+
}),
|
|
191
|
+
issues: [...this.issues, ...dependencyIssues.map(({ issue }) => issue)],
|
|
192
|
+
hasCorruption: true,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
event(eventId) {
|
|
196
|
+
return this.eventsById.get(eventId);
|
|
197
|
+
}
|
|
198
|
+
checkpoint() {
|
|
199
|
+
return this.undoLog.length;
|
|
200
|
+
}
|
|
201
|
+
append(events) {
|
|
202
|
+
this.consume(events, true);
|
|
203
|
+
}
|
|
204
|
+
rollback(checkpoint) {
|
|
205
|
+
this.assertCheckpoint(checkpoint);
|
|
206
|
+
for (let index = this.undoLog.length - 1; index >= checkpoint; index -= 1) {
|
|
207
|
+
this.undoLog[index]();
|
|
208
|
+
}
|
|
209
|
+
this.undoLog.length = checkpoint;
|
|
210
|
+
}
|
|
211
|
+
commit(checkpoint) {
|
|
212
|
+
this.assertCheckpoint(checkpoint);
|
|
213
|
+
this.undoLog.length = checkpoint;
|
|
214
|
+
}
|
|
215
|
+
assertCheckpoint(checkpoint) {
|
|
216
|
+
if (!Number.isSafeInteger(checkpoint) || checkpoint < 0 || checkpoint > this.undoLog.length) {
|
|
217
|
+
throw new RangeError('Invalid tool ledger reducer checkpoint');
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
consume(events, recordUndo) {
|
|
221
|
+
const previous = this.recordUndo;
|
|
222
|
+
this.recordUndo = recordUndo;
|
|
223
|
+
try {
|
|
224
|
+
for (const event of events)
|
|
225
|
+
this.consumeEvent(event);
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
this.recordUndo = previous;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
consumeEvent(event) {
|
|
232
|
+
if (this.eventsById.has(event.id)) {
|
|
233
|
+
this.addIssue(undefined, { code: 'duplicate_event_id', eventId: event.id });
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
this.setMap(this.eventsById, event.id, event);
|
|
161
237
|
const spine = JSON.stringify([event.sessionId, event.runId, event.turnId]);
|
|
162
|
-
const existingSpine = invocationSpines.get(event.invocationId);
|
|
238
|
+
const existingSpine = this.invocationSpines.get(event.invocationId);
|
|
163
239
|
if (existingSpine !== undefined && existingSpine !== spine) {
|
|
164
|
-
addIssue(undefined, {
|
|
240
|
+
this.addIssue(undefined, {
|
|
165
241
|
code: 'invocation_identity_conflict',
|
|
166
242
|
eventId: event.id,
|
|
167
243
|
});
|
|
168
244
|
}
|
|
169
245
|
else {
|
|
170
|
-
|
|
246
|
+
this.setMap(this.invocationSpines, event.invocationId, spine);
|
|
171
247
|
}
|
|
172
248
|
const lane = validateToolLedgerEventLane(event);
|
|
173
249
|
if (!lane.ok) {
|
|
174
|
-
addIssue(undefined, { code: lane.code, eventId: lane.eventId });
|
|
175
|
-
|
|
250
|
+
this.addIssue(undefined, { code: lane.code, eventId: lane.eventId });
|
|
251
|
+
return;
|
|
176
252
|
}
|
|
177
253
|
if (event.partial)
|
|
178
|
-
|
|
254
|
+
return;
|
|
179
255
|
if (lane.lane === 'function_call') {
|
|
180
256
|
const content = event.content;
|
|
181
257
|
if (content?.kind !== 'function_call')
|
|
182
|
-
|
|
258
|
+
return;
|
|
183
259
|
const toolCallKey = toolCallIdentity(event.invocationId, content.id);
|
|
184
|
-
const existing = byToolCall.get(toolCallKey);
|
|
260
|
+
const existing = this.byToolCall.get(toolCallKey);
|
|
185
261
|
if (existing) {
|
|
186
262
|
if (!existing.callEvent) {
|
|
187
|
-
existing
|
|
263
|
+
this.setOperationField(existing, 'callEvent', event);
|
|
188
264
|
if (existing.toolName !== content.name) {
|
|
189
|
-
addIssue(existing, {
|
|
265
|
+
this.addIssue(existing, {
|
|
190
266
|
code: 'identity_conflict',
|
|
191
267
|
eventId: event.id,
|
|
192
268
|
toolCallId: content.id,
|
|
193
269
|
...(existing.operationId ? { operationId: existing.operationId } : {}),
|
|
194
270
|
});
|
|
195
271
|
}
|
|
196
|
-
|
|
272
|
+
return;
|
|
197
273
|
}
|
|
198
|
-
addIssue(existing, {
|
|
274
|
+
this.addIssue(existing, {
|
|
199
275
|
code: 'duplicate_call',
|
|
200
276
|
eventId: event.id,
|
|
201
277
|
toolCallId: content.id,
|
|
202
278
|
...(existing.operationId ? { operationId: existing.operationId } : {}),
|
|
203
279
|
});
|
|
204
|
-
|
|
280
|
+
return;
|
|
205
281
|
}
|
|
206
282
|
const operation = {
|
|
207
283
|
toolCallId: content.id,
|
|
@@ -211,16 +287,16 @@ export function scanToolLedger(events) {
|
|
|
211
287
|
decisionEvents: [],
|
|
212
288
|
issues: [],
|
|
213
289
|
};
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
290
|
+
this.setMap(this.byToolCall, toolCallKey, operation);
|
|
291
|
+
this.push(this.operations, operation);
|
|
292
|
+
return;
|
|
217
293
|
}
|
|
218
294
|
if (lane.lane === 'tool_dispatch') {
|
|
219
295
|
const dispatch = event.actions?.toolDispatch;
|
|
220
296
|
if (!dispatch)
|
|
221
|
-
|
|
297
|
+
return;
|
|
222
298
|
const toolCallKey = toolCallIdentity(event.invocationId, dispatch.providerToolCallId);
|
|
223
|
-
let operation = byToolCall.get(toolCallKey);
|
|
299
|
+
let operation = this.byToolCall.get(toolCallKey);
|
|
224
300
|
if (!operation) {
|
|
225
301
|
operation = {
|
|
226
302
|
toolCallId: dispatch.providerToolCallId,
|
|
@@ -231,9 +307,9 @@ export function scanToolLedger(events) {
|
|
|
231
307
|
decisionEvents: [],
|
|
232
308
|
issues: [],
|
|
233
309
|
};
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
addIssue(operation, {
|
|
310
|
+
this.setMap(this.byToolCall, toolCallKey, operation);
|
|
311
|
+
this.push(this.operations, operation);
|
|
312
|
+
this.addIssue(operation, {
|
|
237
313
|
code: 'event_order_conflict',
|
|
238
314
|
eventId: event.id,
|
|
239
315
|
operationId: dispatch.operationId,
|
|
@@ -241,15 +317,15 @@ export function scanToolLedger(events) {
|
|
|
241
317
|
});
|
|
242
318
|
}
|
|
243
319
|
else if (operation.dispatchEvent) {
|
|
244
|
-
addIssue(operation, {
|
|
320
|
+
this.addIssue(operation, {
|
|
245
321
|
code: 'duplicate_dispatch',
|
|
246
322
|
eventId: event.id,
|
|
247
323
|
operationId: dispatch.operationId,
|
|
248
324
|
toolCallId: dispatch.providerToolCallId,
|
|
249
325
|
});
|
|
250
|
-
|
|
326
|
+
return;
|
|
251
327
|
}
|
|
252
|
-
const existingOperation = byOperation.get(dispatch.operationId);
|
|
328
|
+
const existingOperation = this.byOperation.get(dispatch.operationId);
|
|
253
329
|
if (existingOperation && existingOperation !== operation) {
|
|
254
330
|
const issue = {
|
|
255
331
|
code: 'duplicate_operation',
|
|
@@ -257,19 +333,20 @@ export function scanToolLedger(events) {
|
|
|
257
333
|
operationId: dispatch.operationId,
|
|
258
334
|
toolCallId: dispatch.providerToolCallId,
|
|
259
335
|
};
|
|
260
|
-
|
|
261
|
-
existingOperation.issues
|
|
262
|
-
operation.issues
|
|
263
|
-
|
|
336
|
+
this.push(this.issues, issue);
|
|
337
|
+
this.push(existingOperation.issues, issue);
|
|
338
|
+
this.push(operation.issues, issue);
|
|
339
|
+
return;
|
|
264
340
|
}
|
|
265
|
-
operation
|
|
266
|
-
operation
|
|
267
|
-
|
|
341
|
+
this.setOperationField(operation, 'operationId', dispatch.operationId);
|
|
342
|
+
this.setOperationField(operation, 'dispatchEvent', event);
|
|
343
|
+
this.setMap(this.byOperation, dispatch.operationId, operation);
|
|
268
344
|
if (operation.toolName !== dispatch.toolName ||
|
|
269
345
|
event.refs?.operationId !== dispatch.operationId ||
|
|
270
346
|
event.refs?.toolCallId !== dispatch.providerToolCallId ||
|
|
271
|
-
(operation.callEvent !== undefined && !sameExecutionIdentity(operation.callEvent, event))
|
|
272
|
-
|
|
347
|
+
(operation.callEvent !== undefined && !sameExecutionIdentity(operation.callEvent, event)) ||
|
|
348
|
+
callRefsConflict(operation.callEvent, event)) {
|
|
349
|
+
this.addIssue(operation, {
|
|
273
350
|
code: 'identity_conflict',
|
|
274
351
|
eventId: event.id,
|
|
275
352
|
operationId: dispatch.operationId,
|
|
@@ -286,7 +363,7 @@ export function scanToolLedger(events) {
|
|
|
286
363
|
// A provider call that is not strict JSON cannot authenticate T1.
|
|
287
364
|
}
|
|
288
365
|
if (canonicalArgsHash !== dispatch.canonicalArgsHash) {
|
|
289
|
-
addIssue(operation, {
|
|
366
|
+
this.addIssue(operation, {
|
|
290
367
|
code: 'canonical_args_hash_conflict',
|
|
291
368
|
eventId: event.id,
|
|
292
369
|
operationId: dispatch.operationId,
|
|
@@ -295,7 +372,7 @@ export function scanToolLedger(events) {
|
|
|
295
372
|
}
|
|
296
373
|
}
|
|
297
374
|
if (operation.responseEvent) {
|
|
298
|
-
addIssue(operation, {
|
|
375
|
+
this.addIssue(operation, {
|
|
299
376
|
code: 'event_order_conflict',
|
|
300
377
|
eventId: event.id,
|
|
301
378
|
operationId: dispatch.operationId,
|
|
@@ -304,7 +381,7 @@ export function scanToolLedger(events) {
|
|
|
304
381
|
if (operation.responseEvent.refs?.operationId !== dispatch.operationId ||
|
|
305
382
|
operation.responseEvent.refs?.toolCallId !== dispatch.providerToolCallId ||
|
|
306
383
|
!sameExecutionIdentity(event, operation.responseEvent)) {
|
|
307
|
-
addIssue(operation, {
|
|
384
|
+
this.addIssue(operation, {
|
|
308
385
|
code: 'identity_conflict',
|
|
309
386
|
eventId: operation.responseEvent.id,
|
|
310
387
|
operationId: dispatch.operationId,
|
|
@@ -312,14 +389,14 @@ export function scanToolLedger(events) {
|
|
|
312
389
|
});
|
|
313
390
|
}
|
|
314
391
|
}
|
|
315
|
-
|
|
392
|
+
return;
|
|
316
393
|
}
|
|
317
394
|
if (lane.lane === 'function_response') {
|
|
318
395
|
const content = event.content;
|
|
319
396
|
if (content?.kind !== 'function_response')
|
|
320
|
-
|
|
397
|
+
return;
|
|
321
398
|
const toolCallKey = toolCallIdentity(event.invocationId, content.id);
|
|
322
|
-
const operation = byToolCall.get(toolCallKey);
|
|
399
|
+
const operation = this.byToolCall.get(toolCallKey);
|
|
323
400
|
if (!operation) {
|
|
324
401
|
const orphan = {
|
|
325
402
|
toolCallId: content.id,
|
|
@@ -329,60 +406,229 @@ export function scanToolLedger(events) {
|
|
|
329
406
|
decisionEvents: [],
|
|
330
407
|
issues: [],
|
|
331
408
|
};
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
addIssue(orphan, {
|
|
409
|
+
this.push(this.operations, orphan);
|
|
410
|
+
this.setMap(this.byToolCall, toolCallKey, orphan);
|
|
411
|
+
this.addIssue(orphan, {
|
|
335
412
|
code: 'orphan_response',
|
|
336
413
|
eventId: event.id,
|
|
337
414
|
toolCallId: content.id,
|
|
338
415
|
});
|
|
339
|
-
|
|
416
|
+
return;
|
|
340
417
|
}
|
|
341
418
|
if (operation.responseEvent) {
|
|
342
|
-
addIssue(operation, {
|
|
419
|
+
this.addIssue(operation, {
|
|
343
420
|
code: 'duplicate_response',
|
|
344
421
|
eventId: event.id,
|
|
345
422
|
toolCallId: content.id,
|
|
346
423
|
...(operation.operationId ? { operationId: operation.operationId } : {}),
|
|
347
424
|
});
|
|
348
|
-
|
|
425
|
+
return;
|
|
349
426
|
}
|
|
350
|
-
operation
|
|
427
|
+
this.setOperationField(operation, 'responseEvent', event);
|
|
351
428
|
if (operation.toolName !== content.name ||
|
|
352
429
|
!sameExecutionIdentity(operation.callEvent, event) ||
|
|
353
430
|
(operation.operationId !== undefined &&
|
|
354
431
|
(event.refs?.operationId !== operation.operationId ||
|
|
355
432
|
event.refs.toolCallId !== operation.toolCallId))) {
|
|
356
|
-
addIssue(operation, {
|
|
433
|
+
this.addIssue(operation, {
|
|
357
434
|
code: 'identity_conflict',
|
|
358
435
|
eventId: event.id,
|
|
359
436
|
toolCallId: content.id,
|
|
360
437
|
...(operation.operationId ? { operationId: operation.operationId } : {}),
|
|
361
438
|
});
|
|
362
439
|
}
|
|
363
|
-
|
|
440
|
+
return;
|
|
364
441
|
}
|
|
365
442
|
if (lane.lane === 'reconcile_result' || lane.lane === 'recovery_decision') {
|
|
366
443
|
const fact = event.actions?.toolRecovery;
|
|
367
444
|
if (!fact)
|
|
368
|
-
|
|
369
|
-
const operation = byOperation.get(fact.payload.operationId);
|
|
445
|
+
return;
|
|
446
|
+
const operation = this.byOperation.get(fact.payload.operationId);
|
|
370
447
|
if (!operation) {
|
|
371
|
-
addIssue(undefined, {
|
|
448
|
+
this.addIssue(undefined, {
|
|
372
449
|
code: 'event_order_conflict',
|
|
373
450
|
eventId: event.id,
|
|
374
451
|
operationId: fact.payload.operationId,
|
|
375
452
|
...(event.refs?.toolCallId ? { toolCallId: event.refs.toolCallId } : {}),
|
|
376
453
|
});
|
|
377
|
-
|
|
454
|
+
return;
|
|
378
455
|
}
|
|
379
456
|
if (lane.lane === 'reconcile_result')
|
|
380
|
-
operation.reconcileEvents
|
|
457
|
+
this.push(operation.reconcileEvents, event);
|
|
381
458
|
else
|
|
382
|
-
operation.decisionEvents
|
|
459
|
+
this.push(operation.decisionEvents, event);
|
|
383
460
|
}
|
|
384
461
|
}
|
|
385
|
-
|
|
462
|
+
addIssue(operation, issue) {
|
|
463
|
+
this.push(this.issues, issue);
|
|
464
|
+
if (operation)
|
|
465
|
+
this.push(operation.issues, issue);
|
|
466
|
+
}
|
|
467
|
+
push(values, value) {
|
|
468
|
+
const length = values.length;
|
|
469
|
+
this.undo(() => {
|
|
470
|
+
values.length = length;
|
|
471
|
+
});
|
|
472
|
+
values.push(value);
|
|
473
|
+
}
|
|
474
|
+
setMap(values, key, value) {
|
|
475
|
+
const had = values.has(key);
|
|
476
|
+
const previous = values.get(key);
|
|
477
|
+
this.undo(() => {
|
|
478
|
+
if (had)
|
|
479
|
+
values.set(key, previous);
|
|
480
|
+
else
|
|
481
|
+
values.delete(key);
|
|
482
|
+
});
|
|
483
|
+
values.set(key, value);
|
|
484
|
+
}
|
|
485
|
+
setOperationField(operation, key, value) {
|
|
486
|
+
const had = Object.hasOwn(operation, key);
|
|
487
|
+
const previous = operation[key];
|
|
488
|
+
this.undo(() => {
|
|
489
|
+
if (had)
|
|
490
|
+
operation[key] = previous;
|
|
491
|
+
else
|
|
492
|
+
delete operation[key];
|
|
493
|
+
});
|
|
494
|
+
operation[key] = value;
|
|
495
|
+
}
|
|
496
|
+
undo(operation) {
|
|
497
|
+
if (this.recordUndo)
|
|
498
|
+
this.undoLog.push(operation);
|
|
499
|
+
}
|
|
500
|
+
toolDependencyIssues() {
|
|
501
|
+
const result = [];
|
|
502
|
+
const parents = new Map();
|
|
503
|
+
for (const operation of this.operations) {
|
|
504
|
+
const dispatch = operation.dispatchEvent;
|
|
505
|
+
const parentOperationId = dispatch?.refs?.parentOperationId;
|
|
506
|
+
const parentToolCallId = dispatch?.refs?.parentToolCallId;
|
|
507
|
+
if (!dispatch || !parentOperationId || !parentToolCallId)
|
|
508
|
+
continue;
|
|
509
|
+
const parent = this.byOperation.get(parentOperationId);
|
|
510
|
+
if (!parent) {
|
|
511
|
+
result.push({
|
|
512
|
+
operation,
|
|
513
|
+
issue: {
|
|
514
|
+
code: 'parent_operation_missing',
|
|
515
|
+
eventId: dispatch.id,
|
|
516
|
+
...(operation.operationId ? { operationId: operation.operationId } : {}),
|
|
517
|
+
toolCallId: operation.toolCallId,
|
|
518
|
+
},
|
|
519
|
+
});
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
if (parent.toolCallId !== parentToolCallId) {
|
|
523
|
+
result.push({
|
|
524
|
+
operation,
|
|
525
|
+
issue: {
|
|
526
|
+
code: 'parent_identity_conflict',
|
|
527
|
+
eventId: dispatch.id,
|
|
528
|
+
...(operation.operationId ? { operationId: operation.operationId } : {}),
|
|
529
|
+
toolCallId: operation.toolCallId,
|
|
530
|
+
},
|
|
531
|
+
});
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
534
|
+
parents.set(operation, parent);
|
|
535
|
+
}
|
|
536
|
+
const state = new Map();
|
|
537
|
+
const stack = [];
|
|
538
|
+
const stackIndex = new Map();
|
|
539
|
+
const cyclic = new Set();
|
|
540
|
+
const visit = (operation) => {
|
|
541
|
+
if (state.get(operation) === 'visited')
|
|
542
|
+
return;
|
|
543
|
+
state.set(operation, 'visiting');
|
|
544
|
+
stackIndex.set(operation, stack.length);
|
|
545
|
+
stack.push(operation);
|
|
546
|
+
const parent = parents.get(operation);
|
|
547
|
+
if (parent) {
|
|
548
|
+
const parentState = state.get(parent);
|
|
549
|
+
if (parentState === 'visiting') {
|
|
550
|
+
const index = stackIndex.get(parent);
|
|
551
|
+
if (index !== undefined) {
|
|
552
|
+
for (let cursor = index; cursor < stack.length; cursor += 1)
|
|
553
|
+
cyclic.add(stack[cursor]);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
else if (parentState !== 'visited') {
|
|
557
|
+
visit(parent);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
stack.pop();
|
|
561
|
+
stackIndex.delete(operation);
|
|
562
|
+
state.set(operation, 'visited');
|
|
563
|
+
};
|
|
564
|
+
for (const operation of parents.keys())
|
|
565
|
+
visit(operation);
|
|
566
|
+
for (const operation of this.operations) {
|
|
567
|
+
if (!cyclic.has(operation) || !operation.dispatchEvent)
|
|
568
|
+
continue;
|
|
569
|
+
result.push({
|
|
570
|
+
operation,
|
|
571
|
+
issue: {
|
|
572
|
+
code: 'parent_dependency_cycle',
|
|
573
|
+
eventId: operation.dispatchEvent.id,
|
|
574
|
+
...(operation.operationId ? { operationId: operation.operationId } : {}),
|
|
575
|
+
toolCallId: operation.toolCallId,
|
|
576
|
+
},
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
return result;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Applies one prospective writer batch to a checked prefix. A successful call
|
|
584
|
+
* leaves the candidate delta applied until the caller commits or rolls back the
|
|
585
|
+
* returned checkpoint. A rejected candidate restores the reducer immediately.
|
|
586
|
+
*/
|
|
587
|
+
export function validateIncrementalToolLedgerTransition(input) {
|
|
588
|
+
const existing = input.reducer.scan();
|
|
589
|
+
if (existing.hasCorruption) {
|
|
590
|
+
return { source: 'existing', ...issueValidation(existing.issues[0]) };
|
|
591
|
+
}
|
|
592
|
+
const candidates = [];
|
|
593
|
+
for (const candidate of input.candidateEvents) {
|
|
594
|
+
const prior = input.reducer.event(candidate.id);
|
|
595
|
+
if (!prior) {
|
|
596
|
+
candidates.push(candidate);
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
599
|
+
if (!nodeUtil.isDeepStrictEqual(prior, candidate)) {
|
|
600
|
+
return {
|
|
601
|
+
ok: false,
|
|
602
|
+
source: 'candidate',
|
|
603
|
+
code: 'duplicate_event_id',
|
|
604
|
+
eventId: candidate.id,
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
const shape = validateTransitionShape(candidates, input.expectedTransition);
|
|
609
|
+
if (!shape.ok)
|
|
610
|
+
return { source: 'candidate', ...shape };
|
|
611
|
+
const checkpoint = input.reducer.checkpoint();
|
|
612
|
+
try {
|
|
613
|
+
input.reducer.append(candidates);
|
|
614
|
+
}
|
|
615
|
+
catch (error) {
|
|
616
|
+
input.reducer.rollback(checkpoint);
|
|
617
|
+
throw error;
|
|
618
|
+
}
|
|
619
|
+
const issue = input.reducer.scan().issues[0];
|
|
620
|
+
if (issue) {
|
|
621
|
+
input.reducer.rollback(checkpoint);
|
|
622
|
+
return { source: 'candidate', ...issueValidation(issue) };
|
|
623
|
+
}
|
|
624
|
+
return { ok: true, checkpoint, appendedEvents: candidates.length };
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Scans immutable RuntimeEvents once, in physical ledger order. Resolver,
|
|
628
|
+
* projection rebuild and incremental writers all use the same reducer rules.
|
|
629
|
+
*/
|
|
630
|
+
export function scanToolLedger(events) {
|
|
631
|
+
return new ToolLedgerReducer(events).scan();
|
|
386
632
|
}
|
|
387
633
|
function matchesLaneEnvelope(event, lane) {
|
|
388
634
|
if (event.partial || event.status !== undefined || event.branch !== undefined)
|
|
@@ -472,6 +718,21 @@ function sameExecutionIdentity(first, second) {
|
|
|
472
718
|
first.runId === second.runId &&
|
|
473
719
|
first.turnId === second.turnId);
|
|
474
720
|
}
|
|
721
|
+
function callRefsConflict(call, dispatch) {
|
|
722
|
+
if (!call?.refs)
|
|
723
|
+
return false;
|
|
724
|
+
const expected = dispatch.actions?.toolDispatch;
|
|
725
|
+
if (!expected)
|
|
726
|
+
return false;
|
|
727
|
+
if ((call.refs.operationId !== undefined && call.refs.operationId !== expected.operationId) ||
|
|
728
|
+
(call.refs.toolCallId !== undefined && call.refs.toolCallId !== expected.providerToolCallId)) {
|
|
729
|
+
return true;
|
|
730
|
+
}
|
|
731
|
+
const callHasParent = call.refs.parentOperationId !== undefined || call.refs.parentToolCallId !== undefined;
|
|
732
|
+
return (callHasParent &&
|
|
733
|
+
(call.refs.parentOperationId !== dispatch.refs?.parentOperationId ||
|
|
734
|
+
call.refs.parentToolCallId !== dispatch.refs?.parentToolCallId));
|
|
735
|
+
}
|
|
475
736
|
function hasOnlyKeys(value, expected) {
|
|
476
737
|
if (!value)
|
|
477
738
|
return false;
|
|
@@ -25,6 +25,20 @@ const AGENT_GRAPH_ORIGIN_SHAPE = defineObjectShape()(['kind', 'graphId', 'wakeId
|
|
|
25
25
|
export function decodeTurnOrigin(value) {
|
|
26
26
|
if (!isRecord(value))
|
|
27
27
|
return undefined;
|
|
28
|
+
if (value.kind === 'workhub_result') {
|
|
29
|
+
const keys = ['kind', 'eventId', 'actionId', 'delegationId', 'targetSessionId', 'targetTurnId'];
|
|
30
|
+
if (Object.keys(value).length !== keys.length ||
|
|
31
|
+
!keys.every((key) => typeof value[key] === 'string' && value[key].length > 0 && value[key].length <= 256))
|
|
32
|
+
return undefined;
|
|
33
|
+
return {
|
|
34
|
+
kind: 'workhub_result',
|
|
35
|
+
eventId: value.eventId,
|
|
36
|
+
actionId: value.actionId,
|
|
37
|
+
delegationId: value.delegationId,
|
|
38
|
+
targetSessionId: value.targetSessionId,
|
|
39
|
+
targetTurnId: value.targetTurnId,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
28
42
|
if (hasExactShape(value, SCHEDULED_TASK_ORIGIN_SHAPE) &&
|
|
29
43
|
value.kind === 'scheduled_task' &&
|
|
30
44
|
typeof value.scheduledTaskId === 'string') {
|