effect-agent 0.1.0-beta.97 → 0.1.0-beta.99
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/{AgentRuntime-B64362Id.d.mts → AgentRuntime-BMzrJos6.d.mts} +2 -2
- package/dist/{AgentRuntime-Cdvqw7l_.mjs → AgentRuntime-BWOnNc0d.mjs} +78 -42
- package/dist/AgentRuntime-BWOnNc0d.mjs.map +1 -0
- package/dist/{DurableAgentRuntime-DbUvZHDZ.mjs → DurableAgentRuntime-BE_OjQjz.mjs} +471 -252
- package/dist/DurableAgentRuntime-BE_OjQjz.mjs.map +1 -0
- package/dist/{DurableFailpoint-DQJet828.d.mts → DurableFailpoint-mx3-nsxU.d.mts} +3 -3
- package/dist/{EventSource-D6PAAEyK.d.mts → EventSource-BZ73J0s5.d.mts} +3 -3
- package/dist/{PreparedInputAdmission-omMbwd--.d.mts → PreparedInputAdmission-BkeI-Xvr.d.mts} +4 -4
- package/dist/{Records-CV49DgQK.d.mts → Records-BIiRLqlz.d.mts} +92 -128
- package/dist/{Records-BAutSSnJ.mjs → Records-DR1xtbXY.mjs} +35 -8
- package/dist/Records-DR1xtbXY.mjs.map +1 -0
- package/dist/{RunJournal-DRRRZmG7.mjs → RunJournal-DNs3PM4K.mjs} +80 -23
- package/dist/RunJournal-DNs3PM4K.mjs.map +1 -0
- package/dist/{RunOptions-Clj8cLsp.d.mts → RunOptions-Bruk54SE.d.mts} +13 -4
- package/dist/{Schedule-DePbGfgd.d.mts → Schedule-BNFlluAl.d.mts} +2 -2
- package/dist/{Scheduling-C3QpYn0W.mjs → Scheduling-HFH0pST1.mjs} +2 -2
- package/dist/{Scheduling-C3QpYn0W.mjs.map → Scheduling-HFH0pST1.mjs.map} +1 -1
- package/dist/{Subagent-Cbfzylz1.mjs → Subagent-C2s8PFrd.mjs} +2 -2
- package/dist/{Subagent-Cbfzylz1.mjs.map → Subagent-C2s8PFrd.mjs.map} +1 -1
- package/dist/{Subagent-Bm1dRecN.d.mts → Subagent-m7ywTCe4.d.mts} +3 -3
- package/dist/{Subscription-BR_8Cxh3.d.mts → Subscription-BCQ3L9Zp.d.mts} +3 -3
- package/dist/{SubscriptionInput-B95sQbuk.d.mts → SubscriptionInput-Cqu4_RW3.d.mts} +3 -3
- package/dist/{ToolReconciler-DQVaJfpE.d.mts → ToolReconciler-BmVRAHKs.d.mts} +8 -4
- package/dist/agent-registration-cXpB8cBU.mjs +199 -0
- package/dist/agent-registration-cXpB8cBU.mjs.map +1 -0
- package/dist/capabilities/Commands.d.mts +1 -1
- package/dist/capabilities/RunHooks.d.mts +1 -1
- 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/ActivityStore.mjs +1 -1
- package/dist/durable/Admin.d.mts +1 -1
- package/dist/durable/Admin.mjs +12 -10
- package/dist/durable/Admin.mjs.map +1 -1
- package/dist/durable/AgentRegistration.d.mts +2 -2
- package/dist/durable/AgentRegistration.mjs +4 -8
- package/dist/durable/AgentRegistration.mjs.map +1 -1
- package/dist/durable/Certification.d.mts +2 -2
- package/dist/durable/CommittedActivity.d.mts +1 -1
- package/dist/durable/CommittedActivity.mjs +1 -1
- package/dist/durable/Digest.d.mts +1 -1
- package/dist/durable/Digest.mjs +1 -1
- package/dist/durable/DurableAgentRuntime.d.mts +1 -1
- package/dist/durable/DurableAgentRuntime.mjs +1 -1
- package/dist/durable/DurableFailpoint.d.mts +1 -1
- package/dist/durable/DurableFailpoint.mjs +2 -0
- package/dist/durable/DurableFailpoint.mjs.map +1 -1
- package/dist/durable/DurableFailpointTestControl.d.mts +1 -1
- package/dist/durable/EventSource.d.mts +1 -1
- package/dist/durable/EventSource.mjs +1 -1
- package/dist/durable/GitHubWorkflowSource.d.mts +3 -3
- package/dist/durable/GitHubWorkflowSource.mjs +1 -1
- package/dist/durable/MessageDelivery.d.mts +3 -3
- package/dist/durable/MessageDelivery.mjs +1 -1
- package/dist/durable/MessageDeliveryStoreConformance.d.mts +39 -39
- package/dist/durable/MessageDeliveryStoreConformance.mjs +1 -1
- package/dist/durable/PersistentHistory.d.mts +1 -1
- package/dist/durable/PersistentHistory.mjs +2 -2
- package/dist/durable/PreparedInputAdmission.d.mts +1 -1
- package/dist/durable/Records.d.mts +2 -2
- package/dist/durable/Records.mjs +2 -2
- package/dist/durable/Recovery.d.mts +1 -1
- package/dist/durable/Recovery.mjs +9 -9
- package/dist/durable/Recovery.mjs.map +1 -1
- package/dist/durable/RunJournal.d.mts +2 -2
- package/dist/durable/RunJournal.mjs +2 -2
- package/dist/durable/Schedule.d.mts +1 -1
- package/dist/durable/Schedule.mjs +1 -1
- package/dist/durable/ScheduleStoreConformance.d.mts +1 -1
- package/dist/durable/ScheduleStoreConformance.mjs +1 -1
- package/dist/durable/ScheduleTransition.d.mts +1 -1
- package/dist/durable/ScheduleTransition.mjs +1 -1
- package/dist/durable/Scheduling.d.mts +2 -2
- package/dist/durable/Scheduling.mjs +1 -1
- package/dist/durable/SqlStorageV2Upgrade.d.mts +2 -2
- package/dist/durable/SqlStorageV2Upgrade.mjs +1 -1
- package/dist/durable/SqlSubscriptionStore.d.mts +2 -2
- package/dist/durable/SqlSubscriptionStore.mjs +1 -1
- package/dist/durable/SubmissionLedger.d.mts +1 -1
- package/dist/durable/SubmissionLedger.mjs +14 -13
- package/dist/durable/SubmissionLedger.mjs.map +1 -1
- package/dist/durable/SubmissionLedgerConformance.d.mts +1 -1
- package/dist/durable/SubmissionLedgerConformance.mjs +9 -2
- package/dist/durable/SubmissionLedgerConformance.mjs.map +1 -1
- package/dist/durable/SubmissionStatus.d.mts +1 -1
- package/dist/durable/Subscription.d.mts +1 -1
- package/dist/durable/Subscription.mjs +1 -1
- package/dist/durable/SubscriptionInput.d.mts +1 -1
- package/dist/durable/SubscriptionInput.mjs +2 -2
- package/dist/durable/SubscriptionStoreConformance.d.mts +1 -1
- package/dist/durable/SubscriptionStoreConformance.mjs +1 -1
- package/dist/durable/SubscriptionTools.d.mts +3 -3
- package/dist/durable/SubscriptionTransition.d.mts +1 -1
- package/dist/durable/SubscriptionTransition.mjs +1 -1
- package/dist/durable/Subscriptions.d.mts +5 -5
- package/dist/durable/Subscriptions.mjs +1 -1
- package/dist/durable/ThreadContextHistory.d.mts +1 -1
- package/dist/durable/ThreadContextHistory.mjs +1 -1
- package/dist/durable/ThreadContextHistoryProjection.d.mts +1 -1
- package/dist/durable/ThreadContextHistoryProjection.mjs +1 -1
- package/dist/durable/ThreadInvariants.d.mts +4 -2
- package/dist/durable/ThreadInvariants.mjs +49 -3
- package/dist/durable/ThreadInvariants.mjs.map +1 -1
- package/dist/durable/ThreadProjection.d.mts +1 -1
- package/dist/durable/ThreadProjection.mjs +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/ToolReconciler.d.mts +1 -1
- package/dist/durable/ToolReconciler.mjs +9 -5
- package/dist/durable/ToolReconciler.mjs.map +1 -1
- package/dist/durable/WorkerHost.d.mts +1 -1
- package/dist/engine/AgentRuntime.d.mts +1 -1
- package/dist/engine/AgentRuntime.mjs +1 -1
- package/dist/engine/RunOptions.d.mts +1 -1
- package/dist/engine/RunOptions.mjs.map +1 -1
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +6 -6
- package/package.json +1 -1
- package/src/durable/Admin.ts +20 -11
- package/src/durable/AgentRegistration.ts +1 -5
- package/src/durable/DurableAgentRuntime.ts +947 -464
- package/src/durable/DurableFailpoint.ts +2 -0
- package/src/durable/Records.ts +30 -5
- package/src/durable/Recovery.ts +8 -8
- package/src/durable/RunJournal.ts +128 -51
- package/src/durable/SubmissionLedger.ts +13 -12
- package/src/durable/SubmissionLedgerConformance.ts +13 -2
- package/src/durable/ThreadInvariants.ts +70 -5
- package/src/durable/ToolReconciler.ts +7 -3
- package/src/durable/internal/agent-registration.ts +65 -414
- package/src/durable/internal/messaging-host.ts +0 -2
- package/src/durable/internal/worker-host.ts +34 -96
- package/src/engine/RunOptions.ts +13 -3
- package/src/engine/internal/agent-runtime.ts +160 -106
- package/dist/AgentRuntime-Cdvqw7l_.mjs.map +0 -1
- package/dist/DurableAgentRuntime-DbUvZHDZ.mjs.map +0 -1
- package/dist/Records-BAutSSnJ.mjs.map +0 -1
- package/dist/RunJournal-DRRRZmG7.mjs.map +0 -1
- package/dist/agent-registration-CXGDwvJH.mjs +0 -379
- package/dist/agent-registration-CXGDwvJH.mjs.map +0 -1
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type Crypto,
|
|
3
|
-
type Option,
|
|
4
|
-
type Scope,
|
|
5
|
-
Array,
|
|
6
|
-
Context,
|
|
7
|
-
Effect,
|
|
8
|
-
Layer,
|
|
9
|
-
Schema,
|
|
10
|
-
} from "effect";
|
|
1
|
+
import { type Crypto, type Option, type Scope, Context, Effect, Layer, Schema } from "effect";
|
|
11
2
|
import { Tool } from "effect/unstable/ai";
|
|
12
3
|
|
|
13
4
|
import type * as Agent from "../../core/Agent.ts";
|
|
@@ -27,6 +18,7 @@ import {
|
|
|
27
18
|
ToolNamespace,
|
|
28
19
|
} from "../../core/ToolExposure.ts";
|
|
29
20
|
import { type RuntimeBinding } from "../../engine/AgentRuntime.ts";
|
|
21
|
+
import { ContextRolloverTool } from "../../engine/ContextWindow.ts";
|
|
30
22
|
import { getToolExecutionClass } from "../../engine/DurableStep.ts";
|
|
31
23
|
import {
|
|
32
24
|
BackgroundReporting,
|
|
@@ -35,44 +27,19 @@ import {
|
|
|
35
27
|
} from "../../engine/SubagentHost.ts";
|
|
36
28
|
import { digestDefinitions, digestJson, DigestError } from "../Digest.ts";
|
|
37
29
|
import type { DurableWorkerFailure, DurableWorkerRequirements } from "../DurableAgentRuntime.ts";
|
|
38
|
-
import {
|
|
39
|
-
|
|
40
|
-
DefinitionDigests,
|
|
41
|
-
ReplayContract,
|
|
42
|
-
PersistedJson,
|
|
43
|
-
} from "../Records.ts";
|
|
30
|
+
import type { DefinitionDigestInput, PersistedJson } from "../Records.ts";
|
|
31
|
+
import { DefinitionDigests, ReplayContract } from "../Records.ts";
|
|
44
32
|
import type { Claim, Settlement } from "../SubmissionLedger.ts";
|
|
45
33
|
|
|
46
|
-
/**
|
|
47
|
-
* No Agent Binding is registered for the requested stable identity. Recovery
|
|
48
|
-
* fails closed: it never substitutes the latest Binding or runs different
|
|
49
|
-
* code.
|
|
50
|
-
*/
|
|
34
|
+
/** No unique current executable is registered for the stable Agent identity. */
|
|
51
35
|
export class BindingUnavailable extends Schema.TaggedError<BindingUnavailable>()(
|
|
52
36
|
"BindingUnavailable",
|
|
53
|
-
{
|
|
54
|
-
agentId: AgentId,
|
|
55
|
-
message: Schema.String,
|
|
56
|
-
},
|
|
57
|
-
) {}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* A Binding is registered for the identity but neither the exact admission fingerprints
|
|
61
|
-
* nor its declared replay contract support the retained pending operations. Refusal leaves
|
|
62
|
-
* the original Submission pending until compatible code is available.
|
|
63
|
-
*/
|
|
64
|
-
export class BindingDigestMismatch extends Schema.TaggedError<BindingDigestMismatch>()(
|
|
65
|
-
"BindingDigestMismatch",
|
|
66
|
-
{
|
|
67
|
-
agentId: AgentId,
|
|
68
|
-
message: Schema.String,
|
|
69
|
-
},
|
|
37
|
+
{ agentId: AgentId, message: Schema.String },
|
|
70
38
|
) {}
|
|
71
39
|
|
|
72
|
-
|
|
73
|
-
export type DurableBindingFailure = BindingUnavailable | BindingDigestMismatch;
|
|
40
|
+
export type DurableBindingFailure = BindingUnavailable;
|
|
74
41
|
|
|
75
|
-
/**
|
|
42
|
+
/** Exact immutable admission, lineage and delivery evidence; never an executable-code gate. */
|
|
76
43
|
export const definitionDigestsEqual = (
|
|
77
44
|
left: DefinitionDigests,
|
|
78
45
|
right: DefinitionDigests,
|
|
@@ -82,91 +49,35 @@ export const definitionDigestsEqual = (
|
|
|
82
49
|
left.tools === right.tools &&
|
|
83
50
|
Schema.toEquivalence(Schema.UndefinedOr(ReplayContract))(left.replay, right.replay);
|
|
84
51
|
|
|
85
|
-
/**
|
|
86
|
-
* Host-owned semantic versions, independent of deployment and tool inventory. Change a version
|
|
87
|
-
* when the meaning of an operation, its durable Step names or external idempotency keys changes.
|
|
88
|
-
* Codecs and execution class are included automatically; JSON Schema alone cannot prove semantics.
|
|
89
|
-
*/
|
|
52
|
+
/** Change an operation version when its meaning, durable Steps or idempotency keys change. */
|
|
90
53
|
export interface ReplayVersions {
|
|
91
|
-
readonly agent: PersistedJson;
|
|
92
54
|
readonly tools: Readonly<Record<string, PersistedJson>>;
|
|
93
55
|
}
|
|
94
56
|
|
|
95
|
-
/**
|
|
96
|
-
|
|
97
|
-
* manifest from the original release for work admitted before replay contracts were retained.
|
|
98
|
-
* Its original declarations must hash to that admission; a bare old digest is not a manifest.
|
|
99
|
-
*/
|
|
100
|
-
const ToolReplayDeclaration = Schema.Struct({
|
|
101
|
-
version: PersistedJson,
|
|
102
|
-
parameters: PersistedJson,
|
|
103
|
-
success: PersistedJson,
|
|
104
|
-
failure: PersistedJson,
|
|
105
|
-
failureMode: Schema.String,
|
|
106
|
-
needsApproval: Schema.Union([Schema.Boolean, Schema.Literal("dynamic")]),
|
|
107
|
-
executionClass: Schema.String,
|
|
108
|
-
executionKind: Schema.String,
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
const AgentReplayDeclaration = Schema.Struct({
|
|
112
|
-
version: PersistedJson,
|
|
113
|
-
id: AgentId,
|
|
114
|
-
input: PersistedJson,
|
|
115
|
-
output: PersistedJson,
|
|
116
|
-
updates: Schema.NullOr(PersistedJson),
|
|
117
|
-
completion: Schema.NullOr(Schema.Struct({ tool: Schema.String, required: Schema.Boolean })),
|
|
118
|
-
completionFromTools: Schema.Array(Schema.String),
|
|
119
|
-
disposition: Schema.NullOr(PersistedJson),
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
export class BindingManifest extends Schema.Class<BindingManifest>("BindingManifest")({
|
|
123
|
-
agentId: AgentId,
|
|
124
|
-
definitions: DefinitionDigestInput,
|
|
125
|
-
replay: ReplayContract,
|
|
126
|
-
agentContract: Schema.optionalKey(AgentReplayDeclaration),
|
|
127
|
-
toolContracts: Schema.optionalKey(Schema.Record(Schema.String, ToolReplayDeclaration)),
|
|
128
|
-
}) {}
|
|
129
|
-
|
|
130
|
-
export const makeBindingManifest = Effect.fn("AgentRegistration.makeBindingManifest")(function* (
|
|
57
|
+
/** Hash current operation contracts; no historical definitions or schemas are retained. */
|
|
58
|
+
export const toolReplayContracts = Effect.fn("AgentRegistration.toolReplayContracts")(function* (
|
|
131
59
|
definition: Agent.AnyDefinition,
|
|
132
|
-
|
|
133
|
-
|
|
60
|
+
versions?: ReplayVersions,
|
|
61
|
+
fallbackVersion: PersistedJson = null,
|
|
134
62
|
) {
|
|
135
|
-
const
|
|
136
|
-
Schema.decodeUnknownSync(Schema.Json)(Tool.getJsonSchemaFromSchema(schema));
|
|
137
|
-
|
|
138
|
-
const contracts = yield* Effect.try({
|
|
63
|
+
const declarations = yield* Effect.try({
|
|
139
64
|
try: () => {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
version
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
definition.completion === undefined
|
|
154
|
-
? null
|
|
155
|
-
: {
|
|
156
|
-
tool: definition.completion.tool,
|
|
157
|
-
required: definition.completion.required ?? false,
|
|
158
|
-
},
|
|
159
|
-
completionFromTools:
|
|
160
|
-
definition.completionFromTools?.map((entry) => entry.tool).sort() ?? [],
|
|
161
|
-
disposition:
|
|
162
|
-
definition.runDisposition === undefined
|
|
163
|
-
? null
|
|
164
|
-
: jsonSchema(definition.runDisposition.schema),
|
|
165
|
-
},
|
|
166
|
-
tools: tools.map((tool) => ({
|
|
65
|
+
const jsonSchema = (schema: Schema.Top) =>
|
|
66
|
+
Schema.decodeUnknownSync(Schema.Json)(Tool.getJsonSchemaFromSchema(schema));
|
|
67
|
+
|
|
68
|
+
return Object.values(definition.toolkit.tools).map((tool) => {
|
|
69
|
+
const version = versions === undefined ? fallbackVersion : versions.tools[tool.name];
|
|
70
|
+
|
|
71
|
+
if (
|
|
72
|
+
version === undefined ||
|
|
73
|
+
(versions !== undefined && !Object.hasOwn(versions.tools, tool.name))
|
|
74
|
+
)
|
|
75
|
+
throw new Error("Every Tool needs an explicit replay semantic version");
|
|
76
|
+
|
|
77
|
+
return {
|
|
167
78
|
name: tool.name,
|
|
168
79
|
contract: {
|
|
169
|
-
version
|
|
80
|
+
version,
|
|
170
81
|
parameters: jsonSchema(tool.parametersSchema),
|
|
171
82
|
success: jsonSchema(tool.successSchema),
|
|
172
83
|
failure: jsonSchema(tool.failureSchema),
|
|
@@ -175,273 +86,48 @@ export const makeBindingManifest = Effect.fn("AgentRegistration.makeBindingManif
|
|
|
175
86
|
typeof tool.needsApproval === "function" ? "dynamic" : (tool.needsApproval ?? false),
|
|
176
87
|
executionClass: getToolExecutionClass(tool),
|
|
177
88
|
executionKind: getToolExecutionKind(tool.annotations),
|
|
89
|
+
contextRollover: Context.get(tool.annotations, ContextRolloverTool),
|
|
90
|
+
completion: definition.completion?.tool === tool.name,
|
|
91
|
+
completionFromTool:
|
|
92
|
+
definition.completionFromTools?.some(
|
|
93
|
+
(declaration) => declaration.tool === tool.name,
|
|
94
|
+
) ?? false,
|
|
178
95
|
},
|
|
179
|
-
}
|
|
180
|
-
};
|
|
96
|
+
};
|
|
97
|
+
});
|
|
181
98
|
},
|
|
182
99
|
catch: () =>
|
|
183
100
|
DigestError.make({
|
|
184
|
-
message:
|
|
185
|
-
"Replay contracts require serializable codecs and an explicit semantic version for every Tool",
|
|
101
|
+
message: "Operation contracts require serializable codecs and a version for every Tool",
|
|
186
102
|
}),
|
|
187
103
|
});
|
|
188
104
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const tools = yield* Effect.forEach(contracts.tools, ({ name, contract }) =>
|
|
193
|
-
digestJson(contract).pipe(Effect.map((digest) => [name, digest] as const)),
|
|
194
|
-
);
|
|
195
|
-
|
|
196
|
-
return BindingManifest.make({
|
|
197
|
-
agentId: definition.id,
|
|
198
|
-
definitions,
|
|
199
|
-
replay: ReplayContract.make({ agent, agentBehavior, tools: Object.fromEntries(tools) }),
|
|
200
|
-
agentContract: contracts.agent,
|
|
201
|
-
toolContracts: Object.fromEntries(
|
|
202
|
-
contracts.tools.map(({ name, contract }) => [name, contract]),
|
|
105
|
+
return Object.fromEntries(
|
|
106
|
+
yield* Effect.forEach(declarations, ({ name, contract }) =>
|
|
107
|
+
digestJson(contract).pipe(Effect.map((digest) => [name, digest] as const)),
|
|
203
108
|
),
|
|
204
|
-
|
|
109
|
+
);
|
|
205
110
|
});
|
|
206
111
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
// JSON Schema generation can widen object openness without changing an Effect codec.
|
|
210
|
-
// Prove only this widening; all other codec changes still require an exact contract.
|
|
211
|
-
const schemasCompatible = (previous: PersistedJson, current: PersistedJson): boolean => {
|
|
212
|
-
if (jsonEqual(previous, current)) return true;
|
|
213
|
-
|
|
214
|
-
const hasNegativeSchema = (value: PersistedJson): boolean => {
|
|
215
|
-
if (Array.isArray<PersistedJson>(value)) return value.some(hasNegativeSchema);
|
|
216
|
-
if (value === null || typeof value !== "object") return false;
|
|
217
|
-
|
|
218
|
-
return Object.entries(value).some(
|
|
219
|
-
([key, child]) =>
|
|
220
|
-
key === "oneOf" ||
|
|
221
|
-
key === "maxContains" ||
|
|
222
|
-
key === "unevaluatedProperties" ||
|
|
223
|
-
key === "unevaluatedItems" ||
|
|
224
|
-
key === "if" ||
|
|
225
|
-
key === "then" ||
|
|
226
|
-
key === "else" ||
|
|
227
|
-
key === "$dynamicRef" ||
|
|
228
|
-
key === "$recursiveRef" ||
|
|
229
|
-
(key === "not" && !jsonEqual(child, {})) ||
|
|
230
|
-
hasNegativeSchema(child),
|
|
231
|
-
);
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
if (hasNegativeSchema(previous) || hasNegativeSchema(current)) return false;
|
|
235
|
-
|
|
236
|
-
const compare = (before: PersistedJson, after: PersistedJson): boolean => {
|
|
237
|
-
if (jsonEqual(before, after)) return true;
|
|
238
|
-
if (
|
|
239
|
-
before === null ||
|
|
240
|
-
typeof before !== "object" ||
|
|
241
|
-
Array.isArray<PersistedJson>(before) ||
|
|
242
|
-
after === null ||
|
|
243
|
-
typeof after !== "object" ||
|
|
244
|
-
Array.isArray<PersistedJson>(after)
|
|
245
|
-
)
|
|
246
|
-
return false;
|
|
247
|
-
if (Object.keys(before).length !== Object.keys(after).length) return false;
|
|
248
|
-
|
|
249
|
-
return Object.entries(before).every(([key, value]) => {
|
|
250
|
-
if (!Object.hasOwn(after, key)) return false;
|
|
251
|
-
const next = after[key]!;
|
|
252
|
-
|
|
253
|
-
if (jsonEqual(value, next)) return true;
|
|
254
|
-
if (key === "additionalProperties") return value === false && next === true;
|
|
255
|
-
if (key === "items") return compare(value, next);
|
|
256
|
-
if (
|
|
257
|
-
(key === "anyOf" || key === "allOf") &&
|
|
258
|
-
Array.isArray<PersistedJson>(value) &&
|
|
259
|
-
Array.isArray<PersistedJson>(next)
|
|
260
|
-
)
|
|
261
|
-
return (
|
|
262
|
-
value.length === next.length &&
|
|
263
|
-
value.every((entry, index) => compare(entry, next[index]!))
|
|
264
|
-
);
|
|
265
|
-
if (
|
|
266
|
-
(key === "properties" || key === "$defs" || key === "definitions") &&
|
|
267
|
-
value !== null &&
|
|
268
|
-
typeof value === "object" &&
|
|
269
|
-
!Array.isArray<PersistedJson>(value) &&
|
|
270
|
-
next !== null &&
|
|
271
|
-
typeof next === "object" &&
|
|
272
|
-
!Array.isArray<PersistedJson>(next)
|
|
273
|
-
)
|
|
274
|
-
return (
|
|
275
|
-
Object.keys(value).length === Object.keys(next).length &&
|
|
276
|
-
Object.entries(value).every(
|
|
277
|
-
([name, schema]) => Object.hasOwn(next, name) && compare(schema, next[name]!),
|
|
278
|
-
)
|
|
279
|
-
);
|
|
280
|
-
|
|
281
|
-
return false;
|
|
282
|
-
});
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
return compare(previous, current);
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
/** Compile audited declaration data once, without acquiring an executable or rewriting receipts.
|
|
289
|
-
* Full input schemas stay in registration metadata, never in each admission's replay contract. */
|
|
290
|
-
export const compileBindingManifest = Effect.fn("AgentRegistration.compileBindingManifest")(
|
|
112
|
+
/** Compile current metadata without acquiring executable services. */
|
|
113
|
+
export const compileBindingContracts = Effect.fn("AgentRegistration.compileBindingContracts")(
|
|
291
114
|
function* (
|
|
292
115
|
definition: Agent.AnyDefinition,
|
|
293
116
|
definitions: DefinitionDigestInput,
|
|
294
|
-
versions
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
DigestError,
|
|
299
|
-
Crypto.Crypto
|
|
300
|
-
> {
|
|
301
|
-
const manifest = yield* makeBindingManifest(definition, definitions, versions);
|
|
302
|
-
|
|
303
|
-
const validContract = Effect.fnUntraced(function* (entry: BindingManifest) {
|
|
304
|
-
if (entry.agentContract === undefined) return undefined;
|
|
305
|
-
if (
|
|
306
|
-
entry.agentContract.id !== entry.agentId ||
|
|
307
|
-
(yield* digestJson(entry.agentContract)) !== entry.replay.agent ||
|
|
308
|
-
(entry.replay.agentBehavior !== undefined &&
|
|
309
|
-
(yield* digestJson({ ...entry.agentContract, input: null })) !==
|
|
310
|
-
entry.replay.agentBehavior)
|
|
311
|
-
)
|
|
312
|
-
return yield* DigestError.make({
|
|
313
|
-
message: "A manifest's Agent contract does not match its replay digest",
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
return entry.agentContract;
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
const current = manifest.agentContract!;
|
|
320
|
-
const acceptsInput = Schema.is(Schema.toEncoded(definition.input));
|
|
321
|
-
|
|
322
|
-
const validateTools = Effect.fnUntraced(function* (entry: BindingManifest) {
|
|
323
|
-
for (const [name, contract] of Object.entries(entry.toolContracts ?? {}))
|
|
324
|
-
if ((yield* digestJson(contract)) !== entry.replay.tools[name])
|
|
325
|
-
return yield* DigestError.make({
|
|
326
|
-
message: "A manifest's Tool contract does not match its replay digest",
|
|
327
|
-
});
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
const digests = yield* digestDefinitions(manifest.definitions);
|
|
331
|
-
|
|
332
|
-
const retainedManifests = yield* Effect.forEach(
|
|
333
|
-
retained,
|
|
334
|
-
Effect.fnUntraced(function* (entry) {
|
|
335
|
-
if (entry.agentId !== manifest.agentId)
|
|
336
|
-
return yield* DigestError.make({
|
|
337
|
-
message: "A retained manifest belongs to another Agent",
|
|
338
|
-
});
|
|
339
|
-
const previous = yield* validContract(entry);
|
|
340
|
-
|
|
341
|
-
yield* validateTools(entry);
|
|
342
|
-
|
|
343
|
-
const compatible =
|
|
344
|
-
previous !== undefined &&
|
|
345
|
-
jsonEqual(
|
|
346
|
-
{ ...previous, input: null, output: null, updates: null, disposition: null },
|
|
347
|
-
{ ...current, input: null, output: null, updates: null, disposition: null },
|
|
348
|
-
) &&
|
|
349
|
-
schemasCompatible(previous.output, current.output) &&
|
|
350
|
-
schemasCompatible(previous.updates, current.updates) &&
|
|
351
|
-
schemasCompatible(previous.disposition, current.disposition);
|
|
352
|
-
|
|
353
|
-
const compatibleTools: Record<string, string> = {};
|
|
354
|
-
|
|
355
|
-
for (const [name, oldTool] of Object.entries(entry.toolContracts ?? {})) {
|
|
356
|
-
const newTool = manifest.toolContracts?.[name];
|
|
357
|
-
|
|
358
|
-
if (
|
|
359
|
-
newTool !== undefined &&
|
|
360
|
-
jsonEqual(
|
|
361
|
-
{ ...oldTool, parameters: null, success: null, failure: null },
|
|
362
|
-
{ ...newTool, parameters: null, success: null, failure: null },
|
|
363
|
-
) &&
|
|
364
|
-
schemasCompatible(oldTool.parameters, newTool.parameters) &&
|
|
365
|
-
schemasCompatible(oldTool.success, newTool.success) &&
|
|
366
|
-
schemasCompatible(oldTool.failure, newTool.failure)
|
|
367
|
-
)
|
|
368
|
-
compatibleTools[name] = manifest.replay.tools[name]!;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
return {
|
|
372
|
-
digests: yield* digestDefinitions(entry.definitions),
|
|
373
|
-
replay: entry.replay,
|
|
374
|
-
compatibleTools,
|
|
375
|
-
...(compatible ? { compatibleAgent: manifest.replay.agent } : {}),
|
|
376
|
-
};
|
|
377
|
-
}),
|
|
378
|
-
);
|
|
117
|
+
versions?: ReplayVersions,
|
|
118
|
+
): Effect.fn.Return<Pick<ResolvedBinding, "digests">, DigestError, Crypto.Crypto> {
|
|
119
|
+
const digests = yield* digestDefinitions(definitions);
|
|
120
|
+
const tools = yield* toolReplayContracts(definition, versions, definitions.tools);
|
|
379
121
|
|
|
380
122
|
return {
|
|
381
|
-
digests: DefinitionDigests.make({
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
// Async checks and defective guards cannot establish synchronous replay proof.
|
|
386
|
-
try {
|
|
387
|
-
return acceptsInput(input);
|
|
388
|
-
} catch {
|
|
389
|
-
return false;
|
|
390
|
-
}
|
|
391
|
-
},
|
|
123
|
+
digests: DefinitionDigests.make({
|
|
124
|
+
...digests,
|
|
125
|
+
replay: ReplayContract.make({ agent: digests.agent, tools }),
|
|
126
|
+
}),
|
|
392
127
|
};
|
|
393
128
|
},
|
|
394
129
|
);
|
|
395
130
|
|
|
396
|
-
const replaySupports = (
|
|
397
|
-
current: ReplayContract,
|
|
398
|
-
retained: ReplayContract,
|
|
399
|
-
requiredTools?: ReadonlyArray<string>,
|
|
400
|
-
inputCompatible = false,
|
|
401
|
-
compatibleTools: Readonly<Record<string, string>> = {},
|
|
402
|
-
): boolean =>
|
|
403
|
-
(current.agent === retained.agent || inputCompatible) &&
|
|
404
|
-
(requiredTools ?? Object.keys(retained.tools)).every(
|
|
405
|
-
(name) =>
|
|
406
|
-
retained.tools[name] !== undefined &&
|
|
407
|
-
(current.tools[name] === retained.tools[name] ||
|
|
408
|
-
(current.tools[name] !== undefined && compatibleTools[name] === current.tools[name])),
|
|
409
|
-
);
|
|
410
|
-
|
|
411
|
-
/** Resolve executable code only. Admission, delivery, lineage and receipt comparisons stay exact. */
|
|
412
|
-
export const bindingSupports = (
|
|
413
|
-
binding: Pick<ResolvedBinding, "digests" | "retainedManifests" | "acceptsInput">,
|
|
414
|
-
digests: DefinitionDigests,
|
|
415
|
-
requiredTools?: ReadonlyArray<string>,
|
|
416
|
-
input?: PersistedJson,
|
|
417
|
-
): boolean => {
|
|
418
|
-
if (definitionDigestsEqual(binding.digests, digests)) return true;
|
|
419
|
-
|
|
420
|
-
const manifest = binding.retainedManifests?.find(
|
|
421
|
-
(entry) =>
|
|
422
|
-
definitionDigestsEqual(entry.digests, digests) ||
|
|
423
|
-
definitionDigestsEqual({ ...entry.digests, replay: entry.replay }, digests),
|
|
424
|
-
);
|
|
425
|
-
|
|
426
|
-
const retained = digests.replay ?? manifest?.replay;
|
|
427
|
-
|
|
428
|
-
return (
|
|
429
|
-
binding.digests.replay !== undefined &&
|
|
430
|
-
retained !== undefined &&
|
|
431
|
-
replaySupports(
|
|
432
|
-
binding.digests.replay,
|
|
433
|
-
retained,
|
|
434
|
-
requiredTools,
|
|
435
|
-
input !== undefined &&
|
|
436
|
-
binding.acceptsInput?.(input) === true &&
|
|
437
|
-
((binding.digests.replay.agentBehavior !== undefined &&
|
|
438
|
-
binding.digests.replay.agentBehavior === retained.agentBehavior) ||
|
|
439
|
-
manifest?.compatibleAgent === binding.digests.replay.agent),
|
|
440
|
-
manifest?.compatibleTools,
|
|
441
|
-
)
|
|
442
|
-
);
|
|
443
|
-
};
|
|
444
|
-
|
|
445
131
|
type ExecutableDefinition = Agent.AnyDefinition & {
|
|
446
132
|
readonly instructions: InstructionSource<never, unknown, unknown>;
|
|
447
133
|
readonly inputPrompt?: InputPromptSource<never, unknown, unknown> | undefined;
|
|
@@ -572,16 +258,6 @@ const backgroundReports = (definition: Agent.AnyDefinition) => [
|
|
|
572
258
|
/** One exact executable registration used by durable claim-time resolution. */
|
|
573
259
|
export interface ResolvedBinding extends CapturedBinding {
|
|
574
260
|
readonly digests: DefinitionDigests;
|
|
575
|
-
readonly manifest?: BindingManifest;
|
|
576
|
-
/** Current encoded input guard, acquired without executable services. */
|
|
577
|
-
readonly acceptsInput?: (input: PersistedJson) => boolean;
|
|
578
|
-
readonly retainedManifests?: ReadonlyArray<{
|
|
579
|
-
readonly digests: DefinitionDigests;
|
|
580
|
-
readonly replay: ReplayContract;
|
|
581
|
-
readonly compatibleTools?: Readonly<Record<string, string>>;
|
|
582
|
-
/** Original declarations prove unchanged semantics and output/completion contracts. */
|
|
583
|
-
readonly compatibleAgent?: string;
|
|
584
|
-
}>;
|
|
585
261
|
}
|
|
586
262
|
|
|
587
263
|
/** Trusted claim identity for resolving per-Attempt application services. Not model input. */
|
|
@@ -678,38 +354,18 @@ export const makeLegacyWorkerBinding = capture;
|
|
|
678
354
|
export const resolveWorkerBinding = (
|
|
679
355
|
bindings: ReadonlyArray<ResolvedBinding>,
|
|
680
356
|
agentId: AgentId,
|
|
681
|
-
|
|
682
|
-
requiredTools?: ReadonlyArray<string>,
|
|
683
|
-
input?: PersistedJson,
|
|
684
|
-
): Effect.Effect<ResolvedBinding, DurableBindingFailure> => {
|
|
357
|
+
): Effect.Effect<ResolvedBinding, BindingUnavailable> => {
|
|
685
358
|
const registered = bindings.filter((binding) => binding.agentId === agentId);
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
const compatible =
|
|
698
|
-
exact ??
|
|
699
|
-
(registered.length === 1 && bindingSupports(registered[0]!, digests, requiredTools, input)
|
|
700
|
-
? registered[0]
|
|
701
|
-
: undefined);
|
|
702
|
-
|
|
703
|
-
if (compatible === undefined) {
|
|
704
|
-
return Effect.fail(
|
|
705
|
-
BindingDigestMismatch.make({
|
|
706
|
-
agentId,
|
|
707
|
-
message: `No registered Binding proves the retained replay contracts for ${agentId}; the original request and receipts remain pending`,
|
|
708
|
-
}),
|
|
709
|
-
);
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
return Effect.succeed(compatible);
|
|
359
|
+
const binding = registered[0];
|
|
360
|
+
|
|
361
|
+
return registered.length === 1 && binding !== undefined
|
|
362
|
+
? Effect.succeed(binding)
|
|
363
|
+
: Effect.fail(
|
|
364
|
+
BindingUnavailable.make({
|
|
365
|
+
agentId,
|
|
366
|
+
message: `Exactly one current Agent Binding must be registered for ${agentId}`,
|
|
367
|
+
}),
|
|
368
|
+
);
|
|
713
369
|
};
|
|
714
370
|
|
|
715
371
|
/** Resolve authoring-time admission through the one exact host registration, never by identity alone. */
|
|
@@ -750,10 +406,9 @@ export type AgentRegistration<A extends ExecutableAgentBinding = ExecutableAgent
|
|
|
750
406
|
readonly definitions: DefinitionDigestInput;
|
|
751
407
|
}
|
|
752
408
|
) & {
|
|
753
|
-
/**
|
|
409
|
+
/** Explicit operation versions let unchanged unfinished handlers survive toolbox changes. */
|
|
754
410
|
readonly continuity?: {
|
|
755
411
|
readonly versions: ReplayVersions;
|
|
756
|
-
readonly retainedManifests?: ReadonlyArray<BindingManifest>;
|
|
757
412
|
};
|
|
758
413
|
/**
|
|
759
414
|
* Source-owned reports capture services outside attemptLayer and open a fresh Scope per
|
|
@@ -897,16 +552,12 @@ const compileRegistration = <Entry extends AgentRegistration>(
|
|
|
897
552
|
...backgroundReports(binding.definition),
|
|
898
553
|
]);
|
|
899
554
|
|
|
900
|
-
if (entry.continuity === undefined)
|
|
901
|
-
return { ...binding, digests: yield* digestDefinitions(definitions), reporting };
|
|
902
|
-
|
|
903
555
|
return {
|
|
904
556
|
...binding,
|
|
905
|
-
...(yield*
|
|
557
|
+
...(yield* compileBindingContracts(
|
|
906
558
|
binding.definition,
|
|
907
559
|
definitions,
|
|
908
|
-
entry.continuity
|
|
909
|
-
entry.continuity.retainedManifests,
|
|
560
|
+
entry.continuity?.versions,
|
|
910
561
|
)),
|
|
911
562
|
reporting,
|
|
912
563
|
};
|
|
@@ -52,7 +52,6 @@ import {
|
|
|
52
52
|
} from "../ThreadStore.ts";
|
|
53
53
|
import {
|
|
54
54
|
definitionDigestsEqual,
|
|
55
|
-
bindingSupports,
|
|
56
55
|
resolveDefinitionBinding,
|
|
57
56
|
type ResolvedBinding,
|
|
58
57
|
} from "./agent-registration.ts";
|
|
@@ -307,7 +306,6 @@ export const makeMessagingRuntime = Effect.fn("MessagingHost.make")(function* (
|
|
|
307
306
|
!Schema.is(MessageAdmission)(metadata) ||
|
|
308
307
|
metadata.peerName !== request.name ||
|
|
309
308
|
saved.envelope.agentId !== target.agentId ||
|
|
310
|
-
!bindingSupports(target, saved.envelope.definitions, undefined, saved.envelope.input) ||
|
|
311
309
|
!sameJson(saved.envelope.input, input) ||
|
|
312
310
|
(inReplyTo === undefined || metadata.inReplyTo === undefined
|
|
313
311
|
? inReplyTo !== metadata.inReplyTo
|