maka-agent 0.2.0-dev.25.20260908 → 0.2.0-dev.26.20260909
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mcp-capability-provider.js +4 -1
- package/dist/pi-tui-mcp-status.js +2 -2
- package/dist/pi-tui-pickers.js +19 -29
- package/dist/tui-autocomplete-layout.js +3 -1
- package/dist/tui-copy-catalog.js +6 -3
- package/dist/tui-editor-render.js +36 -0
- package/dist/tui-mcp-control.js +41 -6
- package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
- package/node_modules/@maka/core/dist/runtime-event.js +3 -0
- package/node_modules/@maka/core/dist/session.js +29 -4
- package/node_modules/@maka/core/dist/workhub-action-result.js +68 -0
- package/node_modules/@maka/core/package.json +2 -3
- package/node_modules/@maka/eval/dist/toolchain-verification.js +1 -1
- package/node_modules/@maka/mcp/dist/form-elicitation.js +213 -0
- package/node_modules/@maka/mcp/dist/index.js +337 -71
- package/node_modules/@maka/runtime/dist/agent-run.js +10 -1
- package/node_modules/@maka/runtime/dist/goal-continuation.js +5 -1
- package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +20 -1
- package/node_modules/@maka/runtime/dist/runtime-kernel.js +120 -13
- package/node_modules/@maka/runtime/dist/session-manager.js +20 -36
- package/node_modules/@maka/runtime-host/dist/client/connection.js +30 -5
- package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +17 -1
- package/node_modules/@maka/runtime-host/dist/client/host-retirement.js +4 -2
- package/node_modules/@maka/runtime-host/dist/client/peer-client.js +18 -1
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +5 -1
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +3 -2
- package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +1 -0
- package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +68 -168
- package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +4 -0
- package/node_modules/@maka/runtime-host/dist/server/canonical-session-projection.js +2 -1
- package/node_modules/@maka/runtime-host/dist/server/connection-session.js +28 -8
- package/node_modules/@maka/runtime-host/dist/server/daily-review-coordinator.js +112 -56
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +45 -20
- package/node_modules/@maka/runtime-host/dist/server/failure-diagnostic.js +24 -0
- package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +7 -3
- package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +3 -3
- package/node_modules/@maka/runtime-host/dist/server/host-session-availability.js +5 -2
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +3 -2
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-tool-profile.js +34 -4
- package/node_modules/@maka/runtime-host/dist/server/interactive-run-composer.js +4 -1
- package/node_modules/@maka/runtime-host/dist/server/operation-dispatcher.js +2 -7
- package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +110 -14
- package/node_modules/@maka/runtime-host/dist/server/runtime-resource-coordinator.js +11 -8
- package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +31 -21
- package/node_modules/@maka/runtime-host/dist/server/serial-outbound-writer.js +1 -1
- package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +20 -8
- package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +15 -104
- package/node_modules/@maka/runtime-host/dist/server/shared-session-transcript.js +3 -0
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +44 -85
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +120 -137
- package/node_modules/@maka/storage/dist/agent-run-store.js +14 -1
- package/node_modules/@maka/storage/dist/artifact-store.js +40 -3
- package/node_modules/@maka/storage/dist/atomic-file-write.js +74 -0
- package/node_modules/@maka/storage/dist/credential-store.js +12 -63
- package/node_modules/@maka/storage/dist/execution-stores.js +4 -1
- package/node_modules/@maka/storage/dist/mcp-config-store.js +10 -25
- package/node_modules/@maka/storage/dist/session-store.js +14 -2
- package/node_modules/@maka/storage/dist/settings-store.js +8 -4
- package/node_modules/@maka/storage/dist/sqlite-artifact-metadata.js +11 -0
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-schema.js +12 -1
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +67 -3
- package/node_modules/@maka/storage/dist/stable-storage.js +14 -1
- package/package.json +1 -1
- package/node_modules/@maka/core/dist/workhub-creation-intent.js +0 -990
- package/node_modules/@maka/core/dist/workhub-session-resolver.js +0 -50
|
@@ -530,6 +530,111 @@ export class RuntimeKernel {
|
|
|
530
530
|
runId: continuation.runId,
|
|
531
531
|
}, options, () => this.revalidateContinuationSafety(continuation), inheritedSandboxBoundaryDenied);
|
|
532
532
|
}
|
|
533
|
+
/** Host coordination uses the same Run owner and terminal authority without a provider send. */
|
|
534
|
+
async *runCoordinationOperation(sessionId, input, options, execute) {
|
|
535
|
+
const execution = this.takeExecutionClaim(sessionId);
|
|
536
|
+
execution.hostOperation = true;
|
|
537
|
+
try {
|
|
538
|
+
await this.enterExecutionClaim(execution);
|
|
539
|
+
const header = await this.deps.store.readHeader(sessionId);
|
|
540
|
+
const run = new AgentRun({
|
|
541
|
+
sessionId,
|
|
542
|
+
header,
|
|
543
|
+
userInput: input,
|
|
544
|
+
runId: options.runId,
|
|
545
|
+
userMessageId: options.userMessageId,
|
|
546
|
+
durability: 'required',
|
|
547
|
+
runStore: this.deps.runStore,
|
|
548
|
+
runtimeEventStore: this.deps.runtimeEventStore,
|
|
549
|
+
newId: this.deps.newId,
|
|
550
|
+
now: this.deps.now,
|
|
551
|
+
effectiveOrchestration: resolveEffectiveOrchestration('default', undefined),
|
|
552
|
+
hooks: {
|
|
553
|
+
reserveRun: async (id, nextHeader, activeRun) => {
|
|
554
|
+
const active = await this.reserveParentRun(id, nextHeader, activeRun, execution);
|
|
555
|
+
this.reserveExecutionClaim(execution, active, activeRun);
|
|
556
|
+
return active;
|
|
557
|
+
},
|
|
558
|
+
unregisterRun: (active, activeRun) => this.unregisterParentRun(active, activeRun),
|
|
559
|
+
updateHeader: (id, patch) => this.updateHeader(id, patch),
|
|
560
|
+
updateStatus: (id, status, reason, ts) => this.updateStatus(id, status, reason, ts),
|
|
561
|
+
...this.messageProjectionHook(),
|
|
562
|
+
},
|
|
563
|
+
});
|
|
564
|
+
this.attachExecutionClaim(execution, run);
|
|
565
|
+
const owners = this.createRunOwnerScope(run, execution);
|
|
566
|
+
try {
|
|
567
|
+
owners.bindMessage(this.deps.messageAuthority, {
|
|
568
|
+
sessionId,
|
|
569
|
+
turnId: input.turnId,
|
|
570
|
+
runId: run.runId,
|
|
571
|
+
});
|
|
572
|
+
// Keep the execution claim attached until finalization. Stop/drain can
|
|
573
|
+
// therefore cancel and await this Run without a provider generation.
|
|
574
|
+
await run.beginCoordination();
|
|
575
|
+
await options.onRunStarted?.(run.runId, header);
|
|
576
|
+
}
|
|
577
|
+
catch (error) {
|
|
578
|
+
await this.finalizeFailedRunStart(owners, run, execution, error);
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
try {
|
|
582
|
+
if (run.isStopped())
|
|
583
|
+
return;
|
|
584
|
+
const executed = await execute();
|
|
585
|
+
const receipt = {
|
|
586
|
+
...executed,
|
|
587
|
+
result: executed.result.disposition === 'clarify'
|
|
588
|
+
? { ...executed.result, coordinationTurnId: input.turnId }
|
|
589
|
+
: executed.result,
|
|
590
|
+
};
|
|
591
|
+
const receiptEvent = {
|
|
592
|
+
id: this.deps.newId(),
|
|
593
|
+
sessionId,
|
|
594
|
+
turnId: input.turnId,
|
|
595
|
+
runId: run.runId,
|
|
596
|
+
invocationId: run.runId,
|
|
597
|
+
ts: this.deps.now(),
|
|
598
|
+
partial: false,
|
|
599
|
+
role: 'system',
|
|
600
|
+
author: 'host',
|
|
601
|
+
modelVisibility: 'hidden',
|
|
602
|
+
actions: { coordination: receipt },
|
|
603
|
+
};
|
|
604
|
+
await run.recordRuntimeEvents([receiptEvent], { requireDurableWrite: true });
|
|
605
|
+
if (run.isStopped())
|
|
606
|
+
return;
|
|
607
|
+
const complete = {
|
|
608
|
+
type: 'complete',
|
|
609
|
+
id: this.deps.newId(),
|
|
610
|
+
turnId: input.turnId,
|
|
611
|
+
ts: this.deps.now(),
|
|
612
|
+
stopReason: 'end_turn',
|
|
613
|
+
};
|
|
614
|
+
await run.acceptMappedEvent(complete, mapSessionEventToRuntimeEvent(complete, this.runtimeEventMapContext({
|
|
615
|
+
sessionId,
|
|
616
|
+
invocationId: run.runId,
|
|
617
|
+
runId: run.runId,
|
|
618
|
+
turnId: input.turnId,
|
|
619
|
+
})), { requireTerminalWrite: true });
|
|
620
|
+
yield complete;
|
|
621
|
+
}
|
|
622
|
+
catch (error) {
|
|
623
|
+
await run.recordFailure(error);
|
|
624
|
+
throw error;
|
|
625
|
+
}
|
|
626
|
+
finally {
|
|
627
|
+
const failures = new FailureCollector();
|
|
628
|
+
await failures.capture(() => owners.finalize());
|
|
629
|
+
await failures.capture(() => owners.releaseMessage());
|
|
630
|
+
failures.throwIfAny(`Coordination cleanup failed for ${run.runId}`);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
finally {
|
|
634
|
+
this.releaseExecutionClaim(execution);
|
|
635
|
+
await this.flushBackendInvalidation(sessionId);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
533
638
|
async *compactSession(sessionId, input = {}) {
|
|
534
639
|
const execution = this.takeExecutionClaim(sessionId);
|
|
535
640
|
try {
|
|
@@ -1455,24 +1560,26 @@ export class RuntimeKernel {
|
|
|
1455
1560
|
const generations = this.backendGenerationsFor(sessionId);
|
|
1456
1561
|
await Promise.all(generations.map((active) => active.backend.respondToUserQuestion?.(response)));
|
|
1457
1562
|
}
|
|
1563
|
+
activeRunsFor(sessionId) {
|
|
1564
|
+
const runs = new Set();
|
|
1565
|
+
for (const active of this.backendGenerationsFor(sessionId)) {
|
|
1566
|
+
for (const run of active.activeRuns.values())
|
|
1567
|
+
runs.add(run);
|
|
1568
|
+
}
|
|
1569
|
+
for (const claim of this.executionClaims.get(sessionId) ?? []) {
|
|
1570
|
+
if (claim.hostOperation && claim.run)
|
|
1571
|
+
runs.add(claim.run);
|
|
1572
|
+
}
|
|
1573
|
+
return [...runs];
|
|
1574
|
+
}
|
|
1458
1575
|
hasActiveRuns(sessionId) {
|
|
1459
|
-
return this.
|
|
1576
|
+
return this.activeRunsFor(sessionId).length > 0;
|
|
1460
1577
|
}
|
|
1461
1578
|
runningTurnIds(sessionId) {
|
|
1462
|
-
|
|
1463
|
-
for (const active of this.backendGenerationsFor(sessionId)) {
|
|
1464
|
-
for (const run of active.activeRuns.values()) {
|
|
1465
|
-
if (!turnIds.includes(run.turnId))
|
|
1466
|
-
turnIds.push(run.turnId);
|
|
1467
|
-
}
|
|
1468
|
-
}
|
|
1469
|
-
return turnIds;
|
|
1579
|
+
return [...new Set(this.activeRunsFor(sessionId).map((run) => run.turnId))];
|
|
1470
1580
|
}
|
|
1471
1581
|
hasActiveRun(sessionId, runId, turnId) {
|
|
1472
|
-
return this.
|
|
1473
|
-
const run = active.activeRuns.get(runId);
|
|
1474
|
-
return run !== undefined && (turnId === undefined || run.turnId === turnId);
|
|
1475
|
-
});
|
|
1582
|
+
return this.activeRunsFor(sessionId).some((run) => run.runId === runId && (turnId === undefined || run.turnId === turnId));
|
|
1476
1583
|
}
|
|
1477
1584
|
requestRunHandoff(sessionId, runId, pause, signal) {
|
|
1478
1585
|
if (!this.deps.inspectContinuationSafety)
|
|
@@ -16,17 +16,6 @@
|
|
|
16
16
|
* specific language governing permissions and limitations
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
|
-
/**
|
|
20
|
-
* SessionManager — the public Runtime API.
|
|
21
|
-
*
|
|
22
|
-
* Ties together:
|
|
23
|
-
* SessionStore (storage) — SQLite persistence
|
|
24
|
-
* AgentBackend (AiSdkBackend etc) — SDK adapter
|
|
25
|
-
* ExecutionBoundary — session sandbox authority
|
|
26
|
-
*
|
|
27
|
-
* `SessionStore` comes from `@maka/storage`; its public interface owns
|
|
28
|
-
* persistence and same-session serialization semantics.
|
|
29
|
-
*/
|
|
30
19
|
import { createHash } from 'node:crypto';
|
|
31
20
|
import { isDeepStrictEqual } from 'node:util';
|
|
32
21
|
import { setTimeout as delay } from 'node:timers/promises';
|
|
@@ -1280,6 +1269,9 @@ export class SessionManager {
|
|
|
1280
1269
|
// Operational telemetry must never alter resume correctness.
|
|
1281
1270
|
}
|
|
1282
1271
|
}
|
|
1272
|
+
runCoordinationOperation(sessionId, input, options, execute) {
|
|
1273
|
+
return this.runtimeKernel.runCoordinationOperation(sessionId, input, options, execute);
|
|
1274
|
+
}
|
|
1283
1275
|
async *compactSession(sessionId, input = {}) {
|
|
1284
1276
|
yield* this.runtimeKernel.compactSession(sessionId, input);
|
|
1285
1277
|
}
|
|
@@ -2314,43 +2306,30 @@ export class SessionManager {
|
|
|
2314
2306
|
const hostedAuthority = isRuntimeHostedRootAuthority(this.deps.messageAuthority)
|
|
2315
2307
|
? this.deps.messageAuthority
|
|
2316
2308
|
: undefined;
|
|
2317
|
-
|
|
2309
|
+
await this.#stopSessionTree(sessionId, hostedAuthority
|
|
2318
2310
|
? hostedAuthority.stopSession(sessionId, input)
|
|
2319
|
-
: this.runtimeKernel.stopSession(sessionId, input)
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
try {
|
|
2323
|
-
const children = await this.listChildSessions(sessionId);
|
|
2324
|
-
childStops = await Promise.allSettled(children
|
|
2325
|
-
.filter((child) => child.subagentParent?.lifecycle === 'foreground')
|
|
2326
|
-
.map((child) => hostedAuthority
|
|
2327
|
-
? hostedAuthority.stopSession(child.id, input)
|
|
2328
|
-
: this.runtimeKernel.stopSession(child.id, input)));
|
|
2329
|
-
}
|
|
2330
|
-
catch (error) {
|
|
2331
|
-
childLookupError = error;
|
|
2332
|
-
}
|
|
2333
|
-
await ownStop;
|
|
2334
|
-
const childStopError = childStops.find((result) => result.status === 'rejected')?.reason;
|
|
2335
|
-
if (childLookupError !== undefined)
|
|
2336
|
-
throw childLookupError;
|
|
2337
|
-
if (childStopError !== undefined)
|
|
2338
|
-
throw childStopError;
|
|
2311
|
+
: this.runtimeKernel.stopSession(sessionId, input), (childSessionId) => hostedAuthority
|
|
2312
|
+
? hostedAuthority.stopSession(childSessionId, input)
|
|
2313
|
+
: this.runtimeKernel.stopSession(childSessionId, input));
|
|
2339
2314
|
}
|
|
2340
2315
|
async deliverHostedRootStop(sessionId, input = {}) {
|
|
2341
|
-
const ownStop = this.runtimeKernel.stopSession(sessionId, input);
|
|
2342
2316
|
const authority = isRuntimeHostedRootAuthority(this.deps.messageAuthority)
|
|
2343
2317
|
? this.deps.messageAuthority
|
|
2344
2318
|
: undefined;
|
|
2319
|
+
await this.#stopSessionTree(sessionId, this.runtimeKernel.stopSession(sessionId, input), (childSessionId) => authority
|
|
2320
|
+
? authority.stopSession(childSessionId, input)
|
|
2321
|
+
: this.runtimeKernel.stopSession(childSessionId, input));
|
|
2322
|
+
}
|
|
2323
|
+
async #stopSessionTree(sessionId, ownStop, stopChild) {
|
|
2324
|
+
// Observe immediately while child lookup runs; await below still propagates the original error.
|
|
2325
|
+
void ownStop.catch(() => undefined);
|
|
2345
2326
|
let childStops = [];
|
|
2346
2327
|
let childLookupError;
|
|
2347
2328
|
try {
|
|
2348
2329
|
const children = await this.listChildSessions(sessionId);
|
|
2349
2330
|
childStops = await Promise.allSettled(children
|
|
2350
2331
|
.filter((child) => child.subagentParent?.lifecycle === 'foreground')
|
|
2351
|
-
.map((child) =>
|
|
2352
|
-
? authority.stopSession(child.id, input)
|
|
2353
|
-
: this.runtimeKernel.stopSession(child.id, input)));
|
|
2332
|
+
.map((child) => stopChild(child.id)));
|
|
2354
2333
|
}
|
|
2355
2334
|
catch (error) {
|
|
2356
2335
|
childLookupError = error;
|
|
@@ -2385,6 +2364,11 @@ export class SessionManager {
|
|
|
2385
2364
|
goalId: input.execution.goalId,
|
|
2386
2365
|
};
|
|
2387
2366
|
}
|
|
2367
|
+
else if (input.execution.kind === 'workhub_coordination' &&
|
|
2368
|
+
input.execution.operation === 'action') {
|
|
2369
|
+
recoveryReason = 'coordination_action_admission_without_run';
|
|
2370
|
+
diagnostic = { executionKind: input.execution.kind, operation: input.execution.operation };
|
|
2371
|
+
}
|
|
2388
2372
|
else if (input.execution.kind === 'legacy_automation') {
|
|
2389
2373
|
root = { kind: 'legacy_automation', legacyAutomationId: input.execution.automationId };
|
|
2390
2374
|
recoveryReason = 'legacy_automation_authority_removed';
|
|
@@ -78,6 +78,12 @@ export class RuntimeHostRequestInterruptedError extends Error {
|
|
|
78
78
|
this.retryable = mode === 'query';
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
+
// A Host response can reach the Client before the Host's transport write
|
|
82
|
+
// promise resumes and retires that request. Leave one slot free so replacing
|
|
83
|
+
// the observed response cannot transiently cross the Host's hard limit. The
|
|
84
|
+
// Host serializes outbound writes, so at most one response occupies this
|
|
85
|
+
// acknowledgement window.
|
|
86
|
+
const CLIENT_MAX_IN_FLIGHT_DOMAIN_REQUESTS = RUNTIME_HOST_MAX_IN_FLIGHT_DOMAIN_REQUESTS - 1;
|
|
81
87
|
class RuntimeHostConnectionImpl {
|
|
82
88
|
cooperativeHandoff;
|
|
83
89
|
rootId;
|
|
@@ -212,7 +218,7 @@ class RuntimeHostConnectionImpl {
|
|
|
212
218
|
}
|
|
213
219
|
#drainDomainRequests() {
|
|
214
220
|
while (!this.#terminalError &&
|
|
215
|
-
this.#inFlightDomainRequests <
|
|
221
|
+
this.#inFlightDomainRequests < CLIENT_MAX_IN_FLIGHT_DOMAIN_REQUESTS) {
|
|
216
222
|
const queued = this.#queuedDomainFrames.shift();
|
|
217
223
|
if (!queued)
|
|
218
224
|
return;
|
|
@@ -243,9 +249,28 @@ class RuntimeHostConnectionImpl {
|
|
|
243
249
|
}
|
|
244
250
|
return status;
|
|
245
251
|
}
|
|
246
|
-
openSessionSubscription(input, timeoutMs) {
|
|
252
|
+
async openSessionSubscription(input, timeoutMs) {
|
|
253
|
+
const deadline = Date.now() + (timeoutMs === undefined ? 30_000 : requireTimeout(timeoutMs, 'timeoutMs'));
|
|
254
|
+
for (;;) {
|
|
255
|
+
try {
|
|
256
|
+
return await this.#openSessionSubscription(input, Math.max(1, deadline - Date.now()), timeoutMs);
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
if (!(error instanceof RuntimeHostOperationError) ||
|
|
260
|
+
error.code !== 'transcript_preparing' ||
|
|
261
|
+
input.transcript.kind !== 'tail' ||
|
|
262
|
+
this.#terminalError ||
|
|
263
|
+
Date.now() >= deadline)
|
|
264
|
+
throw error;
|
|
265
|
+
// Each refusal committed a bounded, resumable index batch. Keep the
|
|
266
|
+
// caller in its loading state and yield before requesting more work.
|
|
267
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
#openSessionSubscription(input, openTimeoutMs, requestTimeoutMs) {
|
|
247
272
|
const expectedSessionId = input.sessionId;
|
|
248
|
-
return this.#requestOperation('subscription.open', input,
|
|
273
|
+
return this.#requestOperation('subscription.open', input, openTimeoutMs, (result) => {
|
|
249
274
|
if (result.hostEpoch !== this.hostEpoch) {
|
|
250
275
|
throw new RuntimeHostSubscriptionError('host_epoch_changed', 'Session subscription opened for a different Host Epoch');
|
|
251
276
|
}
|
|
@@ -255,9 +280,9 @@ class RuntimeHostConnectionImpl {
|
|
|
255
280
|
if (this.#subscriptions.has(result.subscriptionId)) {
|
|
256
281
|
throw new RuntimeHostSubscriptionError('correlation_changed', 'Runtime Host returned a duplicate subscription identity');
|
|
257
282
|
}
|
|
258
|
-
const subscription = new ClientSessionSubscription(result, () => this.#closeSessionSubscription(result.subscriptionId), (query) => this.request('session.transcript.page', query,
|
|
283
|
+
const subscription = new ClientSessionSubscription(result, () => this.#closeSessionSubscription(result.subscriptionId), (query) => this.request('session.transcript.page', query, requestTimeoutMs), async () => {
|
|
259
284
|
try {
|
|
260
|
-
await this.request('session.transcript.overlay.release', { subscriptionId: result.subscriptionId },
|
|
285
|
+
await this.request('session.transcript.overlay.release', { subscriptionId: result.subscriptionId }, requestTimeoutMs);
|
|
261
286
|
}
|
|
262
287
|
catch (error) {
|
|
263
288
|
this.#fail(asError(error));
|
|
@@ -90,6 +90,20 @@ export function formatHostHandoff(view, locale) {
|
|
|
90
90
|
descriptions.operator_required = guidance[view.recoveryBlocker];
|
|
91
91
|
}
|
|
92
92
|
const activity = view.activity;
|
|
93
|
+
const background = activity?.drainResidencies;
|
|
94
|
+
const backgroundFacts = !activity
|
|
95
|
+
? ''
|
|
96
|
+
: background !== undefined
|
|
97
|
+
? tw
|
|
98
|
+
? `${background} 個背景工作`
|
|
99
|
+
: zh
|
|
100
|
+
? `${background} 个后台工作`
|
|
101
|
+
: `${background} background activities`
|
|
102
|
+
: tw
|
|
103
|
+
? '背景工作數量未知'
|
|
104
|
+
: zh
|
|
105
|
+
? '后台工作数量未知'
|
|
106
|
+
: 'Background activity count unknown';
|
|
93
107
|
const facts = activity
|
|
94
108
|
? tw
|
|
95
109
|
? `${activity.connections} 個連線 · ${activity.activeOperations} 個進行中的操作`
|
|
@@ -173,7 +187,9 @@ export function formatHostHandoff(view, locale) {
|
|
|
173
187
|
: zh
|
|
174
188
|
? '正在完成交接或安全收尾,请稍候。'
|
|
175
189
|
: 'Finishing the handoff or its safe recovery. Please wait.'
|
|
176
|
-
: [facts, waiting, repairNotice, view.operatorStep]
|
|
190
|
+
: [facts, backgroundFacts, waiting, repairNotice, view.operatorStep]
|
|
191
|
+
.filter(Boolean)
|
|
192
|
+
.join('\n'),
|
|
177
193
|
actions: view.actions.map((action) => ({ action, label: labels[action] })),
|
|
178
194
|
};
|
|
179
195
|
}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* transport detail here so lifecycle owners can model the operation as
|
|
24
24
|
* retirement instead of spreading update-specific authority.
|
|
25
25
|
*/
|
|
26
|
-
export async function prepareConnectedRuntimeHostRetirement(connection, mode, timeoutMs, signal) {
|
|
26
|
+
export async function prepareConnectedRuntimeHostRetirement(connection, mode, timeoutMs, signal, options) {
|
|
27
27
|
signal?.throwIfAborted();
|
|
28
28
|
// Retirement uses a dedicated lifecycle connection. Closing it cancels the
|
|
29
29
|
// Host's reversible preparation; a committed retirement remains committed.
|
|
@@ -35,7 +35,9 @@ export async function prepareConnectedRuntimeHostRetirement(connection, mode, ti
|
|
|
35
35
|
return await connection.request('host.upgrade.prepare', {
|
|
36
36
|
expectedHostEpoch: connection.hostEpoch,
|
|
37
37
|
allowInterruptActiveTasks: mode === 'interrupt_active_work',
|
|
38
|
-
...(mode === 'refuse_active_work' &&
|
|
38
|
+
...(mode === 'refuse_active_work' &&
|
|
39
|
+
connection.cooperativeHandoff &&
|
|
40
|
+
options?.allowCooperativeHandoff !== false
|
|
39
41
|
? { allowCooperativeHandoff: true }
|
|
40
42
|
: {}),
|
|
41
43
|
}, timeoutMs);
|
|
@@ -149,6 +149,23 @@ class RuntimeHostPeerClientImpl {
|
|
|
149
149
|
};
|
|
150
150
|
}
|
|
151
151
|
subscribeRoutes(peerId, listener) {
|
|
152
|
+
const snapshot = () => this.#connectionResolution({ peerId, routeHints: [], directDeadlineMs: 0 }, 'application', false);
|
|
153
|
+
let previous = snapshot();
|
|
154
|
+
let connected = this.isConnected(peerId);
|
|
155
|
+
return this.#subscribeRouteResolution(peerId, () => {
|
|
156
|
+
const next = snapshot();
|
|
157
|
+
const nextConnected = this.isConnected(peerId);
|
|
158
|
+
const available = next.state === 'available' &&
|
|
159
|
+
(!sameCandidates(previous, next) || (nextConnected && !connected));
|
|
160
|
+
previous = next;
|
|
161
|
+
connected = nextConnected;
|
|
162
|
+
// A dial's own recovery sweep toggles recovering/exhausted. Waking its
|
|
163
|
+
// reconnect owner for those transitions would bypass every backoff.
|
|
164
|
+
if (available)
|
|
165
|
+
listener();
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
#subscribeRouteResolution(peerId, listener) {
|
|
152
169
|
const listeners = this.#routeListeners.get(peerId) ?? new Set();
|
|
153
170
|
const first = listeners.size === 0;
|
|
154
171
|
listeners.add(listener);
|
|
@@ -362,7 +379,7 @@ class RuntimeHostPeerClientImpl {
|
|
|
362
379
|
updateTail = updateTail.then(() => updatePeerConnect(endpoint, requestId, candidates, () => settled), () => updatePeerConnect(endpoint, requestId, candidates, () => settled));
|
|
363
380
|
void updateTail.catch(() => undefined);
|
|
364
381
|
};
|
|
365
|
-
const unsubscribe = kind === 'application' ? this
|
|
382
|
+
const unsubscribe = kind === 'application' ? this.#subscribeRouteResolution(input.peerId, update) : undefined;
|
|
366
383
|
let connection;
|
|
367
384
|
try {
|
|
368
385
|
connection = endpoint[kind === 'application' ? 'connect' : 'connectMeshControl']({
|
|
@@ -62,7 +62,11 @@ export const RUNTIME_HOST_REGISTRATION_SCHEMA_VERSION = 1;
|
|
|
62
62
|
export const RUNTIME_HOST_PROTOCOL_VERSION = 0;
|
|
63
63
|
// Increment when the same protocol version no longer guarantees safe Client-Host
|
|
64
64
|
// interoperability. Mismatches are rejected before domain commands are admitted.
|
|
65
|
-
export const RUNTIME_HOST_COMPATIBILITY_EPOCH =
|
|
65
|
+
export const RUNTIME_HOST_COMPATIBILITY_EPOCH = 135;
|
|
66
|
+
// 135: WorkHub model Turns replace direct action proposals with active-Turn task tools.
|
|
67
|
+
// 134: Coordination actions own real Runtime Turns. Removes the synthetic record
|
|
68
|
+
// operation, projects typed action receipts and admitted action identities, and
|
|
69
|
+
// distinguishes stale candidate refusals and resumable transcript preparation.
|
|
66
70
|
// 133: WorkHub actions carry attachments and new-Work model/permission defaults.
|
|
67
71
|
// Epoch-132 peers reject these additional fields on strict action shapes.
|
|
68
72
|
// 132: new Tool Result archives use versioned ledger references, not Artifact payloads.
|
|
@@ -218,9 +218,10 @@ export const REMOTE_OWNER_OPERATION_GRANTS = Object.freeze([
|
|
|
218
218
|
'usage.query',
|
|
219
219
|
'web-search.execute',
|
|
220
220
|
'workhub.coordination.answer',
|
|
221
|
-
'workhub.coordination.
|
|
221
|
+
'workhub.coordination.actFromTurn',
|
|
222
222
|
'workhub.coordination.candidates',
|
|
223
|
-
'workhub.coordination.
|
|
223
|
+
'workhub.coordination.configureModel',
|
|
224
|
+
'workhub.coordination.query',
|
|
224
225
|
'workhub.coordination.resolve',
|
|
225
226
|
]);
|
|
226
227
|
const REMOTE_OWNER_OPERATION_GRANT_SET = new Set(REMOTE_OWNER_OPERATION_GRANTS);
|