@tangle-network/agent-interface 1.2.0 → 1.4.0
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/README.md +6 -0
- package/dist/agent-execution-preparation-receipt.d.ts +308 -0
- package/dist/agent-execution-preparation-receipt.js +217 -0
- package/dist/agent-execution-preparation.d.ts +5 -300
- package/dist/agent-execution-preparation.js +6 -219
- package/dist/agent-workspace-lease.d.ts +2 -18
- package/dist/agent-workspace-lease.js +2 -14
- package/dist/agent-workspace-source-snapshot.d.ts +21 -0
- package/dist/agent-workspace-source-snapshot.js +18 -0
- package/dist/environment-interactive-control.d.ts +1694 -0
- package/dist/environment-interactive-control.js +456 -0
- package/dist/environment-interactive-shared.d.ts +5 -0
- package/dist/environment-interactive-shared.js +16 -0
- package/dist/environment-interactive-start.d.ts +238 -0
- package/dist/environment-interactive-start.js +95 -0
- package/dist/environment-interactive.d.ts +2 -1930
- package/dist/environment-interactive.js +2 -557
- package/dist/environment-observation.d.ts +3 -3
- package/dist/environment-runtime.d.ts +41 -1
- package/dist/environment-runtime.js +27 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/runtime-control.js +66 -0
- package/dist/stream-events.d.ts +59 -1
- package/package.json +6 -1
|
@@ -1,557 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { agentExecutionPreparationReceiptSchema, canonicalAgentProfileDigest, } from "./agent-execution-preparation.js";
|
|
4
|
-
import { boundedIdentifierSchema, boundedStringSchema, } from "./contract-limits.js";
|
|
5
|
-
import { agentProfileSchema } from "./profile-schema.js";
|
|
6
|
-
import { AgentExactRunControlRefSchema, } from "./runtime-control.js";
|
|
7
|
-
const INTERACTIVE_MAX_DIMENSION = 10_000;
|
|
8
|
-
const interactiveDimensionSchema = z
|
|
9
|
-
.number()
|
|
10
|
-
.int()
|
|
11
|
-
.positive()
|
|
12
|
-
.max(INTERACTIVE_MAX_DIMENSION);
|
|
13
|
-
const AgentInteractiveSessionRunCoordinatesSchema = z.strictObject({
|
|
14
|
-
provider: boundedIdentifierSchema,
|
|
15
|
-
environmentId: boundedIdentifierSchema,
|
|
16
|
-
sessionId: boundedIdentifierSchema,
|
|
17
|
-
executionId: boundedIdentifierSchema,
|
|
18
|
-
});
|
|
19
|
-
/**
|
|
20
|
-
* Durable identity of one coding-agent TUI.
|
|
21
|
-
*
|
|
22
|
-
* This reference identifies the exact admitted run and preparation receipt.
|
|
23
|
-
* It is not a generic shell id and cannot be used to create another process.
|
|
24
|
-
*/
|
|
25
|
-
export const AgentInteractiveSessionRefSchema = z.strictObject({
|
|
26
|
-
run: AgentExactRunControlRefSchema,
|
|
27
|
-
/** Canonical executor receipt containing the effective route and its proof. */
|
|
28
|
-
preparationReceipt: agentExecutionPreparationReceiptSchema,
|
|
29
|
-
/** Provider-issued identity of this exact process incarnation. */
|
|
30
|
-
incarnationId: boundedIdentifierSchema,
|
|
31
|
-
startedAt: z.iso.datetime().max(64),
|
|
32
|
-
});
|
|
33
|
-
/**
|
|
34
|
-
* Provider-issued write authority for one exact interactive process.
|
|
35
|
-
*
|
|
36
|
-
* Expiry blocks mutations but does not kill the coding process. A coordinator
|
|
37
|
-
* can issue a new compare-and-swap claim after expiry. The provider's PTY owner
|
|
38
|
-
* lease remains the separate process-cleanup authority.
|
|
39
|
-
*/
|
|
40
|
-
export const AgentInteractiveSessionControlClaimSchema = z.strictObject({
|
|
41
|
-
/** Canonical identity of the process ref this authority can mutate. */
|
|
42
|
-
refDigest: sha256DigestSchema,
|
|
43
|
-
/** Provider generation. A recovered coordinator must obtain a greater value. */
|
|
44
|
-
generation: z.number().int().positive().safe(),
|
|
45
|
-
/** Provider lease identity for this generation. */
|
|
46
|
-
leaseId: boundedIdentifierSchema,
|
|
47
|
-
/** Stable identity of the coordinator holding this lease. */
|
|
48
|
-
holderId: boundedIdentifierSchema,
|
|
49
|
-
expiresAt: z.iso.datetime().max(64),
|
|
50
|
-
});
|
|
51
|
-
const AgentInteractiveSessionControlClaimRequestMaterialSchema = z.strictObject({
|
|
52
|
-
operationId: boundedIdentifierSchema,
|
|
53
|
-
ref: AgentInteractiveSessionRefSchema,
|
|
54
|
-
holderId: boundedIdentifierSchema,
|
|
55
|
-
expectedGeneration: z.number().int().nonnegative().safe(),
|
|
56
|
-
});
|
|
57
|
-
export function agentInteractiveSessionControlClaimRequestDigest(value) {
|
|
58
|
-
const parsed = AgentInteractiveSessionControlClaimRequestMaterialSchema.parse(value);
|
|
59
|
-
return canonicalCandidateDigest({
|
|
60
|
-
kind: "agent-interactive-session-control-claim.v1",
|
|
61
|
-
operationId: parsed.operationId,
|
|
62
|
-
ref: parsed.ref,
|
|
63
|
-
holderId: parsed.holderId,
|
|
64
|
-
expectedGeneration: parsed.expectedGeneration,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
export const AgentInteractiveSessionControlClaimRequestSchema = z
|
|
68
|
-
.strictObject({
|
|
69
|
-
...AgentInteractiveSessionControlClaimRequestMaterialSchema.shape,
|
|
70
|
-
requestDigest: sha256DigestSchema,
|
|
71
|
-
})
|
|
72
|
-
.superRefine((request, refinement) => {
|
|
73
|
-
const { requestDigest: _requestDigest, ...material } = request;
|
|
74
|
-
if (request.requestDigest !==
|
|
75
|
-
agentInteractiveSessionControlClaimRequestDigest(material)) {
|
|
76
|
-
refinement.addIssue({
|
|
77
|
-
code: "custom",
|
|
78
|
-
path: ["requestDigest"],
|
|
79
|
-
message: "interactive session control claim request digest does not match its content",
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
export const AgentInteractiveSessionControlClaimAcknowledgementSchema = z
|
|
84
|
-
.strictObject({
|
|
85
|
-
operationId: boundedIdentifierSchema,
|
|
86
|
-
requestDigest: sha256DigestSchema,
|
|
87
|
-
ref: AgentInteractiveSessionRefSchema,
|
|
88
|
-
status: z.enum(["accepted", "replayed", "conflict", "unknown"]),
|
|
89
|
-
control: AgentInteractiveSessionControlClaimSchema.optional(),
|
|
90
|
-
conflictReason: z
|
|
91
|
-
.enum(["generation_mismatch", "operation_reuse"])
|
|
92
|
-
.optional(),
|
|
93
|
-
currentGeneration: z.number().int().nonnegative().safe().optional(),
|
|
94
|
-
existingRequestDigest: sha256DigestSchema.optional(),
|
|
95
|
-
message: boundedStringSchema.min(1).optional(),
|
|
96
|
-
retryable: z.boolean().optional(),
|
|
97
|
-
})
|
|
98
|
-
.superRefine((acknowledgement, refinement) => {
|
|
99
|
-
const hasControl = acknowledgement.control !== undefined;
|
|
100
|
-
if ((acknowledgement.status === "accepted" ||
|
|
101
|
-
acknowledgement.status === "replayed") &&
|
|
102
|
-
!hasControl) {
|
|
103
|
-
refinement.addIssue({
|
|
104
|
-
code: "custom",
|
|
105
|
-
path: ["control"],
|
|
106
|
-
message: "an accepted control claim must return its provider claim",
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
if (acknowledgement.status !== "accepted" &&
|
|
110
|
-
acknowledgement.status !== "replayed" &&
|
|
111
|
-
hasControl) {
|
|
112
|
-
refinement.addIssue({
|
|
113
|
-
code: "custom",
|
|
114
|
-
path: ["control"],
|
|
115
|
-
message: "only an accepted or replayed claim may return control",
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
if (acknowledgement.status === "conflict" &&
|
|
119
|
-
acknowledgement.conflictReason === undefined) {
|
|
120
|
-
refinement.addIssue({
|
|
121
|
-
code: "custom",
|
|
122
|
-
path: ["conflictReason"],
|
|
123
|
-
message: "a control claim conflict must distinguish generation mismatch from operation reuse",
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
if (acknowledgement.status !== "conflict" &&
|
|
127
|
-
acknowledgement.conflictReason !== undefined) {
|
|
128
|
-
refinement.addIssue({
|
|
129
|
-
code: "custom",
|
|
130
|
-
path: ["conflictReason"],
|
|
131
|
-
message: "only a control claim conflict may report a conflict reason",
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
if (hasControl &&
|
|
135
|
-
!agentInteractiveSessionControlClaimMatchesRef(acknowledgement.ref, acknowledgement.control)) {
|
|
136
|
-
refinement.addIssue({
|
|
137
|
-
code: "custom",
|
|
138
|
-
path: ["control", "refDigest"],
|
|
139
|
-
message: "interactive control claim acknowledgement does not match its process ref",
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
if (acknowledgement.status === "conflict" &&
|
|
143
|
-
acknowledgement.currentGeneration === undefined) {
|
|
144
|
-
refinement.addIssue({
|
|
145
|
-
code: "custom",
|
|
146
|
-
path: ["currentGeneration"],
|
|
147
|
-
message: "a control claim conflict must report the current generation",
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
if (acknowledgement.conflictReason === "generation_mismatch" &&
|
|
151
|
-
acknowledgement.existingRequestDigest !== undefined) {
|
|
152
|
-
refinement.addIssue({
|
|
153
|
-
code: "custom",
|
|
154
|
-
path: ["existingRequestDigest"],
|
|
155
|
-
message: "a generation mismatch must not be reported as operation reuse",
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
if (acknowledgement.conflictReason === "operation_reuse" &&
|
|
159
|
-
acknowledgement.existingRequestDigest === undefined) {
|
|
160
|
-
refinement.addIssue({
|
|
161
|
-
code: "custom",
|
|
162
|
-
path: ["existingRequestDigest"],
|
|
163
|
-
message: "operation reuse must report the digest already stored for this operation",
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
if (acknowledgement.status === "conflict" &&
|
|
167
|
-
acknowledgement.existingRequestDigest === acknowledgement.requestDigest) {
|
|
168
|
-
refinement.addIssue({
|
|
169
|
-
code: "custom",
|
|
170
|
-
path: ["existingRequestDigest"],
|
|
171
|
-
message: "a control claim conflict must identify different request material",
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
if (acknowledgement.status !== "conflict" &&
|
|
175
|
-
(acknowledgement.currentGeneration !== undefined ||
|
|
176
|
-
acknowledgement.existingRequestDigest !== undefined)) {
|
|
177
|
-
refinement.addIssue({
|
|
178
|
-
code: "custom",
|
|
179
|
-
path: ["currentGeneration"],
|
|
180
|
-
message: "only a control claim conflict may report existing generation state",
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
if (acknowledgement.status === "unknown" &&
|
|
184
|
-
(acknowledgement.message === undefined || acknowledgement.retryable !== true)) {
|
|
185
|
-
refinement.addIssue({
|
|
186
|
-
code: "custom",
|
|
187
|
-
path: ["retryable"],
|
|
188
|
-
message: "an unknown control claim outcome must explicitly permit safe same-operation retry",
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
export function agentInteractiveSessionControlClaimAcknowledgementMatchesRequest(request, acknowledgement) {
|
|
193
|
-
const exactRequest = AgentInteractiveSessionControlClaimRequestSchema.safeParse(request);
|
|
194
|
-
const exactAcknowledgement = AgentInteractiveSessionControlClaimAcknowledgementSchema.safeParse(acknowledgement);
|
|
195
|
-
if (!exactRequest.success || !exactAcknowledgement.success)
|
|
196
|
-
return false;
|
|
197
|
-
return (exactAcknowledgement.data.operationId === exactRequest.data.operationId &&
|
|
198
|
-
exactAcknowledgement.data.requestDigest === exactRequest.data.requestDigest &&
|
|
199
|
-
canonicalCandidateDigest(exactAcknowledgement.data.ref) ===
|
|
200
|
-
canonicalCandidateDigest(exactRequest.data.ref));
|
|
201
|
-
}
|
|
202
|
-
/** Bind a provider-issued control claim to the exact process it can mutate. */
|
|
203
|
-
export function agentInteractiveSessionControlClaimMatchesRef(ref, claim) {
|
|
204
|
-
const parsedRef = AgentInteractiveSessionRefSchema.safeParse(ref);
|
|
205
|
-
const parsedClaim = AgentInteractiveSessionControlClaimSchema.safeParse(claim);
|
|
206
|
-
return (parsedRef.success &&
|
|
207
|
-
parsedClaim.success &&
|
|
208
|
-
parsedClaim.data.refDigest === canonicalCandidateDigest(parsedRef.data));
|
|
209
|
-
}
|
|
210
|
-
/** Compare two claims for one process without making a provider state claim. */
|
|
211
|
-
export function agentInteractiveSessionControlClaimIsNewer(candidate, current) {
|
|
212
|
-
const parsedCandidate = AgentInteractiveSessionControlClaimSchema.safeParse(candidate);
|
|
213
|
-
const parsedCurrent = AgentInteractiveSessionControlClaimSchema.safeParse(current);
|
|
214
|
-
return (parsedCandidate.success &&
|
|
215
|
-
parsedCurrent.success &&
|
|
216
|
-
parsedCandidate.data.refDigest === parsedCurrent.data.refDigest &&
|
|
217
|
-
parsedCandidate.data.generation > parsedCurrent.data.generation);
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Start one native coding-agent TUI from caller-owned request material.
|
|
221
|
-
*
|
|
222
|
-
* The provider owns profile materialization and returns its preparation receipt
|
|
223
|
-
* in the resulting reference. Replaying the same exact request/run returns the
|
|
224
|
-
* same reference, even after the process exits; changed material cannot reuse it.
|
|
225
|
-
*/
|
|
226
|
-
export const AgentInteractiveSessionStartSchema = z.strictObject({
|
|
227
|
-
run: AgentExactRunControlRefSchema,
|
|
228
|
-
profile: agentProfileSchema,
|
|
229
|
-
requestedProfileDigest: sha256DigestSchema,
|
|
230
|
-
initialPrompt: boundedStringSchema.optional(),
|
|
231
|
-
cwd: boundedStringSchema.min(1).optional(),
|
|
232
|
-
cols: interactiveDimensionSchema.optional(),
|
|
233
|
-
rows: interactiveDimensionSchema.optional(),
|
|
234
|
-
});
|
|
235
|
-
/** Digest the exact process-start request independently of its derived run id. */
|
|
236
|
-
export function agentInteractiveSessionRequestDigest(coordinates, input) {
|
|
237
|
-
const exactCoordinates = AgentInteractiveSessionRunCoordinatesSchema.parse(coordinates);
|
|
238
|
-
const exactInput = AgentInteractiveSessionStartSchema.omit({ run: true }).parse(input);
|
|
239
|
-
return canonicalCandidateDigest({
|
|
240
|
-
kind: "agent-interactive-session-start.v1",
|
|
241
|
-
run: exactCoordinates,
|
|
242
|
-
requestedProfileDigest: exactInput.requestedProfileDigest,
|
|
243
|
-
...(exactInput.initialPrompt === undefined
|
|
244
|
-
? {}
|
|
245
|
-
: { initialPrompt: exactInput.initialPrompt }),
|
|
246
|
-
...(exactInput.cwd === undefined ? {} : { cwd: exactInput.cwd }),
|
|
247
|
-
...(exactInput.cols === undefined ? {} : { cols: exactInput.cols }),
|
|
248
|
-
...(exactInput.rows === undefined ? {} : { rows: exactInput.rows }),
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
/** Mint the one exact run reference a provider must acknowledge for this start. */
|
|
252
|
-
export function agentInteractiveSessionRunRef(coordinates, input) {
|
|
253
|
-
const exactCoordinates = AgentInteractiveSessionRunCoordinatesSchema.parse(coordinates);
|
|
254
|
-
const requestDigest = agentInteractiveSessionRequestDigest(exactCoordinates, input);
|
|
255
|
-
return AgentExactRunControlRefSchema.parse({
|
|
256
|
-
...exactCoordinates,
|
|
257
|
-
runId: `interactive-run-${requestDigest.slice("sha256:".length)}`,
|
|
258
|
-
requestDigest,
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
/** Geometry for one attachment to the existing coding-agent TUI. */
|
|
262
|
-
export const AgentInteractiveSessionAttachSchema = z.strictObject({
|
|
263
|
-
/** Required because the returned terminal permits input and resize. */
|
|
264
|
-
control: AgentInteractiveSessionControlClaimSchema,
|
|
265
|
-
cols: interactiveDimensionSchema.optional(),
|
|
266
|
-
rows: interactiveDimensionSchema.optional(),
|
|
267
|
-
});
|
|
268
|
-
/** Provider-observed lifecycle of one native coding-agent TUI. */
|
|
269
|
-
export const AgentInteractiveSessionStatusSchema = z.discriminatedUnion("state", [
|
|
270
|
-
z.strictObject({
|
|
271
|
-
state: z.literal("running"),
|
|
272
|
-
ref: AgentInteractiveSessionRefSchema,
|
|
273
|
-
}),
|
|
274
|
-
z.strictObject({
|
|
275
|
-
state: z.literal("exited"),
|
|
276
|
-
ref: AgentInteractiveSessionRefSchema,
|
|
277
|
-
endedAt: z.iso.datetime().max(64),
|
|
278
|
-
reason: z.enum(["exited", "stopped", "lost"]),
|
|
279
|
-
exitCode: z.number().int().optional(),
|
|
280
|
-
exitSignal: boundedStringSchema.min(1).optional(),
|
|
281
|
-
}),
|
|
282
|
-
z.strictObject({
|
|
283
|
-
state: z.literal("unknown"),
|
|
284
|
-
ref: AgentInteractiveSessionRefSchema,
|
|
285
|
-
message: boundedStringSchema.min(1),
|
|
286
|
-
retryable: z.boolean(),
|
|
287
|
-
}),
|
|
288
|
-
]);
|
|
289
|
-
const AgentInteractiveSessionStopCommandMaterialSchema = z
|
|
290
|
-
.strictObject({
|
|
291
|
-
operationId: boundedIdentifierSchema,
|
|
292
|
-
ref: AgentInteractiveSessionRefSchema,
|
|
293
|
-
control: AgentInteractiveSessionControlClaimSchema,
|
|
294
|
-
})
|
|
295
|
-
.superRefine((command, refinement) => {
|
|
296
|
-
if (!agentInteractiveSessionControlClaimMatchesRef(command.ref, command.control)) {
|
|
297
|
-
refinement.addIssue({
|
|
298
|
-
code: "custom",
|
|
299
|
-
path: ["control", "refDigest"],
|
|
300
|
-
message: "interactive stop control claim does not match its process ref",
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
export function agentInteractiveSessionStopRequestDigest(value) {
|
|
305
|
-
const parsed = AgentInteractiveSessionStopCommandMaterialSchema.parse(value);
|
|
306
|
-
return canonicalCandidateDigest({
|
|
307
|
-
kind: "agent-interactive-session-stop.v1",
|
|
308
|
-
operationId: parsed.operationId,
|
|
309
|
-
ref: parsed.ref,
|
|
310
|
-
control: parsed.control,
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
export const AgentInteractiveSessionStopCommandSchema = z
|
|
314
|
-
.strictObject({
|
|
315
|
-
...AgentInteractiveSessionStopCommandMaterialSchema.shape,
|
|
316
|
-
requestDigest: sha256DigestSchema,
|
|
317
|
-
})
|
|
318
|
-
.superRefine((command, refinement) => {
|
|
319
|
-
const { requestDigest: _requestDigest, ...material } = command;
|
|
320
|
-
if (command.requestDigest !==
|
|
321
|
-
agentInteractiveSessionStopRequestDigest(material)) {
|
|
322
|
-
refinement.addIssue({
|
|
323
|
-
code: "custom",
|
|
324
|
-
path: ["requestDigest"],
|
|
325
|
-
message: "interactive stop request digest does not match its content",
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
});
|
|
329
|
-
export const AgentInteractiveSessionStopAcknowledgementSchema = z
|
|
330
|
-
.strictObject({
|
|
331
|
-
operationId: boundedIdentifierSchema,
|
|
332
|
-
requestDigest: sha256DigestSchema,
|
|
333
|
-
ref: AgentInteractiveSessionRefSchema,
|
|
334
|
-
control: AgentInteractiveSessionControlClaimSchema,
|
|
335
|
-
status: z.enum(["accepted", "replayed", "conflict", "unknown"]),
|
|
336
|
-
effect: z.enum(["stop_requested", "stopped", "not_live", "unknown"]),
|
|
337
|
-
message: boundedStringSchema.min(1).optional(),
|
|
338
|
-
retryable: z.boolean().optional(),
|
|
339
|
-
existingRequestDigest: sha256DigestSchema.optional(),
|
|
340
|
-
})
|
|
341
|
-
.superRefine((acknowledgement, refinement) => {
|
|
342
|
-
if (!agentInteractiveSessionControlClaimMatchesRef(acknowledgement.ref, acknowledgement.control)) {
|
|
343
|
-
refinement.addIssue({
|
|
344
|
-
code: "custom",
|
|
345
|
-
path: ["control", "refDigest"],
|
|
346
|
-
message: "interactive stop acknowledgement control does not match its process ref",
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
const known = acknowledgement.effect !== "unknown";
|
|
350
|
-
if (((acknowledgement.status === "accepted" ||
|
|
351
|
-
acknowledgement.status === "replayed") &&
|
|
352
|
-
!known) ||
|
|
353
|
-
((acknowledgement.status === "conflict" ||
|
|
354
|
-
acknowledgement.status === "unknown") &&
|
|
355
|
-
known)) {
|
|
356
|
-
refinement.addIssue({
|
|
357
|
-
code: "custom",
|
|
358
|
-
path: ["effect"],
|
|
359
|
-
message: "interactive stop status and effect certainty do not agree",
|
|
360
|
-
});
|
|
361
|
-
}
|
|
362
|
-
if (acknowledgement.status === "conflict" &&
|
|
363
|
-
(acknowledgement.existingRequestDigest === undefined ||
|
|
364
|
-
acknowledgement.existingRequestDigest === acknowledgement.requestDigest)) {
|
|
365
|
-
refinement.addIssue({
|
|
366
|
-
code: "custom",
|
|
367
|
-
path: ["existingRequestDigest"],
|
|
368
|
-
message: "an interactive stop conflict must identify a different existing request",
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
if (acknowledgement.status !== "conflict" &&
|
|
372
|
-
acknowledgement.existingRequestDigest !== undefined) {
|
|
373
|
-
refinement.addIssue({
|
|
374
|
-
code: "custom",
|
|
375
|
-
path: ["existingRequestDigest"],
|
|
376
|
-
message: "only an interactive stop conflict may include an existing digest",
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
if (acknowledgement.status === "unknown" &&
|
|
380
|
-
(acknowledgement.message === undefined || acknowledgement.retryable !== true)) {
|
|
381
|
-
refinement.addIssue({
|
|
382
|
-
code: "custom",
|
|
383
|
-
path: ["retryable"],
|
|
384
|
-
message: "an unknown interactive stop outcome must explicitly permit safe same-operation retry",
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
});
|
|
388
|
-
export function agentInteractiveSessionStopAcknowledgementMatchesCommand(command, acknowledgement) {
|
|
389
|
-
const exactCommand = AgentInteractiveSessionStopCommandSchema.safeParse(command);
|
|
390
|
-
const exactAcknowledgement = AgentInteractiveSessionStopAcknowledgementSchema.safeParse(acknowledgement);
|
|
391
|
-
if (!exactCommand.success || !exactAcknowledgement.success)
|
|
392
|
-
return false;
|
|
393
|
-
return (exactAcknowledgement.data.operationId === exactCommand.data.operationId &&
|
|
394
|
-
exactAcknowledgement.data.requestDigest === exactCommand.data.requestDigest &&
|
|
395
|
-
canonicalCandidateDigest(exactAcknowledgement.data.ref) ===
|
|
396
|
-
canonicalCandidateDigest(exactCommand.data.ref) &&
|
|
397
|
-
canonicalCandidateDigest(exactAcknowledgement.data.control) ===
|
|
398
|
-
canonicalCandidateDigest(exactCommand.data.control));
|
|
399
|
-
}
|
|
400
|
-
const AgentInteractiveSessionPromptCommandMaterialSchema = z
|
|
401
|
-
.strictObject({
|
|
402
|
-
operationId: boundedIdentifierSchema,
|
|
403
|
-
ref: AgentInteractiveSessionRefSchema,
|
|
404
|
-
control: AgentInteractiveSessionControlClaimSchema,
|
|
405
|
-
prompt: boundedStringSchema.min(1),
|
|
406
|
-
})
|
|
407
|
-
.superRefine((command, refinement) => {
|
|
408
|
-
if (!agentInteractiveSessionControlClaimMatchesRef(command.ref, command.control)) {
|
|
409
|
-
refinement.addIssue({
|
|
410
|
-
code: "custom",
|
|
411
|
-
path: ["control", "refDigest"],
|
|
412
|
-
message: "interactive prompt control claim does not match its process ref",
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
});
|
|
416
|
-
export function agentInteractiveSessionPromptRequestDigest(value) {
|
|
417
|
-
const parsed = AgentInteractiveSessionPromptCommandMaterialSchema.parse(value);
|
|
418
|
-
return canonicalCandidateDigest({
|
|
419
|
-
kind: "agent-interactive-session-prompt.v1",
|
|
420
|
-
operationId: parsed.operationId,
|
|
421
|
-
ref: parsed.ref,
|
|
422
|
-
control: parsed.control,
|
|
423
|
-
prompt: parsed.prompt,
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
export const AgentInteractiveSessionPromptCommandSchema = z
|
|
427
|
-
.strictObject({
|
|
428
|
-
...AgentInteractiveSessionPromptCommandMaterialSchema.shape,
|
|
429
|
-
requestDigest: sha256DigestSchema,
|
|
430
|
-
})
|
|
431
|
-
.superRefine((command, refinement) => {
|
|
432
|
-
const { requestDigest: _requestDigest, ...material } = command;
|
|
433
|
-
if (command.requestDigest !== agentInteractiveSessionPromptRequestDigest(material)) {
|
|
434
|
-
refinement.addIssue({
|
|
435
|
-
code: "custom",
|
|
436
|
-
path: ["requestDigest"],
|
|
437
|
-
message: "interactive session prompt request digest does not match its content",
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
});
|
|
441
|
-
export const AgentInteractiveSessionPromptAcknowledgementSchema = z
|
|
442
|
-
.strictObject({
|
|
443
|
-
operationId: boundedIdentifierSchema,
|
|
444
|
-
requestDigest: sha256DigestSchema,
|
|
445
|
-
ref: AgentInteractiveSessionRefSchema,
|
|
446
|
-
control: AgentInteractiveSessionControlClaimSchema,
|
|
447
|
-
status: z.enum(["accepted", "replayed", "conflict", "unknown"]),
|
|
448
|
-
message: boundedStringSchema.min(1).optional(),
|
|
449
|
-
retryable: z.boolean().optional(),
|
|
450
|
-
existingRequestDigest: sha256DigestSchema.optional(),
|
|
451
|
-
})
|
|
452
|
-
.superRefine((acknowledgement, refinement) => {
|
|
453
|
-
if (!agentInteractiveSessionControlClaimMatchesRef(acknowledgement.ref, acknowledgement.control)) {
|
|
454
|
-
refinement.addIssue({
|
|
455
|
-
code: "custom",
|
|
456
|
-
path: ["control", "refDigest"],
|
|
457
|
-
message: "interactive prompt acknowledgement control claim does not match its process ref",
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
|
-
if (acknowledgement.status === "conflict" &&
|
|
461
|
-
(acknowledgement.existingRequestDigest === undefined ||
|
|
462
|
-
acknowledgement.existingRequestDigest === acknowledgement.requestDigest)) {
|
|
463
|
-
refinement.addIssue({
|
|
464
|
-
code: "custom",
|
|
465
|
-
path: ["existingRequestDigest"],
|
|
466
|
-
message: "an interactive prompt conflict must identify a different existing request",
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
if (acknowledgement.status !== "conflict" &&
|
|
470
|
-
acknowledgement.existingRequestDigest !== undefined) {
|
|
471
|
-
refinement.addIssue({
|
|
472
|
-
code: "custom",
|
|
473
|
-
path: ["existingRequestDigest"],
|
|
474
|
-
message: "only an interactive prompt conflict may include an existing digest",
|
|
475
|
-
});
|
|
476
|
-
}
|
|
477
|
-
if (acknowledgement.status === "unknown" &&
|
|
478
|
-
(acknowledgement.message === undefined || acknowledgement.retryable !== true)) {
|
|
479
|
-
refinement.addIssue({
|
|
480
|
-
code: "custom",
|
|
481
|
-
path: ["retryable"],
|
|
482
|
-
message: "an unknown interactive prompt outcome must explicitly permit safe same-operation retry",
|
|
483
|
-
});
|
|
484
|
-
}
|
|
485
|
-
});
|
|
486
|
-
export function agentInteractiveSessionPromptAcknowledgementMatchesCommand(command, acknowledgement) {
|
|
487
|
-
const exactCommand = AgentInteractiveSessionPromptCommandSchema.safeParse(command);
|
|
488
|
-
const exactAcknowledgement = AgentInteractiveSessionPromptAcknowledgementSchema.safeParse(acknowledgement);
|
|
489
|
-
if (!exactCommand.success || !exactAcknowledgement.success)
|
|
490
|
-
return false;
|
|
491
|
-
return (exactAcknowledgement.data.operationId === exactCommand.data.operationId &&
|
|
492
|
-
exactAcknowledgement.data.requestDigest === exactCommand.data.requestDigest &&
|
|
493
|
-
canonicalCandidateDigest(exactAcknowledgement.data.ref) ===
|
|
494
|
-
canonicalCandidateDigest(exactCommand.data.ref) &&
|
|
495
|
-
canonicalCandidateDigest(exactAcknowledgement.data.control) ===
|
|
496
|
-
canonicalCandidateDigest(exactCommand.data.control));
|
|
497
|
-
}
|
|
498
|
-
/** Parse a start request and prove its profile identity before provider work. */
|
|
499
|
-
export function exactAgentInteractiveSessionStart(value) {
|
|
500
|
-
const parsed = AgentInteractiveSessionStartSchema.parse(value);
|
|
501
|
-
if (parsed.profile.harness === undefined) {
|
|
502
|
-
throw new Error("interactive agent sessions require AgentProfile.harness");
|
|
503
|
-
}
|
|
504
|
-
const digest = canonicalAgentProfileDigest(parsed.profile);
|
|
505
|
-
if (digest !== parsed.requestedProfileDigest) {
|
|
506
|
-
throw new Error("interactive agent session requested profile digest does not match its profile");
|
|
507
|
-
}
|
|
508
|
-
const { run, ...input } = parsed;
|
|
509
|
-
const expectedRun = agentInteractiveSessionRunRef(runCoordinates(run), input);
|
|
510
|
-
if (!sameExactRun(run, expectedRun)) {
|
|
511
|
-
throw new Error("interactive agent session run identity does not match its start request");
|
|
512
|
-
}
|
|
513
|
-
return parsed;
|
|
514
|
-
}
|
|
515
|
-
/** Prove that a provider returned the exact run and preparation receipt requested. */
|
|
516
|
-
export function agentInteractiveSessionRefMatchesStart(request, ref) {
|
|
517
|
-
const parsedRequest = AgentInteractiveSessionStartSchema.safeParse(request);
|
|
518
|
-
const parsedRef = AgentInteractiveSessionRefSchema.safeParse(ref);
|
|
519
|
-
if (!parsedRequest.success || !parsedRef.success)
|
|
520
|
-
return false;
|
|
521
|
-
const requestedHarness = parsedRequest.data.profile.harness;
|
|
522
|
-
if (requestedHarness === undefined)
|
|
523
|
-
return false;
|
|
524
|
-
return (parsedRef.data.preparationReceipt.authoredProfileDigest ===
|
|
525
|
-
parsedRequest.data.requestedProfileDigest &&
|
|
526
|
-
parsedRef.data.preparationReceipt.harness === requestedHarness &&
|
|
527
|
-
sameExactRun(parsedRef.data.run, parsedRequest.data.run));
|
|
528
|
-
}
|
|
529
|
-
/** Prove that a status belongs to the handle that requested it. */
|
|
530
|
-
export function agentInteractiveSessionStatusMatchesRef(ref, status) {
|
|
531
|
-
const parsedRef = AgentInteractiveSessionRefSchema.safeParse(ref);
|
|
532
|
-
const parsedStatus = AgentInteractiveSessionStatusSchema.safeParse(status);
|
|
533
|
-
if (!parsedRef.success || !parsedStatus.success)
|
|
534
|
-
return false;
|
|
535
|
-
const observed = parsedStatus.data.ref;
|
|
536
|
-
return (observed.preparationReceipt.digest ===
|
|
537
|
-
parsedRef.data.preparationReceipt.digest &&
|
|
538
|
-
observed.incarnationId === parsedRef.data.incarnationId &&
|
|
539
|
-
observed.startedAt === parsedRef.data.startedAt &&
|
|
540
|
-
sameExactRun(observed.run, parsedRef.data.run));
|
|
541
|
-
}
|
|
542
|
-
function sameExactRun(left, right) {
|
|
543
|
-
return (left.runId === right.runId &&
|
|
544
|
-
left.provider === right.provider &&
|
|
545
|
-
left.environmentId === right.environmentId &&
|
|
546
|
-
left.sessionId === right.sessionId &&
|
|
547
|
-
left.executionId === right.executionId &&
|
|
548
|
-
left.requestDigest === right.requestDigest);
|
|
549
|
-
}
|
|
550
|
-
function runCoordinates(run) {
|
|
551
|
-
return {
|
|
552
|
-
provider: run.provider,
|
|
553
|
-
environmentId: run.environmentId,
|
|
554
|
-
sessionId: run.sessionId,
|
|
555
|
-
executionId: run.executionId,
|
|
556
|
-
};
|
|
557
|
-
}
|
|
1
|
+
export * from "./environment-interactive-control.js";
|
|
2
|
+
export * from "./environment-interactive-start.js";
|
|
@@ -135,8 +135,8 @@ export declare const EnvironmentLifecycleSchema: z.ZodObject<{
|
|
|
135
135
|
resumable: z.ZodBoolean;
|
|
136
136
|
mode: z.ZodOptional<z.ZodEnum<{
|
|
137
137
|
none: "none";
|
|
138
|
-
replayed: "replayed";
|
|
139
138
|
native: "native";
|
|
139
|
+
replayed: "replayed";
|
|
140
140
|
}>>;
|
|
141
141
|
}, z.core.$strict>>;
|
|
142
142
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
@@ -460,8 +460,8 @@ export declare const AgentEnvironmentObservationSchema: z.ZodObject<{
|
|
|
460
460
|
resumable: z.ZodBoolean;
|
|
461
461
|
mode: z.ZodOptional<z.ZodEnum<{
|
|
462
462
|
none: "none";
|
|
463
|
-
replayed: "replayed";
|
|
464
463
|
native: "native";
|
|
464
|
+
replayed: "replayed";
|
|
465
465
|
}>>;
|
|
466
466
|
}, z.core.$strict>>;
|
|
467
467
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
@@ -508,8 +508,8 @@ export declare const AgentEnvironmentObservationSchema: z.ZodObject<{
|
|
|
508
508
|
resumable: z.ZodBoolean;
|
|
509
509
|
mode: z.ZodOptional<z.ZodEnum<{
|
|
510
510
|
none: "none";
|
|
511
|
-
replayed: "replayed";
|
|
512
511
|
native: "native";
|
|
512
|
+
replayed: "replayed";
|
|
513
513
|
}>>;
|
|
514
514
|
}, z.core.$strict>>;
|
|
515
515
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
@@ -624,10 +624,34 @@ export interface AgentSession {
|
|
|
624
624
|
signal?: AbortSignal;
|
|
625
625
|
}): Promise<void>;
|
|
626
626
|
}
|
|
627
|
+
/**
|
|
628
|
+
* What one {@link AgentEnvironmentProvider.create} call did for the
|
|
629
|
+
* environment it returned.
|
|
630
|
+
*
|
|
631
|
+
* - `created`: this call provisioned the environment.
|
|
632
|
+
* - `replayed`: an existing environment that matched the idempotency key was
|
|
633
|
+
* returned. This call provisioned nothing.
|
|
634
|
+
*
|
|
635
|
+
* Absent when the provider cannot distinguish the two. A consumer treats an
|
|
636
|
+
* absent value as unknown and fails closed: it never destroys an environment
|
|
637
|
+
* whose creation it cannot prove, because another caller can hold it.
|
|
638
|
+
*/
|
|
639
|
+
export type AgentEnvironmentCreation = "created" | "replayed";
|
|
640
|
+
export declare const AgentEnvironmentCreationSchema: z.ZodEnum<{
|
|
641
|
+
replayed: "replayed";
|
|
642
|
+
created: "created";
|
|
643
|
+
}>;
|
|
627
644
|
export interface AgentEnvironment {
|
|
628
645
|
readonly id: string;
|
|
629
646
|
readonly provider: string;
|
|
630
647
|
readonly name?: string;
|
|
648
|
+
/**
|
|
649
|
+
* The verdict of the create call that returned this object. It is a
|
|
650
|
+
* per-call fact: a same-key replay returns a view of the same environment
|
|
651
|
+
* with `creation: "replayed"`. Absent on `get()` results and when the
|
|
652
|
+
* provider cannot prove which outcome happened.
|
|
653
|
+
*/
|
|
654
|
+
readonly creation?: AgentEnvironmentCreation;
|
|
631
655
|
/**
|
|
632
656
|
* Detached metadata returned by the provider.
|
|
633
657
|
* It can contain caller-authored annotations and is not authorization evidence.
|
|
@@ -945,15 +969,31 @@ export interface AgentEnvironmentCreateIdempotencyRecord<T> {
|
|
|
945
969
|
readonly pending: Promise<T>;
|
|
946
970
|
environment?: T;
|
|
947
971
|
}
|
|
972
|
+
/**
|
|
973
|
+
* Return the per-call view of an environment that a same-key create replayed.
|
|
974
|
+
*
|
|
975
|
+
* The view shares every member of the environment, so operations act on the
|
|
976
|
+
* one environment, and it states `creation: "replayed"` because this call
|
|
977
|
+
* provisioned nothing. The copy is shallow, so the environment must be a plain
|
|
978
|
+
* object whose members do not read `this`; a class instance loses its
|
|
979
|
+
* prototype members in a copy and is rejected.
|
|
980
|
+
* @internal
|
|
981
|
+
*/
|
|
982
|
+
export declare function replayedAgentEnvironmentView<T extends object>(environment: T): T;
|
|
948
983
|
/**
|
|
949
984
|
* Apply the generic create contract to one provider adapter's keyed requests.
|
|
950
985
|
*
|
|
951
986
|
* The provider's backing service remains responsible for retaining the key
|
|
952
987
|
* across adapter reconstruction. This helper coalesces concurrent retries and
|
|
953
988
|
* rejects collisions before the provider performs another create effect.
|
|
989
|
+
*
|
|
990
|
+
* The call that runs `create` receives the environment the provider built,
|
|
991
|
+
* with the creation verdict the provider could prove. Every same-key call
|
|
992
|
+
* after it, including one that awaited the same pending create, receives
|
|
993
|
+
* {@link replayedAgentEnvironmentView} of that environment.
|
|
954
994
|
* @internal
|
|
955
995
|
*/
|
|
956
|
-
export declare function createAgentEnvironmentWithIdempotency<T>(records: Map<string, AgentEnvironmentCreateIdempotencyRecord<T>>, input: CreateAgentEnvironmentInput, create: () => Promise<T>): Promise<T>;
|
|
996
|
+
export declare function createAgentEnvironmentWithIdempotency<T extends object>(records: Map<string, AgentEnvironmentCreateIdempotencyRecord<T>>, input: CreateAgentEnvironmentInput, create: () => Promise<T>): Promise<T>;
|
|
957
997
|
export interface AgentEnvironmentProvider {
|
|
958
998
|
readonly name: string;
|
|
959
999
|
readonly exactProcess?: AgentExactProcessProvider;
|