effect-agent 0.1.0-beta.125 → 0.1.0-beta.129
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/{Records-uGX4_EGf.d.mts → Admin-C34cVKlT.d.mts} +2908 -3941
- package/dist/{AgentRuntime-ov0LFEb-.d.mts → AgentRuntime-DEDvMkAR.d.mts} +2 -2
- package/dist/Digest-U69rDHuO.d.mts +22 -0
- package/dist/{DurableAgentRuntime-BvDGe7F9.mjs → DurableAgentRuntime-BydyN_n-.mjs} +88 -15
- package/dist/DurableAgentRuntime-BydyN_n-.mjs.map +1 -0
- package/dist/{EventSource-CNBoY8AA.d.mts → EventSource-Bac0SxKL.d.mts} +3 -3
- package/dist/{PreparedInputAdmission--_APJzWY.d.mts → PreparedInputAdmission-DcQGQ0Yp.d.mts} +4 -4
- package/dist/Records-B5GFWCpn.d.mts +1104 -0
- package/dist/{Schedule-C8ze8WTW.d.mts → Schedule-CtYREFnz.d.mts} +2 -2
- package/dist/{Subagent-CudP5BlT.mjs → Subagent-DJeZDrbD.mjs} +5 -2
- package/dist/Subagent-DJeZDrbD.mjs.map +1 -0
- package/dist/{Subagent-CCf7rY70.d.mts → Subagent-DRFyQxdb.d.mts} +13 -4
- package/dist/{SubagentHost-B0-cRCqs.d.mts → SubagentHost-DQjHFGqH.d.mts} +7 -2
- package/dist/{Subscription-CYb8ltMK.d.mts → Subscription-Bk2Smmqc.d.mts} +34 -3
- package/dist/{SubscriptionInput-C1XE9Vyi.d.mts → SubscriptionInput-ekbJz3pF.d.mts} +3 -3
- package/dist/capabilities/Subagent.d.mts +1 -1
- package/dist/capabilities/Subagent.mjs +1 -1
- package/dist/durable/ActivityStore.d.mts +1 -1
- package/dist/durable/Admin.d.mts +1 -1
- package/dist/durable/AgentRegistration.d.mts +1 -1
- package/dist/durable/Certification.d.mts +1 -1
- package/dist/durable/CommittedActivity.d.mts +3 -1
- package/dist/durable/Digest.d.mts +1 -1
- package/dist/durable/DurableAgentRuntime.d.mts +1 -1
- package/dist/durable/DurableAgentRuntime.mjs +1 -1
- package/dist/durable/EventSource.d.mts +1 -1
- package/dist/durable/GitHubWorkflowSource.d.mts +3 -3
- package/dist/durable/MessageDelivery.d.mts +44 -3
- package/dist/durable/MessageDeliveryStoreConformance.d.mts +23 -1
- package/dist/durable/PersistentHistory.d.mts +1 -1
- package/dist/durable/PreparedInputAdmission.d.mts +1 -1
- package/dist/durable/Records.d.mts +2 -2
- package/dist/durable/Records.mjs +12 -2
- package/dist/durable/Records.mjs.map +1 -1
- package/dist/durable/Recovery.d.mts +1 -1
- package/dist/durable/RunJournal.d.mts +1 -1
- package/dist/durable/Schedule.d.mts +1 -1
- package/dist/durable/ScheduleStoreConformance.d.mts +1 -1
- package/dist/durable/ScheduleTransition.d.mts +1 -1
- package/dist/durable/Scheduling.d.mts +3 -2
- package/dist/durable/SqlStorageV2Upgrade.d.mts +2 -2
- package/dist/durable/SqlSubscriptionStore.d.mts +2 -2
- package/dist/durable/SqlThreadNativeReads.d.mts +2 -1
- package/dist/durable/SqlThreadNativeReads.mjs +1 -1
- package/dist/durable/SqlThreadNativeReads.mjs.map +1 -1
- package/dist/durable/SubmissionLedger.d.mts +1 -1
- package/dist/durable/SubmissionLedgerConformance.d.mts +2 -1
- package/dist/durable/SubmissionStatus.d.mts +1 -1
- package/dist/durable/Subscription.d.mts +1 -1
- package/dist/durable/SubscriptionInput.d.mts +1 -1
- package/dist/durable/SubscriptionStoreConformance.d.mts +1 -1
- package/dist/durable/SubscriptionTools.d.mts +4 -3
- package/dist/durable/SubscriptionTransition.d.mts +1 -1
- package/dist/durable/Subscriptions.d.mts +6 -5
- package/dist/durable/ThreadContextHistory.d.mts +1 -1
- package/dist/durable/ThreadContextHistoryProjection.d.mts +1 -1
- package/dist/durable/ThreadInvariants.d.mts +2 -1
- package/dist/durable/ThreadProjection.d.mts +1 -1
- package/dist/durable/ThreadProjectionMaintenance.d.mts +1 -1
- package/dist/durable/ThreadStore.d.mts +1 -1
- package/dist/durable/ThreadStoreConformance.d.mts +1 -1
- package/dist/durable/ThreadStoreConformance.mjs +10 -1
- package/dist/durable/ThreadStoreConformance.mjs.map +1 -1
- package/dist/durable/WorkerHost.d.mts +9 -2
- package/dist/durable/WorkerHost.mjs.map +1 -1
- package/dist/engine/AgentRuntime.d.mts +1 -1
- package/dist/engine/SubagentHost.d.mts +1 -1
- package/dist/engine/SubagentHost.mjs.map +1 -1
- package/dist/index.d.mts +12 -10
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
- package/src/capabilities/internal/subagent-background.ts +25 -3
- package/src/durable/Records.ts +13 -1
- package/src/durable/SqlThreadNativeReads.ts +1 -1
- package/src/durable/ThreadStoreConformance.ts +28 -0
- package/src/durable/WorkerHost.ts +14 -2
- package/src/durable/internal/worker-host.ts +282 -9
- package/src/engine/SubagentHost.ts +6 -0
- package/dist/DurableAgentRuntime-BvDGe7F9.mjs.map +0 -1
- package/dist/Subagent-CudP5BlT.mjs.map +0 -1
|
@@ -71,6 +71,7 @@ import {
|
|
|
71
71
|
WorkerInputRequested,
|
|
72
72
|
WorkerStopRequested,
|
|
73
73
|
WorkerOrigin,
|
|
74
|
+
WorkerContinuation,
|
|
74
75
|
WorkerOriginRecorded,
|
|
75
76
|
WorkerInputCompleted,
|
|
76
77
|
WorkerReportPrepared,
|
|
@@ -292,6 +293,7 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
292
293
|
origin: WorkerOrigin,
|
|
293
294
|
principal: Principal,
|
|
294
295
|
) {
|
|
296
|
+
yield* verifyContinuation(origin);
|
|
295
297
|
if (origin.budgetScope !== "worker-run") return;
|
|
296
298
|
// Independence changes accounting ownership, never delegation generations.
|
|
297
299
|
if (origin.depth !== 1) return yield* failure("start", "denied");
|
|
@@ -300,6 +302,7 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
300
302
|
source: origin.source,
|
|
301
303
|
principal,
|
|
302
304
|
worker: origin.worker,
|
|
305
|
+
...(origin.continuationOf === undefined ? {} : { continuationOf: origin.continuationOf }),
|
|
303
306
|
policy: origin.policy,
|
|
304
307
|
budget: origin.budget,
|
|
305
308
|
});
|
|
@@ -321,6 +324,170 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
321
324
|
);
|
|
322
325
|
});
|
|
323
326
|
|
|
327
|
+
const completedContinuation = Effect.fn("WorkerHost.completedContinuation")(function* (
|
|
328
|
+
source: WorkerContext["source"],
|
|
329
|
+
worker: WorkerRef,
|
|
330
|
+
targetAgentId: AgentId,
|
|
331
|
+
delegationId: WorkerRef["delegationId"],
|
|
332
|
+
expected?: WorkerContinuation,
|
|
333
|
+
) {
|
|
334
|
+
const selected = yield* decode(WorkerRef, worker, "start");
|
|
335
|
+
|
|
336
|
+
if (
|
|
337
|
+
selected.targetAgentId !== targetAgentId ||
|
|
338
|
+
selected.delegationId !== delegationId ||
|
|
339
|
+
selected.threadId === source.threadId ||
|
|
340
|
+
deps.ledger.inspectWorker === undefined
|
|
341
|
+
)
|
|
342
|
+
return yield* failure("start", "worker-mismatch");
|
|
343
|
+
const sourceState = yield* readWorkerState(source.threadId, "start");
|
|
344
|
+
|
|
345
|
+
if (
|
|
346
|
+
sourceState.records.some(
|
|
347
|
+
({ record }) =>
|
|
348
|
+
record.payload._tag === "WorkerStopRequested" &&
|
|
349
|
+
record.payload.command.worker.threadId === selected.threadId,
|
|
350
|
+
)
|
|
351
|
+
)
|
|
352
|
+
return yield* failure("start", "denied");
|
|
353
|
+
|
|
354
|
+
const first = sourceState.records.find(
|
|
355
|
+
({ record }) => record.recordId === firstWorkerInputRecordId(selected),
|
|
356
|
+
)?.record.payload;
|
|
357
|
+
|
|
358
|
+
const origin = first?._tag === "WorkerInputRequested" ? first.admission.origin : undefined;
|
|
359
|
+
|
|
360
|
+
if (
|
|
361
|
+
origin === undefined ||
|
|
362
|
+
origin.lifecycle !== "assignment" ||
|
|
363
|
+
!Schema.toEquivalence(WorkerRef)(origin.worker, selected) ||
|
|
364
|
+
origin.source.threadId !== source.threadId ||
|
|
365
|
+
origin.source.agentId !== source.agentId ||
|
|
366
|
+
first?._tag !== "WorkerInputRequested" ||
|
|
367
|
+
first.admission.messageId !== origin.firstMessageId
|
|
368
|
+
)
|
|
369
|
+
return yield* failure("start", "worker-mismatch");
|
|
370
|
+
|
|
371
|
+
const recorded = Option.getOrUndefined(
|
|
372
|
+
yield* exactRecord(selected.threadId, workerOriginRecordId(selected.threadId), "start"),
|
|
373
|
+
)?.record.payload;
|
|
374
|
+
|
|
375
|
+
if (recorded?._tag !== "WorkerOriginRecorded" || !sameOrigin(recorded.origin, origin))
|
|
376
|
+
return yield* failure("start", "worker-mismatch");
|
|
377
|
+
|
|
378
|
+
const control = yield* deps.ledger
|
|
379
|
+
.inspectWorker(selected.threadId)
|
|
380
|
+
.pipe(Effect.mapError(storageFailure("start")));
|
|
381
|
+
|
|
382
|
+
if (control.terminal !== "completed" || !control.stopped || control.active !== null)
|
|
383
|
+
return yield* failure("start", "denied");
|
|
384
|
+
|
|
385
|
+
const tail = yield* deps.store
|
|
386
|
+
.inspectTail(ThreadTailRequest.make({ threadId: selected.threadId }))
|
|
387
|
+
.pipe(Effect.mapError(storageFailure("start")));
|
|
388
|
+
|
|
389
|
+
const execution = yield* deps.store
|
|
390
|
+
.read({
|
|
391
|
+
threadId: selected.threadId,
|
|
392
|
+
selection: {
|
|
393
|
+
_tag: "WorkerExecution",
|
|
394
|
+
expectedTailSequence: tail.tailSequence,
|
|
395
|
+
expectedTailDigest: tail.tailDigest,
|
|
396
|
+
},
|
|
397
|
+
page: { limit: 2 },
|
|
398
|
+
})
|
|
399
|
+
.pipe(Stream.runCollect, Effect.mapError(storageFailure("start")));
|
|
400
|
+
|
|
401
|
+
const run = execution.find(({ record }) => record.payload._tag === "RunStarted")?.record
|
|
402
|
+
.payload;
|
|
403
|
+
|
|
404
|
+
if (run?._tag !== "RunStarted") return yield* failure("start", "corrupt");
|
|
405
|
+
|
|
406
|
+
const input = Option.getOrUndefined(
|
|
407
|
+
yield* getRunInput({ threadId: selected.threadId, runId: run.runId }).pipe(
|
|
408
|
+
Effect.provideService(ThreadStore, deps.store),
|
|
409
|
+
Effect.mapError(storageFailure("start")),
|
|
410
|
+
),
|
|
411
|
+
)?.record.payload;
|
|
412
|
+
|
|
413
|
+
if (input?._tag !== "UserInputRecorded" || input.submissionId === undefined)
|
|
414
|
+
return yield* failure("start", "corrupt");
|
|
415
|
+
|
|
416
|
+
const found = yield* deps.ledger
|
|
417
|
+
.lookup(SubmissionLookupById.make({ submissionId: input.submissionId }))
|
|
418
|
+
.pipe(Effect.mapError(storageFailure("start")));
|
|
419
|
+
|
|
420
|
+
const row = Option.getOrUndefined(found);
|
|
421
|
+
|
|
422
|
+
const settlement = Option.getOrUndefined(
|
|
423
|
+
yield* exactRecord(
|
|
424
|
+
selected.threadId,
|
|
425
|
+
submissionSettlementRecordId(input.submissionId),
|
|
426
|
+
"start",
|
|
427
|
+
),
|
|
428
|
+
)?.record.payload;
|
|
429
|
+
|
|
430
|
+
if (
|
|
431
|
+
row === undefined ||
|
|
432
|
+
row.threadId !== selected.threadId ||
|
|
433
|
+
row.state !== "settled" ||
|
|
434
|
+
row.settledOutcome !== "completed" ||
|
|
435
|
+
row.workerAdmission === undefined ||
|
|
436
|
+
!sameOrigin(row.workerAdmission.origin, origin) ||
|
|
437
|
+
settlement?._tag !== "SubmissionSettled" ||
|
|
438
|
+
settlement.outcome !== "completed" ||
|
|
439
|
+
settlement.runDisposition !== "completed" ||
|
|
440
|
+
settlement.finishReason !== undefined ||
|
|
441
|
+
settlement.runId !== run.runId ||
|
|
442
|
+
settlement.submissionId !== row.submissionId ||
|
|
443
|
+
settlement.receiptId !== row.receiptId
|
|
444
|
+
)
|
|
445
|
+
return yield* failure("start", "denied");
|
|
446
|
+
|
|
447
|
+
const evidence = WorkerContinuation.make({
|
|
448
|
+
worker: selected,
|
|
449
|
+
receipt: Receipt.make({
|
|
450
|
+
threadId: row.threadId,
|
|
451
|
+
submissionId: row.submissionId,
|
|
452
|
+
receiptId: row.receiptId,
|
|
453
|
+
queueSequence: row.queueSequence,
|
|
454
|
+
}),
|
|
455
|
+
settlementId: settlement.settlementId,
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
if (expected !== undefined && !Schema.toEquivalence(WorkerContinuation)(expected, evidence))
|
|
459
|
+
return yield* failure("start", "worker-mismatch");
|
|
460
|
+
|
|
461
|
+
return { evidence, origin };
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
const verifyContinuation = Effect.fn("WorkerHost.verifyContinuation")(function* (
|
|
465
|
+
origin: WorkerOrigin,
|
|
466
|
+
) {
|
|
467
|
+
if (origin.continuationOf === undefined) return;
|
|
468
|
+
|
|
469
|
+
const previous = yield* completedContinuation(
|
|
470
|
+
origin.source,
|
|
471
|
+
origin.continuationOf.worker,
|
|
472
|
+
origin.worker.targetAgentId,
|
|
473
|
+
origin.worker.delegationId,
|
|
474
|
+
origin.continuationOf,
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
if (
|
|
478
|
+
origin.worker.threadId === previous.origin.worker.threadId ||
|
|
479
|
+
origin.lifecycle !== "assignment" ||
|
|
480
|
+
!samePolicy(origin.policy, previous.origin.policy) ||
|
|
481
|
+
!Schema.toEquivalence(WorkerOrigin.fields.budget)(origin.budget, previous.origin.budget) ||
|
|
482
|
+
!Schema.toEquivalence(SubagentGrant)(origin.grant, previous.origin.grant) ||
|
|
483
|
+
origin.budgetScope !== previous.origin.budgetScope ||
|
|
484
|
+
origin.depth !== previous.origin.depth ||
|
|
485
|
+
origin.toolCallAllowance !== previous.origin.toolCallAllowance ||
|
|
486
|
+
origin.expiresAtMillis > previous.origin.expiresAtMillis
|
|
487
|
+
)
|
|
488
|
+
return yield* failure("start", "denied");
|
|
489
|
+
});
|
|
490
|
+
|
|
324
491
|
const readIdentity = Effect.fn("WorkerHost.readIdentity")(function* (
|
|
325
492
|
threadId: ThreadId,
|
|
326
493
|
operation: WorkerError["operation"],
|
|
@@ -885,6 +1052,8 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
885
1052
|
retainedFrameworkInput: boolean,
|
|
886
1053
|
): Effect.fn.Return<void, WorkerError> {
|
|
887
1054
|
const origin = admission.origin;
|
|
1055
|
+
|
|
1056
|
+
yield* verifyContinuation(origin);
|
|
888
1057
|
const id = workerInputRecordId(admission.messageId);
|
|
889
1058
|
|
|
890
1059
|
for (let attempt = 0; attempt < 16; attempt++) {
|
|
@@ -895,6 +1064,16 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
895
1064
|
);
|
|
896
1065
|
|
|
897
1066
|
const current = source.current;
|
|
1067
|
+
|
|
1068
|
+
if (
|
|
1069
|
+
origin.continuationOf !== undefined &&
|
|
1070
|
+
current.records.some(
|
|
1071
|
+
({ record }) =>
|
|
1072
|
+
record.payload._tag === "WorkerStopRequested" &&
|
|
1073
|
+
record.payload.command.worker.threadId === origin.continuationOf?.worker.threadId,
|
|
1074
|
+
)
|
|
1075
|
+
)
|
|
1076
|
+
return yield* failure("start", "denied");
|
|
898
1077
|
const rows = requests(current.records);
|
|
899
1078
|
const existing = current.records.find(({ record }) => record.recordId === id)?.record.payload;
|
|
900
1079
|
|
|
@@ -955,6 +1134,9 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
955
1134
|
? {
|
|
956
1135
|
...targetRequest,
|
|
957
1136
|
_tag: "InitialInput",
|
|
1137
|
+
...(origin.continuationOf === undefined
|
|
1138
|
+
? {}
|
|
1139
|
+
: { continuationOf: origin.continuationOf }),
|
|
958
1140
|
input,
|
|
959
1141
|
inputDigest,
|
|
960
1142
|
...(source.submission === undefined ? {} : { sourceSubmission: source.submission }),
|
|
@@ -1057,6 +1239,7 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
1057
1239
|
const selectedConcurrency = yield* deps.concurrencyResolver.resolve({
|
|
1058
1240
|
source: origin.source,
|
|
1059
1241
|
worker: origin.worker,
|
|
1242
|
+
...(origin.continuationOf === undefined ? {} : { continuationOf: origin.continuationOf }),
|
|
1060
1243
|
principal,
|
|
1061
1244
|
...(source.submission === undefined ? {} : { sourceSubmission: source.submission }),
|
|
1062
1245
|
});
|
|
@@ -1168,6 +1351,7 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
1168
1351
|
yield* validateCompletion(options.messageAdmission, options, agentId, inputDigest);
|
|
1169
1352
|
}
|
|
1170
1353
|
|
|
1354
|
+
yield* verifyContinuation(admission.origin);
|
|
1171
1355
|
yield* deps.authorizer.authorize({
|
|
1172
1356
|
sourceThreadId: admission.origin.source.threadId,
|
|
1173
1357
|
...(admission.sourceSubmissionId === undefined
|
|
@@ -1177,6 +1361,9 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
1177
1361
|
operation: "start",
|
|
1178
1362
|
access: "send",
|
|
1179
1363
|
worker: admission.origin.worker,
|
|
1364
|
+
...(admission.origin.continuationOf === undefined
|
|
1365
|
+
? {}
|
|
1366
|
+
: { continuationOf: admission.origin.continuationOf }),
|
|
1180
1367
|
});
|
|
1181
1368
|
yield* authorizeBudget(admission.origin, options.principal);
|
|
1182
1369
|
if (
|
|
@@ -1440,7 +1627,11 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
1440
1627
|
},
|
|
1441
1628
|
};
|
|
1442
1629
|
|
|
1443
|
-
const projection = yield* Effect.suspend(() =>
|
|
1630
|
+
const projection = yield* Effect.suspend(() =>
|
|
1631
|
+
descriptor.reportCompletion?.(report) === false
|
|
1632
|
+
? Effect.succeed(undefined)
|
|
1633
|
+
: descriptor.prepare(report),
|
|
1634
|
+
).pipe(
|
|
1444
1635
|
Effect.timeout(
|
|
1445
1636
|
Math.min(deps.limits.reportPreparationTimeoutMillis ?? 5_000, deadlineAtMillis - now),
|
|
1446
1637
|
),
|
|
@@ -1457,6 +1648,8 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
1457
1648
|
|
|
1458
1649
|
if (projection._tag === "WorkerReportRefused") return projection;
|
|
1459
1650
|
|
|
1651
|
+
if (projection.value === undefined) return refused("filtered");
|
|
1652
|
+
|
|
1460
1653
|
const message = projection.value.message;
|
|
1461
1654
|
|
|
1462
1655
|
if (!Schema.is(WorkerCompletion)(message)) return refused("input");
|
|
@@ -1678,6 +1871,7 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
1678
1871
|
operation: WorkerError["operation"],
|
|
1679
1872
|
access: "context" | "read" | "send" | "control",
|
|
1680
1873
|
worker?: WorkerRef,
|
|
1874
|
+
continuationOf?: WorkerContinuation,
|
|
1681
1875
|
) =>
|
|
1682
1876
|
deps.authorizer.authorize({
|
|
1683
1877
|
sourceThreadId: context.source.threadId,
|
|
@@ -1686,6 +1880,7 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
1686
1880
|
operation,
|
|
1687
1881
|
access,
|
|
1688
1882
|
...(worker === undefined ? {} : { worker }),
|
|
1883
|
+
...(continuationOf === undefined ? {} : { continuationOf }),
|
|
1689
1884
|
});
|
|
1690
1885
|
|
|
1691
1886
|
const binding = (target: Agent.AnyDefinition, operation: WorkerError["operation"]) =>
|
|
@@ -1699,6 +1894,7 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
1699
1894
|
const preparedTarget = Effect.fn("WorkerHost.preparedTarget")(function* (
|
|
1700
1895
|
target: Agent.AnyDefinition,
|
|
1701
1896
|
encodedInput: unknown,
|
|
1897
|
+
continuationOf?: WorkerContinuation,
|
|
1702
1898
|
) {
|
|
1703
1899
|
const resolved = yield* binding(target, "start");
|
|
1704
1900
|
|
|
@@ -1715,6 +1911,7 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
1715
1911
|
|
|
1716
1912
|
const policy = yield* resolveTargetPolicy({
|
|
1717
1913
|
_tag: "InitialInput",
|
|
1914
|
+
...(continuationOf === undefined ? {} : { continuationOf }),
|
|
1718
1915
|
definition: resolved.definition,
|
|
1719
1916
|
definitions: resolved.digests,
|
|
1720
1917
|
source: context.source,
|
|
@@ -2187,14 +2384,35 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
2187
2384
|
};
|
|
2188
2385
|
}),
|
|
2189
2386
|
resolveTargetPolicy: Effect.fn("WorkerHost.resolvePreparedTargetPolicy")(function* (request) {
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2387
|
+
const previous =
|
|
2388
|
+
request.continuationOf === undefined
|
|
2389
|
+
? undefined
|
|
2390
|
+
: yield* completedContinuation(
|
|
2391
|
+
context.source,
|
|
2392
|
+
request.continuationOf,
|
|
2393
|
+
request.target.id,
|
|
2394
|
+
request.continuationOf.delegationId,
|
|
2395
|
+
);
|
|
2396
|
+
|
|
2397
|
+
yield* authorize("start", "send", undefined, previous?.evidence);
|
|
2398
|
+
|
|
2399
|
+
return (yield* preparedTarget(request.target, request.encodedInput, previous?.evidence))
|
|
2400
|
+
.policy;
|
|
2193
2401
|
}),
|
|
2194
2402
|
start: Effect.fn("WorkerHost.start")(function* <E = never, R = never>(
|
|
2195
2403
|
command: StartWorkerRequest | DeferredStartWorkerRequest<E, R>,
|
|
2196
2404
|
): Effect.fn.Return<WorkerStarted, WorkerError | E, R> {
|
|
2197
|
-
const
|
|
2405
|
+
const previous =
|
|
2406
|
+
command.continuationOf === undefined
|
|
2407
|
+
? undefined
|
|
2408
|
+
: yield* completedContinuation(
|
|
2409
|
+
context.source,
|
|
2410
|
+
command.continuationOf,
|
|
2411
|
+
command.target.id,
|
|
2412
|
+
command.delegationId,
|
|
2413
|
+
);
|
|
2414
|
+
|
|
2415
|
+
const principal = yield* authorize("start", "send", undefined, previous?.evidence);
|
|
2198
2416
|
|
|
2199
2417
|
if (context.depth !== 0 && sourceSubmissionId === undefined)
|
|
2200
2418
|
return yield* failure("start", "denied");
|
|
@@ -2221,7 +2439,23 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
2221
2439
|
|
|
2222
2440
|
const replay = (saved: MessageDeliveryRecord) =>
|
|
2223
2441
|
Effect.gen(function* () {
|
|
2224
|
-
const
|
|
2442
|
+
const currentPrevious =
|
|
2443
|
+
command.continuationOf === undefined
|
|
2444
|
+
? undefined
|
|
2445
|
+
: yield* completedContinuation(
|
|
2446
|
+
context.source,
|
|
2447
|
+
command.continuationOf,
|
|
2448
|
+
command.target.id,
|
|
2449
|
+
command.delegationId,
|
|
2450
|
+
previous?.evidence,
|
|
2451
|
+
);
|
|
2452
|
+
|
|
2453
|
+
const replayPrincipal = yield* authorize(
|
|
2454
|
+
"start",
|
|
2455
|
+
"send",
|
|
2456
|
+
undefined,
|
|
2457
|
+
currentPrevious?.evidence,
|
|
2458
|
+
);
|
|
2225
2459
|
|
|
2226
2460
|
yield* binding(command.target, "start");
|
|
2227
2461
|
const metadata = saved.envelope.workerAdmission;
|
|
@@ -2230,6 +2464,10 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
2230
2464
|
const origin = metadata.origin;
|
|
2231
2465
|
|
|
2232
2466
|
if (
|
|
2467
|
+
!Schema.toEquivalence(Schema.UndefinedOr(WorkerContinuation))(
|
|
2468
|
+
origin.continuationOf,
|
|
2469
|
+
currentPrevious?.evidence,
|
|
2470
|
+
) ||
|
|
2233
2471
|
origin.firstMessageId !== messageId ||
|
|
2234
2472
|
metadata.messageId !== messageId ||
|
|
2235
2473
|
origin.source.threadId !== context.source.threadId ||
|
|
@@ -2249,6 +2487,8 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
2249
2487
|
)
|
|
2250
2488
|
return yield* failure("start", "idempotency-conflict");
|
|
2251
2489
|
|
|
2490
|
+
yield* verifyContinuation(origin);
|
|
2491
|
+
|
|
2252
2492
|
return {
|
|
2253
2493
|
worker: origin.worker,
|
|
2254
2494
|
delivery: yield* send(
|
|
@@ -2270,7 +2510,34 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
2270
2510
|
const request =
|
|
2271
2511
|
"prepare" in command ? { ...(yield* command.prepare), ...command } : command;
|
|
2272
2512
|
|
|
2273
|
-
const
|
|
2513
|
+
const currentPrevious =
|
|
2514
|
+
command.continuationOf === undefined
|
|
2515
|
+
? undefined
|
|
2516
|
+
: yield* completedContinuation(
|
|
2517
|
+
context.source,
|
|
2518
|
+
command.continuationOf,
|
|
2519
|
+
command.target.id,
|
|
2520
|
+
command.delegationId,
|
|
2521
|
+
previous?.evidence,
|
|
2522
|
+
);
|
|
2523
|
+
|
|
2524
|
+
if (currentPrevious !== undefined) {
|
|
2525
|
+
const preparedPrincipal = yield* authorize(
|
|
2526
|
+
"start",
|
|
2527
|
+
"send",
|
|
2528
|
+
undefined,
|
|
2529
|
+
currentPrevious.evidence,
|
|
2530
|
+
);
|
|
2531
|
+
|
|
2532
|
+
if (preparedPrincipal !== principal) return yield* failure("start", "denied");
|
|
2533
|
+
}
|
|
2534
|
+
|
|
2535
|
+
const prepared = yield* preparedTarget(
|
|
2536
|
+
request.target,
|
|
2537
|
+
request.encodedInput,
|
|
2538
|
+
currentPrevious?.evidence,
|
|
2539
|
+
);
|
|
2540
|
+
|
|
2274
2541
|
const resolved = prepared.resolved;
|
|
2275
2542
|
|
|
2276
2543
|
const sourcePolicy = Option.getOrElse(
|
|
@@ -2304,6 +2571,9 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
2304
2571
|
threadId: Schema.decodeSync(ThreadId)(messageId),
|
|
2305
2572
|
},
|
|
2306
2573
|
source: context.source,
|
|
2574
|
+
...(currentPrevious === undefined
|
|
2575
|
+
? {}
|
|
2576
|
+
: { continuationOf: currentPrevious.evidence }),
|
|
2307
2577
|
...(resolved.definition.runDisposition?.workerLifecycle === "assignment"
|
|
2308
2578
|
? { lifecycle: "assignment" }
|
|
2309
2579
|
: {}),
|
|
@@ -2315,7 +2585,10 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
2315
2585
|
depth: context.depth + 1,
|
|
2316
2586
|
firstMessageId: messageId,
|
|
2317
2587
|
createdAtMillis: now,
|
|
2318
|
-
expiresAtMillis:
|
|
2588
|
+
expiresAtMillis: Math.min(
|
|
2589
|
+
now + deps.limits.lifetimeMillis,
|
|
2590
|
+
currentPrevious?.origin.expiresAtMillis ?? Infinity,
|
|
2591
|
+
),
|
|
2319
2592
|
...(reporting === undefined ? {} : { reporting }),
|
|
2320
2593
|
...(request.toolCallAllowance === undefined
|
|
2321
2594
|
? {}
|
|
@@ -2798,7 +3071,7 @@ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
|
|
|
2798
3071
|
...(sourceSubmissionId === undefined ? {} : { sourceSubmissionId }),
|
|
2799
3072
|
principal: options.principal,
|
|
2800
3073
|
operation: "followUp",
|
|
2801
|
-
access: "
|
|
3074
|
+
access: "report",
|
|
2802
3075
|
worker: receiving?.origin.worker ?? origin.worker,
|
|
2803
3076
|
});
|
|
2804
3077
|
|
|
@@ -27,6 +27,8 @@ import {
|
|
|
27
27
|
/** Prepared values cross this port only to be Schema-decoded before durable storage. */
|
|
28
28
|
export interface StartWorkerRequest {
|
|
29
29
|
readonly delegationId: DelegationId;
|
|
30
|
+
/** Start a distinct assignment using verified completed predecessor authority. */
|
|
31
|
+
readonly continuationOf?: WorkerRef;
|
|
30
32
|
readonly target: Agent.AnyDefinition;
|
|
31
33
|
readonly idempotencyKey: IdempotencyKey;
|
|
32
34
|
readonly encodedInput: unknown;
|
|
@@ -50,6 +52,7 @@ export interface StartWorkerRequest {
|
|
|
50
52
|
export interface DeferredStartWorkerRequest<E = never, R = never> extends Pick<
|
|
51
53
|
StartWorkerRequest,
|
|
52
54
|
| "delegationId"
|
|
55
|
+
| "continuationOf"
|
|
53
56
|
| "target"
|
|
54
57
|
| "idempotencyKey"
|
|
55
58
|
| "encodedParameters"
|
|
@@ -140,6 +143,8 @@ export interface WorkerReporting<E = never, R = never> {
|
|
|
140
143
|
readonly target: Agent.AnyDefinition;
|
|
141
144
|
/** Pure first-emission selection. False retains the canonical update without parent delivery. */
|
|
142
145
|
readonly reportUpdate?: (update: Update) => boolean;
|
|
146
|
+
/** False retains a filtered report receipt without waking the parent. */
|
|
147
|
+
readonly reportCompletion?: (report: WorkerRunReport) => boolean;
|
|
143
148
|
readonly prepare: (report: WorkerRunReport) => Effect.Effect<
|
|
144
149
|
{
|
|
145
150
|
readonly message: WorkerCompletion;
|
|
@@ -165,6 +170,7 @@ export class SubagentHost extends Context.Service<
|
|
|
165
170
|
readonly context: Effect.Effect<WorkerContext, WorkerError>;
|
|
166
171
|
/** Resolve prepared input through host authority; None retains legacy target inheritance. */
|
|
167
172
|
readonly resolveTargetPolicy: (request: {
|
|
173
|
+
readonly continuationOf?: WorkerRef;
|
|
168
174
|
readonly target: Agent.AnyDefinition;
|
|
169
175
|
readonly encodedInput: unknown;
|
|
170
176
|
}) => Effect.Effect<Option.Option<AgentPolicy>, WorkerError>;
|