maka-agent 0.2.0-dev.31.20260913 → 0.2.0-dev.32.20260914
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/dist/pi-transcript.js +3 -4
- package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
- package/node_modules/@maka/core/dist/agent-graph-schedule.js +15 -4
- package/node_modules/@maka/core/dist/executor-id.js +22 -0
- package/node_modules/@maka/core/dist/external-session.js +18 -0
- package/node_modules/@maka/core/dist/model-call-usage-projection.js +0 -13
- package/node_modules/@maka/core/dist/runtime-event.js +19 -3
- package/node_modules/@maka/core/dist/session-send-projection.js +6 -3
- package/node_modules/@maka/core/dist/session.js +8 -2
- package/node_modules/@maka/core/dist/shell-run-result.js +1 -0
- package/node_modules/@maka/core/dist/shell-run.js +4 -0
- package/node_modules/@maka/core/dist/work-board.js +94 -1
- package/node_modules/@maka/core/package.json +1 -0
- package/node_modules/@maka/eval/dist/fleet-simulation.js +270 -0
- package/node_modules/@maka/eval/dist/fleet-store.js +243 -0
- package/node_modules/@maka/eval/dist/fleet-worker.js +125 -0
- package/node_modules/@maka/eval/dist/fleet.js +329 -0
- package/node_modules/@maka/eval/dist/index.js +3 -0
- package/node_modules/@maka/runtime/dist/agent-run.js +2 -17
- package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +6 -2
- package/node_modules/@maka/runtime/dist/ai-sdk-message-projection.js +36 -24
- package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +257 -330
- package/node_modules/@maka/runtime/dist/background-task-health-tool.js +104 -0
- package/node_modules/@maka/runtime/dist/history-compaction.js +3 -1
- package/node_modules/@maka/runtime/dist/local-web-fetch.js +1 -1
- package/node_modules/@maka/runtime/dist/model-adapter.js +62 -53
- package/node_modules/@maka/runtime/dist/model-history.js +1 -5
- package/node_modules/@maka/runtime/dist/plugin-executor-backend.js +311 -0
- package/node_modules/@maka/runtime/dist/plugin-executor-service.js +344 -0
- package/node_modules/@maka/runtime/dist/provider-error-classification.js +7 -1
- package/node_modules/@maka/runtime/dist/provider-request-telemetry.js +35 -8
- package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +7 -1
- package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +1 -0
- package/node_modules/@maka/runtime/dist/runtime-invocation-route.js +49 -0
- package/node_modules/@maka/runtime/dist/runtime-kernel.js +72 -150
- package/node_modules/@maka/runtime/dist/runtime-read-model.js +0 -2
- package/node_modules/@maka/runtime/dist/session-event-runtime-mapper.js +3 -0
- package/node_modules/@maka/runtime/dist/session-manager.js +100 -58
- package/node_modules/@maka/runtime/dist/shell-run-manager.js +9 -3
- package/node_modules/@maka/runtime/dist/shell-run-tool-result.js +1 -0
- package/node_modules/@maka/runtime/dist/stream-graph-schedule-reconcile.js +1 -0
- package/node_modules/@maka/runtime/dist/stream-graph-supervisor-tools.js +26 -4
- package/node_modules/@maka/runtime/dist/subagent-tools.js +7 -0
- package/node_modules/@maka/runtime/dist/tool-runtime.js +45 -466
- package/node_modules/@maka/runtime/package.json +3 -0
- package/node_modules/@maka/runtime-host/dist/adapter/session-projector.js +7 -2
- package/node_modules/@maka/runtime-host/dist/client/session-catalog-summary.js +1 -0
- package/node_modules/@maka/runtime-host/dist/protocol/external-session.js +24 -3
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +4 -1
- package/node_modules/@maka/runtime-host/dist/protocol/plugin-platform.js +42 -5
- package/node_modules/@maka/runtime-host/dist/protocol/session-catalog.js +31 -3
- package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +6 -0
- package/node_modules/@maka/runtime-host/dist/server/child-agent-composition.js +1 -0
- package/node_modules/@maka/runtime-host/dist/server/execution-artifacts.js +1 -22
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +54 -8
- package/node_modules/@maka/runtime-host/dist/server/external-session-coordinator.js +14 -1
- package/node_modules/@maka/runtime-host/dist/server/host-session-availability.js +10 -2
- package/node_modules/@maka/runtime-host/dist/server/plugin-platform-coordinator.js +6 -0
- package/node_modules/@maka/runtime-host/dist/server/plugin-platform.js +6 -0
- package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +56 -16
- package/node_modules/@maka/runtime-host/dist/server/session-continuity-coordinator.js +4 -3
- package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +4 -0
- package/node_modules/@maka/runtime-host/dist/server/web-fetch-tool.js +37 -1
- package/node_modules/@maka/storage/dist/claude-code-session-adapter.js +450 -234
- package/node_modules/@maka/storage/dist/claude-code-transcript-lineage.js +106 -77
- package/node_modules/@maka/storage/dist/legacy-run-header.js +2 -2
- package/node_modules/@maka/storage/dist/model-call-usage-sql.js +1 -1
- package/node_modules/@maka/storage/dist/session-store.js +12 -2
- package/node_modules/@maka/storage/dist/sqlite-long-term-memory-store.js +86 -12
- package/node_modules/@maka/storage/dist/work-board-store.js +40 -1
- package/package.json +1 -1
|
@@ -0,0 +1,329 @@
|
|
|
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 { stableJsonStringify } from '@maka/core/canonical-json';
|
|
20
|
+
import { expandExperiment } from './experiment.js';
|
|
21
|
+
import { decodeEvalResult } from './result.js';
|
|
22
|
+
import { parseExperimentSpec } from './spec.js';
|
|
23
|
+
export function createFleetState(spec, policy) {
|
|
24
|
+
const frozenSpec = parseExperimentSpec(spec);
|
|
25
|
+
for (const key of ['runId', 'environmentId'])
|
|
26
|
+
nonempty(policy[key], key);
|
|
27
|
+
for (const key of [
|
|
28
|
+
'groupCpus',
|
|
29
|
+
'groupMemoryMb',
|
|
30
|
+
'leaseMs',
|
|
31
|
+
'recoveryGraceMs',
|
|
32
|
+
'maxAttemptsPerCell',
|
|
33
|
+
])
|
|
34
|
+
positive(policy[key], key);
|
|
35
|
+
if (!Number.isSafeInteger(policy.retryBackoffMs) || policy.retryBackoffMs < 0) {
|
|
36
|
+
throw new Error('invalid retryBackoffMs');
|
|
37
|
+
}
|
|
38
|
+
const groups = new Map();
|
|
39
|
+
const ids = new Set();
|
|
40
|
+
for (const cell of expandExperiment(frozenSpec)) {
|
|
41
|
+
if (ids.has(cell.id))
|
|
42
|
+
throw new Error('ambiguous experiment cell identity');
|
|
43
|
+
ids.add(cell.id);
|
|
44
|
+
const id = JSON.stringify([cell.task.id, cell.repetition]);
|
|
45
|
+
const group = groups.get(id) ?? [];
|
|
46
|
+
group.push(cell.id);
|
|
47
|
+
groups.set(id, group);
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
version: 'maka.eval.fleet.v1',
|
|
51
|
+
spec: frozenSpec,
|
|
52
|
+
policy: structuredClone(policy),
|
|
53
|
+
clock: 0,
|
|
54
|
+
nextAssignment: 1,
|
|
55
|
+
workers: [],
|
|
56
|
+
assignments: [],
|
|
57
|
+
attempts: [],
|
|
58
|
+
blocked: [],
|
|
59
|
+
paused: false,
|
|
60
|
+
groups: [...groups].map(([id, cellIds]) => ({ id, cellIds, generation: 0, readyAt: 0 })),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** Pure deterministic transition. Persist the returned state before delivering its reply. */
|
|
64
|
+
export function transitionFleet(previous, command, now) {
|
|
65
|
+
if (!Number.isSafeInteger(now) || now < 0)
|
|
66
|
+
throw new Error('invalid fleet clock');
|
|
67
|
+
const state = structuredClone(previous);
|
|
68
|
+
state.clock = Math.max(state.clock, now);
|
|
69
|
+
if (command.kind === 'pause') {
|
|
70
|
+
state.paused = true;
|
|
71
|
+
return { state, reply: {} };
|
|
72
|
+
}
|
|
73
|
+
// Recovery must run BEFORE expiry: a coordinator outage is not evidence of VM loss.
|
|
74
|
+
if (command.kind === 'recover') {
|
|
75
|
+
state.paused = false;
|
|
76
|
+
for (const worker of state.workers)
|
|
77
|
+
worker.reconciled = false;
|
|
78
|
+
for (const assignment of active(state)) {
|
|
79
|
+
assignment.expiresAt = Math.max(assignment.expiresAt, state.clock + state.policy.recoveryGraceMs);
|
|
80
|
+
}
|
|
81
|
+
return { state, reply: {} };
|
|
82
|
+
}
|
|
83
|
+
for (const assignment of active(state)) {
|
|
84
|
+
if (!state.paused && assignment.expiresAt <= state.clock)
|
|
85
|
+
settle(state, assignment, 'expired');
|
|
86
|
+
}
|
|
87
|
+
const reply = {};
|
|
88
|
+
switch (command.kind) {
|
|
89
|
+
case 'register': {
|
|
90
|
+
const description = command.worker;
|
|
91
|
+
nonempty(description.id, 'worker id');
|
|
92
|
+
positive(description.groupSlots, 'groupSlots');
|
|
93
|
+
positive(description.cpus, 'cpus');
|
|
94
|
+
positive(description.memoryMb, 'memoryMb');
|
|
95
|
+
if (description.environmentId !== state.policy.environmentId ||
|
|
96
|
+
description.cpus < description.groupSlots * state.policy.groupCpus ||
|
|
97
|
+
description.memoryMb < description.groupSlots * state.policy.groupMemoryMb) {
|
|
98
|
+
throw new Error('worker does not satisfy execution and verifier admission');
|
|
99
|
+
}
|
|
100
|
+
const existing = state.workers.find((w) => w.description.id === description.id);
|
|
101
|
+
if (existing &&
|
|
102
|
+
stableJsonStringify(existing.description) !== stableJsonStringify(description)) {
|
|
103
|
+
throw new Error('worker incarnation changed description');
|
|
104
|
+
}
|
|
105
|
+
if (!existing)
|
|
106
|
+
state.workers.push({ description: structuredClone(description), reconciled: false });
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case 'heartbeat': {
|
|
110
|
+
const worker = requireWorker(state, command.workerId);
|
|
111
|
+
if (new Set(command.assignmentIds).size !== command.assignmentIds.length) {
|
|
112
|
+
throw new Error('duplicate heartbeat assignment');
|
|
113
|
+
}
|
|
114
|
+
for (const id of command.assignmentIds) {
|
|
115
|
+
const assignment = requireAssignment(state, command.workerId, id);
|
|
116
|
+
if (assignment.status === 'active')
|
|
117
|
+
assignment.expiresAt = state.clock + state.policy.leaseMs;
|
|
118
|
+
}
|
|
119
|
+
// Omitted assignments are allowed to expire; they are not silently renewed.
|
|
120
|
+
worker.reconciled = true;
|
|
121
|
+
reply.activeAssignmentIds = active(state)
|
|
122
|
+
.filter((a) => a.workerId === command.workerId)
|
|
123
|
+
.map((a) => a.id);
|
|
124
|
+
// Includes a claim whose reply was lost. The worker can adopt it rather than leak a slot.
|
|
125
|
+
reply.work = active(state)
|
|
126
|
+
.filter((a) => a.workerId === command.workerId)
|
|
127
|
+
.map((a) => workFor(state, a));
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
case 'claim': {
|
|
131
|
+
const worker = requireWorker(state, command.workerId);
|
|
132
|
+
const running = active(state);
|
|
133
|
+
if (state.paused ||
|
|
134
|
+
!worker.reconciled ||
|
|
135
|
+
state.blocked.length ||
|
|
136
|
+
running.length >= state.spec.execution.maxConcurrentTaskGroups ||
|
|
137
|
+
running.filter((a) => a.workerId === command.workerId).length >=
|
|
138
|
+
worker.description.groupSlots)
|
|
139
|
+
break;
|
|
140
|
+
const group = state.groups.find((g) => g.readyAt <= state.clock &&
|
|
141
|
+
!running.some((a) => a.groupId === g.id) &&
|
|
142
|
+
pendingCells(state, g.cellIds).length > 0);
|
|
143
|
+
if (!group)
|
|
144
|
+
break;
|
|
145
|
+
const id = `${state.policy.runId}/assignment-${state.nextAssignment++}`;
|
|
146
|
+
const attempts = pendingCells(state, group.cellIds).map((cellId, index) => ({
|
|
147
|
+
id: `${id}/attempt-${index + 1}`,
|
|
148
|
+
cellId,
|
|
149
|
+
sequence: state.attempts.filter((a) => a.cellId === cellId).length + 1,
|
|
150
|
+
assignmentId: id,
|
|
151
|
+
report: null,
|
|
152
|
+
disposition: 'pending',
|
|
153
|
+
}));
|
|
154
|
+
const assignment = {
|
|
155
|
+
id,
|
|
156
|
+
groupId: group.id,
|
|
157
|
+
workerId: command.workerId,
|
|
158
|
+
generation: ++group.generation,
|
|
159
|
+
attemptIds: attempts.map((a) => a.id),
|
|
160
|
+
status: 'active',
|
|
161
|
+
expiresAt: state.clock + state.policy.leaseMs,
|
|
162
|
+
};
|
|
163
|
+
state.attempts.push(...attempts);
|
|
164
|
+
state.assignments.push(assignment);
|
|
165
|
+
reply.assignment = structuredClone(assignment);
|
|
166
|
+
reply.work = [workFor(state, assignment)];
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
case 'report': {
|
|
170
|
+
const attempt = state.attempts.find((a) => a.id === command.attemptId);
|
|
171
|
+
if (!attempt)
|
|
172
|
+
throw new Error('unknown attempt');
|
|
173
|
+
const assignment = requireAssignment(state, command.workerId, attempt.assignmentId);
|
|
174
|
+
const report = validateFleetReport(command.report);
|
|
175
|
+
if (attempt.report) {
|
|
176
|
+
if (stableJsonStringify(attempt.report) !== stableJsonStringify(report)) {
|
|
177
|
+
throw new Error('conflicting attempt report');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
attempt.report = report;
|
|
182
|
+
attempt.disposition =
|
|
183
|
+
assignment.status !== 'active' ? 'late' : selectable(report) ? 'selected' : 'retryable';
|
|
184
|
+
if (attempt.disposition !== 'late' &&
|
|
185
|
+
report.environmentFailure &&
|
|
186
|
+
!state.blocked.includes(report.environmentFailure))
|
|
187
|
+
state.blocked.push(report.environmentFailure);
|
|
188
|
+
}
|
|
189
|
+
reply.disposition = attempt.disposition;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
case 'finish': {
|
|
193
|
+
const assignment = requireAssignment(state, command.workerId, command.assignmentId);
|
|
194
|
+
if (assignment.status !== 'active')
|
|
195
|
+
break;
|
|
196
|
+
if (assignment.attemptIds.some((id) => !state.attempts.find((a) => a.id === id)?.report)) {
|
|
197
|
+
throw new Error('cannot finish before all cell reports are committed');
|
|
198
|
+
}
|
|
199
|
+
settle(state, assignment, 'finished');
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
case 'repair':
|
|
203
|
+
state.blocked = state.blocked.filter((reason) => reason !== command.reason);
|
|
204
|
+
break;
|
|
205
|
+
case 'tick':
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
return { state, reply };
|
|
209
|
+
}
|
|
210
|
+
export function summarizeFleet(state) {
|
|
211
|
+
const selected = state.attempts.filter((a) => a.disposition === 'selected');
|
|
212
|
+
const cells = state.groups.flatMap((g) => g.cellIds);
|
|
213
|
+
const running = active(state);
|
|
214
|
+
const exhausted = cells.filter((id) => !selected.some((a) => a.cellId === id) &&
|
|
215
|
+
!running.some((a) => a.attemptIds.some((attemptId) => state.attempts.some((attempt) => attempt.id === attemptId && attempt.cellId === id))) &&
|
|
216
|
+
state.attempts.filter((a) => a.cellId === id).length >= state.policy.maxAttemptsPerCell);
|
|
217
|
+
const reported = state.attempts.filter((a) => a.report);
|
|
218
|
+
return {
|
|
219
|
+
runId: state.policy.runId,
|
|
220
|
+
totalCells: cells.length,
|
|
221
|
+
completedCells: selected.length,
|
|
222
|
+
incompleteCells: cells.length - selected.length,
|
|
223
|
+
exhaustedCells: exhausted.length,
|
|
224
|
+
activeGroups: running.length,
|
|
225
|
+
blocked: [...state.blocked],
|
|
226
|
+
paused: state.paused,
|
|
227
|
+
settled: running.length === 0 && cells.length === selected.length + exhausted.length,
|
|
228
|
+
observedCostUsd: reported.reduce((sum, a) => sum + (a.report.result.costUsd ?? 0), 0),
|
|
229
|
+
usageComplete: state.attempts.every((a) => a.report?.usage === 'complete'),
|
|
230
|
+
results: selected.map((a) => ({
|
|
231
|
+
cellId: a.cellId,
|
|
232
|
+
attemptId: a.id,
|
|
233
|
+
result: selectedResult(a.report),
|
|
234
|
+
artifacts: structuredClone(a.report.artifacts),
|
|
235
|
+
})),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
export function validateFleetReport(value) {
|
|
239
|
+
const report = structuredClone(value);
|
|
240
|
+
report.result = decodeEvalResult(value.result);
|
|
241
|
+
member(report.execution, ['completed', 'subject_failed', 'not_started', 'unknown'], 'execution');
|
|
242
|
+
member(report.verification, ['valid', 'invalid', 'not_run'], 'verification');
|
|
243
|
+
member(report.usage, ['complete', 'partial', 'missing'], 'usage');
|
|
244
|
+
member(report.cleanup, ['confirmed', 'unknown'], 'cleanup');
|
|
245
|
+
if (report.environmentFailure !== null)
|
|
246
|
+
nonempty(report.environmentFailure, 'environmentFailure');
|
|
247
|
+
if (!Array.isArray(report.artifacts))
|
|
248
|
+
throw new Error('invalid artifacts');
|
|
249
|
+
for (const artifact of report.artifacts) {
|
|
250
|
+
if (!/^[a-f0-9]{64}$/.test(artifact.sha256) ||
|
|
251
|
+
!Number.isSafeInteger(artifact.bytes) ||
|
|
252
|
+
artifact.bytes < 0) {
|
|
253
|
+
throw new Error('invalid artifact reference');
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (report.usage === 'missing' && report.result.usage !== null)
|
|
257
|
+
throw new Error('missing usage has tokens');
|
|
258
|
+
if (report.usage === 'complete' && report.result.usage === null)
|
|
259
|
+
throw new Error('complete usage lacks tokens');
|
|
260
|
+
if (report.usage !== 'complete' && report.result.costUsd !== null)
|
|
261
|
+
throw new Error('incomplete usage has settled cost');
|
|
262
|
+
if (report.verification === 'valid' &&
|
|
263
|
+
(report.result.score === null || !['completed', 'subject_failed'].includes(report.execution)))
|
|
264
|
+
throw new Error('invalid verification evidence');
|
|
265
|
+
return report;
|
|
266
|
+
}
|
|
267
|
+
function selectedResult(report) {
|
|
268
|
+
// Keep raw execution evidence in the attempt; project settled status only in selected results.
|
|
269
|
+
return {
|
|
270
|
+
...report.result,
|
|
271
|
+
status: report.execution === 'subject_failed' || report.result.status === 'subject_failed'
|
|
272
|
+
? 'subject_failed'
|
|
273
|
+
: 'completed',
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function selectable(report) {
|
|
277
|
+
return (['completed', 'subject_failed'].includes(report.execution) &&
|
|
278
|
+
report.verification === 'valid' &&
|
|
279
|
+
report.cleanup === 'confirmed' &&
|
|
280
|
+
report.environmentFailure === null);
|
|
281
|
+
}
|
|
282
|
+
function active(state) {
|
|
283
|
+
return state.assignments.filter((a) => a.status === 'active');
|
|
284
|
+
}
|
|
285
|
+
function workFor(state, assignment) {
|
|
286
|
+
const cells = expandExperiment(state.spec);
|
|
287
|
+
return {
|
|
288
|
+
assignment: structuredClone(assignment),
|
|
289
|
+
cells: assignment.attemptIds.flatMap((id) => {
|
|
290
|
+
const attempt = state.attempts.find((a) => a.id === id);
|
|
291
|
+
return attempt.report
|
|
292
|
+
? []
|
|
293
|
+
: [{ attemptId: id, cell: cells.find((c) => c.id === attempt.cellId) }];
|
|
294
|
+
}),
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
function pendingCells(state, ids) {
|
|
298
|
+
return ids.filter((id) => !state.attempts.some((a) => a.cellId === id && a.disposition === 'selected') &&
|
|
299
|
+
state.attempts.filter((a) => a.cellId === id).length < state.policy.maxAttemptsPerCell);
|
|
300
|
+
}
|
|
301
|
+
function requireWorker(state, id) {
|
|
302
|
+
const worker = state.workers.find((w) => w.description.id === id);
|
|
303
|
+
if (!worker)
|
|
304
|
+
throw new Error('unknown worker incarnation');
|
|
305
|
+
return worker;
|
|
306
|
+
}
|
|
307
|
+
function requireAssignment(state, workerId, id) {
|
|
308
|
+
const assignment = state.assignments.find((a) => a.id === id);
|
|
309
|
+
if (!assignment || assignment.workerId !== workerId)
|
|
310
|
+
throw new Error('unknown or foreign assignment');
|
|
311
|
+
return assignment;
|
|
312
|
+
}
|
|
313
|
+
function settle(state, assignment, status) {
|
|
314
|
+
assignment.status = status;
|
|
315
|
+
state.groups.find((g) => g.id === assignment.groupId).readyAt =
|
|
316
|
+
state.clock + state.policy.retryBackoffMs;
|
|
317
|
+
}
|
|
318
|
+
function positive(value, name) {
|
|
319
|
+
if (!Number.isSafeInteger(value) || value < 1)
|
|
320
|
+
throw new Error(`invalid ${name}`);
|
|
321
|
+
}
|
|
322
|
+
function nonempty(value, name) {
|
|
323
|
+
if (typeof value !== 'string' || !value.trim())
|
|
324
|
+
throw new Error(`invalid ${name}`);
|
|
325
|
+
}
|
|
326
|
+
function member(value, values, name) {
|
|
327
|
+
if (!values.includes(value))
|
|
328
|
+
throw new Error(`invalid ${name}`);
|
|
329
|
+
}
|
|
@@ -21,6 +21,9 @@ export * from './cli.js';
|
|
|
21
21
|
export * from './experiment-directory.js';
|
|
22
22
|
export * from './experiment.js';
|
|
23
23
|
export * from './external-subject.js';
|
|
24
|
+
export * from './fleet.js';
|
|
25
|
+
export * from './fleet-store.js';
|
|
26
|
+
export * from './fleet-worker.js';
|
|
24
27
|
export * from './harness-executor.js';
|
|
25
28
|
export * from './maka-subject.js';
|
|
26
29
|
export * from './result.js';
|
|
@@ -20,6 +20,7 @@ import { RUN_COMPOSITION_RECORDED_EVENT_TYPE } from '@maka/core/agent-run';
|
|
|
20
20
|
import { isRuntimeHandoffPause } from '@maka/core/runtime-handoff';
|
|
21
21
|
import { RunHandoffGate } from './run-handoff-gate.js';
|
|
22
22
|
import { preserveHandoffOpening } from './runtime-resume.js';
|
|
23
|
+
import { runtimeInvocationRouteForHeader } from './runtime-invocation-route.js';
|
|
23
24
|
import { createRequestCompositionSnapshot, decodeRequestCompositionSnapshot, decodeRunCompositionSnapshot, } from '@maka/core/run-composition';
|
|
24
25
|
import { DurableStoreWriteError, RunSealedError } from '@maka/core/runtime-event-store';
|
|
25
26
|
import { buildInvocationOpenedEvent, buildSyntheticTerminalRuntimeEvent, isSessionInlineInvocation, } from '@maka/core/runtime-invocation';
|
|
@@ -86,7 +87,6 @@ export class AgentRun {
|
|
|
86
87
|
failureClass;
|
|
87
88
|
failureMessage;
|
|
88
89
|
lastTs = 0;
|
|
89
|
-
sawCompletion = false;
|
|
90
90
|
finalStatus;
|
|
91
91
|
turnFailed = false;
|
|
92
92
|
finalized = false;
|
|
@@ -877,7 +877,6 @@ export class AgentRun {
|
|
|
877
877
|
const terminalSessionEvent = (ev.type === 'complete' || ev.type === 'abort') && !this.turnFailed;
|
|
878
878
|
const turnStatus = terminalSessionEvent ? turnStatusFromEvent(ev) : undefined;
|
|
879
879
|
if (terminalSessionEvent) {
|
|
880
|
-
this.sawCompletion = true;
|
|
881
880
|
if (ev.type === 'abort' && !this.abortSource)
|
|
882
881
|
this.abortSource = ev.reason;
|
|
883
882
|
if (ev.type === 'complete' && ev.stopReason === 'user_stop' && !this.abortSource)
|
|
@@ -1128,21 +1127,7 @@ export class AgentRun {
|
|
|
1128
1127
|
const opening = {
|
|
1129
1128
|
kind: 'invocation_opened',
|
|
1130
1129
|
protocol: 'invocation_opened_v1',
|
|
1131
|
-
route: this.header
|
|
1132
|
-
? {
|
|
1133
|
-
provenance: 'unknown',
|
|
1134
|
-
backendKind: this.header.backend,
|
|
1135
|
-
llmConnectionSlug: this.header.llmConnectionSlug,
|
|
1136
|
-
modelId: this.header.model,
|
|
1137
|
-
}
|
|
1138
|
-
: {
|
|
1139
|
-
provenance: 'runtime',
|
|
1140
|
-
backendKind: this.header.backend,
|
|
1141
|
-
llmConnectionId: this.header.llmConnectionId,
|
|
1142
|
-
llmConnectionSlug: this.header.llmConnectionSlug,
|
|
1143
|
-
modelId: this.header.model,
|
|
1144
|
-
...(providerStateIdentity ? { providerStateIdentity } : {}),
|
|
1145
|
-
},
|
|
1130
|
+
route: runtimeInvocationRouteForHeader(this.header, providerStateIdentity),
|
|
1146
1131
|
configuration: {
|
|
1147
1132
|
cwd: this.header.cwd,
|
|
1148
1133
|
permissionMode: this.header.permissionMode,
|
|
@@ -285,7 +285,9 @@ export class AiSdkCompaction {
|
|
|
285
285
|
const route = invocation.opening.route;
|
|
286
286
|
return {
|
|
287
287
|
runId: invocation.runId,
|
|
288
|
-
...(route.provenance === 'runtime'
|
|
288
|
+
...(route.provenance === 'runtime' && route.backendKind !== 'plugin-executor'
|
|
289
|
+
? { connectionId: route.llmConnectionId }
|
|
290
|
+
: {}),
|
|
289
291
|
modelId: route.modelId,
|
|
290
292
|
};
|
|
291
293
|
})
|
|
@@ -882,8 +884,9 @@ export class AiSdkCompaction {
|
|
|
882
884
|
*/
|
|
883
885
|
async recoverFromOverflowError(input) {
|
|
884
886
|
const state = input.midTurnState;
|
|
885
|
-
if (
|
|
887
|
+
if (!state || state.compactionAttemptedThisSend || state.omittedImageToolResults.size > 0) {
|
|
886
888
|
return undefined;
|
|
889
|
+
}
|
|
887
890
|
if (this.modelAdapter.classifyError(input.error) !== 'context_overflow')
|
|
888
891
|
return undefined;
|
|
889
892
|
const eligibleImages = collectHistoricalImageToolResults(state.priorContentEvents);
|
|
@@ -1136,6 +1139,7 @@ function persistedRequestAnchor(events, invocations, modelId, connectionId) {
|
|
|
1136
1139
|
continue;
|
|
1137
1140
|
const route = invocations.find((candidate) => candidate.runId === event?.runId)?.opening.route;
|
|
1138
1141
|
if (route?.provenance !== 'runtime' ||
|
|
1142
|
+
route.backendKind === 'plugin-executor' ||
|
|
1139
1143
|
route.modelId !== modelId ||
|
|
1140
1144
|
route.llmConnectionId !== connectionId) {
|
|
1141
1145
|
return undefined;
|
|
@@ -24,6 +24,31 @@ import { admitProviderReasoningReplayItems, buildRuntimeEventReplayTimeline, for
|
|
|
24
24
|
import { openAiChatReasoningFieldFromProviderOptions } from './openai-chat-reasoning-transport.js';
|
|
25
25
|
import { decodePlaintextResponsesReasoningState, replayPlaintextResponsesProviderOptions, } from './responses-reasoning-state.js';
|
|
26
26
|
import { toolResultOutput } from './tool-result-output.js';
|
|
27
|
+
function isRedactedThinking(providerOptions) {
|
|
28
|
+
const anthropic = providerOptions?.anthropic;
|
|
29
|
+
return (!!anthropic &&
|
|
30
|
+
typeof anthropic === 'object' &&
|
|
31
|
+
!Array.isArray(anthropic) &&
|
|
32
|
+
typeof anthropic.redactedData === 'string');
|
|
33
|
+
}
|
|
34
|
+
function encryptedResponsesReasoning(providerOptions) {
|
|
35
|
+
const openai = providerOptions?.openai;
|
|
36
|
+
if (!openai || typeof openai !== 'object' || Array.isArray(openai))
|
|
37
|
+
return undefined;
|
|
38
|
+
const { itemId, reasoningEncryptedContent } = openai;
|
|
39
|
+
return typeof itemId === 'string' &&
|
|
40
|
+
itemId.length > 0 &&
|
|
41
|
+
typeof reasoningEncryptedContent === 'string' &&
|
|
42
|
+
reasoningEncryptedContent.length > 0
|
|
43
|
+
? { itemId, reasoningEncryptedContent }
|
|
44
|
+
: undefined;
|
|
45
|
+
}
|
|
46
|
+
export function hasFinalizedReasoning(part) {
|
|
47
|
+
return (!!part.signature ||
|
|
48
|
+
isRedactedThinking(part.providerOptions) ||
|
|
49
|
+
decodePlaintextResponsesReasoningState(part.providerOptions).kind === 'valid' ||
|
|
50
|
+
encryptedResponsesReasoning(part.providerOptions) !== undefined);
|
|
51
|
+
}
|
|
27
52
|
function isImageToolResult(value) {
|
|
28
53
|
if (!value || typeof value !== 'object')
|
|
29
54
|
return false;
|
|
@@ -167,11 +192,7 @@ export class AiSdkMessageProjection {
|
|
|
167
192
|
}
|
|
168
193
|
: undefined;
|
|
169
194
|
}
|
|
170
|
-
|
|
171
|
-
if (anthropic &&
|
|
172
|
-
typeof anthropic === 'object' &&
|
|
173
|
-
!Array.isArray(anthropic) &&
|
|
174
|
-
typeof anthropic.redactedData === 'string') {
|
|
195
|
+
if (isRedactedThinking(item.providerOptions)) {
|
|
175
196
|
return replaySupport.signedThinking
|
|
176
197
|
? {
|
|
177
198
|
part: {
|
|
@@ -218,26 +239,17 @@ export class AiSdkMessageProjection {
|
|
|
218
239
|
return { part: { type: 'reasoning', text: item.text } };
|
|
219
240
|
}
|
|
220
241
|
if (replaySupport.responsesReasoning === 'encrypted-content') {
|
|
221
|
-
const
|
|
222
|
-
if (
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
part: {
|
|
230
|
-
type: 'reasoning',
|
|
231
|
-
text: item.text,
|
|
232
|
-
providerOptions: {
|
|
233
|
-
openai: {
|
|
234
|
-
itemId,
|
|
235
|
-
reasoningEncryptedContent,
|
|
236
|
-
},
|
|
237
|
-
},
|
|
242
|
+
const encrypted = encryptedResponsesReasoning(item.providerOptions);
|
|
243
|
+
if (encrypted) {
|
|
244
|
+
return {
|
|
245
|
+
part: {
|
|
246
|
+
type: 'reasoning',
|
|
247
|
+
text: item.text,
|
|
248
|
+
providerOptions: {
|
|
249
|
+
openai: encrypted,
|
|
238
250
|
},
|
|
239
|
-
}
|
|
240
|
-
}
|
|
251
|
+
},
|
|
252
|
+
};
|
|
241
253
|
}
|
|
242
254
|
}
|
|
243
255
|
if (!replaySupport.unsignedThinking)
|