@tangle-network/agent-interface 0.44.0 → 0.46.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 +1 -1
- package/dist/agent-candidate-code-schema.d.ts +1 -0
- package/dist/agent-candidate-execution-plan-schema.d.ts +8 -6
- package/dist/agent-candidate-profile-schema.d.ts +3 -2
- package/dist/agent-candidate-promotion-schema.d.ts +59 -42
- package/dist/agent-candidate-receipt-schema.d.ts +5 -4
- package/dist/agent-candidate-schema-common.js +1 -1
- package/dist/agent-candidate-schema.d.ts +4 -2
- package/dist/agent-execution-preparation.d.ts +27 -26
- package/dist/agent-profile.d.ts +10 -3
- package/dist/agent-profile.js +45 -22
- package/dist/backend-message.d.ts +14 -0
- package/dist/backend-message.js +1 -0
- package/dist/contract-limits.d.ts +26 -0
- package/dist/contract-limits.js +175 -0
- package/dist/environment-exact-process.d.ts +161 -0
- package/dist/environment-exact-process.js +1 -0
- package/dist/environment-profile-capabilities.d.ts +26 -0
- package/dist/environment-profile-capabilities.js +34 -0
- package/dist/environment-provider.d.ts +3 -730
- package/dist/environment-provider.js +3 -245
- package/dist/environment-requests.d.ts +70 -0
- package/dist/environment-requests.js +1 -0
- package/dist/environment-runtime.d.ts +834 -0
- package/dist/environment-runtime.js +228 -0
- package/dist/execution-types.d.ts +47 -0
- package/dist/execution-types.js +1 -0
- package/dist/harness-capabilities.js +5 -0
- package/dist/harness.d.ts +6 -1
- package/dist/harness.js +1 -0
- package/dist/host-services.d.ts +91 -0
- package/dist/host-services.js +1 -0
- package/dist/index.d.ts +10 -617
- package/dist/index.js +10 -125
- package/dist/interaction-answer-validation.d.ts +13 -0
- package/dist/interaction-answer-validation.js +149 -0
- package/dist/interaction-data.d.ts +22 -0
- package/dist/interaction-data.js +46 -0
- package/dist/interaction-envelope.d.ts +258 -0
- package/dist/interaction-envelope.js +245 -0
- package/dist/interaction-fields.d.ts +130 -0
- package/dist/interaction-fields.js +227 -0
- package/dist/interaction-permissions.d.ts +28 -0
- package/dist/interaction-permissions.js +57 -0
- package/dist/interaction-resolution-validation.d.ts +9 -0
- package/dist/interaction-resolution-validation.js +50 -0
- package/dist/interaction-response-validation.d.ts +17 -0
- package/dist/interaction-response-validation.js +102 -0
- package/dist/interaction.d.ts +6 -397
- package/dist/interaction.js +6 -603
- package/dist/mcp.d.ts +38 -0
- package/dist/mcp.js +1 -0
- package/dist/parts.d.ts +104 -0
- package/dist/parts.js +55 -0
- package/dist/portable-context-base.d.ts +82 -0
- package/dist/portable-context-base.js +63 -0
- package/dist/portable-context-continuation.d.ts +168 -0
- package/dist/portable-context-continuation.js +194 -0
- package/dist/portable-context-plan-request.d.ts +86 -0
- package/dist/portable-context-plan-request.js +102 -0
- package/dist/portable-context-plan.d.ts +229 -0
- package/dist/portable-context-plan.js +241 -0
- package/dist/portable-context-shared.d.ts +36 -0
- package/dist/portable-context-shared.js +46 -0
- package/dist/portable-context-transfer.d.ts +319 -0
- package/dist/portable-context-transfer.js +206 -0
- package/dist/portable-context.d.ts +5 -753
- package/dist/portable-context.js +5 -754
- package/dist/profile-diff.js +56 -47
- package/dist/profile-schema.d.ts +1 -0
- package/dist/provider-adapter.d.ts +45 -0
- package/dist/provider-adapter.js +1 -0
- package/dist/provider-config.d.ts +58 -0
- package/dist/provider-config.js +42 -0
- package/dist/runtime-control.d.ts +87 -10
- package/dist/runtime-control.js +159 -38
- package/dist/stream-events.d.ts +55 -0
- package/dist/stream-events.js +1 -0
- package/dist/workspace-branching-shared.d.ts +7 -0
- package/dist/workspace-branching-shared.js +20 -0
- package/dist/workspace-branching.d.ts +4 -254
- package/dist/workspace-branching.js +4 -400
- package/dist/workspace-checkpoint.d.ts +99 -0
- package/dist/workspace-checkpoint.js +169 -0
- package/dist/workspace-cleanup.d.ts +85 -0
- package/dist/workspace-cleanup.js +156 -0
- package/dist/workspace-confidentiality.d.ts +59 -0
- package/dist/workspace-confidentiality.js +123 -0
- package/dist/workspace-fork.d.ts +182 -0
- package/dist/workspace-fork.js +267 -0
- package/package.json +1 -1
|
@@ -221,7 +221,7 @@ function configRecordSchema(keySchema) {
|
|
|
221
221
|
return z
|
|
222
222
|
.record(keySchema, agentCandidateConfigValueSchema)
|
|
223
223
|
.superRefine((config, ctx) => {
|
|
224
|
-
for (const
|
|
224
|
+
for (const name of Object.keys(config)) {
|
|
225
225
|
if (secretNamePattern.test(name)) {
|
|
226
226
|
ctx.addIssue({
|
|
227
227
|
code: "custom",
|
|
@@ -41,6 +41,7 @@ export declare const agentCandidateBundleSchema: z.ZodObject<{
|
|
|
41
41
|
opencode: "opencode";
|
|
42
42
|
"kimi-code": "kimi-code";
|
|
43
43
|
pi: "pi";
|
|
44
|
+
prime: "prime";
|
|
44
45
|
gemini: "gemini";
|
|
45
46
|
hermes: "hermes";
|
|
46
47
|
openclaw: "openclaw";
|
|
@@ -60,9 +61,9 @@ export declare const agentCandidateBundleSchema: z.ZodObject<{
|
|
|
60
61
|
mcp: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<import("./agent-candidate.js").AgentCandidateMcpServer, unknown, z.core.$ZodTypeInternals<import("./agent-candidate.js").AgentCandidateMcpServer, unknown>>>>;
|
|
61
62
|
subagents: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
62
63
|
prompt: z.ZodOptional<z.ZodString>;
|
|
63
|
-
permissions: z.ZodOptional<z.ZodType<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown, z.core.$ZodTypeInternals<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown>>>;
|
|
64
64
|
tools: z.ZodOptional<z.ZodType<Record<string, boolean>, unknown, z.core.$ZodTypeInternals<Record<string, boolean>, unknown>>>;
|
|
65
65
|
description: z.ZodOptional<z.ZodString>;
|
|
66
|
+
permissions: z.ZodOptional<z.ZodType<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown, z.core.$ZodTypeInternals<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown>>>;
|
|
66
67
|
model: z.ZodOptional<z.ZodString>;
|
|
67
68
|
maxSteps: z.ZodOptional<z.ZodNumber>;
|
|
68
69
|
}, z.core.$strict>>>;
|
|
@@ -539,9 +540,9 @@ export declare const agentCandidateBundleSchema: z.ZodObject<{
|
|
|
539
540
|
}, z.core.$strict>>>>;
|
|
540
541
|
modes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
541
542
|
prompt: z.ZodOptional<z.ZodString>;
|
|
542
|
-
permissions: z.ZodOptional<z.ZodType<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown, z.core.$ZodTypeInternals<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown>>>;
|
|
543
543
|
tools: z.ZodOptional<z.ZodType<Record<string, boolean>, unknown, z.core.$ZodTypeInternals<Record<string, boolean>, unknown>>>;
|
|
544
544
|
description: z.ZodOptional<z.ZodString>;
|
|
545
|
+
permissions: z.ZodOptional<z.ZodType<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown, z.core.$ZodTypeInternals<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown>>>;
|
|
545
546
|
model: z.ZodOptional<z.ZodString>;
|
|
546
547
|
}, z.core.$strict>>>;
|
|
547
548
|
confidential: z.ZodOptional<z.ZodObject<{
|
|
@@ -591,6 +592,7 @@ export declare const agentCandidateBundleSchema: z.ZodObject<{
|
|
|
591
592
|
opencode: "opencode";
|
|
592
593
|
"kimi-code": "kimi-code";
|
|
593
594
|
pi: "pi";
|
|
595
|
+
prime: "prime";
|
|
594
596
|
gemini: "gemini";
|
|
595
597
|
hermes: "hermes";
|
|
596
598
|
openclaw: "openclaw";
|
|
@@ -148,27 +148,27 @@ export type AgentExecutionPreparationValidationResult = {
|
|
|
148
148
|
};
|
|
149
149
|
export declare const agentExecutionPreparationAxisResultSchema: z.ZodObject<{
|
|
150
150
|
axis: z.ZodEnum<{
|
|
151
|
-
|
|
151
|
+
name: "name";
|
|
152
|
+
systemPrompt: "systemPrompt";
|
|
153
|
+
appendSystemPrompt: "appendSystemPrompt";
|
|
154
|
+
instructions: "instructions";
|
|
155
|
+
files: "files";
|
|
152
156
|
tools: "tools";
|
|
157
|
+
skills: "skills";
|
|
158
|
+
commands: "commands";
|
|
159
|
+
description: "description";
|
|
160
|
+
version: "version";
|
|
161
|
+
tags: "tags";
|
|
162
|
+
harness: "harness";
|
|
163
|
+
permissions: "permissions";
|
|
153
164
|
mcp: "mcp";
|
|
154
165
|
connections: "connections";
|
|
155
166
|
subagents: "subagents";
|
|
156
167
|
hooks: "hooks";
|
|
157
168
|
modes: "modes";
|
|
158
|
-
metadata: "metadata";
|
|
159
|
-
description: "description";
|
|
160
|
-
name: "name";
|
|
161
|
-
files: "files";
|
|
162
|
-
version: "version";
|
|
163
|
-
tags: "tags";
|
|
164
|
-
harness: "harness";
|
|
165
169
|
confidential: "confidential";
|
|
170
|
+
metadata: "metadata";
|
|
166
171
|
extensions: "extensions";
|
|
167
|
-
systemPrompt: "systemPrompt";
|
|
168
|
-
appendSystemPrompt: "appendSystemPrompt";
|
|
169
|
-
instructions: "instructions";
|
|
170
|
-
skills: "skills";
|
|
171
|
-
commands: "commands";
|
|
172
172
|
modelDefault: "modelDefault";
|
|
173
173
|
modelSmall: "modelSmall";
|
|
174
174
|
modelProvider: "modelProvider";
|
|
@@ -234,6 +234,7 @@ export declare const agentExecutionPreparationReceiptSchema: z.ZodObject<{
|
|
|
234
234
|
opencode: "opencode";
|
|
235
235
|
"kimi-code": "kimi-code";
|
|
236
236
|
pi: "pi";
|
|
237
|
+
prime: "prime";
|
|
237
238
|
gemini: "gemini";
|
|
238
239
|
hermes: "hermes";
|
|
239
240
|
openclaw: "openclaw";
|
|
@@ -295,27 +296,27 @@ export declare const agentExecutionPreparationReceiptSchema: z.ZodObject<{
|
|
|
295
296
|
}, z.core.$strict>;
|
|
296
297
|
axisResults: z.ZodArray<z.ZodObject<{
|
|
297
298
|
axis: z.ZodEnum<{
|
|
298
|
-
|
|
299
|
+
name: "name";
|
|
300
|
+
systemPrompt: "systemPrompt";
|
|
301
|
+
appendSystemPrompt: "appendSystemPrompt";
|
|
302
|
+
instructions: "instructions";
|
|
303
|
+
files: "files";
|
|
299
304
|
tools: "tools";
|
|
305
|
+
skills: "skills";
|
|
306
|
+
commands: "commands";
|
|
307
|
+
description: "description";
|
|
308
|
+
version: "version";
|
|
309
|
+
tags: "tags";
|
|
310
|
+
harness: "harness";
|
|
311
|
+
permissions: "permissions";
|
|
300
312
|
mcp: "mcp";
|
|
301
313
|
connections: "connections";
|
|
302
314
|
subagents: "subagents";
|
|
303
315
|
hooks: "hooks";
|
|
304
316
|
modes: "modes";
|
|
305
|
-
metadata: "metadata";
|
|
306
|
-
description: "description";
|
|
307
|
-
name: "name";
|
|
308
|
-
files: "files";
|
|
309
|
-
version: "version";
|
|
310
|
-
tags: "tags";
|
|
311
|
-
harness: "harness";
|
|
312
317
|
confidential: "confidential";
|
|
318
|
+
metadata: "metadata";
|
|
313
319
|
extensions: "extensions";
|
|
314
|
-
systemPrompt: "systemPrompt";
|
|
315
|
-
appendSystemPrompt: "appendSystemPrompt";
|
|
316
|
-
instructions: "instructions";
|
|
317
|
-
skills: "skills";
|
|
318
|
-
commands: "commands";
|
|
319
320
|
modelDefault: "modelDefault";
|
|
320
321
|
modelSmall: "modelSmall";
|
|
321
322
|
modelProvider: "modelProvider";
|
package/dist/agent-profile.d.ts
CHANGED
|
@@ -442,9 +442,16 @@ export interface AgentProfileValidationResult {
|
|
|
442
442
|
/**
|
|
443
443
|
* Merge two public AgentProfile values.
|
|
444
444
|
*
|
|
445
|
-
* Overlay fields win on conflicts
|
|
446
|
-
*
|
|
447
|
-
*
|
|
445
|
+
* Overlay fields win on conflicts, but only where they carry a value: an
|
|
446
|
+
* `undefined` entry reads as "not specified" and keeps the base value, because
|
|
447
|
+
* removal is the `remove` channel's job on {@link AgentProfileDiff}. Keys that
|
|
448
|
+
* resolve to nothing are omitted rather than written as `undefined` — RFC 8785
|
|
449
|
+
* canonicalization enumerates own keys, so a present-but-undefined key is a
|
|
450
|
+
* different document from an absent one.
|
|
451
|
+
*
|
|
452
|
+
* Additive fields compose instead of overwriting: array-like instruction sets
|
|
453
|
+
* are concatenated, and `prompt.appendSystemPrompt` values are joined
|
|
454
|
+
* base-first with a blank line between them.
|
|
448
455
|
*/
|
|
449
456
|
export declare function mergeAgentProfiles(base: AgentProfile | undefined, overlay: AgentProfile | undefined): AgentProfile | undefined;
|
|
450
457
|
export {};
|
package/dist/agent-profile.js
CHANGED
|
@@ -23,10 +23,12 @@ export function defineInlineResource(name, content) {
|
|
|
23
23
|
export function defineGitHubResource(path, options = {}) {
|
|
24
24
|
return {
|
|
25
25
|
kind: "github",
|
|
26
|
-
repository: options.repository,
|
|
27
26
|
path,
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
...(options.repository === undefined
|
|
28
|
+
? {}
|
|
29
|
+
: { repository: options.repository }),
|
|
30
|
+
...(options.ref === undefined ? {} : { ref: options.ref }),
|
|
31
|
+
...(options.name === undefined ? {} : { name: options.name }),
|
|
30
32
|
};
|
|
31
33
|
}
|
|
32
34
|
/**
|
|
@@ -67,6 +69,29 @@ export function defineAgentProfileSecretRef(key, format) {
|
|
|
67
69
|
export function defineAgentProfile(profile) {
|
|
68
70
|
return profile;
|
|
69
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Layer objects the way a spread would, except that an `undefined` entry means
|
|
74
|
+
* "not specified" and is never written to the result.
|
|
75
|
+
*
|
|
76
|
+
* Profile identity is an RFC 8785 digest over the profile, and canonicalization
|
|
77
|
+
* enumerates own keys: `{ tools: undefined }` is a different document from `{}`,
|
|
78
|
+
* so writing a key with no value moves the digest of a profile whose content did
|
|
79
|
+
* not change, or is refused outright by the canonical JSON domain. Later sources
|
|
80
|
+
* therefore win only where they carry a value; removal is expressed through
|
|
81
|
+
* {@link AgentProfileDiff}'s `remove` channel, never by overlaying `undefined`.
|
|
82
|
+
*/
|
|
83
|
+
function assignDefined(...sources) {
|
|
84
|
+
const merged = {};
|
|
85
|
+
for (const source of sources) {
|
|
86
|
+
if (source === undefined)
|
|
87
|
+
continue;
|
|
88
|
+
for (const [key, value] of Object.entries(source)) {
|
|
89
|
+
if (value !== undefined)
|
|
90
|
+
merged[key] = value;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return merged;
|
|
94
|
+
}
|
|
70
95
|
function mergeStringArrays(base, overlay) {
|
|
71
96
|
if (!base && !overlay)
|
|
72
97
|
return undefined;
|
|
@@ -88,10 +113,7 @@ function mergeAppendedSystemPrompts(base, overlay) {
|
|
|
88
113
|
function mergeRecord(base, overlay) {
|
|
89
114
|
if (!base && !overlay)
|
|
90
115
|
return undefined;
|
|
91
|
-
return
|
|
92
|
-
...(base ?? {}),
|
|
93
|
-
...(overlay ?? {}),
|
|
94
|
-
};
|
|
116
|
+
return assignDefined(base, overlay);
|
|
95
117
|
}
|
|
96
118
|
function mergeOptionalArrays(base, overlay) {
|
|
97
119
|
if (!base && !overlay)
|
|
@@ -101,36 +123,37 @@ function mergeOptionalArrays(base, overlay) {
|
|
|
101
123
|
/**
|
|
102
124
|
* Merge two public AgentProfile values.
|
|
103
125
|
*
|
|
104
|
-
* Overlay fields win on conflicts
|
|
105
|
-
*
|
|
106
|
-
*
|
|
126
|
+
* Overlay fields win on conflicts, but only where they carry a value: an
|
|
127
|
+
* `undefined` entry reads as "not specified" and keeps the base value, because
|
|
128
|
+
* removal is the `remove` channel's job on {@link AgentProfileDiff}. Keys that
|
|
129
|
+
* resolve to nothing are omitted rather than written as `undefined` — RFC 8785
|
|
130
|
+
* canonicalization enumerates own keys, so a present-but-undefined key is a
|
|
131
|
+
* different document from an absent one.
|
|
132
|
+
*
|
|
133
|
+
* Additive fields compose instead of overwriting: array-like instruction sets
|
|
134
|
+
* are concatenated, and `prompt.appendSystemPrompt` values are joined
|
|
135
|
+
* base-first with a blank line between them.
|
|
107
136
|
*/
|
|
108
137
|
export function mergeAgentProfiles(base, overlay) {
|
|
109
138
|
if (!base && !overlay)
|
|
110
139
|
return undefined;
|
|
111
140
|
const mergedPrompt = base?.prompt || overlay?.prompt
|
|
112
|
-
? {
|
|
113
|
-
...(base?.prompt ?? {}),
|
|
114
|
-
...(overlay?.prompt ?? {}),
|
|
141
|
+
? assignDefined(base?.prompt, overlay?.prompt, {
|
|
115
142
|
appendSystemPrompt: mergeAppendedSystemPrompts(base?.prompt?.appendSystemPrompt, overlay?.prompt?.appendSystemPrompt),
|
|
116
143
|
instructions: mergeStringArrays(base?.prompt?.instructions, overlay?.prompt?.instructions),
|
|
117
|
-
}
|
|
144
|
+
})
|
|
118
145
|
: undefined;
|
|
119
146
|
const mergedResources = base?.resources || overlay?.resources
|
|
120
|
-
? {
|
|
121
|
-
...(base?.resources ?? {}),
|
|
122
|
-
...(overlay?.resources ?? {}),
|
|
147
|
+
? assignDefined(base?.resources, overlay?.resources, {
|
|
123
148
|
files: mergeOptionalArrays(base?.resources?.files, overlay?.resources?.files),
|
|
124
149
|
tools: mergeOptionalArrays(base?.resources?.tools, overlay?.resources?.tools),
|
|
125
150
|
skills: mergeOptionalArrays(base?.resources?.skills, overlay?.resources?.skills),
|
|
126
151
|
agents: mergeOptionalArrays(base?.resources?.agents, overlay?.resources?.agents),
|
|
127
152
|
commands: mergeOptionalArrays(base?.resources?.commands, overlay?.resources?.commands),
|
|
128
153
|
instructions: overlay?.resources?.instructions ?? base?.resources?.instructions,
|
|
129
|
-
}
|
|
154
|
+
})
|
|
130
155
|
: undefined;
|
|
131
|
-
return {
|
|
132
|
-
...(base ?? {}),
|
|
133
|
-
...(overlay ?? {}),
|
|
156
|
+
return assignDefined(base, overlay, {
|
|
134
157
|
prompt: mergedPrompt,
|
|
135
158
|
permissions: mergeRecord(base?.permissions, overlay?.permissions),
|
|
136
159
|
tools: mergeRecord(base?.tools, overlay?.tools),
|
|
@@ -142,5 +165,5 @@ export function mergeAgentProfiles(base, overlay) {
|
|
|
142
165
|
modes: mergeRecord(base?.modes, overlay?.modes),
|
|
143
166
|
metadata: mergeRecord(base?.metadata, overlay?.metadata),
|
|
144
167
|
extensions: mergeRecord(base?.extensions, overlay?.extensions),
|
|
145
|
-
};
|
|
168
|
+
});
|
|
146
169
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { InputPart, Part } from "./parts.js";
|
|
2
|
+
export type BackendMessage = {
|
|
3
|
+
id: string;
|
|
4
|
+
role: "user" | "assistant" | "system";
|
|
5
|
+
parts: Array<Part | InputPart | unknown>;
|
|
6
|
+
timestamp: string;
|
|
7
|
+
metadata?: Record<string, unknown>;
|
|
8
|
+
};
|
|
9
|
+
export type GetMessagesOptions = {
|
|
10
|
+
sessionId: string;
|
|
11
|
+
limit?: number;
|
|
12
|
+
offset?: number;
|
|
13
|
+
since?: number;
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Limits applied before a value is hashed, copied, or sent to a provider. */
|
|
3
|
+
export declare const CONTRACT_MAX_STRING_LENGTH = 16384;
|
|
4
|
+
export declare const CONTRACT_MAX_IDENTIFIER_LENGTH = 512;
|
|
5
|
+
export declare const CONTRACT_MAX_ARRAY_LENGTH = 1024;
|
|
6
|
+
export declare const CONTRACT_MAX_MAP_ENTRIES = 256;
|
|
7
|
+
export declare const CONTRACT_MAX_JSON_DEPTH = 16;
|
|
8
|
+
export declare const CONTRACT_MAX_JSON_BYTES = 1048576;
|
|
9
|
+
export declare const CONTRACT_MAX_JSON_NODES = 8192;
|
|
10
|
+
export declare const boundedStringSchema: z.ZodString;
|
|
11
|
+
export declare const boundedIdentifierSchema: z.ZodString;
|
|
12
|
+
/**
|
|
13
|
+
* Validate JSON without asking Zod to recursively copy an attacker-sized
|
|
14
|
+
* value. This is intentionally iterative so depth and collection limits are
|
|
15
|
+
* checked before canonical serialization.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isBoundedJsonValue(value: unknown): boolean;
|
|
18
|
+
/** Validate digest input while matching JSON's omission of undefined object fields. */
|
|
19
|
+
export declare function isBoundedJsonMaterial(value: unknown): boolean;
|
|
20
|
+
export declare const boundedJsonSchema: z.ZodCustom<unknown, unknown>;
|
|
21
|
+
export declare const boundedJsonRecordSchema: z.ZodCustom<Record<string, unknown>, Record<string, unknown>>;
|
|
22
|
+
export declare function assertBoundedJson(value: unknown): void;
|
|
23
|
+
export declare function assertBoundedSerializedJson(value: string): void;
|
|
24
|
+
/** Copy arbitrary metadata into a map that cannot inherit prototype keys. */
|
|
25
|
+
export declare function nullPrototypeRecord<T>(value: Record<string, T>): Record<string, T>;
|
|
26
|
+
export declare function hasOwn(value: object, key: PropertyKey): boolean;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Limits applied before a value is hashed, copied, or sent to a provider. */
|
|
3
|
+
export const CONTRACT_MAX_STRING_LENGTH = 16_384;
|
|
4
|
+
export const CONTRACT_MAX_IDENTIFIER_LENGTH = 512;
|
|
5
|
+
export const CONTRACT_MAX_ARRAY_LENGTH = 1_024;
|
|
6
|
+
export const CONTRACT_MAX_MAP_ENTRIES = 256;
|
|
7
|
+
export const CONTRACT_MAX_JSON_DEPTH = 16;
|
|
8
|
+
export const CONTRACT_MAX_JSON_BYTES = 1_048_576;
|
|
9
|
+
export const CONTRACT_MAX_JSON_NODES = 8_192;
|
|
10
|
+
export const boundedStringSchema = z.string().max(CONTRACT_MAX_STRING_LENGTH);
|
|
11
|
+
export const boundedIdentifierSchema = boundedStringSchema
|
|
12
|
+
.min(1)
|
|
13
|
+
.max(CONTRACT_MAX_IDENTIFIER_LENGTH)
|
|
14
|
+
.refine((value) => value.trim() === value, "identifier cannot have outer whitespace");
|
|
15
|
+
/**
|
|
16
|
+
* Validate JSON without asking Zod to recursively copy an attacker-sized
|
|
17
|
+
* value. This is intentionally iterative so depth and collection limits are
|
|
18
|
+
* checked before canonical serialization.
|
|
19
|
+
*/
|
|
20
|
+
export function isBoundedJsonValue(value) {
|
|
21
|
+
const pending = [{ value, depth: 0 }];
|
|
22
|
+
const ancestors = new Set();
|
|
23
|
+
let nodes = 0;
|
|
24
|
+
while (pending.length > 0) {
|
|
25
|
+
const item = pending.pop();
|
|
26
|
+
if (!item)
|
|
27
|
+
continue;
|
|
28
|
+
nodes += 1;
|
|
29
|
+
if (nodes > CONTRACT_MAX_JSON_NODES)
|
|
30
|
+
return false;
|
|
31
|
+
const current = item.value;
|
|
32
|
+
if (item.leave) {
|
|
33
|
+
ancestors.delete(current);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (current === undefined)
|
|
37
|
+
return false;
|
|
38
|
+
if (current === null || typeof current === "boolean")
|
|
39
|
+
continue;
|
|
40
|
+
if (typeof current === "string") {
|
|
41
|
+
if (current.length > CONTRACT_MAX_STRING_LENGTH)
|
|
42
|
+
return false;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (typeof current === "number") {
|
|
46
|
+
if (!Number.isFinite(current))
|
|
47
|
+
return false;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (typeof current !== "object" || item.depth >= CONTRACT_MAX_JSON_DEPTH) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
if (ancestors.has(current))
|
|
54
|
+
return false;
|
|
55
|
+
ancestors.add(current);
|
|
56
|
+
pending.push({ value: current, depth: item.depth, leave: true });
|
|
57
|
+
if (Array.isArray(current)) {
|
|
58
|
+
if (current.length > CONTRACT_MAX_ARRAY_LENGTH)
|
|
59
|
+
return false;
|
|
60
|
+
for (const entry of current) {
|
|
61
|
+
pending.push({ value: entry, depth: item.depth + 1 });
|
|
62
|
+
}
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const prototype = Object.getPrototypeOf(current);
|
|
66
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
67
|
+
return false;
|
|
68
|
+
const keys = Object.keys(current);
|
|
69
|
+
if (keys.length > CONTRACT_MAX_MAP_ENTRIES)
|
|
70
|
+
return false;
|
|
71
|
+
for (const key of keys) {
|
|
72
|
+
if (key.length > CONTRACT_MAX_IDENTIFIER_LENGTH)
|
|
73
|
+
return false;
|
|
74
|
+
pending.push({
|
|
75
|
+
value: current[key],
|
|
76
|
+
depth: item.depth + 1,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
/** Validate digest input while matching JSON's omission of undefined object fields. */
|
|
83
|
+
export function isBoundedJsonMaterial(value) {
|
|
84
|
+
const pending = [{ value, depth: 0 }];
|
|
85
|
+
const ancestors = new Set();
|
|
86
|
+
let nodes = 0;
|
|
87
|
+
while (pending.length > 0) {
|
|
88
|
+
const item = pending.pop();
|
|
89
|
+
if (!item)
|
|
90
|
+
continue;
|
|
91
|
+
if (item.leave) {
|
|
92
|
+
ancestors.delete(item.value);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (item.value === undefined) {
|
|
96
|
+
if (item.omitUndefined === true)
|
|
97
|
+
continue;
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
nodes += 1;
|
|
101
|
+
if (nodes > CONTRACT_MAX_JSON_NODES)
|
|
102
|
+
return false;
|
|
103
|
+
const current = item.value;
|
|
104
|
+
if (current === null || typeof current === "boolean")
|
|
105
|
+
continue;
|
|
106
|
+
if (typeof current === "string") {
|
|
107
|
+
if (current.length > CONTRACT_MAX_STRING_LENGTH)
|
|
108
|
+
return false;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (typeof current === "number") {
|
|
112
|
+
if (!Number.isFinite(current))
|
|
113
|
+
return false;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (typeof current !== "object" || item.depth >= CONTRACT_MAX_JSON_DEPTH) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
if (ancestors.has(current))
|
|
120
|
+
return false;
|
|
121
|
+
ancestors.add(current);
|
|
122
|
+
pending.push({ value: current, depth: item.depth, leave: true });
|
|
123
|
+
if (Array.isArray(current)) {
|
|
124
|
+
if (current.length > CONTRACT_MAX_ARRAY_LENGTH)
|
|
125
|
+
return false;
|
|
126
|
+
for (const entry of current) {
|
|
127
|
+
pending.push({ value: entry, depth: item.depth + 1 });
|
|
128
|
+
}
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const prototype = Object.getPrototypeOf(current);
|
|
132
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
133
|
+
return false;
|
|
134
|
+
const keys = Object.keys(current);
|
|
135
|
+
if (keys.length > CONTRACT_MAX_MAP_ENTRIES)
|
|
136
|
+
return false;
|
|
137
|
+
for (const key of keys) {
|
|
138
|
+
if (key.length > CONTRACT_MAX_IDENTIFIER_LENGTH)
|
|
139
|
+
return false;
|
|
140
|
+
pending.push({
|
|
141
|
+
value: current[key],
|
|
142
|
+
depth: item.depth + 1,
|
|
143
|
+
omitUndefined: true,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
export const boundedJsonSchema = z.custom(isBoundedJsonValue, {
|
|
150
|
+
message: "value exceeds the contract bounds or is not finite JSON",
|
|
151
|
+
});
|
|
152
|
+
export const boundedJsonRecordSchema = z.custom((value) => typeof value === "object" &&
|
|
153
|
+
value !== null &&
|
|
154
|
+
!Array.isArray(value) &&
|
|
155
|
+
isBoundedJsonValue(value), { message: "metadata exceeds the contract bounds or is not a JSON object" });
|
|
156
|
+
export function assertBoundedJson(value) {
|
|
157
|
+
if (!isBoundedJsonValue(value)) {
|
|
158
|
+
throw new Error("value exceeds the contract bounds or is not finite JSON");
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
export function assertBoundedSerializedJson(value) {
|
|
162
|
+
if (new TextEncoder().encode(value).byteLength > CONTRACT_MAX_JSON_BYTES) {
|
|
163
|
+
throw new Error("serialized contract material exceeds its byte bound");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/** Copy arbitrary metadata into a map that cannot inherit prototype keys. */
|
|
167
|
+
export function nullPrototypeRecord(value) {
|
|
168
|
+
const result = Object.create(null);
|
|
169
|
+
for (const key of Object.keys(value))
|
|
170
|
+
result[key] = value[key];
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
export function hasOwn(value, key) {
|
|
174
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
175
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import type { AgentCandidateTermination } from "./agent-candidate.js";
|
|
2
|
+
export type AgentExactProcessEgressMode = "blocked" | "strict";
|
|
3
|
+
/**
|
|
4
|
+
* Outbound network policy for an exact process environment. `blocked` denies
|
|
5
|
+
* every protocol. `strict` permits only the named domains; direct-address,
|
|
6
|
+
* alternate-protocol, and cross-environment bypasses must fail.
|
|
7
|
+
*/
|
|
8
|
+
export type AgentExactProcessEgressPolicy = {
|
|
9
|
+
mode: "blocked";
|
|
10
|
+
} | {
|
|
11
|
+
mode: "strict";
|
|
12
|
+
allowDomains: readonly string[];
|
|
13
|
+
};
|
|
14
|
+
/** Explicit portable limits for an exact process environment. */
|
|
15
|
+
export interface AgentExactProcessResources {
|
|
16
|
+
/** Positive CPU core count. */
|
|
17
|
+
cpu: number;
|
|
18
|
+
/** Positive integer mebibytes of memory. */
|
|
19
|
+
memoryMb: number;
|
|
20
|
+
/** Positive integer mebibytes of disk. */
|
|
21
|
+
diskMb: number;
|
|
22
|
+
}
|
|
23
|
+
/** Terminal or running state reported by an exact process host. */
|
|
24
|
+
export interface AgentExactProcessStatus {
|
|
25
|
+
pid: number;
|
|
26
|
+
running: boolean;
|
|
27
|
+
/** -1 while running; the exact process exit code after termination. */
|
|
28
|
+
exitCode: number;
|
|
29
|
+
exitSignal?: string;
|
|
30
|
+
/** Required after termination; absent only while running. */
|
|
31
|
+
termination?: AgentCandidateTermination;
|
|
32
|
+
}
|
|
33
|
+
/** Recoverable handle for one shell-free process. */
|
|
34
|
+
export interface AgentExactProcess {
|
|
35
|
+
readonly pid: number;
|
|
36
|
+
status(options?: {
|
|
37
|
+
signal?: AbortSignal;
|
|
38
|
+
}): Promise<AgentExactProcessStatus>;
|
|
39
|
+
wait(options?: {
|
|
40
|
+
signal?: AbortSignal;
|
|
41
|
+
}): Promise<AgentCandidateTermination>;
|
|
42
|
+
/** Force-stop the full process tree. Idempotent after the process exits. */
|
|
43
|
+
kill(options?: {
|
|
44
|
+
signal?: AbortSignal;
|
|
45
|
+
}): Promise<void>;
|
|
46
|
+
/** Each iteration replays buffered UTF-8 stdout, then continues until exit. */
|
|
47
|
+
stdout(options?: {
|
|
48
|
+
signal?: AbortSignal;
|
|
49
|
+
}): AsyncIterable<string>;
|
|
50
|
+
/** Each iteration replays buffered UTF-8 stderr, then continues until exit. */
|
|
51
|
+
stderr(options?: {
|
|
52
|
+
signal?: AbortSignal;
|
|
53
|
+
}): AsyncIterable<string>;
|
|
54
|
+
}
|
|
55
|
+
/** Shell-free launch whose environment replaces, rather than extends, ambient variables. */
|
|
56
|
+
export interface AgentExactProcessLaunch {
|
|
57
|
+
/** Absolute path unless {@link env} supplies an explicit `PATH`. */
|
|
58
|
+
executable: string;
|
|
59
|
+
args: readonly string[];
|
|
60
|
+
cwd: string;
|
|
61
|
+
env: Readonly<Record<string, string>>;
|
|
62
|
+
stdin?: string;
|
|
63
|
+
/** Positive integer milliseconds, or zero to disable the process timeout. */
|
|
64
|
+
timeoutMs: number;
|
|
65
|
+
}
|
|
66
|
+
export interface AgentExactProcessManager {
|
|
67
|
+
list(options?: {
|
|
68
|
+
signal?: AbortSignal;
|
|
69
|
+
}): Promise<AgentExactProcessStatus[]>;
|
|
70
|
+
get(pid: number, options?: {
|
|
71
|
+
signal?: AbortSignal;
|
|
72
|
+
}): Promise<AgentExactProcess | null>;
|
|
73
|
+
/**
|
|
74
|
+
* The abort signal is checked before and after spawn dispatch.
|
|
75
|
+
* If abort is observed after a process starts, the provider kills its tree
|
|
76
|
+
* before rejecting the spawn operation.
|
|
77
|
+
*/
|
|
78
|
+
spawn(input: AgentExactProcessLaunch, options?: {
|
|
79
|
+
signal?: AbortSignal;
|
|
80
|
+
}): Promise<AgentExactProcess>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Fresh environment with no provider-managed user workload.
|
|
84
|
+
*
|
|
85
|
+
* Authenticated provider control services may exist, but no customer workload
|
|
86
|
+
* ingress or provider-managed user process may exist. The launched process
|
|
87
|
+
* sees only its supplied environment variables, with no ambient or injected
|
|
88
|
+
* secrets.
|
|
89
|
+
*/
|
|
90
|
+
export interface AgentExactProcessEnvironment {
|
|
91
|
+
readonly id: string;
|
|
92
|
+
readonly provider: string;
|
|
93
|
+
readonly metadata?: Record<string, unknown>;
|
|
94
|
+
readonly process: AgentExactProcessManager;
|
|
95
|
+
/**
|
|
96
|
+
* Write exact bytes to an absolute path with a POSIX mode from 0 through
|
|
97
|
+
* 07777.
|
|
98
|
+
*
|
|
99
|
+
* The abort signal is checked before and after the write.
|
|
100
|
+
* Once dispatched the write is not cancellable, so an abort may reject after
|
|
101
|
+
* the bytes have landed.
|
|
102
|
+
*/
|
|
103
|
+
writeFile(path: string, bytes: Uint8Array, options: {
|
|
104
|
+
mode: number;
|
|
105
|
+
signal?: AbortSignal;
|
|
106
|
+
}): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Read exact bytes, or fail before content is loaded when the file exceeds
|
|
109
|
+
* maxBytes. A file that grows after the size check is still rejected, but
|
|
110
|
+
* only after its content was transferred. Reads have no side effect, so the
|
|
111
|
+
* abort signal may reject at any point.
|
|
112
|
+
*/
|
|
113
|
+
readFile(path: string, options: {
|
|
114
|
+
maxBytes: number;
|
|
115
|
+
signal?: AbortSignal;
|
|
116
|
+
}): Promise<Uint8Array>;
|
|
117
|
+
destroy(options?: {
|
|
118
|
+
signal?: AbortSignal;
|
|
119
|
+
}): Promise<void>;
|
|
120
|
+
}
|
|
121
|
+
export interface AgentExactProcessEnvironmentQuery {
|
|
122
|
+
/** Every supplied key/value must match persisted environment metadata exactly. */
|
|
123
|
+
metadata?: Record<string, unknown>;
|
|
124
|
+
providerOptions?: Record<string, unknown>;
|
|
125
|
+
/** Abort a paginated lookup before the next remote page or conversion. */
|
|
126
|
+
signal?: AbortSignal;
|
|
127
|
+
}
|
|
128
|
+
/** Input for a fresh environment with no provider-managed agent process. */
|
|
129
|
+
export interface CreateAgentExactProcessEnvironmentInput {
|
|
130
|
+
/** Provider-specific immutable image reference. */
|
|
131
|
+
image: string;
|
|
132
|
+
egress: AgentExactProcessEgressPolicy;
|
|
133
|
+
/** Positive integer milliseconds. */
|
|
134
|
+
maxLifetimeMs: number;
|
|
135
|
+
/** Positive integer milliseconds when supplied. */
|
|
136
|
+
provisionTimeoutMs?: number;
|
|
137
|
+
/** Required limits; exact execution never inherits provider defaults. */
|
|
138
|
+
resources: AgentExactProcessResources;
|
|
139
|
+
metadata: Record<string, unknown>;
|
|
140
|
+
idempotencyKey: string;
|
|
141
|
+
signal?: AbortSignal;
|
|
142
|
+
/** Provider-native fields may narrow, but never weaken, the isolation contract. */
|
|
143
|
+
providerOptions?: Record<string, unknown>;
|
|
144
|
+
}
|
|
145
|
+
/** Optional all-or-nothing exact process capability of an environment provider. */
|
|
146
|
+
export interface AgentExactProcessProvider {
|
|
147
|
+
/**
|
|
148
|
+
* Repeating the same idempotency key and input returns the same environment.
|
|
149
|
+
* Reusing the key with any different create input must fail.
|
|
150
|
+
* Unsupported egress modes must fail instead of weakening the policy.
|
|
151
|
+
*/
|
|
152
|
+
create(input: CreateAgentExactProcessEnvironmentInput): Promise<AgentExactProcessEnvironment>;
|
|
153
|
+
/** Ordinary environments must return null. */
|
|
154
|
+
get(id: string, options?: {
|
|
155
|
+
signal?: AbortSignal;
|
|
156
|
+
}): Promise<AgentExactProcessEnvironment | null>;
|
|
157
|
+
/** Return every matching exact environment; providers own any native pagination. */
|
|
158
|
+
list(query?: AgentExactProcessEnvironmentQuery, options?: {
|
|
159
|
+
signal?: AbortSignal;
|
|
160
|
+
}): Promise<AgentExactProcessEnvironment[]>;
|
|
161
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|