@tangle-network/agent-interface 0.48.0 → 0.49.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 +4 -0
- package/dist/agent-candidate-execution-plan-schema.d.ts +4 -0
- package/dist/agent-candidate-execution-plan-schema.js +1 -0
- package/dist/agent-candidate-outcome-schema.d.ts +7 -0
- package/dist/agent-candidate-outcome-schema.js +20 -1
- package/dist/agent-candidate-promotion-schema.d.ts +40 -0
- package/dist/agent-candidate-receipt-schema.d.ts +6 -0
- package/dist/agent-candidate-task-schema.d.ts +4 -0
- package/dist/agent-candidate.d.ts +7 -0
- package/dist/agent-execution-limits.js +10 -0
- package/dist/agent-profile-improvement-schema.d.ts +10 -0
- package/dist/environment-observation.d.ts +1076 -0
- package/dist/environment-observation.js +306 -0
- package/dist/environment-provider.d.ts +2 -0
- package/dist/environment-provider.js +2 -0
- package/dist/environment-runtime.d.ts +50 -0
- package/dist/environment-runtime.js +31 -0
- package/dist/environment-terminal.d.ts +172 -0
- package/dist/environment-terminal.js +162 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { boundedIdentifierSchema, boundedStringSchema, } from "./contract-limits.js";
|
|
3
|
+
export const ObservationStateSchema = z.enum([
|
|
4
|
+
"known",
|
|
5
|
+
"stale",
|
|
6
|
+
"unavailable",
|
|
7
|
+
"redacted",
|
|
8
|
+
"unknown",
|
|
9
|
+
]);
|
|
10
|
+
export const ObservationProvenanceSchema = z.strictObject({
|
|
11
|
+
origin: z.enum(["measured", "reported", "estimated"]),
|
|
12
|
+
observedAt: z.iso.datetime().max(64),
|
|
13
|
+
source: boundedIdentifierSchema.optional(),
|
|
14
|
+
});
|
|
15
|
+
/** Build a freshness-tagged observation schema around one value schema. */
|
|
16
|
+
export function observationOf(value) {
|
|
17
|
+
return z.discriminatedUnion("state", [
|
|
18
|
+
z.strictObject({
|
|
19
|
+
state: z.literal("known"),
|
|
20
|
+
value,
|
|
21
|
+
provenance: ObservationProvenanceSchema,
|
|
22
|
+
}),
|
|
23
|
+
z.strictObject({
|
|
24
|
+
state: z.literal("stale"),
|
|
25
|
+
value,
|
|
26
|
+
provenance: ObservationProvenanceSchema,
|
|
27
|
+
reason: boundedStringSchema.min(1),
|
|
28
|
+
}),
|
|
29
|
+
z.strictObject({
|
|
30
|
+
state: z.literal("unavailable"),
|
|
31
|
+
reason: boundedStringSchema.min(1),
|
|
32
|
+
}),
|
|
33
|
+
z.strictObject({
|
|
34
|
+
state: z.literal("redacted"),
|
|
35
|
+
reason: boundedStringSchema.min(1),
|
|
36
|
+
}),
|
|
37
|
+
z.strictObject({ state: z.literal("unknown") }),
|
|
38
|
+
]);
|
|
39
|
+
}
|
|
40
|
+
const nonNegativeNumberSchema = z.number().finite().nonnegative();
|
|
41
|
+
export const ProviderIdentitySchema = z.strictObject({
|
|
42
|
+
provider: boundedIdentifierSchema,
|
|
43
|
+
environmentId: boundedIdentifierSchema,
|
|
44
|
+
sessionId: boundedIdentifierSchema.optional(),
|
|
45
|
+
backend: boundedIdentifierSchema.optional(),
|
|
46
|
+
});
|
|
47
|
+
export const AgentEnvironmentStatusSchema = z.enum([
|
|
48
|
+
"pending",
|
|
49
|
+
"provisioning",
|
|
50
|
+
"running",
|
|
51
|
+
"stopped",
|
|
52
|
+
"failed",
|
|
53
|
+
"expired",
|
|
54
|
+
"unknown",
|
|
55
|
+
]);
|
|
56
|
+
/** Lifecycle, cleanup, continuity, and persistence of one environment. */
|
|
57
|
+
export const EnvironmentLifecycleSchema = z.strictObject({
|
|
58
|
+
status: AgentEnvironmentStatusSchema,
|
|
59
|
+
cleanup: z
|
|
60
|
+
.strictObject({
|
|
61
|
+
policy: z.enum(["manual", "idle", "scheduled", "on-exit"]).optional(),
|
|
62
|
+
scheduledAt: z.iso.datetime().max(64).optional(),
|
|
63
|
+
confirmed: z.boolean().optional(),
|
|
64
|
+
})
|
|
65
|
+
.optional(),
|
|
66
|
+
continuity: z
|
|
67
|
+
.strictObject({
|
|
68
|
+
resumable: z.boolean(),
|
|
69
|
+
mode: z.enum(["native", "replayed", "none"]).optional(),
|
|
70
|
+
})
|
|
71
|
+
.optional(),
|
|
72
|
+
persistence: z
|
|
73
|
+
.strictObject({
|
|
74
|
+
durable: z.boolean(),
|
|
75
|
+
scope: z.enum(["ephemeral", "session", "durable"]).optional(),
|
|
76
|
+
})
|
|
77
|
+
.optional(),
|
|
78
|
+
});
|
|
79
|
+
/**
|
|
80
|
+
* Credential-free network location. There is no field for a user, password,
|
|
81
|
+
* token, or other secret, and the host and scheme reject embedded credentials.
|
|
82
|
+
*/
|
|
83
|
+
export const SafeEndpointSchema = z
|
|
84
|
+
.strictObject({
|
|
85
|
+
scheme: boundedIdentifierSchema.optional(),
|
|
86
|
+
host: boundedIdentifierSchema,
|
|
87
|
+
port: z.number().int().min(1).max(65_535).optional(),
|
|
88
|
+
region: boundedIdentifierSchema.optional(),
|
|
89
|
+
})
|
|
90
|
+
.superRefine((endpoint, refinement) => {
|
|
91
|
+
if (/[@/\s]|:\/\//.test(endpoint.host)) {
|
|
92
|
+
refinement.addIssue({
|
|
93
|
+
code: "custom",
|
|
94
|
+
path: ["host"],
|
|
95
|
+
message: "endpoint host must not carry credentials, a scheme, or a path",
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
if (endpoint.scheme !== undefined && /[@:/\s]/.test(endpoint.scheme)) {
|
|
99
|
+
refinement.addIssue({
|
|
100
|
+
code: "custom",
|
|
101
|
+
path: ["scheme"],
|
|
102
|
+
message: "endpoint scheme must be a bare protocol name",
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
/** Requested or effective compute shape, including an optional accelerator. */
|
|
107
|
+
export const ResourceProfileSchema = z.strictObject({
|
|
108
|
+
cpu: z.number().finite().positive().optional(),
|
|
109
|
+
memoryMb: z.number().int().positive().optional(),
|
|
110
|
+
diskMb: z.number().int().positive().optional(),
|
|
111
|
+
accelerator: z
|
|
112
|
+
.strictObject({
|
|
113
|
+
kind: boundedIdentifierSchema,
|
|
114
|
+
count: z.number().int().positive(),
|
|
115
|
+
memoryMb: z.number().int().positive().optional(),
|
|
116
|
+
})
|
|
117
|
+
.optional(),
|
|
118
|
+
});
|
|
119
|
+
/** A point-in-time or peak resource sample. */
|
|
120
|
+
export const ResourceUseSampleSchema = z.strictObject({
|
|
121
|
+
cpu: nonNegativeNumberSchema.optional(),
|
|
122
|
+
memoryMb: nonNegativeNumberSchema.optional(),
|
|
123
|
+
diskMb: nonNegativeNumberSchema.optional(),
|
|
124
|
+
acceleratorMemoryMb: nonNegativeNumberSchema.optional(),
|
|
125
|
+
});
|
|
126
|
+
/** Where an environment was requested or verified to run. */
|
|
127
|
+
export const PlacementDescriptorSchema = z.strictObject({
|
|
128
|
+
kind: z.enum(["local", "sandbox", "fleet", "provider"]),
|
|
129
|
+
sandboxId: boundedIdentifierSchema.optional(),
|
|
130
|
+
fleetId: boundedIdentifierSchema.optional(),
|
|
131
|
+
machineId: boundedIdentifierSchema.optional(),
|
|
132
|
+
region: boundedIdentifierSchema.optional(),
|
|
133
|
+
});
|
|
134
|
+
/**
|
|
135
|
+
* Token usage and cost for one execution. Bound to the shared {@link TokenUsage}
|
|
136
|
+
* type so a change to the canonical shape is caught here.
|
|
137
|
+
*/
|
|
138
|
+
export const ModelUsageSchema = z.strictObject({
|
|
139
|
+
inputTokens: z.number().int().nonnegative(),
|
|
140
|
+
outputTokens: z.number().int().nonnegative(),
|
|
141
|
+
totalTokens: z.number().int().nonnegative().optional(),
|
|
142
|
+
cacheReadInputTokens: z.number().int().nonnegative().optional(),
|
|
143
|
+
cacheCreationInputTokens: z.number().int().nonnegative().optional(),
|
|
144
|
+
reasoningTokens: z.number().int().nonnegative().optional(),
|
|
145
|
+
cost: z.number().finite().nonnegative().optional(),
|
|
146
|
+
});
|
|
147
|
+
/** Provider compute cost charged for one environment. */
|
|
148
|
+
export const ComputeBillingSchema = z.strictObject({
|
|
149
|
+
amount: nonNegativeNumberSchema,
|
|
150
|
+
currency: boundedIdentifierSchema,
|
|
151
|
+
});
|
|
152
|
+
/** Account plan, credits, quota, and billing period. */
|
|
153
|
+
export const AccountUsageSchema = z.strictObject({
|
|
154
|
+
plan: observationOf(boundedIdentifierSchema).optional(),
|
|
155
|
+
credits: observationOf(z.strictObject({
|
|
156
|
+
remaining: nonNegativeNumberSchema,
|
|
157
|
+
unit: boundedIdentifierSchema,
|
|
158
|
+
})).optional(),
|
|
159
|
+
quota: observationOf(z.strictObject({
|
|
160
|
+
limit: nonNegativeNumberSchema,
|
|
161
|
+
used: nonNegativeNumberSchema,
|
|
162
|
+
remaining: nonNegativeNumberSchema,
|
|
163
|
+
unit: boundedIdentifierSchema,
|
|
164
|
+
})).optional(),
|
|
165
|
+
period: observationOf(z.strictObject({
|
|
166
|
+
start: z.iso.datetime().max(64),
|
|
167
|
+
end: z.iso.datetime().max(64),
|
|
168
|
+
})).optional(),
|
|
169
|
+
});
|
|
170
|
+
/**
|
|
171
|
+
* Optional normalized observation of one execution environment.
|
|
172
|
+
*
|
|
173
|
+
* `subject` is the always-known identity used to bind a live observation to its
|
|
174
|
+
* replay. Every other surface is optional and freshness-tagged, so a provider
|
|
175
|
+
* that reports nothing still validates and no absent value is a measured zero.
|
|
176
|
+
*/
|
|
177
|
+
export const AgentEnvironmentObservationSchema = z.strictObject({
|
|
178
|
+
subject: ProviderIdentitySchema,
|
|
179
|
+
capturedAt: z.iso.datetime().max(64),
|
|
180
|
+
identity: observationOf(ProviderIdentitySchema).optional(),
|
|
181
|
+
lifecycle: observationOf(EnvironmentLifecycleSchema).optional(),
|
|
182
|
+
endpoint: observationOf(SafeEndpointSchema).optional(),
|
|
183
|
+
placement: z
|
|
184
|
+
.strictObject({
|
|
185
|
+
requested: PlacementDescriptorSchema.optional(),
|
|
186
|
+
verified: observationOf(PlacementDescriptorSchema).optional(),
|
|
187
|
+
})
|
|
188
|
+
.optional(),
|
|
189
|
+
resources: z
|
|
190
|
+
.strictObject({
|
|
191
|
+
requested: ResourceProfileSchema.optional(),
|
|
192
|
+
effective: observationOf(ResourceProfileSchema).optional(),
|
|
193
|
+
})
|
|
194
|
+
.optional(),
|
|
195
|
+
resourceUse: z
|
|
196
|
+
.strictObject({
|
|
197
|
+
current: observationOf(ResourceUseSampleSchema).optional(),
|
|
198
|
+
peak: observationOf(ResourceUseSampleSchema).optional(),
|
|
199
|
+
})
|
|
200
|
+
.optional(),
|
|
201
|
+
modelUsage: observationOf(ModelUsageSchema).optional(),
|
|
202
|
+
computeBilling: observationOf(ComputeBillingSchema).optional(),
|
|
203
|
+
accountUsage: AccountUsageSchema.optional(),
|
|
204
|
+
});
|
|
205
|
+
function providerIdentityEquals(left, right) {
|
|
206
|
+
return (left.provider === right.provider &&
|
|
207
|
+
left.environmentId === right.environmentId &&
|
|
208
|
+
left.sessionId === right.sessionId &&
|
|
209
|
+
left.backend === right.backend);
|
|
210
|
+
}
|
|
211
|
+
function observedIdentityMatches(left, right) {
|
|
212
|
+
if (left === undefined && right === undefined)
|
|
213
|
+
return true;
|
|
214
|
+
if (left === undefined || right === undefined)
|
|
215
|
+
return false;
|
|
216
|
+
if (left.state !== right.state)
|
|
217
|
+
return false;
|
|
218
|
+
const leftValue = "value" in left ? left.value : undefined;
|
|
219
|
+
const rightValue = "value" in right ? right.value : undefined;
|
|
220
|
+
if (leftValue === undefined && rightValue === undefined)
|
|
221
|
+
return true;
|
|
222
|
+
if (leftValue === undefined || rightValue === undefined)
|
|
223
|
+
return false;
|
|
224
|
+
const leftSource = "provenance" in left ? left.provenance.source : undefined;
|
|
225
|
+
const rightSource = "provenance" in right ? right.provenance.source : undefined;
|
|
226
|
+
return providerIdentityEquals(leftValue, rightValue) && leftSource === rightSource;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* A live observation and its replay must name the same environment and the
|
|
230
|
+
* same observed identity and provenance source. Time and freshness may differ,
|
|
231
|
+
* but the identifiers may not.
|
|
232
|
+
*/
|
|
233
|
+
export function agentEnvironmentObservationIdentityMatches(live, replay) {
|
|
234
|
+
const parsedLive = AgentEnvironmentObservationSchema.safeParse(live);
|
|
235
|
+
const parsedReplay = AgentEnvironmentObservationSchema.safeParse(replay);
|
|
236
|
+
if (!parsedLive.success || !parsedReplay.success)
|
|
237
|
+
return false;
|
|
238
|
+
return (providerIdentityEquals(parsedLive.data.subject, parsedReplay.data.subject) &&
|
|
239
|
+
observedIdentityMatches(parsedLive.data.identity, parsedReplay.data.identity));
|
|
240
|
+
}
|
|
241
|
+
const USERINFO_URL_PATTERN = /[a-z][a-z0-9+.-]*:\/\/[^/@\s]*@/i;
|
|
242
|
+
/**
|
|
243
|
+
* Secret-shaped whole words. Matching whole words, not substrings, keeps a
|
|
244
|
+
* token-count field such as `inputTokens` from reading as an auth token.
|
|
245
|
+
*/
|
|
246
|
+
const CREDENTIAL_WORDS = new Set([
|
|
247
|
+
"token",
|
|
248
|
+
"secret",
|
|
249
|
+
"secrets",
|
|
250
|
+
"password",
|
|
251
|
+
"passwd",
|
|
252
|
+
"passphrase",
|
|
253
|
+
"credential",
|
|
254
|
+
"credentials",
|
|
255
|
+
"authorization",
|
|
256
|
+
"bearer",
|
|
257
|
+
"key",
|
|
258
|
+
"keys",
|
|
259
|
+
]);
|
|
260
|
+
/** Split a key into lowercase words across camelCase and separators. */
|
|
261
|
+
function keyWords(key) {
|
|
262
|
+
return key
|
|
263
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
264
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
265
|
+
.map((word) => word.toLowerCase())
|
|
266
|
+
.filter(Boolean);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Report whether an observation payload carries a credential. A credential is a
|
|
270
|
+
* secret-shaped object key or a string value with embedded userinfo. Contract
|
|
271
|
+
* tests use this to prove the observation surface never transports a secret.
|
|
272
|
+
*/
|
|
273
|
+
export function observationContainsCredential(value) {
|
|
274
|
+
const pending = [value];
|
|
275
|
+
const seen = new Set();
|
|
276
|
+
while (pending.length > 0) {
|
|
277
|
+
const current = pending.pop();
|
|
278
|
+
if (typeof current === "string") {
|
|
279
|
+
if (USERINFO_URL_PATTERN.test(current))
|
|
280
|
+
return true;
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (current === null || typeof current !== "object")
|
|
284
|
+
continue;
|
|
285
|
+
if (seen.has(current))
|
|
286
|
+
continue;
|
|
287
|
+
seen.add(current);
|
|
288
|
+
if (Array.isArray(current)) {
|
|
289
|
+
for (const item of current)
|
|
290
|
+
pending.push(item);
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
for (const [key, entry] of Object.entries(current)) {
|
|
294
|
+
if (keyWords(key).some((word) => CREDENTIAL_WORDS.has(word)))
|
|
295
|
+
return true;
|
|
296
|
+
pending.push(entry);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
/** Throw when an observation payload carries a credential. */
|
|
302
|
+
export function assertObservationCredentialFree(value) {
|
|
303
|
+
if (observationContainsCredential(value)) {
|
|
304
|
+
throw new Error("observation payload must not carry a credential");
|
|
305
|
+
}
|
|
306
|
+
}
|
|
@@ -9,6 +9,8 @@ import { type AgentRunCancellationAcknowledgement, type AgentRunCancellationRequ
|
|
|
9
9
|
import type { AgentWorkspaceBranching } from "./workspace-branching.js";
|
|
10
10
|
import type { AgentEnvironmentQuery, AgentEnvironmentStatus, AgentEnvironmentSummary, AgentProfileRef, AgentSessionStatus, CheckpointRef, CheckpointRequest, ExecRequest, ExecResult, ForkRequest, PlacementInfo, ResourceRequest, WorkspaceRequest } from "./environment-requests.js";
|
|
11
11
|
import type { AgentExactProcessEgressMode, AgentExactProcessProvider } from "./environment-exact-process.js";
|
|
12
|
+
import type { AgentEnvironmentObservation } from "./environment-observation.js";
|
|
13
|
+
import type { AgentTerminalSession, TerminalAttachRequest, TerminalAttachResult } from "./environment-terminal.js";
|
|
12
14
|
export interface AgentTurnInput {
|
|
13
15
|
prompt?: string;
|
|
14
16
|
parts?: InputPart[];
|
|
@@ -653,6 +655,18 @@ export interface AgentEnvironment {
|
|
|
653
655
|
placement?(options?: {
|
|
654
656
|
signal?: AbortSignal;
|
|
655
657
|
}): Promise<PlacementInfo>;
|
|
658
|
+
/** Normalized, freshness-tagged observation of this environment. */
|
|
659
|
+
observe?(options?: {
|
|
660
|
+
signal?: AbortSignal;
|
|
661
|
+
}): Promise<AgentEnvironmentObservation>;
|
|
662
|
+
/** Open or reattach an interactive terminal under a parent execution. */
|
|
663
|
+
attachTerminal?(request: TerminalAttachRequest, options?: {
|
|
664
|
+
signal?: AbortSignal;
|
|
665
|
+
}): Promise<TerminalAttachResult>;
|
|
666
|
+
/** Accessor for a live interactive terminal handle. */
|
|
667
|
+
terminal?(terminalSessionId: string, options?: {
|
|
668
|
+
signal?: AbortSignal;
|
|
669
|
+
}): AgentTerminalSession;
|
|
656
670
|
refresh?(options?: {
|
|
657
671
|
signal?: AbortSignal;
|
|
658
672
|
}): Promise<void>;
|
|
@@ -712,6 +726,25 @@ export interface AgentEnvironmentCapabilities {
|
|
|
712
726
|
exactProcess?: {
|
|
713
727
|
egress: readonly AgentExactProcessEgressMode[];
|
|
714
728
|
};
|
|
729
|
+
/** Per-surface flags for the normalized environment observation. */
|
|
730
|
+
observation?: {
|
|
731
|
+
identity: boolean;
|
|
732
|
+
lifecycle: boolean;
|
|
733
|
+
endpoint: boolean;
|
|
734
|
+
placement: boolean;
|
|
735
|
+
resources: boolean;
|
|
736
|
+
resourceUse: boolean;
|
|
737
|
+
modelUsage: boolean;
|
|
738
|
+
computeBilling: boolean;
|
|
739
|
+
accountUsage: boolean;
|
|
740
|
+
};
|
|
741
|
+
/** Present only when the provider serves an interactive terminal. */
|
|
742
|
+
interactiveTerminal?: {
|
|
743
|
+
attach: boolean;
|
|
744
|
+
input: boolean;
|
|
745
|
+
resize: boolean;
|
|
746
|
+
reattach: boolean;
|
|
747
|
+
};
|
|
715
748
|
}
|
|
716
749
|
/** Strict runtime validator for provider capability negotiation. */
|
|
717
750
|
export declare const AgentEnvironmentCapabilitiesSchema: z.ZodObject<{
|
|
@@ -804,6 +837,23 @@ export declare const AgentEnvironmentCapabilitiesSchema: z.ZodObject<{
|
|
|
804
837
|
strict: "strict";
|
|
805
838
|
}>>;
|
|
806
839
|
}, z.core.$strict>>;
|
|
840
|
+
observation: z.ZodOptional<z.ZodObject<{
|
|
841
|
+
identity: z.ZodBoolean;
|
|
842
|
+
lifecycle: z.ZodBoolean;
|
|
843
|
+
endpoint: z.ZodBoolean;
|
|
844
|
+
placement: z.ZodBoolean;
|
|
845
|
+
resources: z.ZodBoolean;
|
|
846
|
+
resourceUse: z.ZodBoolean;
|
|
847
|
+
modelUsage: z.ZodBoolean;
|
|
848
|
+
computeBilling: z.ZodBoolean;
|
|
849
|
+
accountUsage: z.ZodBoolean;
|
|
850
|
+
}, z.core.$strict>>;
|
|
851
|
+
interactiveTerminal: z.ZodOptional<z.ZodObject<{
|
|
852
|
+
attach: z.ZodBoolean;
|
|
853
|
+
input: z.ZodBoolean;
|
|
854
|
+
resize: z.ZodBoolean;
|
|
855
|
+
reattach: z.ZodBoolean;
|
|
856
|
+
}, z.core.$strict>>;
|
|
807
857
|
}, z.core.$strict>;
|
|
808
858
|
export interface CreateAgentEnvironmentInput {
|
|
809
859
|
profile: AgentProfileRef;
|
|
@@ -167,6 +167,27 @@ export const AgentEnvironmentCapabilitiesSchema = z
|
|
|
167
167
|
.max(CONTRACT_MAX_ARRAY_LENGTH),
|
|
168
168
|
})
|
|
169
169
|
.optional(),
|
|
170
|
+
observation: z
|
|
171
|
+
.strictObject({
|
|
172
|
+
identity: z.boolean(),
|
|
173
|
+
lifecycle: z.boolean(),
|
|
174
|
+
endpoint: z.boolean(),
|
|
175
|
+
placement: z.boolean(),
|
|
176
|
+
resources: z.boolean(),
|
|
177
|
+
resourceUse: z.boolean(),
|
|
178
|
+
modelUsage: z.boolean(),
|
|
179
|
+
computeBilling: z.boolean(),
|
|
180
|
+
accountUsage: z.boolean(),
|
|
181
|
+
})
|
|
182
|
+
.optional(),
|
|
183
|
+
interactiveTerminal: z
|
|
184
|
+
.strictObject({
|
|
185
|
+
attach: z.boolean(),
|
|
186
|
+
input: z.boolean(),
|
|
187
|
+
resize: z.boolean(),
|
|
188
|
+
reattach: z.boolean(),
|
|
189
|
+
})
|
|
190
|
+
.optional(),
|
|
170
191
|
})
|
|
171
192
|
.superRefine((capabilities, refinement) => {
|
|
172
193
|
if (capabilities.retainedControl !== undefined &&
|
|
@@ -217,6 +238,16 @@ export const AgentEnvironmentCapabilitiesSchema = z
|
|
|
217
238
|
message: "exact process egress modes must be unique",
|
|
218
239
|
});
|
|
219
240
|
}
|
|
241
|
+
const terminal = capabilities.interactiveTerminal;
|
|
242
|
+
if (terminal !== undefined &&
|
|
243
|
+
(terminal.input || terminal.resize || terminal.reattach) &&
|
|
244
|
+
!terminal.attach) {
|
|
245
|
+
refinement.addIssue({
|
|
246
|
+
code: "custom",
|
|
247
|
+
path: ["interactiveTerminal"],
|
|
248
|
+
message: "interactive terminal input, resize, and reattach each require attach",
|
|
249
|
+
});
|
|
250
|
+
}
|
|
220
251
|
const extensions = capabilities.profile.extensions;
|
|
221
252
|
if (extensions && new Set(extensions).size !== extensions.length) {
|
|
222
253
|
refinement.addIssue({
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Provider-neutral handle for one interactive terminal.
|
|
4
|
+
*
|
|
5
|
+
* The handle carries no raw process id and no environment map, so a terminal
|
|
6
|
+
* reference never leaks host process detail or injected secrets. Every terminal
|
|
7
|
+
* is bound to a parent execution and carries an explicit expiry, so an orphan
|
|
8
|
+
* or an expired terminal fails closed at the call sites that read it.
|
|
9
|
+
*/
|
|
10
|
+
export declare const TerminalSessionRefSchema: z.ZodObject<{
|
|
11
|
+
terminalSessionId: z.ZodString;
|
|
12
|
+
parentExecutionId: z.ZodString;
|
|
13
|
+
name: z.ZodString;
|
|
14
|
+
shell: z.ZodString;
|
|
15
|
+
command: z.ZodOptional<z.ZodString>;
|
|
16
|
+
cwd: z.ZodString;
|
|
17
|
+
cols: z.ZodNumber;
|
|
18
|
+
rows: z.ZodNumber;
|
|
19
|
+
connectionId: z.ZodOptional<z.ZodString>;
|
|
20
|
+
createdAt: z.ZodISODateTime;
|
|
21
|
+
lastActivityAt: z.ZodISODateTime;
|
|
22
|
+
expiresAt: z.ZodISODateTime;
|
|
23
|
+
isRunning: z.ZodBoolean;
|
|
24
|
+
exitCode: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
exitSignal: z.ZodOptional<z.ZodString>;
|
|
26
|
+
attachCount: z.ZodNumber;
|
|
27
|
+
}, z.core.$strict>;
|
|
28
|
+
export type TerminalSessionRef = z.infer<typeof TerminalSessionRefSchema>;
|
|
29
|
+
/** Raw bytes written to the terminal, normalized to UTF-8 text. */
|
|
30
|
+
export declare const TerminalInputSchema: z.ZodObject<{
|
|
31
|
+
data: z.ZodString;
|
|
32
|
+
}, z.core.$strict>;
|
|
33
|
+
export type TerminalInput = z.infer<typeof TerminalInputSchema>;
|
|
34
|
+
/** New terminal geometry. */
|
|
35
|
+
export declare const TerminalResizeSchema: z.ZodObject<{
|
|
36
|
+
cols: z.ZodNumber;
|
|
37
|
+
rows: z.ZodNumber;
|
|
38
|
+
}, z.core.$strict>;
|
|
39
|
+
export type TerminalResize = z.infer<typeof TerminalResizeSchema>;
|
|
40
|
+
/**
|
|
41
|
+
* Create-or-reattach request. A present `terminalSessionId` reattaches to an
|
|
42
|
+
* existing terminal; its absence opens a new one under the parent execution.
|
|
43
|
+
* `mode` selects an `attach` to a live process or a `logical` resume that
|
|
44
|
+
* replays retained output.
|
|
45
|
+
*/
|
|
46
|
+
export declare const TerminalAttachRequestSchema: z.ZodObject<{
|
|
47
|
+
parentExecutionId: z.ZodString;
|
|
48
|
+
terminalSessionId: z.ZodOptional<z.ZodString>;
|
|
49
|
+
connectionId: z.ZodOptional<z.ZodString>;
|
|
50
|
+
mode: z.ZodEnum<{
|
|
51
|
+
attach: "attach";
|
|
52
|
+
logical: "logical";
|
|
53
|
+
}>;
|
|
54
|
+
cols: z.ZodOptional<z.ZodNumber>;
|
|
55
|
+
rows: z.ZodOptional<z.ZodNumber>;
|
|
56
|
+
command: z.ZodOptional<z.ZodString>;
|
|
57
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
58
|
+
}, z.core.$strict>;
|
|
59
|
+
export type TerminalAttachRequest = z.infer<typeof TerminalAttachRequestSchema>;
|
|
60
|
+
/** Result of a create-or-reattach request. */
|
|
61
|
+
export declare const TerminalAttachResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
62
|
+
status: z.ZodEnum<{
|
|
63
|
+
attached: "attached";
|
|
64
|
+
reattached: "reattached";
|
|
65
|
+
}>;
|
|
66
|
+
mode: z.ZodEnum<{
|
|
67
|
+
attach: "attach";
|
|
68
|
+
logical: "logical";
|
|
69
|
+
}>;
|
|
70
|
+
ref: z.ZodObject<{
|
|
71
|
+
terminalSessionId: z.ZodString;
|
|
72
|
+
parentExecutionId: z.ZodString;
|
|
73
|
+
name: z.ZodString;
|
|
74
|
+
shell: z.ZodString;
|
|
75
|
+
command: z.ZodOptional<z.ZodString>;
|
|
76
|
+
cwd: z.ZodString;
|
|
77
|
+
cols: z.ZodNumber;
|
|
78
|
+
rows: z.ZodNumber;
|
|
79
|
+
connectionId: z.ZodOptional<z.ZodString>;
|
|
80
|
+
createdAt: z.ZodISODateTime;
|
|
81
|
+
lastActivityAt: z.ZodISODateTime;
|
|
82
|
+
expiresAt: z.ZodISODateTime;
|
|
83
|
+
isRunning: z.ZodBoolean;
|
|
84
|
+
exitCode: z.ZodOptional<z.ZodNumber>;
|
|
85
|
+
exitSignal: z.ZodOptional<z.ZodString>;
|
|
86
|
+
attachCount: z.ZodNumber;
|
|
87
|
+
}, z.core.$strict>;
|
|
88
|
+
attachCount: z.ZodNumber;
|
|
89
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
90
|
+
status: z.ZodLiteral<"unavailable">;
|
|
91
|
+
reason: z.ZodString;
|
|
92
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
93
|
+
status: z.ZodLiteral<"unknown">;
|
|
94
|
+
message: z.ZodString;
|
|
95
|
+
retryable: z.ZodBoolean;
|
|
96
|
+
}, z.core.$strict>], "status">;
|
|
97
|
+
export type TerminalAttachResult = z.infer<typeof TerminalAttachResultSchema>;
|
|
98
|
+
/**
|
|
99
|
+
* One ordered terminal output frame. `output` frames carry a monotonic `seq`
|
|
100
|
+
* that a consumer replays from, so a reconnect resumes without loss or
|
|
101
|
+
* duplication.
|
|
102
|
+
*/
|
|
103
|
+
export declare const TerminalOutputEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
104
|
+
type: z.ZodLiteral<"ready">;
|
|
105
|
+
cols: z.ZodOptional<z.ZodNumber>;
|
|
106
|
+
rows: z.ZodOptional<z.ZodNumber>;
|
|
107
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
108
|
+
type: z.ZodLiteral<"output">;
|
|
109
|
+
seq: z.ZodNumber;
|
|
110
|
+
data: z.ZodString;
|
|
111
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
112
|
+
type: z.ZodLiteral<"resize">;
|
|
113
|
+
cols: z.ZodNumber;
|
|
114
|
+
rows: z.ZodNumber;
|
|
115
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
116
|
+
type: z.ZodLiteral<"exit">;
|
|
117
|
+
exitCode: z.ZodOptional<z.ZodNumber>;
|
|
118
|
+
exitSignal: z.ZodOptional<z.ZodString>;
|
|
119
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
120
|
+
type: z.ZodLiteral<"error">;
|
|
121
|
+
message: z.ZodString;
|
|
122
|
+
}, z.core.$strict>], "type">;
|
|
123
|
+
export type TerminalOutputEvent = z.infer<typeof TerminalOutputEventSchema>;
|
|
124
|
+
/** Acknowledgement of a detach or close. */
|
|
125
|
+
export declare const TerminalDetachAckSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
126
|
+
status: z.ZodLiteral<"detached">;
|
|
127
|
+
terminalSessionId: z.ZodString;
|
|
128
|
+
connectionId: z.ZodOptional<z.ZodString>;
|
|
129
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
130
|
+
status: z.ZodLiteral<"closed">;
|
|
131
|
+
terminalSessionId: z.ZodString;
|
|
132
|
+
exitCode: z.ZodOptional<z.ZodNumber>;
|
|
133
|
+
exitSignal: z.ZodOptional<z.ZodString>;
|
|
134
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
135
|
+
status: z.ZodLiteral<"unknown">;
|
|
136
|
+
terminalSessionId: z.ZodString;
|
|
137
|
+
message: z.ZodString;
|
|
138
|
+
retryable: z.ZodBoolean;
|
|
139
|
+
}, z.core.$strict>], "status">;
|
|
140
|
+
export type TerminalDetachAck = z.infer<typeof TerminalDetachAckSchema>;
|
|
141
|
+
/**
|
|
142
|
+
* Fail-closed usability check for a terminal reference. Returns true only when
|
|
143
|
+
* the reference parses, is running, and its expiry is in the future. A parse
|
|
144
|
+
* failure, a stopped terminal, or a past expiry denies use.
|
|
145
|
+
*/
|
|
146
|
+
export declare function terminalSessionUsable(ref: TerminalSessionRef, nowIso: string): boolean;
|
|
147
|
+
/** Bind an attach result to the parent execution and terminal it targeted. */
|
|
148
|
+
export declare function terminalAttachResultMatchesRequest(request: TerminalAttachRequest, result: TerminalAttachResult): boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Live handle for one interactive terminal. Signatures only; a provider adapter
|
|
151
|
+
* binds the transport in phase two.
|
|
152
|
+
*/
|
|
153
|
+
export interface AgentTerminalSession {
|
|
154
|
+
readonly ref: TerminalSessionRef;
|
|
155
|
+
input(input: TerminalInput, options?: {
|
|
156
|
+
signal?: AbortSignal;
|
|
157
|
+
}): Promise<void>;
|
|
158
|
+
resize(resize: TerminalResize, options?: {
|
|
159
|
+
signal?: AbortSignal;
|
|
160
|
+
}): Promise<void>;
|
|
161
|
+
detach(options?: {
|
|
162
|
+
signal?: AbortSignal;
|
|
163
|
+
}): Promise<TerminalDetachAck>;
|
|
164
|
+
close(options?: {
|
|
165
|
+
signal?: AbortSignal;
|
|
166
|
+
}): Promise<TerminalDetachAck>;
|
|
167
|
+
/** Replays retained frames from `since`, then continues until the terminal exits. */
|
|
168
|
+
events(options?: {
|
|
169
|
+
since?: number;
|
|
170
|
+
signal?: AbortSignal;
|
|
171
|
+
}): AsyncIterable<TerminalOutputEvent>;
|
|
172
|
+
}
|