effect-agent 0.1.0-beta.157 → 0.1.0-beta.159
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/{Admin-BbTZHSLu.d.mts → Admin-DWDYlvvZ.d.mts} +15 -19
- package/dist/{Agent-BCyrGaWg.d.mts → Agent-ZfnNCQXs.d.mts} +2 -2
- package/dist/{AgentPolicy-CnXWWwdg.d.mts → AgentPolicy-B4oH8TbG.d.mts} +13 -1
- package/dist/{AgentRuntime-GQACxY_m.mjs → AgentRuntime-CVMHysXm.mjs} +52 -12
- package/dist/AgentRuntime-CVMHysXm.mjs.map +1 -0
- package/dist/{AgentRuntime-BPlAn5nA.d.mts → AgentRuntime-D1MmB_0z.d.mts} +10 -10
- package/dist/{ContextCompactor-CPlStZRc.d.mts → ContextCompactor-BoKQOjr5.d.mts} +2 -2
- package/dist/{Digest-CNHImGy0.d.mts → Digest-COAt3Orl.d.mts} +2 -2
- package/dist/{DurableAgentRuntime-BAQvZK1e.mjs → DurableAgentRuntime-C7A5guvq.mjs} +60 -30
- package/dist/DurableAgentRuntime-C7A5guvq.mjs.map +1 -0
- package/dist/{EventSource-CETtQTiH.d.mts → EventSource-BfNZBG4A.d.mts} +3 -3
- package/dist/{Messaging-Dkg87ebg.d.mts → Messaging-7VXQnWI3.d.mts} +2 -2
- package/dist/{Messaging-B1zumorg.d.mts → Messaging-CICd_CSi.d.mts} +4 -4
- package/dist/{MessagingHost-B4jqlJmx.d.mts → MessagingHost-DXwWnrMh.d.mts} +4 -4
- package/dist/{Output-WL7JexCm.d.mts → Output-CY7NZByV.d.mts} +2 -2
- package/dist/{PreparedInputAdmission-Swp9t800.d.mts → PreparedInputAdmission-VStpn8u2.d.mts} +4 -4
- package/dist/{Records-BxGWRs-t.d.mts → Records-Bm4Qt70a.d.mts} +3 -3
- package/dist/{RunEventSink-DsbcGXog.d.mts → RunEventSink-9CUdI9Ar.d.mts} +2 -2
- package/dist/{RunOptions-GjDlAuKh.d.mts → RunOptions-BHmBa05n.d.mts} +6 -6
- package/dist/{Schedule-B94iS2X3.d.mts → Schedule-Bi_XVKLF.d.mts} +2 -2
- package/dist/{Subagent-CLaMeZKu.d.mts → Subagent-D59om8SR.d.mts} +11 -13
- package/dist/{Subagent-JjcidJ7q.mjs → Subagent-DH6G120f.mjs} +3 -6
- package/dist/Subagent-DH6G120f.mjs.map +1 -0
- package/dist/{SubagentContract-DdT7Cqe6.d.mts → SubagentContract-tyN9v-Jv.d.mts} +3 -7
- package/dist/{SubagentHost--HBuY8fF.d.mts → SubagentHost-VTyf_wEF.d.mts} +6 -6
- package/dist/{Subscription-DaMCppa_.d.mts → Subscription-Bx1ZRRVS.d.mts} +6 -6
- package/dist/{SubscriptionInput-B0ZtrQoY.d.mts → SubscriptionInput-B5k5vb1S.d.mts} +3 -3
- package/dist/{Worker-2r2zGDkh.d.mts → Worker-XEBYxRQv.d.mts} +3 -3
- package/dist/capabilities/Commands.d.mts +1 -1
- package/dist/capabilities/ContextTools.d.mts +1 -135
- package/dist/capabilities/ContextTools.mjs +1 -40
- package/dist/capabilities/ContextTools.mjs.map +1 -1
- package/dist/capabilities/Messaging.d.mts +2 -2
- package/dist/capabilities/RunHooks.d.mts +1 -1
- package/dist/capabilities/Subagent.d.mts +4 -4
- package/dist/capabilities/Subagent.mjs +2 -2
- package/dist/capabilities/SubagentReservations.d.mts +1 -1
- package/dist/core/Agent.d.mts +1 -1
- package/dist/core/AgentPolicy.d.mts +1 -1
- package/dist/core/AgentPolicy.mjs +6 -0
- package/dist/core/AgentPolicy.mjs.map +1 -1
- package/dist/core/SubagentContract.d.mts +2 -2
- package/dist/core/SubagentContract.mjs +1 -7
- package/dist/core/SubagentContract.mjs.map +1 -1
- package/dist/core/Worker.d.mts +2 -2
- 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 -3
- 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/LifecyclePublication.d.mts +1 -1
- package/dist/durable/MessageDelivery.d.mts +26 -12
- package/dist/durable/MessageDelivery.mjs +49 -17
- package/dist/durable/MessageDelivery.mjs.map +1 -1
- package/dist/durable/MessageDeliveryStoreConformance.d.mts +7 -7
- package/dist/durable/PersistentHistory.d.mts +1 -1
- package/dist/durable/PreparedInputAdmission.d.mts +1 -1
- package/dist/durable/Records.d.mts +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 -3
- package/dist/durable/SubmissionLedger.d.mts +1 -1
- package/dist/durable/SubmissionLedgerConformance.d.mts +2 -2
- 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 -4
- package/dist/durable/SubscriptionTransition.d.mts +1 -1
- package/dist/durable/Subscriptions.d.mts +6 -6
- package/dist/durable/ThreadContextHistory.d.mts +1 -1
- package/dist/durable/ThreadContextHistoryProjection.d.mts +1 -1
- package/dist/durable/ThreadInvariants.d.mts +2 -2
- 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/WorkerAdmission.d.mts +4 -4
- package/dist/durable/WorkerHost.d.mts +6 -6
- package/dist/engine/AgentRuntime.d.mts +1 -1
- package/dist/engine/AgentRuntime.mjs +1 -1
- package/dist/engine/Compaction.d.mts +1 -1
- package/dist/engine/ContextCompactor.d.mts +1 -1
- package/dist/engine/MessagingHost.d.mts +1 -1
- package/dist/engine/Output.d.mts +1 -1
- package/dist/engine/RunEventSink.d.mts +1 -1
- package/dist/engine/RunOptions.d.mts +1 -1
- package/dist/engine/SubagentHost.d.mts +1 -1
- package/dist/index.d.mts +21 -21
- package/dist/index.mjs +3 -3
- package/package.json +1 -1
- package/src/capabilities/ContextTools.ts +0 -55
- package/src/capabilities/Subagent.ts +0 -3
- package/src/core/AgentPolicy.ts +6 -0
- package/src/core/SubagentContract.ts +0 -7
- package/src/durable/DurableAgentRuntime.ts +100 -121
- package/src/durable/MessageDelivery.ts +64 -20
- package/src/engine/internal/agent-runtime.ts +109 -30
- package/dist/AgentRuntime-GQACxY_m.mjs.map +0 -1
- package/dist/DurableAgentRuntime-BAQvZK1e.mjs.map +0 -1
- package/dist/Subagent-JjcidJ7q.mjs.map +0 -1
package/src/core/AgentPolicy.ts
CHANGED
|
@@ -67,6 +67,12 @@ const AgentPolicyFields = Schema.Struct({
|
|
|
67
67
|
runStatus: Schema.Literals(["appended", "off"]),
|
|
68
68
|
/** Restart a disposable model call on joined input, at most twice per Run. Default off. */
|
|
69
69
|
restartOnJoinedInput: Schema.optionalKey(Schema.Boolean),
|
|
70
|
+
/**
|
|
71
|
+
* Retries per model call after a retryable `AiError` or a 429/5xx stream error part,
|
|
72
|
+
* before any content. Provider-defined Tools must be `Tool.Readonly`. Exponential
|
|
73
|
+
* backoff honors longer `retryAfter` delays and counts toward `maxDuration`. Default 0.
|
|
74
|
+
*/
|
|
75
|
+
modelRetries: Schema.optionalKey(NonNegativeInt),
|
|
70
76
|
compaction: CompactionPolicy,
|
|
71
77
|
}).check(
|
|
72
78
|
Schema.makeFilter((policy) =>
|
|
@@ -77,13 +77,6 @@ export type SubagentBudgetReservation = typeof SubagentBudgetReservation.Type;
|
|
|
77
77
|
export const DelegationDepth = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1));
|
|
78
78
|
export type DelegationDepth = typeof DelegationDepth.Type;
|
|
79
79
|
|
|
80
|
-
/** @deprecated Names are application-owned; use DelegationTool metadata for classification. */
|
|
81
|
-
export const delegationToolPrefix = "delegate_";
|
|
82
|
-
|
|
83
|
-
/** @deprecated Checks a legacy spelling only, never execution, nesting or recovery semantics. */
|
|
84
|
-
export const isDelegationToolName = (toolName: string): boolean =>
|
|
85
|
-
toolName.startsWith(delegationToolPrefix);
|
|
86
|
-
|
|
87
80
|
/** Marks a Tool implementing the idempotent Subagent establishment protocol. */
|
|
88
81
|
export const DelegationTool = Context.Reference<boolean>("@effect-agent/core/DelegationTool", {
|
|
89
82
|
defaultValue: () => false,
|
|
@@ -167,6 +167,7 @@ import { makeMessagingRuntime } from "./internal/messaging-host.ts";
|
|
|
167
167
|
import * as ThreadInitialization from "./internal/thread-initialization.ts";
|
|
168
168
|
import { makeWorkerRuntime, WorkerInputControl } from "./internal/worker-host.ts";
|
|
169
169
|
import { WorkerRuntime } from "./internal/worker-runtime.ts";
|
|
170
|
+
import { MessageDeliveryStore } from "./MessageDelivery.ts";
|
|
170
171
|
import {
|
|
171
172
|
OperationAuthorizationRequest,
|
|
172
173
|
OperationAuthorizer,
|
|
@@ -1266,6 +1267,7 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
1266
1267
|
const ledger = yield* SubmissionLedger;
|
|
1267
1268
|
const submissionScheduling = yield* SubmissionScheduling;
|
|
1268
1269
|
const store = yield* ThreadStore;
|
|
1270
|
+
const deliveries = yield* Effect.serviceOption(MessageDeliveryStore);
|
|
1269
1271
|
|
|
1270
1272
|
// Disposable: canonical tail and owner identify the exact projection, never ownership.
|
|
1271
1273
|
// Retain only the most recent view; persisted checkpoints still govern cold recovery.
|
|
@@ -3112,7 +3114,75 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
3112
3114
|
*/
|
|
3113
3115
|
const notifyParentOfChildSettlement = Effect.fn(
|
|
3114
3116
|
"DurableAgentRuntime.notifyParentOfChildSettlement",
|
|
3115
|
-
)(function* (
|
|
3117
|
+
)(function* (
|
|
3118
|
+
submission: SubmissionSnapshot,
|
|
3119
|
+
record: RecordEnvelope,
|
|
3120
|
+
): Effect.fn.Return<void, LedgerError> {
|
|
3121
|
+
const admission = submission.messageAdmission;
|
|
3122
|
+
const worker = submission.workerAdmission;
|
|
3123
|
+
|
|
3124
|
+
const key =
|
|
3125
|
+
admission === undefined
|
|
3126
|
+
? worker === undefined
|
|
3127
|
+
? undefined
|
|
3128
|
+
: {
|
|
3129
|
+
ownerThreadId: worker.origin.source.threadId,
|
|
3130
|
+
messageId: worker.messageId,
|
|
3131
|
+
}
|
|
3132
|
+
: Schema.is(MessageAdmission)(admission)
|
|
3133
|
+
? admission.message
|
|
3134
|
+
: {
|
|
3135
|
+
ownerThreadId:
|
|
3136
|
+
admission._tag === "WorkerCompletion"
|
|
3137
|
+
? admission.report.worker.threadId
|
|
3138
|
+
: admission.worker.threadId,
|
|
3139
|
+
messageId: submission.idempotencyKey,
|
|
3140
|
+
};
|
|
3141
|
+
|
|
3142
|
+
// Commit the destination's exact canonical acknowledgement at the source before
|
|
3143
|
+
// making the ledger terminal. A failed/lost response is replayed during recovery.
|
|
3144
|
+
if (key !== undefined && Option.isSome(deliveries)) {
|
|
3145
|
+
const settled = yield* settlementPayloadFromRecord(record, submission.submissionId);
|
|
3146
|
+
|
|
3147
|
+
yield* deliveries.value
|
|
3148
|
+
.change(key, {
|
|
3149
|
+
_tag: "Complete",
|
|
3150
|
+
nowMillis: yield* Clock.currentTimeMillis,
|
|
3151
|
+
admissionKey: submission.idempotencyKey,
|
|
3152
|
+
inputDigest: submission.inputDigest,
|
|
3153
|
+
receipt: Receipt.make({
|
|
3154
|
+
threadId: submission.threadId,
|
|
3155
|
+
submissionId: submission.submissionId,
|
|
3156
|
+
receiptId: submission.receiptId,
|
|
3157
|
+
queueSequence: submission.queueSequence,
|
|
3158
|
+
}),
|
|
3159
|
+
settlement: Settlement.make({
|
|
3160
|
+
submissionId: settled.submissionId,
|
|
3161
|
+
receiptId: settled.receiptId,
|
|
3162
|
+
settlementId: settled.settlementId,
|
|
3163
|
+
outcome: settled.outcome,
|
|
3164
|
+
settledAt: record.createdAt,
|
|
3165
|
+
...(settled.outcome === "failed" ? { failure: settled.result } : {}),
|
|
3166
|
+
...(settled.usageSummary === undefined ? {} : { usageSummary: settled.usageSummary }),
|
|
3167
|
+
...(settled.runDisposition === undefined
|
|
3168
|
+
? {}
|
|
3169
|
+
: { runDisposition: settled.runDisposition }),
|
|
3170
|
+
}),
|
|
3171
|
+
})
|
|
3172
|
+
.pipe(
|
|
3173
|
+
Effect.catchCause((cause) =>
|
|
3174
|
+
Effect.failCause(
|
|
3175
|
+
Cause.map(cause, (error) =>
|
|
3176
|
+
LedgerError.make({
|
|
3177
|
+
operation: "delivery-completion",
|
|
3178
|
+
message: "Destination acknowledgement remains pending",
|
|
3179
|
+
cause: error,
|
|
3180
|
+
}),
|
|
3181
|
+
),
|
|
3182
|
+
),
|
|
3183
|
+
),
|
|
3184
|
+
);
|
|
3185
|
+
}
|
|
3116
3186
|
if (submission.workerAdmission?.origin.reporting?.mode === "standard")
|
|
3117
3187
|
yield* updateRuntime.repair(submission.threadId).pipe(
|
|
3118
3188
|
Effect.mapError(() =>
|
|
@@ -3227,14 +3297,14 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
3227
3297
|
Effect.asVoid,
|
|
3228
3298
|
);
|
|
3229
3299
|
yield* hit("terminalize:after-canonical-append");
|
|
3230
|
-
yield* notifyParentOfChildSettlement(submission);
|
|
3300
|
+
yield* notifyParentOfChildSettlement(submission, record);
|
|
3231
3301
|
|
|
3232
3302
|
const settlement = yield* ledger.finalizeSettlement(
|
|
3233
3303
|
SettlementFinalization.make({ submissionId, settlementId }),
|
|
3234
3304
|
);
|
|
3235
3305
|
|
|
3236
3306
|
yield* wake.notify(submission.threadId);
|
|
3237
|
-
yield* notifyParentOfChildSettlement(submission);
|
|
3307
|
+
yield* notifyParentOfChildSettlement(submission, record);
|
|
3238
3308
|
|
|
3239
3309
|
return settlement;
|
|
3240
3310
|
});
|
|
@@ -3349,7 +3419,7 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
3349
3419
|
Effect.asVoid,
|
|
3350
3420
|
);
|
|
3351
3421
|
yield* hit("terminalize:after-canonical-append");
|
|
3352
|
-
yield* notifyParentOfChildSettlement(submission);
|
|
3422
|
+
yield* notifyParentOfChildSettlement(submission, reserved.record);
|
|
3353
3423
|
|
|
3354
3424
|
const settlement = yield* ledger.finalizeSettlement(
|
|
3355
3425
|
SettlementFinalization.make({ submissionId, settlementId }),
|
|
@@ -3358,7 +3428,7 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
3358
3428
|
const canonicalSettlement = yield* settlementPayloadFromRecord(reserved.record, submissionId);
|
|
3359
3429
|
|
|
3360
3430
|
yield* wake.notify(submission.threadId);
|
|
3361
|
-
yield* notifyParentOfChildSettlement(submission);
|
|
3431
|
+
yield* notifyParentOfChildSettlement(submission, reserved.record);
|
|
3362
3432
|
yield* settleJoinedSubmissions(ctx, canonicalSettlement);
|
|
3363
3433
|
|
|
3364
3434
|
return materializeSettlement(settlement, reserved.record);
|
|
@@ -3385,7 +3455,7 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
3385
3455
|
);
|
|
3386
3456
|
yield* hit("terminalize:after-canonical-append");
|
|
3387
3457
|
}
|
|
3388
|
-
yield* notifyParentOfChildSettlement(submission);
|
|
3458
|
+
yield* notifyParentOfChildSettlement(submission, reservation.record);
|
|
3389
3459
|
|
|
3390
3460
|
const settlement = yield* ledger.finalizeSettlement(
|
|
3391
3461
|
SettlementFinalization.make({
|
|
@@ -3400,7 +3470,7 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
3400
3470
|
);
|
|
3401
3471
|
|
|
3402
3472
|
yield* wake.notify(submission.threadId);
|
|
3403
|
-
yield* notifyParentOfChildSettlement(submission);
|
|
3473
|
+
yield* notifyParentOfChildSettlement(submission, reservation.record);
|
|
3404
3474
|
yield* settleJoinedSubmissions(ctx, canonicalSettlement);
|
|
3405
3475
|
|
|
3406
3476
|
return materializeSettlement(settlement, reservation.record);
|
|
@@ -3413,7 +3483,7 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
3413
3483
|
): Effect.fn.Return<Settlement, LedgerError | SettlementConflict> {
|
|
3414
3484
|
const canonicalSettlement = yield* settlementPayloadFromRecord(record, submission.submissionId);
|
|
3415
3485
|
|
|
3416
|
-
yield* notifyParentOfChildSettlement(submission);
|
|
3486
|
+
yield* notifyParentOfChildSettlement(submission, record);
|
|
3417
3487
|
|
|
3418
3488
|
const settlement = yield* ledger.finalizeSettlement(
|
|
3419
3489
|
SettlementFinalization.make({
|
|
@@ -3427,7 +3497,7 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
3427
3497
|
);
|
|
3428
3498
|
|
|
3429
3499
|
yield* wake.notify(submission.threadId);
|
|
3430
|
-
yield* notifyParentOfChildSettlement(submission);
|
|
3500
|
+
yield* notifyParentOfChildSettlement(submission, record);
|
|
3431
3501
|
|
|
3432
3502
|
return materializeSettlement(settlement, snapshot.reservation?.record);
|
|
3433
3503
|
});
|
|
@@ -4594,6 +4664,10 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
4594
4664
|
journalMetadata,
|
|
4595
4665
|
);
|
|
4596
4666
|
|
|
4667
|
+
// Do not retain the metadata snapshot across model or Tool waits, including cache hits.
|
|
4668
|
+
// The projected prompt owns its needed context.
|
|
4669
|
+
journalMetadata = undefined;
|
|
4670
|
+
|
|
4597
4671
|
projectedJournal = {
|
|
4598
4672
|
threadId: ctx.threadId,
|
|
4599
4673
|
through: canonicalThrough,
|
|
@@ -8113,14 +8187,21 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
8113
8187
|
const retainControl = controlRecords([submissionId]);
|
|
8114
8188
|
|
|
8115
8189
|
const collectControl = (record: CanonicalRecordEnvelope): boolean => {
|
|
8116
|
-
|
|
8117
|
-
// scoped to ordinary projection, never retained across this Attempt's model waits.
|
|
8118
|
-
if (record.record.payload._tag === "CompactionCreated") journalMetadata = undefined;
|
|
8119
|
-
else journalMetadata?.add(record);
|
|
8190
|
+
journalMetadata?.add(record);
|
|
8120
8191
|
|
|
8121
8192
|
return retainControl(record);
|
|
8122
8193
|
};
|
|
8123
8194
|
|
|
8195
|
+
const takeJournalMetadata = (): JournalMetadata | undefined => {
|
|
8196
|
+
const metadata = journalMetadata?.snapshot();
|
|
8197
|
+
|
|
8198
|
+
// Reuse the validated prefix once, then release compaction payloads before model
|
|
8199
|
+
// waits. An immediate resume falls back to a fresh canonical metadata scan.
|
|
8200
|
+
if (metadata !== undefined && metadata.compactions.length > 0) journalMetadata = undefined;
|
|
8201
|
+
|
|
8202
|
+
return metadata;
|
|
8203
|
+
};
|
|
8204
|
+
|
|
8124
8205
|
let records: ReadonlyArray<CanonicalRecordEnvelope> = yield* Stream.runCollect(
|
|
8125
8206
|
initialView.canonical.pipe(Stream.filter(collectControl)),
|
|
8126
8207
|
);
|
|
@@ -8492,7 +8573,7 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
8492
8573
|
canonical,
|
|
8493
8574
|
tail.tailSequence,
|
|
8494
8575
|
initialView.seed,
|
|
8495
|
-
|
|
8576
|
+
takeJournalMetadata(),
|
|
8496
8577
|
lineage,
|
|
8497
8578
|
approvalDecisionIntents,
|
|
8498
8579
|
currentContracts,
|
|
@@ -11077,55 +11158,10 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
11077
11158
|
return ObligationReport.make({ thresholds, entries, generatedAt });
|
|
11078
11159
|
});
|
|
11079
11160
|
|
|
11080
|
-
const runWorkerImpl = <
|
|
11081
|
-
InputSchema extends Schema.Top,
|
|
11082
|
-
OutputSchema extends Schema.Top,
|
|
11083
|
-
Instructions,
|
|
11084
|
-
Tools extends Record<string, Tool.Any>,
|
|
11085
|
-
Provider,
|
|
11086
|
-
ModelProvides,
|
|
11087
|
-
ModelRequires,
|
|
11088
|
-
InstructionError = InstructionErrorOf<Instructions, InputSchema["Type"]>,
|
|
11089
|
-
InstructionRequirements = InstructionRequirementsOf<Instructions, InputSchema["Type"]>,
|
|
11090
|
-
RunDispositionValue extends
|
|
11091
|
-
| RunDispositionDeclaration<OutputSchema["Type"], Schema.Top>
|
|
11092
|
-
| undefined = undefined,
|
|
11093
|
-
InputPromptValue extends InputPromptSource<InputSchema["Type"], unknown, unknown> | undefined =
|
|
11094
|
-
undefined,
|
|
11095
|
-
UpdatesSchema extends Schema.Top | undefined = undefined,
|
|
11096
|
-
>(
|
|
11097
|
-
agent: RuntimeBinding<
|
|
11098
|
-
InputSchema,
|
|
11099
|
-
OutputSchema,
|
|
11100
|
-
Instructions,
|
|
11101
|
-
Tools,
|
|
11102
|
-
Provider,
|
|
11103
|
-
ModelProvides,
|
|
11104
|
-
ModelRequires,
|
|
11105
|
-
InstructionError,
|
|
11106
|
-
InstructionRequirements,
|
|
11107
|
-
RunDispositionValue,
|
|
11108
|
-
InputPromptValue,
|
|
11109
|
-
UpdatesSchema
|
|
11110
|
-
>,
|
|
11111
|
-
) =>
|
|
11112
|
-
Effect.gen(function* () {
|
|
11113
|
-
// Wake subscriptions may drop hints, so a ledger scan seeds the worklist (persistence §14).
|
|
11114
|
-
const nonterminal = yield* Stream.runCollect(ledger.scanNonterminal);
|
|
11115
|
-
const seen = new Set<ThreadId>();
|
|
11116
|
-
|
|
11117
|
-
for (const submission of nonterminal) {
|
|
11118
|
-
if (seen.has(submission.threadId)) continue;
|
|
11119
|
-
seen.add(submission.threadId);
|
|
11120
|
-
yield* processThreadImpl(agent, submission.threadId);
|
|
11121
|
-
}
|
|
11122
|
-
yield* Stream.runForEach(wake.wakes, (threadId) => processThreadImpl(agent, threadId));
|
|
11123
|
-
});
|
|
11124
|
-
|
|
11125
11161
|
const runResolvedWorkerImpl = Effect.gen(function* () {
|
|
11126
|
-
//
|
|
11127
|
-
//
|
|
11128
|
-
//
|
|
11162
|
+
// Each claimed head selects a current Binding by stable Agent ID and optional host routing.
|
|
11163
|
+
// Original per-operation replay contracts still govern unfinished handlers, while one worker
|
|
11164
|
+
// pool serves both parent and child lanes.
|
|
11129
11165
|
const nonterminal = yield* Stream.runCollect(ledger.scanNonterminal);
|
|
11130
11166
|
const seen = new Set<ThreadId>();
|
|
11131
11167
|
|
|
@@ -11219,7 +11255,6 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
11219
11255
|
processThread: processThreadImpl,
|
|
11220
11256
|
processThreadResolved: processThreadResolvedImpl,
|
|
11221
11257
|
processThreadHead: processThreadHeadImpl,
|
|
11222
|
-
runWorker: runWorkerImpl,
|
|
11223
11258
|
runResolvedWorker: runResolvedWorkerImpl,
|
|
11224
11259
|
runRecovery,
|
|
11225
11260
|
recoverSubmission,
|
|
@@ -11261,11 +11296,8 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (
|
|
|
11261
11296
|
* seam (Joining/Joined, plan §2.5): the queued input becomes canonical (`input:{sid}`) before
|
|
11262
11297
|
* the next model request, reattaches through the prompt-coverage rule after a crash, and the
|
|
11263
11298
|
* joined Submissions settle with the host outcome (DUR-002/DUR-016).
|
|
11264
|
-
* - `
|
|
11265
|
-
*
|
|
11266
|
-
* runs against this binding. Missing bindings leave accepted roots and children owed.
|
|
11267
|
-
* - `processThreadResolved(threadId)` / `runResolvedWorker` — the
|
|
11268
|
-
* equivalents over registrations owned by the runtime Layer: each stable `agentId` selects
|
|
11299
|
+
* - `processThreadResolved(threadId)` / `runResolvedWorker` — drain or continuously process
|
|
11300
|
+
* lanes using registrations owned by the runtime Layer: each stable `agentId` selects
|
|
11269
11301
|
* one current Binding. Unfinished operation contracts gate handler execution independently
|
|
11270
11302
|
* of immutable admission evidence; missing bindings release the claim with a typed refusal.
|
|
11271
11303
|
* - `runRecovery()` — classify every nonterminal Submission with the pure `classifyRecovery` and
|
|
@@ -11468,59 +11500,6 @@ export class DurableAgentRuntime extends Context.Service<
|
|
|
11468
11500
|
threadId: ThreadId,
|
|
11469
11501
|
options?: { readonly yieldAfter?: DateTime.Utc },
|
|
11470
11502
|
) => Effect.Effect<Option.Option<Settlement>, DurableWorkerFailure | DurableBindingFailure>;
|
|
11471
|
-
readonly runWorker: <
|
|
11472
|
-
InputSchema extends Schema.Top,
|
|
11473
|
-
OutputSchema extends Schema.Top,
|
|
11474
|
-
Instructions,
|
|
11475
|
-
Tools extends Record<string, Tool.Any>,
|
|
11476
|
-
Provider,
|
|
11477
|
-
ModelProvides,
|
|
11478
|
-
ModelRequires,
|
|
11479
|
-
InstructionError = InstructionErrorOf<Instructions, InputSchema["Type"]>,
|
|
11480
|
-
InstructionRequirements = InstructionRequirementsOf<Instructions, InputSchema["Type"]>,
|
|
11481
|
-
RunDispositionValue extends
|
|
11482
|
-
| RunDispositionDeclaration<OutputSchema["Type"], Schema.Top>
|
|
11483
|
-
| undefined = undefined,
|
|
11484
|
-
InputPromptValue extends
|
|
11485
|
-
| InputPromptSource<InputSchema["Type"], unknown, unknown>
|
|
11486
|
-
| undefined = undefined,
|
|
11487
|
-
UpdatesSchema extends Schema.Top | undefined = undefined,
|
|
11488
|
-
>(
|
|
11489
|
-
agent: RuntimeBinding<
|
|
11490
|
-
InputSchema,
|
|
11491
|
-
OutputSchema,
|
|
11492
|
-
Instructions,
|
|
11493
|
-
Tools,
|
|
11494
|
-
Provider,
|
|
11495
|
-
ModelProvides,
|
|
11496
|
-
ModelRequires,
|
|
11497
|
-
InstructionError,
|
|
11498
|
-
InstructionRequirements,
|
|
11499
|
-
RunDispositionValue,
|
|
11500
|
-
InputPromptValue,
|
|
11501
|
-
UpdatesSchema
|
|
11502
|
-
>,
|
|
11503
|
-
) => Effect.Effect<
|
|
11504
|
-
void,
|
|
11505
|
-
DurableWorkerFailure | DurableBindingFailure,
|
|
11506
|
-
DurableWorkerRequirements<
|
|
11507
|
-
RuntimeBinding<
|
|
11508
|
-
InputSchema,
|
|
11509
|
-
OutputSchema,
|
|
11510
|
-
Instructions,
|
|
11511
|
-
Tools,
|
|
11512
|
-
Provider,
|
|
11513
|
-
ModelProvides,
|
|
11514
|
-
ModelRequires,
|
|
11515
|
-
InstructionError,
|
|
11516
|
-
InstructionRequirements,
|
|
11517
|
-
RunDispositionValue,
|
|
11518
|
-
InputPromptValue,
|
|
11519
|
-
UpdatesSchema
|
|
11520
|
-
>,
|
|
11521
|
-
InstructionRequirements
|
|
11522
|
-
>
|
|
11523
|
-
>;
|
|
11524
11503
|
readonly runResolvedWorker: Effect.Effect<void, DurableWorkerFailure | DurableBindingFailure>;
|
|
11525
11504
|
/**
|
|
11526
11505
|
* Recover each pending Thread independently. History/child failures, defects and the
|
|
@@ -14,6 +14,8 @@ import { PreparedInput } from "./Subscription.ts";
|
|
|
14
14
|
|
|
15
15
|
const Positive = Schema.Int.check(Schema.isGreaterThan(0));
|
|
16
16
|
const BoundedName = Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(256));
|
|
17
|
+
const receiptsEqual = Schema.toEquivalence(Receipt);
|
|
18
|
+
const settlementsEqual = Schema.toEquivalence(Settlement);
|
|
17
19
|
|
|
18
20
|
/** An owner is always a source Thread. Destination admission has its own frozen key. */
|
|
19
21
|
export const MessageDeliveryKey = Schema.Struct({
|
|
@@ -66,7 +68,12 @@ export const defaultMessageDeliveryStoreLimits: MessageDeliveryStoreLimits = {
|
|
|
66
68
|
maxRetainedUpdatesPerOwner: 256,
|
|
67
69
|
};
|
|
68
70
|
|
|
69
|
-
const ParkReason = Schema.Literals([
|
|
71
|
+
const ParkReason = Schema.Literals([
|
|
72
|
+
"exhausted",
|
|
73
|
+
"deadline",
|
|
74
|
+
"status-unavailable",
|
|
75
|
+
"awaiting-settlement",
|
|
76
|
+
]);
|
|
70
77
|
|
|
71
78
|
export const MessageDeliveryRecord = Schema.Struct({
|
|
72
79
|
schemaVersion: Schema.Literal(1),
|
|
@@ -152,7 +159,20 @@ export const MessageDeliveryFailpoint = Context.Reference<{
|
|
|
152
159
|
|
|
153
160
|
const fence = { expectedVersion: Positive, nowMillis: ScheduleInstant };
|
|
154
161
|
|
|
162
|
+
/** Terminal destination evidence, independent of an expiring source transport claim. */
|
|
163
|
+
export const MessageDeliveryCompletion = Schema.Struct({
|
|
164
|
+
receipt: Receipt,
|
|
165
|
+
settlement: Settlement,
|
|
166
|
+
admissionKey: IdempotencyKey,
|
|
167
|
+
inputDigest: Digest,
|
|
168
|
+
});
|
|
169
|
+
|
|
155
170
|
export const MessageDeliveryChange = Schema.Union([
|
|
171
|
+
Schema.Struct({
|
|
172
|
+
_tag: Schema.Literal("Complete"),
|
|
173
|
+
nowMillis: ScheduleInstant,
|
|
174
|
+
...MessageDeliveryCompletion.fields,
|
|
175
|
+
}),
|
|
156
176
|
Schema.Struct({ _tag: Schema.Literal("Claim"), ...fence }),
|
|
157
177
|
Schema.Struct({ _tag: Schema.Literal("Accept"), ...fence, receipt: Receipt }),
|
|
158
178
|
Schema.Struct({ _tag: Schema.Literal("Process"), ...fence, settlement: Settlement }),
|
|
@@ -424,6 +444,34 @@ export const applyMessageDeliveryChange = (
|
|
|
424
444
|
): Result.Result<MessageDeliveryRecord, MessageDeliveryError> => {
|
|
425
445
|
const conflict = () => Result.fail(error("conflict", change._tag));
|
|
426
446
|
|
|
447
|
+
if (change._tag === "Complete") {
|
|
448
|
+
if (
|
|
449
|
+
change.admissionKey !== record.envelope.admissionKey ||
|
|
450
|
+
change.inputDigest !== record.envelope.inputDigest ||
|
|
451
|
+
change.receipt.threadId !== record.envelope.threadId ||
|
|
452
|
+
change.settlement.submissionId !== change.receipt.submissionId ||
|
|
453
|
+
change.settlement.receiptId !== change.receipt.receiptId ||
|
|
454
|
+
(record.receipt !== null && !receiptsEqual(record.receipt, change.receipt))
|
|
455
|
+
)
|
|
456
|
+
return Result.fail(error("corrupt", "completion-identity"));
|
|
457
|
+
if (record.status === "refused") return conflict();
|
|
458
|
+
if (record.status === "processed")
|
|
459
|
+
return record.settlement !== null && settlementsEqual(record.settlement, change.settlement)
|
|
460
|
+
? Result.succeed(record)
|
|
461
|
+
: Result.fail(error("corrupt", "completion-identity"));
|
|
462
|
+
|
|
463
|
+
return Result.succeed({
|
|
464
|
+
...record,
|
|
465
|
+
version: record.version + 1,
|
|
466
|
+
status: "processed",
|
|
467
|
+
receipt: change.receipt,
|
|
468
|
+
settlement: change.settlement,
|
|
469
|
+
leaseUntilMillis: null,
|
|
470
|
+
parkReason: null,
|
|
471
|
+
retry: { ...record.retry, parked: false },
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
427
475
|
if (record.version !== change.expectedVersion) return conflict();
|
|
428
476
|
if (record.status === "processed" || record.status === "refused") return conflict();
|
|
429
477
|
const now = change.nowMillis;
|
|
@@ -540,21 +588,8 @@ export const applyMessageDeliveryChange = (
|
|
|
540
588
|
}
|
|
541
589
|
if (change._tag === "ObservePending") {
|
|
542
590
|
if (record.status !== "accepted") return conflict();
|
|
543
|
-
if (now >= record.deadlineAtMillis) return Result.succeed(parked("deadline"));
|
|
544
591
|
|
|
545
|
-
return Result.succeed(
|
|
546
|
-
...base,
|
|
547
|
-
leaseUntilMillis: null,
|
|
548
|
-
retry: {
|
|
549
|
-
...record.retry,
|
|
550
|
-
automaticAttempts: 0,
|
|
551
|
-
lastFailure: null,
|
|
552
|
-
nextAttemptAtMillis: Math.min(
|
|
553
|
-
now + record.policy.settlementPollMillis,
|
|
554
|
-
record.deadlineAtMillis,
|
|
555
|
-
),
|
|
556
|
-
},
|
|
557
|
-
});
|
|
592
|
+
return Result.succeed(parked("awaiting-settlement"));
|
|
558
593
|
}
|
|
559
594
|
if (change._tag === "Refuse") {
|
|
560
595
|
if (record.status !== "pending") return conflict();
|
|
@@ -700,9 +735,10 @@ export class MessageDeliveryDriver extends Context.Service<
|
|
|
700
735
|
// Digest computation cannot extend this claim's admission authority.
|
|
701
736
|
if (timeout <= 0) return claimed;
|
|
702
737
|
|
|
703
|
-
type WithoutFence<T> =
|
|
704
|
-
|
|
705
|
-
|
|
738
|
+
type WithoutFence<T> =
|
|
739
|
+
T extends Exclude<MessageDeliveryChange, { _tag: "Complete" }>
|
|
740
|
+
? Omit<T, "expectedVersion" | "nowMillis">
|
|
741
|
+
: never;
|
|
706
742
|
|
|
707
743
|
const commit = (change: WithoutFence<MessageDeliveryChange>) =>
|
|
708
744
|
Clock.currentTimeMillis.pipe(
|
|
@@ -722,8 +758,16 @@ export class MessageDeliveryDriver extends Context.Service<
|
|
|
722
758
|
).pipe(Effect.mapError((cause) => error("corrupt", "admission", cause)));
|
|
723
759
|
|
|
724
760
|
yield* failpoint.hit("message-delivery:admission:after");
|
|
725
|
-
if (outcome._tag === "Receipt")
|
|
726
|
-
|
|
761
|
+
if (outcome._tag === "Receipt") {
|
|
762
|
+
const accepted = yield* commit({ _tag: "Accept", receipt: outcome.receipt });
|
|
763
|
+
|
|
764
|
+
return yield* store.change(key, {
|
|
765
|
+
_tag: "Park",
|
|
766
|
+
reason: "awaiting-settlement",
|
|
767
|
+
expectedVersion: accepted.version,
|
|
768
|
+
nowMillis: yield* Clock.currentTimeMillis,
|
|
769
|
+
});
|
|
770
|
+
}
|
|
727
771
|
if (outcome._tag === "Refused")
|
|
728
772
|
return yield* commit({
|
|
729
773
|
_tag: "Refuse",
|