effect-agent 0.1.0-beta.152 → 0.1.0-beta.154
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-CKIdJoP8.d.mts → Admin-BjmupLN3.d.mts} +36 -17
- package/dist/{Agent-Cjd_ZveM.d.mts → Agent-BCyrGaWg.d.mts} +2 -2
- package/dist/{AgentPolicy-BqDoSXO6.d.mts → AgentPolicy-CnXWWwdg.d.mts} +5 -1
- package/dist/{AgentRuntime-sXpKcyxu.d.mts → AgentRuntime-BAjT5gXl.d.mts} +10 -10
- package/dist/{AgentRuntime-D8U9gl9Q.mjs → AgentRuntime-IF_1GoUf.mjs} +54 -11
- package/dist/AgentRuntime-IF_1GoUf.mjs.map +1 -0
- package/dist/{ContextCompactor-WwSIG_Z2.d.mts → ContextCompactor-CPlStZRc.d.mts} +2 -2
- package/dist/{Digest-U69rDHuO.d.mts → Digest-CaJ2RIsF.d.mts} +2 -2
- package/dist/{DurableAgentRuntime-DQFV26SB.mjs → DurableAgentRuntime-BQzYkFVy.mjs} +185 -88
- package/dist/DurableAgentRuntime-BQzYkFVy.mjs.map +1 -0
- package/dist/{EventSource-CMbXXmwe.d.mts → EventSource-C8CKwQy5.d.mts} +3 -3
- package/dist/InMemory.d.mts +1 -1
- package/dist/{Messaging-ccQURKCf.d.mts → Messaging-B1zumorg.d.mts} +3 -3
- package/dist/{MessagingHost-D04wE-7W.d.mts → MessagingHost-B4jqlJmx.d.mts} +3 -3
- package/dist/{Output-CFD1CPfU.d.mts → Output-WL7JexCm.d.mts} +2 -2
- package/dist/{PreparedInputAdmission-Bt6rgtVu.d.mts → PreparedInputAdmission-CU1PzUVD.d.mts} +4 -4
- package/dist/{Records-B5GFWCpn.d.mts → Records-BrEpibum.d.mts} +17 -6
- package/dist/{RunEvent-DIrzkjLr.d.mts → RunEvent-DV_llBcq.d.mts} +18 -4
- package/dist/{RunJournal-Gd83HYqG.mjs → RunJournal-ixFRCyW3.mjs} +29 -7
- package/dist/RunJournal-ixFRCyW3.mjs.map +1 -0
- package/dist/{RunOptions-Bv9NpkPZ.d.mts → RunOptions-CkRYnlJa.d.mts} +22 -8
- package/dist/{RunPolicyUsage-ClZxyR46.d.mts → RunPolicyUsage-CUudVtg_.d.mts} +3 -1
- package/dist/{Schedule-CtYREFnz.d.mts → Schedule-B_z7PMg-.d.mts} +2 -2
- package/dist/{Subagent-hG9lJ7tJ.mjs → Subagent-CmFtZaeI.mjs} +2 -2
- package/dist/{Subagent-hG9lJ7tJ.mjs.map → Subagent-CmFtZaeI.mjs.map} +1 -1
- package/dist/{Subagent-VHrANXFy.d.mts → Subagent-Dld4W1BY.d.mts} +7 -7
- package/dist/{SubagentHost-C-4A7tA2.d.mts → SubagentHost--HBuY8fF.d.mts} +4 -4
- package/dist/{Subscription-BJAzYNw1.d.mts → Subscription-BomcQ9_W.d.mts} +5 -5
- package/dist/{SubscriptionInput-CkBJt0AS.d.mts → SubscriptionInput-gpZSR9vB.d.mts} +3 -3
- package/dist/{ThreadHistory-tS1KwxHR.d.mts → ThreadHistory-ZEu_ja6L.d.mts} +2 -2
- package/dist/{Worker-fwWkBg12.d.mts → Worker-2r2zGDkh.d.mts} +2 -2
- package/dist/{WorkerAdmission-CJ_oWRuS.mjs → WorkerAdmission-CNbm4o_x.mjs} +3 -3
- package/dist/{WorkerAdmission-CJ_oWRuS.mjs.map → WorkerAdmission-CNbm4o_x.mjs.map} +1 -1
- package/dist/{agent-registration-CKNsrpwo.mjs → agent-registration-U3kmV7nW.mjs} +18 -18
- package/dist/agent-registration-U3kmV7nW.mjs.map +1 -0
- package/dist/capabilities/BrowserUse.d.mts +545 -0
- package/dist/capabilities/BrowserUse.mjs +254 -0
- package/dist/capabilities/BrowserUse.mjs.map +1 -0
- package/dist/capabilities/Commands.d.mts +1 -1
- package/dist/capabilities/Messaging.d.mts +1 -1
- package/dist/capabilities/Redaction.d.mts +1 -1
- package/dist/capabilities/RunHooks.d.mts +1 -1
- package/dist/capabilities/Subagent.d.mts +2 -2
- package/dist/capabilities/Subagent.mjs +1 -1
- package/dist/core/Agent.d.mts +1 -1
- package/dist/core/AgentPolicy.d.mts +1 -1
- package/dist/core/AgentPolicy.mjs +2 -0
- package/dist/core/AgentPolicy.mjs.map +1 -1
- package/dist/core/RunEvent.d.mts +2 -2
- package/dist/core/RunEvent.mjs +10 -1
- package/dist/core/RunEvent.mjs.map +1 -1
- package/dist/core/RunPolicyUsage.d.mts +1 -1
- package/dist/core/RunPolicyUsage.mjs +6 -1
- package/dist/core/RunPolicyUsage.mjs.map +1 -1
- package/dist/core/Worker.d.mts +1 -1
- package/dist/durable/ActivityStore.d.mts +1 -1
- package/dist/durable/Admin.d.mts +1 -1
- package/dist/durable/AgentRegistration.d.mts +2 -2
- package/dist/durable/AgentRegistration.mjs +3 -2
- package/dist/durable/AgentRegistration.mjs.map +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 +2 -2
- 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 +5 -5
- package/dist/durable/MessageDeliveryStoreConformance.d.mts +42 -42
- package/dist/durable/PersistentHistory.d.mts +2 -2
- package/dist/durable/PersistentHistory.mjs +1 -1
- package/dist/durable/PreparedInputAdmission.d.mts +1 -1
- package/dist/durable/Records.d.mts +2 -2
- package/dist/durable/Records.mjs +16 -1
- 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/RunJournal.mjs +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/SubmissionLedgerConformance.mjs +1 -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/SubscriptionInput.mjs +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/ThreadInvariants.mjs +1 -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/ThreadStore.mjs +1 -1
- package/dist/durable/ThreadStoreConformance.d.mts +1 -1
- package/dist/durable/ThreadStoreConformance.mjs +1 -1
- package/dist/durable/WorkerAdmission.d.mts +3 -3
- package/dist/durable/WorkerAdmission.mjs +1 -1
- package/dist/durable/WorkerHost.d.mts +5 -5
- 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/RunOptions.d.mts +1 -1
- package/dist/engine/RunOptions.mjs.map +1 -1
- package/dist/engine/SubagentHost.d.mts +1 -1
- package/dist/engine/ThreadHistory.d.mts +1 -1
- package/dist/index.d.mts +24 -23
- package/dist/index.mjs +7 -6
- package/package.json +1 -1
- package/src/capabilities/BrowserUse.ts +367 -0
- package/src/core/AgentPolicy.ts +2 -0
- package/src/core/RunEvent.ts +9 -0
- package/src/core/RunPolicyUsage.ts +2 -0
- package/src/durable/AgentRegistration.ts +2 -0
- package/src/durable/DurableAgentRuntime.ts +320 -137
- package/src/durable/Records.ts +12 -0
- package/src/durable/RunJournal.ts +88 -27
- package/src/durable/internal/agent-registration.ts +58 -35
- package/src/engine/RunOptions.ts +17 -2
- package/src/engine/internal/agent-runtime.ts +115 -8
- package/src/index.ts +1 -0
- package/dist/AgentRuntime-D8U9gl9Q.mjs.map +0 -1
- package/dist/DurableAgentRuntime-DQFV26SB.mjs.map +0 -1
- package/dist/RunJournal-Gd83HYqG.mjs.map +0 -1
- package/dist/agent-registration-CKNsrpwo.mjs.map +0 -1
package/src/durable/Records.ts
CHANGED
|
@@ -498,6 +498,17 @@ export class ModelResponseInterrupted extends Schema.TaggedClass<ModelResponseIn
|
|
|
498
498
|
reason: BoundedText,
|
|
499
499
|
}) {}
|
|
500
500
|
|
|
501
|
+
/** Disposable call cancellation: no response or Tool declaration is canonical. */
|
|
502
|
+
export class ModelCallAborted extends Schema.TaggedClass<ModelCallAborted>()("ModelCallAborted", {
|
|
503
|
+
runId: RunId,
|
|
504
|
+
turnId: TurnId,
|
|
505
|
+
turn: TurnNumber,
|
|
506
|
+
restart: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 2 })),
|
|
507
|
+
reason: Schema.Literal("joined-input"),
|
|
508
|
+
modelUsage: Schema.Array(ModelCallUsage),
|
|
509
|
+
unobservedModelCalls: Schema.Natural,
|
|
510
|
+
}) {}
|
|
511
|
+
|
|
501
512
|
/**
|
|
502
513
|
* One engine-native compaction committed before the pre-Turn view changes (RUN-026).
|
|
503
514
|
* `coversThrough` is a Thread record sequence: the projection
|
|
@@ -1020,6 +1031,7 @@ export const CanonicalRecordPayload = Schema.Union([
|
|
|
1020
1031
|
ToolApprovalRequested,
|
|
1021
1032
|
ToolApprovalDecided,
|
|
1022
1033
|
ModelResponseInterrupted,
|
|
1034
|
+
ModelCallAborted,
|
|
1023
1035
|
CompactionCreated,
|
|
1024
1036
|
RunFailed,
|
|
1025
1037
|
RunCompleted,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Crypto, Effect, Schema, Stream, type DateTime } from "effect";
|
|
1
|
+
import { type Crypto, Effect, Predicate, Schema, Stream, type DateTime } from "effect";
|
|
2
2
|
import { Prompt } from "effect/unstable/ai";
|
|
3
3
|
|
|
4
4
|
import { ThreadId, RunId, ToolCallId, TurnId, type SubmissionId } from "../core/Identifiers.ts";
|
|
@@ -330,14 +330,34 @@ export const childIdempotencyKeyFor = (
|
|
|
330
330
|
toolCallId: ToolCallId,
|
|
331
331
|
): IdempotencyKey => decodeIdempotencyKey(`subagent:${parentRunId}:${toolCallId}`);
|
|
332
332
|
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
),
|
|
333
|
+
const decodePersistedPrompt = (
|
|
334
|
+
messages: PersistedJson,
|
|
335
|
+
): Effect.Effect<Prompt.Prompt, RunJournalError> =>
|
|
336
|
+
Schema.decodeUnknownEffect(Prompt.Prompt)(messages).pipe(
|
|
337
|
+
Effect.mapError((cause) =>
|
|
338
|
+
journalError("Canonical messages are not Schema-encoded Prompt messages", cause),
|
|
339
339
|
),
|
|
340
|
-
);
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
// Canonical payloads are immutable. Weak keys let retained storage rows own the lifetime
|
|
343
|
+
// while repeated projections of an advancing tail reuse their validated Prompt values.
|
|
344
|
+
const decodedMessages = new WeakMap<object, Prompt.Prompt>();
|
|
345
|
+
|
|
346
|
+
const decodePromptMessages = (messages: PersistedJson) =>
|
|
347
|
+
Effect.suspend(() => {
|
|
348
|
+
if (!Predicate.isObject(messages)) return decodePersistedPrompt(messages);
|
|
349
|
+
const cached = decodedMessages.get(messages);
|
|
350
|
+
|
|
351
|
+
return cached === undefined
|
|
352
|
+
? decodePersistedPrompt(messages).pipe(
|
|
353
|
+
Effect.tap((prompt) =>
|
|
354
|
+
Effect.sync(() => {
|
|
355
|
+
decodedMessages.set(messages, prompt);
|
|
356
|
+
}),
|
|
357
|
+
),
|
|
358
|
+
)
|
|
359
|
+
: Effect.succeed(cached);
|
|
360
|
+
});
|
|
341
361
|
|
|
342
362
|
interface PendingSettledTool {
|
|
343
363
|
readonly record: ToolCallSettled;
|
|
@@ -345,24 +365,24 @@ interface PendingSettledTool {
|
|
|
345
365
|
readonly cleared: boolean;
|
|
346
366
|
}
|
|
347
367
|
|
|
348
|
-
const toolMessageFromSettled =
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
),
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
);
|
|
368
|
+
const toolMessageFromSettled = (
|
|
369
|
+
settled: ReadonlyArray<PendingSettledTool>,
|
|
370
|
+
): Effect.Effect<Prompt.Message, RunJournalError> =>
|
|
371
|
+
Effect.try({
|
|
372
|
+
try: () =>
|
|
373
|
+
Prompt.makeMessage("tool", {
|
|
374
|
+
content: settled.map(({ record, cleared }) =>
|
|
375
|
+
Prompt.makePart("tool-result", {
|
|
376
|
+
id: record.toolCallId,
|
|
377
|
+
name: record.toolName,
|
|
378
|
+
result: cleared ? CLEARED_TOOL_RESULT : record.result,
|
|
379
|
+
isFailure: record.isFailure,
|
|
380
|
+
providerExecuted: false,
|
|
381
|
+
}),
|
|
382
|
+
),
|
|
383
|
+
}),
|
|
384
|
+
catch: (cause) => journalError("Unable to rebuild Tool message from ToolCallSettled", cause),
|
|
385
|
+
});
|
|
366
386
|
|
|
367
387
|
/**
|
|
368
388
|
* Pure canonical projection of one Run's durable execution state.
|
|
@@ -525,6 +545,7 @@ const PROMPT_TRANSPARENT_TAGS: ReadonlySet<string> = new Set([
|
|
|
525
545
|
"ToolApprovalRequested",
|
|
526
546
|
"ToolApprovalDecided",
|
|
527
547
|
"ModelResponseInterrupted",
|
|
548
|
+
"ModelCallAborted",
|
|
528
549
|
"SubagentRequested",
|
|
529
550
|
"SubagentStarted",
|
|
530
551
|
"SubagentJoined",
|
|
@@ -892,6 +913,7 @@ export const projectRunJournalStream = Effect.fn("RunJournal.projectRunJournalSt
|
|
|
892
913
|
programmaticToolCalls: seed?.policyUsage.programmaticToolCalls ?? 0,
|
|
893
914
|
consecutiveToolFailures: seed?.policyUsage.consecutiveToolFailures ?? 0,
|
|
894
915
|
finalizationUsed: seed?.policyUsage.finalizationUsed ?? false,
|
|
916
|
+
modelRestarts: seed?.policyUsage.modelRestarts ?? 0,
|
|
895
917
|
};
|
|
896
918
|
|
|
897
919
|
const accountResponse = Effect.fn("RunJournal.accountResponse")(function* (
|
|
@@ -1020,7 +1042,7 @@ export const projectRunJournalStream = Effect.fn("RunJournal.projectRunJournalSt
|
|
|
1020
1042
|
|
|
1021
1043
|
let pendingToolOrder = new Map<string, number>();
|
|
1022
1044
|
|
|
1023
|
-
const flushTools = Effect.
|
|
1045
|
+
const flushTools = Effect.fnUntraced(function* (
|
|
1024
1046
|
current: FoldState,
|
|
1025
1047
|
): Effect.fn.Return<FoldState, RunJournalError> {
|
|
1026
1048
|
if (current.pendingTools.length === 0) return current;
|
|
@@ -1068,6 +1090,45 @@ export const projectRunJournalStream = Effect.fn("RunJournal.projectRunJournalSt
|
|
|
1068
1090
|
policyUsage.programmaticToolCalls = payload.programmaticToolCalls;
|
|
1069
1091
|
policyUsage.finalizationUsed = payload.finalizationUsed;
|
|
1070
1092
|
}
|
|
1093
|
+
if (payload._tag === "ModelCallAborted" && payload.runId === ownerRunId) {
|
|
1094
|
+
if (seed !== undefined && envelope.sequence <= seed.throughSequence) return;
|
|
1095
|
+
if (payload.restart !== policyUsage.modelRestarts + 1)
|
|
1096
|
+
return yield* journalError("Model restart reservations must advance once");
|
|
1097
|
+
policyUsage.modelRestarts = payload.restart;
|
|
1098
|
+
|
|
1099
|
+
const summary = yield* summarizeModelUsage(payload.modelUsage).pipe(
|
|
1100
|
+
Effect.mapError((cause) =>
|
|
1101
|
+
journalError("Aborted model usage exceeds accounting bounds", cause),
|
|
1102
|
+
),
|
|
1103
|
+
);
|
|
1104
|
+
|
|
1105
|
+
usage.modelCalls = yield* addProjectedUsage(
|
|
1106
|
+
"modelCalls",
|
|
1107
|
+
usage.modelCalls,
|
|
1108
|
+
summary.modelCalls,
|
|
1109
|
+
);
|
|
1110
|
+
usage.inputTokens = yield* addProjectedUsage(
|
|
1111
|
+
"inputTokens",
|
|
1112
|
+
usage.inputTokens,
|
|
1113
|
+
summary.inputTokens.total,
|
|
1114
|
+
);
|
|
1115
|
+
usage.outputTokens = yield* addProjectedUsage(
|
|
1116
|
+
"outputTokens",
|
|
1117
|
+
usage.outputTokens,
|
|
1118
|
+
summary.outputTokens.total,
|
|
1119
|
+
);
|
|
1120
|
+
usage.costMicrousd = yield* addProjectedUsage(
|
|
1121
|
+
"costMicrousd",
|
|
1122
|
+
usage.costMicrousd,
|
|
1123
|
+
summary.costMicrousd,
|
|
1124
|
+
);
|
|
1125
|
+
usage.modelUsage.push(...payload.modelUsage);
|
|
1126
|
+
unobservedModelCalls = yield* addProjectedUsage(
|
|
1127
|
+
"unobservedModelCalls",
|
|
1128
|
+
unobservedModelCalls,
|
|
1129
|
+
payload.unobservedModelCalls,
|
|
1130
|
+
);
|
|
1131
|
+
}
|
|
1071
1132
|
if (PROMPT_TRANSPARENT_TAGS.has(payload._tag)) return;
|
|
1072
1133
|
// The compaction record governs the fold (pre-scan) and contributes no
|
|
1073
1134
|
// message of its own; records at or below the summarize bound render as
|
|
@@ -39,7 +39,7 @@ import { digestDefinitions, digestJson, DigestError } from "../Digest.ts";
|
|
|
39
39
|
import type { DurableWorkerFailure, DurableWorkerRequirements } from "../DurableAgentRuntime.ts";
|
|
40
40
|
import type { DefinitionDigestInput, PersistedJson } from "../Records.ts";
|
|
41
41
|
import { DefinitionDigests, ReplayContract } from "../Records.ts";
|
|
42
|
-
import type { Claim, Settlement } from "../SubmissionLedger.ts";
|
|
42
|
+
import type { Claim, Settlement, SubmissionSnapshot } from "../SubmissionLedger.ts";
|
|
43
43
|
|
|
44
44
|
/** No unique current executable is registered for the stable Agent identity. */
|
|
45
45
|
export class BindingUnavailable extends Schema.TaggedError<BindingUnavailable>()(
|
|
@@ -49,6 +49,29 @@ export class BindingUnavailable extends Schema.TaggedError<BindingUnavailable>()
|
|
|
49
49
|
|
|
50
50
|
export type DurableBindingFailure = BindingUnavailable;
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Submission execution/recovery routing for stable identities shared by current Definitions.
|
|
54
|
+
* Worker declarations and peer-messaging endpoints still require unique Agent identities.
|
|
55
|
+
*/
|
|
56
|
+
export interface BindingSelection {
|
|
57
|
+
/** Change when routing changes, so hosts can retry parked work without rewriting admission. */
|
|
58
|
+
readonly key: string;
|
|
59
|
+
/**
|
|
60
|
+
* Select an exact registered Definition using the canonical Submission and authoritative host
|
|
61
|
+
* state. Undefined retains unique-identity resolution. Never grant authority or mutate here;
|
|
62
|
+
* input decoding, replay contracts and current Tool authorization still apply after selection.
|
|
63
|
+
*/
|
|
64
|
+
readonly select: (
|
|
65
|
+
submission: SubmissionSnapshot,
|
|
66
|
+
) => Effect.Effect<Agent.AnyDefinition | undefined, DurableWorkerFailure | BindingUnavailable>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Captured at runtime construction; callers cannot replace routing during an Attempt. */
|
|
70
|
+
export const CurrentBindingSelection = Context.Reference<BindingSelection | undefined>(
|
|
71
|
+
"@effect-agent/thread/CurrentBindingSelection",
|
|
72
|
+
{ defaultValue: () => undefined },
|
|
73
|
+
);
|
|
74
|
+
|
|
52
75
|
/** Exact immutable admission, lineage and delivery evidence; never an executable-code gate. */
|
|
53
76
|
export const definitionDigestsEqual = (
|
|
54
77
|
left: DefinitionDigests,
|
|
@@ -358,50 +381,50 @@ export const DurableWorkerBinding = {
|
|
|
358
381
|
/** INTERNAL identity-only capture retained for the legacy direct worker path. */
|
|
359
382
|
export const makeLegacyWorkerBinding = capture;
|
|
360
383
|
|
|
361
|
-
export const resolveWorkerBinding = (
|
|
384
|
+
export const resolveWorkerBinding = Effect.fnUntraced(function* (
|
|
362
385
|
bindings: ReadonlyArray<ResolvedBinding>,
|
|
363
|
-
|
|
364
|
-
)
|
|
365
|
-
const
|
|
386
|
+
submission: SubmissionSnapshot,
|
|
387
|
+
) {
|
|
388
|
+
const selection = yield* CurrentBindingSelection;
|
|
389
|
+
const definition = selection === undefined ? undefined : yield* selection.select(submission);
|
|
390
|
+
|
|
391
|
+
const registered = bindings.filter(
|
|
392
|
+
(binding) =>
|
|
393
|
+
binding.agentId === submission.agentId &&
|
|
394
|
+
(definition === undefined || Object.is(binding.definition, definition)),
|
|
395
|
+
);
|
|
396
|
+
|
|
366
397
|
const binding = registered[0];
|
|
367
398
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
};
|
|
399
|
+
if (registered.length !== 1 || binding === undefined)
|
|
400
|
+
return yield* BindingUnavailable.make({
|
|
401
|
+
agentId: submission.agentId,
|
|
402
|
+
message: "Exactly one current Agent Binding must match the accepted Submission",
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
return binding;
|
|
406
|
+
});
|
|
377
407
|
|
|
378
|
-
/** Resolve authoring-time admission through
|
|
408
|
+
/** Resolve authoring-time admission through exact host registration, never by identity alone. */
|
|
379
409
|
export const resolveDefinitionBinding = (
|
|
380
410
|
bindings: ReadonlyArray<ResolvedBinding>,
|
|
381
411
|
definition: Pick<Agent.AnyDefinition, "id">,
|
|
382
412
|
): Effect.Effect<ResolvedBinding, BindingUnavailable> => {
|
|
383
|
-
const candidates = bindings.filter(
|
|
384
|
-
|
|
413
|
+
const candidates = bindings.filter(
|
|
414
|
+
(binding) => binding.agentId === definition.id && Object.is(binding.definition, definition),
|
|
415
|
+
);
|
|
385
416
|
|
|
386
|
-
|
|
387
|
-
return Effect.fail(
|
|
388
|
-
BindingUnavailable.make({
|
|
389
|
-
agentId: definition.id,
|
|
390
|
-
message: "Registered admission requires exactly one binding for the Agent identity",
|
|
391
|
-
}),
|
|
392
|
-
);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
if (!Object.is(binding.definition, definition)) {
|
|
396
|
-
return Effect.fail(
|
|
397
|
-
BindingUnavailable.make({
|
|
398
|
-
agentId: definition.id,
|
|
399
|
-
message: "Registered admission requires the exact Agent Definition used in registration",
|
|
400
|
-
}),
|
|
401
|
-
);
|
|
402
|
-
}
|
|
417
|
+
const binding = candidates[0];
|
|
403
418
|
|
|
404
|
-
return
|
|
419
|
+
return candidates.length === 1 && binding !== undefined
|
|
420
|
+
? Effect.succeed(binding)
|
|
421
|
+
: Effect.fail(
|
|
422
|
+
BindingUnavailable.make({
|
|
423
|
+
agentId: definition.id,
|
|
424
|
+
message:
|
|
425
|
+
"Registered admission requires exactly one registration of the exact Agent Definition",
|
|
426
|
+
}),
|
|
427
|
+
);
|
|
405
428
|
};
|
|
406
429
|
|
|
407
430
|
/** Application versions and a model Layer, supplied directly or through an existing Binding. */
|
package/src/engine/RunOptions.ts
CHANGED
|
@@ -152,10 +152,17 @@ export interface RunInputCommand {
|
|
|
152
152
|
* Dependency-neutral input seam used by the interpreter.
|
|
153
153
|
*
|
|
154
154
|
* A capability adapter owns queue bounds and Scope finalization. The engine calls
|
|
155
|
-
* `start` before the first drain, `drain` only at safe Turn seams
|
|
155
|
+
* `start` before the first drain, `drain` only at safe Turn seams (including after
|
|
156
|
+
* cancellation of a disposable model call), and `end`
|
|
156
157
|
* exactly once when the Run leaves its Scope.
|
|
157
158
|
*/
|
|
158
159
|
export interface RunInputHook<Error = never, Requirements = never> {
|
|
160
|
+
/**
|
|
161
|
+
* Wait for an eligible join without appending it to history. Must register before checking
|
|
162
|
+
* authority and retain any claimed input for `drain`, even when this wait is interrupted.
|
|
163
|
+
* Used only with `restartOnJoinedInput`; each wait belongs to the model stream's Scope.
|
|
164
|
+
*/
|
|
165
|
+
readonly awaitJoin?: Effect.Effect<void, Error, Requirements> | undefined;
|
|
159
166
|
readonly start?: (() => Effect.Effect<void, Error, Requirements>) | undefined;
|
|
160
167
|
readonly drain: (
|
|
161
168
|
policy: CommandDrainPolicy,
|
|
@@ -577,6 +584,14 @@ export class AgentUpdateAcceptance extends Context.Service<
|
|
|
577
584
|
* the ephemeral runtime always has.
|
|
578
585
|
*/
|
|
579
586
|
export interface RunDurabilityHook<Error = never, Requirements = never> {
|
|
587
|
+
/** Persist replacement count and staged usage after cancellation, before starting its successor. */
|
|
588
|
+
readonly commitModelRestart?:
|
|
589
|
+
| ((restart: {
|
|
590
|
+
readonly turn: number;
|
|
591
|
+
readonly turnId: TurnId;
|
|
592
|
+
readonly restart: number;
|
|
593
|
+
}) => Effect.Effect<void, Error, Requirements>)
|
|
594
|
+
| undefined;
|
|
580
595
|
/** Stage the exact request declarations for the existing canonical response append. */
|
|
581
596
|
readonly noteToolExposure?:
|
|
582
597
|
| ((turn: number, snapshot: Snapshot) => Effect.Effect<void, Error, Requirements>)
|
|
@@ -948,7 +963,7 @@ export interface RunOptions<HookError = never, HookRequirements = never> {
|
|
|
948
963
|
/** Initial or canonically restored run-scoped native selection. */
|
|
949
964
|
readonly toolSelection?: Selection | undefined;
|
|
950
965
|
/**
|
|
951
|
-
* Host preparation boundary before each new model
|
|
966
|
+
* Host preparation boundary before each new or replacement model call, including context preparation
|
|
952
967
|
* and compaction calls. The preceding Tool batch and history advance have finished. A resumed
|
|
953
968
|
* canonical Tool batch bypasses this hook until it continues to a new Turn. This hook does not
|
|
954
969
|
* reset the Run deadline or change prompt protection, and is not automatically inherited by spawned children.
|
|
@@ -78,6 +78,7 @@ import {
|
|
|
78
78
|
BudgetWarning,
|
|
79
79
|
CompactionPerformed,
|
|
80
80
|
ModelStarted,
|
|
81
|
+
ModelRestarted,
|
|
81
82
|
ReasoningDelta,
|
|
82
83
|
RunCompleted,
|
|
83
84
|
RunFailed,
|
|
@@ -555,6 +556,7 @@ interface RunContext {
|
|
|
555
556
|
readonly durationDeadlineMillis: number;
|
|
556
557
|
history: Prompt.Prompt;
|
|
557
558
|
modelCalls: number;
|
|
559
|
+
modelRestarts: number;
|
|
558
560
|
usageStatus: typeof UsageCompleteness.Type;
|
|
559
561
|
pricingStatus: typeof UsageCompleteness.Type;
|
|
560
562
|
unobservedModelCalls: number;
|
|
@@ -1430,7 +1432,15 @@ const decodeResumeUsage = Effect.fn("AgentRuntime.decodeResumeUsage")((input: un
|
|
|
1430
1432
|
};
|
|
1431
1433
|
|
|
1432
1434
|
const optional = Object.fromEntries(
|
|
1433
|
-
(
|
|
1435
|
+
(
|
|
1436
|
+
[
|
|
1437
|
+
"usageStatus",
|
|
1438
|
+
"pricingStatus",
|
|
1439
|
+
"unobservedModelCalls",
|
|
1440
|
+
"children",
|
|
1441
|
+
"modelRestarts",
|
|
1442
|
+
] as const
|
|
1443
|
+
)
|
|
1434
1444
|
.map((key) => [key, read(key, true)])
|
|
1435
1445
|
.filter(([, value]) => value !== undefined),
|
|
1436
1446
|
);
|
|
@@ -1893,7 +1903,11 @@ const agentTelemetryAttributes = (context: RunContext) => ({
|
|
|
1893
1903
|
});
|
|
1894
1904
|
|
|
1895
1905
|
/** Label Effect AI's existing span, preserving provider usage, sampling and host async context. */
|
|
1896
|
-
const modelTelemetryTracer = Effect.fnUntraced(function* (
|
|
1906
|
+
const modelTelemetryTracer = Effect.fnUntraced(function* (
|
|
1907
|
+
context: RunContext,
|
|
1908
|
+
turnId?: TurnId,
|
|
1909
|
+
onSpan?: (span: Tracer.Span) => void,
|
|
1910
|
+
) {
|
|
1897
1911
|
const delegate = yield* Tracer.Tracer;
|
|
1898
1912
|
const model = yield* Model.ModelName;
|
|
1899
1913
|
const provider = yield* Model.ProviderName;
|
|
@@ -1904,6 +1918,8 @@ const modelTelemetryTracer = Effect.fnUntraced(function* (context: RunContext, t
|
|
|
1904
1918
|
|
|
1905
1919
|
const span = delegate.span({ ...options, name: `chat ${model}` });
|
|
1906
1920
|
|
|
1921
|
+
onSpan?.(span);
|
|
1922
|
+
|
|
1907
1923
|
const attributes = {
|
|
1908
1924
|
...agentTelemetryAttributes(context),
|
|
1909
1925
|
"gen_ai.operation.name": "chat",
|
|
@@ -5343,6 +5359,7 @@ function decodeRunDisposition<DispositionSchema extends Schema.Top>(
|
|
|
5343
5359
|
/** Internal control output consumed by the driver before RunEvent publication. */
|
|
5344
5360
|
interface NextTurn {
|
|
5345
5361
|
readonly _tag: "NextTurn";
|
|
5362
|
+
readonly restarting?: boolean;
|
|
5346
5363
|
readonly prompt: Prompt.Prompt;
|
|
5347
5364
|
readonly turn: number;
|
|
5348
5365
|
readonly toolCalls: number;
|
|
@@ -5388,6 +5405,7 @@ const makeTurn = <
|
|
|
5388
5405
|
turn: number,
|
|
5389
5406
|
priorToolCalls: number,
|
|
5390
5407
|
options: RunOptions<HookError, HookRequirements>,
|
|
5408
|
+
restarting = false,
|
|
5391
5409
|
): Stream.Stream<
|
|
5392
5410
|
TurnOutput,
|
|
5393
5411
|
AgentRuntimeFailure<typeof agent, HookError, InstructionError>,
|
|
@@ -5416,7 +5434,7 @@ const makeTurn = <
|
|
|
5416
5434
|
}),
|
|
5417
5435
|
);
|
|
5418
5436
|
}
|
|
5419
|
-
if (context.finalizationUsed) {
|
|
5437
|
+
if (context.finalizationUsed && !restarting) {
|
|
5420
5438
|
return failRunEventStream(
|
|
5421
5439
|
AgentPolicyError.make({
|
|
5422
5440
|
limit:
|
|
@@ -5591,6 +5609,9 @@ const makeTurn = <
|
|
|
5591
5609
|
}
|
|
5592
5610
|
}
|
|
5593
5611
|
|
|
5612
|
+
let restartRequested = false;
|
|
5613
|
+
let activeModelSpan: Tracer.Span | undefined;
|
|
5614
|
+
|
|
5594
5615
|
const trace: TurnTrace = {
|
|
5595
5616
|
responsePartCount: 0,
|
|
5596
5617
|
responsePartBytes: 0,
|
|
@@ -6206,6 +6227,10 @@ const makeTurn = <
|
|
|
6206
6227
|
);
|
|
6207
6228
|
});
|
|
6208
6229
|
|
|
6230
|
+
let failedUsageCause:
|
|
6231
|
+
| Cause.Cause<AgentRuntimeFailure<typeof agent, HookError, InstructionError>>
|
|
6232
|
+
| undefined;
|
|
6233
|
+
|
|
6209
6234
|
// Failure accounting observes the already-selected failure; a secondary
|
|
6210
6235
|
// budget/estimator failure must not replace that native outcome.
|
|
6211
6236
|
const retainFailedUsage = Effect.fn("AgentRuntime.retainFailedUsage")(function* () {
|
|
@@ -6214,7 +6239,9 @@ const makeTurn = <
|
|
|
6214
6239
|
if (trace.usage === undefined) {
|
|
6215
6240
|
return yield* noteIncompleteUsage(context, turn);
|
|
6216
6241
|
}
|
|
6217
|
-
yield* consumeTurnUsage(0).pipe(Effect.exit);
|
|
6242
|
+
const exit = yield* consumeTurnUsage(0).pipe(Effect.exit);
|
|
6243
|
+
|
|
6244
|
+
if (Exit.isFailure(exit)) failedUsageCause = exit.cause;
|
|
6218
6245
|
});
|
|
6219
6246
|
|
|
6220
6247
|
const attempt = (basis: Prompt.Prompt) =>
|
|
@@ -6337,7 +6364,9 @@ const makeTurn = <
|
|
|
6337
6364
|
: stream,
|
|
6338
6365
|
Stream.provideServiceEffect(
|
|
6339
6366
|
Tracer.Tracer,
|
|
6340
|
-
modelTelemetryTracer(context, turnId)
|
|
6367
|
+
modelTelemetryTracer(context, turnId, (span) => {
|
|
6368
|
+
activeModelSpan = span;
|
|
6369
|
+
}),
|
|
6341
6370
|
),
|
|
6342
6371
|
Stream.onStart(
|
|
6343
6372
|
Effect.sync(() => {
|
|
@@ -6365,7 +6394,9 @@ const makeTurn = <
|
|
|
6365
6394
|
),
|
|
6366
6395
|
),
|
|
6367
6396
|
Stream.flatMap(Stream.fromIterable),
|
|
6368
|
-
Stream.
|
|
6397
|
+
Stream.onExit((exit) =>
|
|
6398
|
+
Exit.isFailure(exit) ? retainFailedUsage() : Effect.void,
|
|
6399
|
+
),
|
|
6369
6400
|
),
|
|
6370
6401
|
),
|
|
6371
6402
|
);
|
|
@@ -7059,10 +7090,83 @@ const makeTurn = <
|
|
|
7059
7090
|
}),
|
|
7060
7091
|
);
|
|
7061
7092
|
|
|
7093
|
+
// Only the model stream is cancellable. It resolves no application Tools and
|
|
7094
|
+
// closes its waiter before continuation can commit a response or start a Handler.
|
|
7095
|
+
// Provider-defined Tools may execute remotely before reporting a part: fail closed
|
|
7096
|
+
// for the whole call when any are exposed.
|
|
7097
|
+
const restartSignal =
|
|
7098
|
+
policy.restartOnJoinedInput === true &&
|
|
7099
|
+
context.modelRestarts < 2 &&
|
|
7100
|
+
(options.durability === undefined || options.durability.commitModelRestart !== undefined) &&
|
|
7101
|
+
!Object.values(modelToolkit.tools).some(Tool.isProviderDefined)
|
|
7102
|
+
? options.input?.awaitJoin
|
|
7103
|
+
: undefined;
|
|
7104
|
+
|
|
7105
|
+
const disposableResponse =
|
|
7106
|
+
restartSignal !== undefined
|
|
7107
|
+
? response.pipe(
|
|
7108
|
+
Stream.interruptWhen(
|
|
7109
|
+
restartSignal.pipe(
|
|
7110
|
+
Effect.tap(() =>
|
|
7111
|
+
Effect.sync(() => {
|
|
7112
|
+
restartRequested = true;
|
|
7113
|
+
activeModelSpan?.attribute("effect_agent.model.outcome", "aborted");
|
|
7114
|
+
activeModelSpan?.attribute("effect_agent.model.abort_reason", "joined-input");
|
|
7115
|
+
}),
|
|
7116
|
+
),
|
|
7117
|
+
),
|
|
7118
|
+
),
|
|
7119
|
+
)
|
|
7120
|
+
: response;
|
|
7121
|
+
|
|
7122
|
+
const afterResponse = Stream.unwrap(
|
|
7123
|
+
Effect.gen(function* () {
|
|
7124
|
+
if (!restartRequested)
|
|
7125
|
+
return continuation.pipe(Stream.tapCause(() => retainFailedUsage()));
|
|
7126
|
+
|
|
7127
|
+
const discarded = ModelRestarted.make({
|
|
7128
|
+
...(yield* eventBase(context)),
|
|
7129
|
+
turnId,
|
|
7130
|
+
turn,
|
|
7131
|
+
reason: "joined-input",
|
|
7132
|
+
});
|
|
7133
|
+
|
|
7134
|
+
// Publish invalidation before any fallible persistence, input rendering or budget check.
|
|
7135
|
+
return Stream.succeed(discarded).pipe(
|
|
7136
|
+
Stream.concat(
|
|
7137
|
+
Stream.unwrap(
|
|
7138
|
+
Effect.gen(function* () {
|
|
7139
|
+
yield* retainFailedUsage();
|
|
7140
|
+
context.modelRestarts++;
|
|
7141
|
+
if (options.durability?.commitModelRestart !== undefined)
|
|
7142
|
+
yield* options.durability.commitModelRestart({
|
|
7143
|
+
turn,
|
|
7144
|
+
turnId,
|
|
7145
|
+
restart: context.modelRestarts,
|
|
7146
|
+
});
|
|
7147
|
+
if (failedUsageCause !== undefined)
|
|
7148
|
+
return yield* Effect.failCause(failedUsageCause);
|
|
7149
|
+
const inputs = yield* drainInputs(context, options);
|
|
7150
|
+
const nextPrompt = yield* appendInputs(context, prompt, inputs, options);
|
|
7151
|
+
|
|
7152
|
+
return Stream.succeed<TurnOutput>({
|
|
7153
|
+
_tag: "NextTurn",
|
|
7154
|
+
prompt: nextPrompt,
|
|
7155
|
+
turn,
|
|
7156
|
+
toolCalls: priorToolCalls,
|
|
7157
|
+
restarting: true,
|
|
7158
|
+
});
|
|
7159
|
+
}),
|
|
7160
|
+
),
|
|
7161
|
+
),
|
|
7162
|
+
);
|
|
7163
|
+
}),
|
|
7164
|
+
);
|
|
7165
|
+
|
|
7062
7166
|
const events = Stream.fromIterable(preEvents).pipe(
|
|
7063
7167
|
Stream.concat(started),
|
|
7064
|
-
Stream.concat(
|
|
7065
|
-
Stream.concat(
|
|
7168
|
+
Stream.concat(disposableResponse),
|
|
7169
|
+
Stream.concat(afterResponse),
|
|
7066
7170
|
);
|
|
7067
7171
|
|
|
7068
7172
|
return modelServices === undefined ? events : Stream.provideContext(events, modelServices);
|
|
@@ -8144,6 +8248,7 @@ function streamWithCompletion<
|
|
|
8144
8248
|
// canonical response records so token budgets and the compaction
|
|
8145
8249
|
// trigger keep accounting across ownership changes.
|
|
8146
8250
|
modelCalls: resumeUsage?.modelCalls ?? 0,
|
|
8251
|
+
modelRestarts: resumeUsage?.modelRestarts ?? 0,
|
|
8147
8252
|
usageStatus:
|
|
8148
8253
|
resumeUsage?.usageStatus ?? (resumeUsage === undefined ? "complete" : "unknown"),
|
|
8149
8254
|
pricingStatus:
|
|
@@ -8379,6 +8484,7 @@ function streamWithCompletion<
|
|
|
8379
8484
|
readonly turn: number;
|
|
8380
8485
|
readonly toolCalls: number;
|
|
8381
8486
|
readonly resume?: RunTurnResume;
|
|
8487
|
+
readonly restarting?: boolean;
|
|
8382
8488
|
}
|
|
8383
8489
|
| undefined;
|
|
8384
8490
|
|
|
@@ -8425,6 +8531,7 @@ function streamWithCompletion<
|
|
|
8425
8531
|
request.turn,
|
|
8426
8532
|
request.toolCalls,
|
|
8427
8533
|
options,
|
|
8534
|
+
request.restarting,
|
|
8428
8535
|
)
|
|
8429
8536
|
: makeResumeTurn(
|
|
8430
8537
|
agent,
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * as AgentPolicy from "./core/AgentPolicy.ts";
|
|
|
4
4
|
export * as AgentRuntime from "./engine/AgentRuntime.ts";
|
|
5
5
|
export * as AgentUpdates from "./core/AgentUpdates.ts";
|
|
6
6
|
export * as Approval from "./capabilities/Approval.ts";
|
|
7
|
+
export * as BrowserUse from "./capabilities/BrowserUse.ts";
|
|
7
8
|
export * as Budget from "./capabilities/Budget.ts";
|
|
8
9
|
export * as CodeExecutor from "./sandbox/CodeExecutor.ts";
|
|
9
10
|
export * as CodeMode from "./capabilities/CodeMode.ts";
|