@obversa/api 0.1.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/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/accepted-result-support.d.ts +1 -0
- package/dist/accepted-result-support.js +5 -0
- package/dist/accepted-result-support.js.map +1 -0
- package/dist/action-decision.d.ts +15 -0
- package/dist/approval-support.d.ts +1 -0
- package/dist/approval-support.js +5 -0
- package/dist/approval-support.js.map +1 -0
- package/dist/artifacts/conformance.d.ts +20 -0
- package/dist/artifacts/store.d.ts +30 -0
- package/dist/budget.d.ts +36 -0
- package/dist/callback/approval.d.ts +80 -0
- package/dist/callback/client-contract.d.ts +81 -0
- package/dist/callback/gate.d.ts +49 -0
- package/dist/callback/stored-client.d.ts +22 -0
- package/dist/chunk-6NA4RDQ4.js +81 -0
- package/dist/chunk-6NA4RDQ4.js.map +1 -0
- package/dist/chunk-6NAMCSPJ.js +331 -0
- package/dist/chunk-6NAMCSPJ.js.map +1 -0
- package/dist/chunk-6ZP73HZN.js +293 -0
- package/dist/chunk-6ZP73HZN.js.map +1 -0
- package/dist/chunk-AJ353QD5.js +157 -0
- package/dist/chunk-AJ353QD5.js.map +1 -0
- package/dist/chunk-VWZKI7AG.js +552 -0
- package/dist/chunk-VWZKI7AG.js.map +1 -0
- package/dist/chunk-WGLWWKF3.js +135 -0
- package/dist/chunk-WGLWWKF3.js.map +1 -0
- package/dist/contracts.d.ts +122 -0
- package/dist/engine-conformance.d.ts +80 -0
- package/dist/environment.d.ts +53 -0
- package/dist/error.d.ts +36 -0
- package/dist/events/conformance.d.ts +20 -0
- package/dist/events/envelope.d.ts +26 -0
- package/dist/events/store.d.ts +15 -0
- package/dist/graph-commands.d.ts +23 -0
- package/dist/graph-contract.d.ts +48 -0
- package/dist/graph-executor.d.ts +61 -0
- package/dist/graph-kernel.d.ts +2 -0
- package/dist/graph-plan.d.ts +140 -0
- package/dist/graph-type.d.ts +45 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +806 -0
- package/dist/index.js.map +1 -0
- package/dist/json.d.ts +14 -0
- package/dist/memory-conformance.d.ts +17 -0
- package/dist/memory-types.d.ts +127 -0
- package/dist/model-identity.d.ts +28 -0
- package/dist/node-data-context.d.ts +11 -0
- package/dist/preflight-result.d.ts +17 -0
- package/dist/proof/acceptance.d.ts +60 -0
- package/dist/proof/artifact.d.ts +2 -0
- package/dist/proof/cache.d.ts +46 -0
- package/dist/reasoning-record-contract.d.ts +52 -0
- package/dist/result-contract.d.ts +16 -0
- package/dist/result.d.ts +30 -0
- package/dist/run-definition-support.d.ts +1 -0
- package/dist/run-definition-support.js +5 -0
- package/dist/run-definition-support.js.map +1 -0
- package/dist/run-definition.d.ts +73 -0
- package/dist/storage/error.d.ts +7 -0
- package/dist/storage/id.d.ts +2 -0
- package/dist/testing.d.ts +5 -0
- package/dist/testing.js +1745 -0
- package/dist/testing.js.map +1 -0
- package/dist/workspace/conformance.d.ts +30 -0
- package/dist/workspace/policy.d.ts +6 -0
- package/dist/workspace/provider.d.ts +132 -0
- package/package.json +68 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { StorageError } from './chunk-AJ353QD5.js';
|
|
2
|
+
import { Buffer } from 'buffer';
|
|
3
|
+
|
|
4
|
+
// src/storage/id.ts
|
|
5
|
+
var SAFE_STORAGE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;
|
|
6
|
+
function validateStorageId(value, path) {
|
|
7
|
+
if (typeof value !== "string" || !SAFE_STORAGE_ID.test(value)) {
|
|
8
|
+
throw new StorageError(
|
|
9
|
+
"INVALID_STORED_VALUE",
|
|
10
|
+
"Storage id must contain 1 to 128 ASCII characters, start with a letter or digit, and otherwise use only letters, digits, dots, underscores, or hyphens.",
|
|
11
|
+
{ path }
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
var DIGEST = /^sha256:[0-9a-f]{64}$/u;
|
|
17
|
+
var MEDIA_TYPE = /^[a-z0-9][a-z0-9!#$&^_.+-]*\/[a-z0-9][a-z0-9!#$&^_.+-]*$/iu;
|
|
18
|
+
var CONTROL_CHARACTER = /[\u0000-\u001f\u007f]/u;
|
|
19
|
+
var CONTENT_MODES = /* @__PURE__ */ new Set(["exact", "state", "free-text"]);
|
|
20
|
+
function fail(path, message) {
|
|
21
|
+
throw new StorageError("INVALID_STORED_VALUE", message, { path });
|
|
22
|
+
}
|
|
23
|
+
function record(value, path, label) {
|
|
24
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
25
|
+
fail(path, `${label} must be an object.`);
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
function exactFields(value, required, optional, path) {
|
|
30
|
+
for (const field of required) {
|
|
31
|
+
if (!Object.hasOwn(value, field)) {
|
|
32
|
+
fail(`${path}/${field}`, `Required field "${field}" is missing.`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
|
|
36
|
+
for (const field of Object.keys(value)) {
|
|
37
|
+
if (!allowed.has(field)) {
|
|
38
|
+
fail(`${path}/${field}`, `Unknown field "${field}" is not allowed.`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function text(value, path, label) {
|
|
43
|
+
if (typeof value !== "string" || value.length === 0 || value !== value.trim() || CONTROL_CHARACTER.test(value)) {
|
|
44
|
+
fail(path, `${label} must be a non-empty trimmed string without control characters.`);
|
|
45
|
+
}
|
|
46
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
47
|
+
const unit = value.charCodeAt(index);
|
|
48
|
+
if (unit >= 55296 && unit <= 56319) {
|
|
49
|
+
const next = value.charCodeAt(index + 1);
|
|
50
|
+
if (!Number.isInteger(next) || next < 56320 || next > 57343) {
|
|
51
|
+
fail(path, `${label} must contain valid Unicode.`);
|
|
52
|
+
}
|
|
53
|
+
index += 1;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (unit >= 56320 && unit <= 57343) {
|
|
57
|
+
fail(path, `${label} must contain valid Unicode.`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
function boundedText(value, path, label, maxBytes) {
|
|
63
|
+
const result = text(value, path, label);
|
|
64
|
+
if (Buffer.byteLength(result, "utf8") > maxBytes) {
|
|
65
|
+
fail(path, `${label} must not exceed ${maxBytes} UTF-8 bytes.`);
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
function mediaType(value, path) {
|
|
70
|
+
const result = boundedText(value, path, "Media type", 255);
|
|
71
|
+
if (!MEDIA_TYPE.test(result)) fail(path, "Media type must be a type/subtype value.");
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
function validateArtifactScope(value) {
|
|
75
|
+
const item = record(value, "", "Artifact scope");
|
|
76
|
+
exactFields(item, ["namespace", "runId"], [], "");
|
|
77
|
+
return Object.freeze({
|
|
78
|
+
namespace: validateStorageId(item.namespace, "/namespace"),
|
|
79
|
+
runId: validateStorageId(item.runId, "/runId")
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function validateNewArtifact(value) {
|
|
83
|
+
const item = record(value, "", "New artifact");
|
|
84
|
+
exactFields(
|
|
85
|
+
item,
|
|
86
|
+
["bytes", "mediaType", "purpose", "contentMode"],
|
|
87
|
+
["sensitive"],
|
|
88
|
+
""
|
|
89
|
+
);
|
|
90
|
+
if (!(item.bytes instanceof Uint8Array)) {
|
|
91
|
+
fail("/bytes", "Artifact bytes must be a Uint8Array.");
|
|
92
|
+
}
|
|
93
|
+
if (!CONTENT_MODES.has(item.contentMode)) {
|
|
94
|
+
fail("/contentMode", "Content mode must be exact, state, or free-text.");
|
|
95
|
+
}
|
|
96
|
+
if (item.sensitive !== void 0 && typeof item.sensitive !== "boolean") {
|
|
97
|
+
fail("/sensitive", "Sensitive must be a boolean when supplied.");
|
|
98
|
+
}
|
|
99
|
+
return Object.freeze({
|
|
100
|
+
bytes: Uint8Array.from(item.bytes),
|
|
101
|
+
mediaType: mediaType(item.mediaType, "/mediaType"),
|
|
102
|
+
purpose: boundedText(item.purpose, "/purpose", "Purpose", 512),
|
|
103
|
+
contentMode: item.contentMode,
|
|
104
|
+
...item.sensitive === void 0 ? {} : { sensitive: item.sensitive }
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function validateArtifactReference(value) {
|
|
108
|
+
const item = record(value, "", "Artifact reference");
|
|
109
|
+
exactFields(
|
|
110
|
+
item,
|
|
111
|
+
["schemaVersion", "digest", "byteLength", "mediaType", "purpose"],
|
|
112
|
+
[],
|
|
113
|
+
""
|
|
114
|
+
);
|
|
115
|
+
if (item.schemaVersion !== 1) {
|
|
116
|
+
fail("/schemaVersion", "Artifact reference schemaVersion must be 1.");
|
|
117
|
+
}
|
|
118
|
+
if (typeof item.digest !== "string" || !DIGEST.test(item.digest)) {
|
|
119
|
+
fail("/digest", "Digest must be lowercase sha256 followed by 64 hexadecimal characters.");
|
|
120
|
+
}
|
|
121
|
+
if (!Number.isSafeInteger(item.byteLength) || item.byteLength < 0) {
|
|
122
|
+
fail("/byteLength", "Byte length must be a non-negative safe integer.");
|
|
123
|
+
}
|
|
124
|
+
return Object.freeze({
|
|
125
|
+
schemaVersion: 1,
|
|
126
|
+
digest: item.digest,
|
|
127
|
+
byteLength: item.byteLength,
|
|
128
|
+
mediaType: mediaType(item.mediaType, "/mediaType"),
|
|
129
|
+
purpose: boundedText(item.purpose, "/purpose", "Purpose", 512)
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export { validateArtifactReference, validateArtifactScope, validateNewArtifact, validateStorageId };
|
|
134
|
+
//# sourceMappingURL=chunk-WGLWWKF3.js.map
|
|
135
|
+
//# sourceMappingURL=chunk-WGLWWKF3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/storage/id.ts","../src/artifacts/store.ts"],"names":[],"mappings":"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","file":"chunk-WGLWWKF3.js","sourcesContent":["import { StorageError } from './error.js';\n\nconst SAFE_STORAGE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;\n\n/** Validate one namespace, stream, or run identity used by a storage port. */\nexport function validateStorageId(value: unknown, path: string): string {\n if (typeof value !== 'string' || !SAFE_STORAGE_ID.test(value)) {\n throw new StorageError(\n 'INVALID_STORED_VALUE',\n 'Storage id must contain 1 to 128 ASCII characters, start with a letter or digit, and otherwise use only letters, digits, dots, underscores, or hyphens.',\n { path },\n );\n }\n return value;\n}\n","import { Buffer } from 'node:buffer';\n\nimport { StorageError } from '../storage/error.js';\nimport { validateStorageId } from '../storage/id.js';\nimport type { JsonObject, Sha256Digest } from '../json.js';\n\nexport type ArtifactContentMode = 'exact' | 'state' | 'free-text';\n\nexport interface ArtifactScope {\n readonly namespace: string;\n readonly runId: string;\n}\n\nexport interface NewArtifact {\n readonly bytes: Uint8Array;\n readonly mediaType: string;\n readonly purpose: string;\n readonly contentMode: ArtifactContentMode;\n readonly sensitive?: boolean;\n}\n\nexport type ArtifactBatch = readonly [NewArtifact, ...NewArtifact[]];\n\nexport interface ArtifactReference<Purpose extends string = string> extends JsonObject {\n readonly schemaVersion: 1;\n readonly digest: Sha256Digest;\n readonly byteLength: number;\n readonly mediaType: string;\n readonly purpose: Purpose;\n}\n\nexport interface ArtifactStore {\n preflightWrite(\n scope: ArtifactScope,\n artifacts: ArtifactBatch,\n ): Promise<readonly ArtifactReference[]>;\n write(scope: ArtifactScope, artifact: NewArtifact): Promise<ArtifactReference>;\n read(scope: ArtifactScope, reference: ArtifactReference): Promise<Uint8Array>;\n deleteRun(scope: ArtifactScope): Promise<void>;\n}\n\nconst DIGEST = /^sha256:[0-9a-f]{64}$/u;\nconst MEDIA_TYPE = /^[a-z0-9][a-z0-9!#$&^_.+-]*\\/[a-z0-9][a-z0-9!#$&^_.+-]*$/iu;\nconst CONTROL_CHARACTER = /[\\u0000-\\u001f\\u007f]/u;\nconst CONTENT_MODES = new Set<ArtifactContentMode>(['exact', 'state', 'free-text']);\n\nfunction fail(path: string, message: string): never {\n throw new StorageError('INVALID_STORED_VALUE', message, { path });\n}\n\nfunction record(value: unknown, path: string, label: string): Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n fail(path, `${label} must be an object.`);\n }\n return value as Record<string, unknown>;\n}\n\nfunction exactFields(\n value: Record<string, unknown>,\n required: readonly string[],\n optional: readonly string[],\n path: string,\n): void {\n for (const field of required) {\n if (!Object.hasOwn(value, field)) {\n fail(`${path}/${field}`, `Required field \"${field}\" is missing.`);\n }\n }\n const allowed = new Set([...required, ...optional]);\n for (const field of Object.keys(value)) {\n if (!allowed.has(field)) {\n fail(`${path}/${field}`, `Unknown field \"${field}\" is not allowed.`);\n }\n }\n}\n\nfunction text(value: unknown, path: string, label: string): string {\n if (\n typeof value !== 'string'\n || value.length === 0\n || value !== value.trim()\n || CONTROL_CHARACTER.test(value)\n ) {\n fail(path, `${label} must be a non-empty trimmed string without control characters.`);\n }\n for (let index = 0; index < value.length; index += 1) {\n const unit = value.charCodeAt(index);\n if (unit >= 0xd800 && unit <= 0xdbff) {\n const next = value.charCodeAt(index + 1);\n if (!Number.isInteger(next) || next < 0xdc00 || next > 0xdfff) {\n fail(path, `${label} must contain valid Unicode.`);\n }\n index += 1;\n continue;\n }\n if (unit >= 0xdc00 && unit <= 0xdfff) {\n fail(path, `${label} must contain valid Unicode.`);\n }\n }\n return value;\n}\n\nfunction boundedText(\n value: unknown,\n path: string,\n label: string,\n maxBytes: number,\n): string {\n const result = text(value, path, label);\n if (Buffer.byteLength(result, 'utf8') > maxBytes) {\n fail(path, `${label} must not exceed ${maxBytes} UTF-8 bytes.`);\n }\n return result;\n}\n\nfunction mediaType(value: unknown, path: string): string {\n const result = boundedText(value, path, 'Media type', 255);\n if (!MEDIA_TYPE.test(result)) fail(path, 'Media type must be a type/subtype value.');\n return result;\n}\n\nexport function validateArtifactScope(value: unknown): ArtifactScope {\n const item = record(value, '', 'Artifact scope');\n exactFields(item, ['namespace', 'runId'], [], '');\n return Object.freeze({\n namespace: validateStorageId(item.namespace, '/namespace'),\n runId: validateStorageId(item.runId, '/runId'),\n });\n}\n\nexport function validateNewArtifact(value: unknown): NewArtifact {\n const item = record(value, '', 'New artifact');\n exactFields(\n item,\n ['bytes', 'mediaType', 'purpose', 'contentMode'],\n ['sensitive'],\n '',\n );\n if (!(item.bytes instanceof Uint8Array)) {\n fail('/bytes', 'Artifact bytes must be a Uint8Array.');\n }\n if (!CONTENT_MODES.has(item.contentMode as ArtifactContentMode)) {\n fail('/contentMode', 'Content mode must be exact, state, or free-text.');\n }\n if (item.sensitive !== undefined && typeof item.sensitive !== 'boolean') {\n fail('/sensitive', 'Sensitive must be a boolean when supplied.');\n }\n\n return Object.freeze({\n bytes: Uint8Array.from(item.bytes),\n mediaType: mediaType(item.mediaType, '/mediaType'),\n purpose: boundedText(item.purpose, '/purpose', 'Purpose', 512),\n contentMode: item.contentMode as ArtifactContentMode,\n ...(item.sensitive === undefined ? {} : { sensitive: item.sensitive }),\n });\n}\n\nexport function validateArtifactReference(value: unknown): ArtifactReference {\n const item = record(value, '', 'Artifact reference');\n exactFields(\n item,\n ['schemaVersion', 'digest', 'byteLength', 'mediaType', 'purpose'],\n [],\n '',\n );\n if (item.schemaVersion !== 1) {\n fail('/schemaVersion', 'Artifact reference schemaVersion must be 1.');\n }\n if (typeof item.digest !== 'string' || !DIGEST.test(item.digest)) {\n fail('/digest', 'Digest must be lowercase sha256 followed by 64 hexadecimal characters.');\n }\n if (!Number.isSafeInteger(item.byteLength) || (item.byteLength as number) < 0) {\n fail('/byteLength', 'Byte length must be a non-negative safe integer.');\n }\n\n return Object.freeze({\n schemaVersion: 1,\n digest: item.digest as Sha256Digest,\n byteLength: item.byteLength as number,\n mediaType: mediaType(item.mediaType, '/mediaType'),\n purpose: boundedText(item.purpose, '/purpose', 'Purpose', 512),\n });\n}\n"]}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/** Provider-neutral values and behavior shared by runtimes and engine plugins. */
|
|
2
|
+
import type { JsonValue } from './json.js';
|
|
3
|
+
export type { JsonObject, JsonPrimitive, JsonValue, Sha256Digest, } from './json.js';
|
|
4
|
+
export { JsonValueError, canonicalJson, cloneFrozenJson, digestJson, } from './json.js';
|
|
5
|
+
export interface AttemptMetadata {
|
|
6
|
+
leaf: boolean;
|
|
7
|
+
runId?: string;
|
|
8
|
+
attemptId?: string;
|
|
9
|
+
leafId: string;
|
|
10
|
+
path: string[];
|
|
11
|
+
label: string;
|
|
12
|
+
iteration: number;
|
|
13
|
+
}
|
|
14
|
+
export interface Usage {
|
|
15
|
+
/** Total input, including cache creation and cache reads where reported. */
|
|
16
|
+
inputTokens: number;
|
|
17
|
+
outputTokens: number;
|
|
18
|
+
cacheCreationInputTokens?: number;
|
|
19
|
+
cacheReadInputTokens?: number;
|
|
20
|
+
}
|
|
21
|
+
export type UsageReceipt = {
|
|
22
|
+
readonly kind: 'unknown';
|
|
23
|
+
} | ({
|
|
24
|
+
readonly kind: 'reported';
|
|
25
|
+
} & Usage);
|
|
26
|
+
export type AgentResultPart = {
|
|
27
|
+
readonly kind: 'assistant';
|
|
28
|
+
readonly text: string;
|
|
29
|
+
readonly final: boolean;
|
|
30
|
+
} | {
|
|
31
|
+
readonly kind: 'structured';
|
|
32
|
+
readonly value: JsonValue;
|
|
33
|
+
readonly final: true;
|
|
34
|
+
};
|
|
35
|
+
export interface EngineSelectionRecord {
|
|
36
|
+
readonly adapter: string;
|
|
37
|
+
readonly adapterVersion: string | null;
|
|
38
|
+
readonly provider: string | null;
|
|
39
|
+
readonly modelFamily: string | null;
|
|
40
|
+
readonly model: string | null;
|
|
41
|
+
readonly executable: string | null;
|
|
42
|
+
readonly capabilities: readonly string[];
|
|
43
|
+
}
|
|
44
|
+
export interface ExecutionTarget {
|
|
45
|
+
readonly adapter: string;
|
|
46
|
+
readonly provider: string;
|
|
47
|
+
readonly modelFamily: string;
|
|
48
|
+
readonly model: string;
|
|
49
|
+
readonly tools: readonly string[];
|
|
50
|
+
}
|
|
51
|
+
export interface TeamSeat {
|
|
52
|
+
readonly engine: Engine;
|
|
53
|
+
readonly identity: ExecutionTarget;
|
|
54
|
+
}
|
|
55
|
+
export type EngineFailureKind = 'auth' | 'billing' | 'missing-cli' | 'model-unavailable' | 'invalid-config' | 'rate-limit' | 'quota' | 'transient' | 'timeout' | 'aborted' | 'unknown';
|
|
56
|
+
export interface EngineTransportFailure {
|
|
57
|
+
readonly kind: EngineFailureKind;
|
|
58
|
+
readonly message: string;
|
|
59
|
+
readonly exitCode: number | null;
|
|
60
|
+
}
|
|
61
|
+
/** Tools used by supported agent hosts to dispatch sub-agents. */
|
|
62
|
+
export declare const SUBAGENT_TOOLS: string[];
|
|
63
|
+
export declare const CLAUDE_SUBAGENT_TOOLS: string[];
|
|
64
|
+
export interface AgentRequest {
|
|
65
|
+
prompt: string;
|
|
66
|
+
purpose?: 'preflight';
|
|
67
|
+
system?: string;
|
|
68
|
+
systemMode?: 'append' | 'replace';
|
|
69
|
+
model?: string;
|
|
70
|
+
maxTokens?: number;
|
|
71
|
+
jsonSchema?: JsonValue;
|
|
72
|
+
tools?: string[];
|
|
73
|
+
allowedTools?: string[];
|
|
74
|
+
workspaceMode?: 'none' | 'read' | 'write';
|
|
75
|
+
cwd?: string;
|
|
76
|
+
env?: Record<string, string>;
|
|
77
|
+
timeoutMs?: number;
|
|
78
|
+
timeoutGraceMs?: number;
|
|
79
|
+
maxOutputBytes?: number;
|
|
80
|
+
maxMemoryBytes?: number;
|
|
81
|
+
attempt?: AttemptMetadata;
|
|
82
|
+
leaf?: boolean;
|
|
83
|
+
}
|
|
84
|
+
/** A read-only workspace must expose at least one tool that can read it. */
|
|
85
|
+
export declare function assertReadAccess(request: Pick<AgentRequest, 'tools' | 'workspaceMode'>): void;
|
|
86
|
+
export interface AgentResult {
|
|
87
|
+
/** Ordered assistant continuations with exactly one marked final part. */
|
|
88
|
+
readonly parts: readonly AgentResultPart[];
|
|
89
|
+
readonly usage: UsageReceipt;
|
|
90
|
+
readonly requested: EngineSelectionRecord;
|
|
91
|
+
readonly effective: EngineSelectionRecord;
|
|
92
|
+
readonly stopReason?: string;
|
|
93
|
+
readonly transportFailure?: EngineTransportFailure;
|
|
94
|
+
readonly raw?: unknown;
|
|
95
|
+
}
|
|
96
|
+
export type EngineIncompleteResultEvidence = Omit<AgentResult, 'parts'> & {
|
|
97
|
+
readonly parts: readonly AgentResultPart[];
|
|
98
|
+
};
|
|
99
|
+
export type EngineStreamEvent = {
|
|
100
|
+
type: 'text';
|
|
101
|
+
delta: string;
|
|
102
|
+
} | {
|
|
103
|
+
type: 'thinking';
|
|
104
|
+
delta: string;
|
|
105
|
+
} | {
|
|
106
|
+
type: 'tool';
|
|
107
|
+
name: string;
|
|
108
|
+
phase: 'use' | 'result';
|
|
109
|
+
} | {
|
|
110
|
+
type: 'usage';
|
|
111
|
+
usage: UsageReceipt;
|
|
112
|
+
model: string;
|
|
113
|
+
};
|
|
114
|
+
export type EngineEventSink = (event: EngineStreamEvent) => void;
|
|
115
|
+
export interface Engine {
|
|
116
|
+
readonly name: string;
|
|
117
|
+
admit?(request: Omit<AgentRequest, 'prompt'>, signal: AbortSignal, expectedSelection?: EngineSelectionRecord): Promise<EngineSelectionRecord>;
|
|
118
|
+
run(request: AgentRequest, onEvent: EngineEventSink, signal: AbortSignal): Promise<AgentResult>;
|
|
119
|
+
}
|
|
120
|
+
export type EngineRef = string | Engine;
|
|
121
|
+
export type EngineName = string;
|
|
122
|
+
export declare function isEngine(value: unknown): value is Engine;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { AgentRequest, AgentResultPart, Engine, EngineSelectionRecord } from './contracts.js';
|
|
2
|
+
import type { JsonValue } from './json.js';
|
|
3
|
+
export type EngineConformanceScenario = 'ordered-parts' | 'structured-result' | 'unknown-usage' | 'reported-usage' | 'tool-events' | 'late-final' | 'cancellation' | 'missing-cli' | 'auth' | 'billing' | 'model-unavailable' | 'rate-limit' | 'quota' | 'transient' | 'timeout' | 'invalid-config' | 'read-access' | 'workspace-none' | 'workspace-read' | 'workspace-write';
|
|
4
|
+
type WorkspaceMode = NonNullable<AgentRequest['workspaceMode']>;
|
|
5
|
+
type FeatureScenario = Exclude<EngineConformanceScenario, 'read-access' | `workspace-${WorkspaceMode}`>;
|
|
6
|
+
export interface EngineConformanceFixture {
|
|
7
|
+
readonly request: AgentRequest;
|
|
8
|
+
readonly requested: EngineSelectionRecord;
|
|
9
|
+
readonly effective: EngineSelectionRecord;
|
|
10
|
+
readonly unsupported?: Partial<Record<FeatureScenario, string>>;
|
|
11
|
+
readonly workspace: {
|
|
12
|
+
readonly modes: Record<WorkspaceMode, {
|
|
13
|
+
readonly request: AgentRequest;
|
|
14
|
+
readonly outcome: 'supported' | 'refused';
|
|
15
|
+
readonly requested?: EngineSelectionRecord;
|
|
16
|
+
readonly effective?: EngineSelectionRecord;
|
|
17
|
+
}>;
|
|
18
|
+
/** Observe actual process arguments or provider options, never the input request. */
|
|
19
|
+
observe(): {
|
|
20
|
+
readonly modelCalls: number;
|
|
21
|
+
readonly canRead: boolean;
|
|
22
|
+
readonly canWrite: boolean;
|
|
23
|
+
} | Promise<{
|
|
24
|
+
readonly modelCalls: number;
|
|
25
|
+
readonly canRead: boolean;
|
|
26
|
+
readonly canWrite: boolean;
|
|
27
|
+
}>;
|
|
28
|
+
};
|
|
29
|
+
/** Parse a final assistant part when the backend has no native schema mode. */
|
|
30
|
+
readonly parseStructuredResult?: (part: AgentResultPart, parts: readonly AgentResultPart[]) => JsonValue;
|
|
31
|
+
/**
|
|
32
|
+
* True for an adapter whose provider and model family come from the model
|
|
33
|
+
* it was given rather than from its own name (OpenCode, Devin). The kit then
|
|
34
|
+
* checks that the identity it reports is the one `modelIdentity` reads from
|
|
35
|
+
* the reported model, so two seats on one model cannot pass as two families.
|
|
36
|
+
*/
|
|
37
|
+
readonly identityFromModel?: boolean;
|
|
38
|
+
open(scenario: EngineConformanceScenario): Engine | Promise<Engine>;
|
|
39
|
+
}
|
|
40
|
+
export interface EngineConformanceFailure {
|
|
41
|
+
readonly case: string;
|
|
42
|
+
readonly message: string;
|
|
43
|
+
}
|
|
44
|
+
export interface EngineConformanceReport {
|
|
45
|
+
readonly ok: boolean;
|
|
46
|
+
readonly cases: number;
|
|
47
|
+
readonly failures: readonly EngineConformanceFailure[];
|
|
48
|
+
}
|
|
49
|
+
export interface EngineAdapterConformanceReport extends EngineConformanceReport {
|
|
50
|
+
readonly unsupported: readonly {
|
|
51
|
+
readonly case: FeatureScenario;
|
|
52
|
+
readonly reason: string;
|
|
53
|
+
}[];
|
|
54
|
+
}
|
|
55
|
+
/** Run framework-free behavioral checks against an outside Engine adapter. */
|
|
56
|
+
export declare function runEngineConformance(fixture: EngineConformanceFixture): Promise<EngineAdapterConformanceReport>;
|
|
57
|
+
/** Throw one readable error when an outside Engine breaks the contract. */
|
|
58
|
+
export declare function assertEngineConformance(fixture: EngineConformanceFixture): Promise<void>;
|
|
59
|
+
export interface EngineAdmissionConformanceFixture {
|
|
60
|
+
readonly request: AgentRequest;
|
|
61
|
+
readonly selection: EngineSelectionRecord;
|
|
62
|
+
open(): Engine | Promise<Engine>;
|
|
63
|
+
/** No argument counts all model calls; a path/null counts that target. */
|
|
64
|
+
modelCalls(executable?: string | null): number | Promise<number>;
|
|
65
|
+
readonly cli?: {
|
|
66
|
+
/** Move bare-name lookup while keeping the admitted path runnable. */
|
|
67
|
+
moveLookup(): void | Promise<void>;
|
|
68
|
+
/** Same configuration, except an explicitly different absolute path. */
|
|
69
|
+
openDifferent(): Engine | Promise<Engine>;
|
|
70
|
+
/** A syntactically valid absolute path with no executable. */
|
|
71
|
+
openMissing(): Engine | Promise<Engine>;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export type EngineAdmissionConformanceReport = EngineConformanceReport | {
|
|
75
|
+
readonly kind: 'unsupported';
|
|
76
|
+
readonly adapter: string;
|
|
77
|
+
};
|
|
78
|
+
/** Check optional admission without imposing the full run-scenario protocol. */
|
|
79
|
+
export declare function runEngineAdmissionConformance(fixture: EngineAdmissionConformanceFixture): Promise<EngineAdmissionConformanceReport>;
|
|
80
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Environment provider — the third axis, after Engine (where the agent
|
|
3
|
+
* thinks) and Workspace (where the code lives). Environment is where the code
|
|
4
|
+
* runs: local services, or a per-branch cloud preview. It lets the gate test the
|
|
5
|
+
* running thing, so "done" can mean "the e2e suite passes against the running
|
|
6
|
+
* preview", not just "unit tests pass against static files on disk".
|
|
7
|
+
*
|
|
8
|
+
* Like `Engine`, this is only an interface. API owns the interface and the
|
|
9
|
+
* runtime owns the lifecycle binding; the actual adapter (sst, Vercel, Docker, …) is
|
|
10
|
+
* provider-specific and lives in the consumer's loop definition, next to the
|
|
11
|
+
* deploy config it wraps. The runtime never takes a dependency on a deploy tool.
|
|
12
|
+
* Implement `up`, return a handle:
|
|
13
|
+
*
|
|
14
|
+
* const sstEnv: Environment = {
|
|
15
|
+
* name: 'sst',
|
|
16
|
+
* async up(ws) {
|
|
17
|
+
* const stage = slug(ws.branch); // per-branch stage
|
|
18
|
+
* const out = await sh('sst', ['deploy', '--stage', stage], ws.dir);
|
|
19
|
+
* return {
|
|
20
|
+
* url: out.url,
|
|
21
|
+
* env: { BASE_URL: out.url },
|
|
22
|
+
* down: () => sh('sst', ['remove', '--stage', stage], ws.dir),
|
|
23
|
+
* };
|
|
24
|
+
* },
|
|
25
|
+
* };
|
|
26
|
+
*/
|
|
27
|
+
export interface EnvironmentWorkspace {
|
|
28
|
+
readonly dir: string;
|
|
29
|
+
readonly branch?: string;
|
|
30
|
+
}
|
|
31
|
+
/** A running environment for one workspace. Returned by `Environment.up`. */
|
|
32
|
+
export interface EnvHandle {
|
|
33
|
+
/** Addressable base URL (a preview deployment, or a local server), if any. */
|
|
34
|
+
readonly url?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Variables injected into gate commands, judge calls, and agent turns, e.g.
|
|
37
|
+
* `BASE_URL`, `DATABASE_URL`. This is how `commandSucceeds('playwright', …)`
|
|
38
|
+
* reaches the running preview.
|
|
39
|
+
*/
|
|
40
|
+
readonly env: Record<string, string>;
|
|
41
|
+
/**
|
|
42
|
+
* Redeploy when the branch advances (a cloud preview that tracks commits).
|
|
43
|
+
* Optional: a local-services env has nothing to sync.
|
|
44
|
+
*/
|
|
45
|
+
sync?(commit: string, signal: AbortSignal): Promise<void>;
|
|
46
|
+
/** Tear the environment down. */
|
|
47
|
+
down(signal: AbortSignal): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
/** Brings a workspace's code up so the gate can test the running thing. */
|
|
50
|
+
export interface Environment {
|
|
51
|
+
readonly name: string;
|
|
52
|
+
up(workspace: EnvironmentWorkspace, signal: AbortSignal): Promise<EnvHandle>;
|
|
53
|
+
}
|
package/dist/error.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared engine failure classification. Typed engine failures and compatible
|
|
3
|
+
* runtime codes take priority over process errors and message text.
|
|
4
|
+
*
|
|
5
|
+
* Default fallback treats auth, billing, missing executables, unavailable
|
|
6
|
+
* models, invalid configuration and exhausted long allowances as lasting for
|
|
7
|
+
* the run. Ambiguous limit wording is rate-limit, not evidence of quota.
|
|
8
|
+
* Rate limits and transient failures remain outside the default lasting set.
|
|
9
|
+
*/
|
|
10
|
+
import type { EngineFailureKind, EngineIncompleteResultEvidence, EngineSelectionRecord } from './contracts.js';
|
|
11
|
+
export type { EngineFailureKind } from './contracts.js';
|
|
12
|
+
export interface EngineErrorInit {
|
|
13
|
+
readonly kind: EngineFailureKind;
|
|
14
|
+
readonly message: string;
|
|
15
|
+
readonly cause?: unknown;
|
|
16
|
+
readonly retryAfterMs?: number;
|
|
17
|
+
readonly resetAt?: number;
|
|
18
|
+
readonly effective?: EngineSelectionRecord;
|
|
19
|
+
}
|
|
20
|
+
/** A provider or adapter failure with no runtime policy attached. */
|
|
21
|
+
export declare class EngineError extends Error {
|
|
22
|
+
readonly kind: EngineFailureKind;
|
|
23
|
+
readonly retryAfterMs?: number;
|
|
24
|
+
readonly resetAt?: number;
|
|
25
|
+
readonly effective?: EngineSelectionRecord;
|
|
26
|
+
constructor(init: EngineErrorInit);
|
|
27
|
+
}
|
|
28
|
+
/** A failed engine turn that still produced measured, recordable evidence. */
|
|
29
|
+
export declare class EngineIncompleteResultError extends EngineError {
|
|
30
|
+
readonly evidence: EngineIncompleteResultEvidence;
|
|
31
|
+
constructor(message: string, evidence: EngineIncompleteResultEvidence);
|
|
32
|
+
}
|
|
33
|
+
/** Failures that default fallback treats as lasting for the run. */
|
|
34
|
+
export declare const LANE_DEAD_FAILURES: ReadonlySet<EngineFailureKind>;
|
|
35
|
+
/** Classify a failed engine turn. Typed signals win over substring rules. */
|
|
36
|
+
export declare function classifyEngineFailure(error: unknown): EngineFailureKind;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { EventStore } from './store.js';
|
|
2
|
+
export interface EventStoreConformanceOptions {
|
|
3
|
+
readonly maxEventPayloadBytes: number;
|
|
4
|
+
readonly maxAppendBatchBytes: number;
|
|
5
|
+
readonly knownSecrets: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
export type EventStoreConformanceFactory = (options: EventStoreConformanceOptions) => EventStore | Promise<EventStore>;
|
|
8
|
+
export interface EventStoreConformanceFailure {
|
|
9
|
+
readonly case: string;
|
|
10
|
+
readonly message: string;
|
|
11
|
+
}
|
|
12
|
+
export interface EventStoreConformanceReport {
|
|
13
|
+
readonly ok: boolean;
|
|
14
|
+
readonly cases: number;
|
|
15
|
+
readonly failures: readonly EventStoreConformanceFailure[];
|
|
16
|
+
}
|
|
17
|
+
/** Run framework-free checks against an outside EventStore implementation. */
|
|
18
|
+
export declare function runEventStoreConformance(factory: EventStoreConformanceFactory): Promise<EventStoreConformanceReport>;
|
|
19
|
+
/** Throw one readable error when an outside EventStore breaks the contract. */
|
|
20
|
+
export declare function assertEventStoreConformance(factory: EventStoreConformanceFactory): Promise<void>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type JsonValue } from '../json.js';
|
|
2
|
+
export type DomainEventId = string;
|
|
3
|
+
export type EventStreamId = string;
|
|
4
|
+
export type StorageNamespace = string;
|
|
5
|
+
export type StreamRevision = number;
|
|
6
|
+
export interface EventStreamRef {
|
|
7
|
+
readonly namespace: StorageNamespace;
|
|
8
|
+
readonly streamId: EventStreamId;
|
|
9
|
+
}
|
|
10
|
+
export interface NewDomainEvent<Type extends string = string, Version extends number = number, Payload extends JsonValue = JsonValue> {
|
|
11
|
+
readonly eventId: DomainEventId;
|
|
12
|
+
readonly type: Type;
|
|
13
|
+
readonly version: Version;
|
|
14
|
+
readonly timestamp: string;
|
|
15
|
+
readonly correlationId: string;
|
|
16
|
+
readonly causationId: DomainEventId | null;
|
|
17
|
+
readonly payload: Payload;
|
|
18
|
+
}
|
|
19
|
+
export interface DomainEventEnvelope<Type extends string = string, Version extends number = number, Payload extends JsonValue = JsonValue> extends NewDomainEvent<Type, Version, Payload> {
|
|
20
|
+
readonly envelopeVersion: 1;
|
|
21
|
+
readonly streamId: EventStreamId;
|
|
22
|
+
readonly revision: StreamRevision;
|
|
23
|
+
}
|
|
24
|
+
export declare function validateDomainEventId(value: unknown, path: string): string;
|
|
25
|
+
export declare function validateNewDomainEvent(value: unknown): NewDomainEvent;
|
|
26
|
+
export declare function validateDomainEventEnvelope(value: unknown): DomainEventEnvelope;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type DomainEventEnvelope, type EventStreamRef, type NewDomainEvent, type StreamRevision } from './envelope.js';
|
|
2
|
+
export type DomainEventBatch = readonly [
|
|
3
|
+
NewDomainEvent,
|
|
4
|
+
...NewDomainEvent[]
|
|
5
|
+
];
|
|
6
|
+
export interface EventStore {
|
|
7
|
+
preflightAppend(stream: EventStreamRef, expectedRevision: StreamRevision, events: DomainEventBatch): Promise<void>;
|
|
8
|
+
read(stream: EventStreamRef, afterRevision?: StreamRevision): AsyncIterable<DomainEventEnvelope>;
|
|
9
|
+
append(stream: EventStreamRef, expectedRevision: StreamRevision, events: DomainEventBatch): Promise<StreamRevision>;
|
|
10
|
+
}
|
|
11
|
+
export { validateStorageId } from '../storage/id.js';
|
|
12
|
+
export declare function validateEventStreamRef(value: unknown): EventStreamRef;
|
|
13
|
+
export declare function validateStreamRevision(value: unknown, path: string): StreamRevision;
|
|
14
|
+
export declare function validateDomainEventBatch(value: unknown): DomainEventBatch;
|
|
15
|
+
export declare function findKnownSecretInEvents(knownSecrets: readonly string[], serializedBytes: string, events: readonly NewDomainEvent[]): string | undefined;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { NodeId } from './graph-contract.js';
|
|
2
|
+
import type { JsonValue } from './json.js';
|
|
3
|
+
export interface DispatchGraphCommand<Input extends JsonValue = JsonValue> {
|
|
4
|
+
readonly kind: 'dispatch';
|
|
5
|
+
readonly nodeId: NodeId;
|
|
6
|
+
readonly input: Input;
|
|
7
|
+
/** Stable logical identity and location of this requested node occurrence. */
|
|
8
|
+
readonly position: string;
|
|
9
|
+
}
|
|
10
|
+
export interface PauseGraphCommand {
|
|
11
|
+
readonly kind: 'pause';
|
|
12
|
+
readonly reason: string;
|
|
13
|
+
}
|
|
14
|
+
export interface CompleteGraphCommand<Output extends JsonValue = JsonValue> {
|
|
15
|
+
readonly kind: 'complete';
|
|
16
|
+
readonly output: Output;
|
|
17
|
+
}
|
|
18
|
+
export interface FailGraphCommand {
|
|
19
|
+
readonly kind: 'fail';
|
|
20
|
+
readonly code: string;
|
|
21
|
+
readonly message: string;
|
|
22
|
+
}
|
|
23
|
+
export type GraphCommand<Input extends JsonValue = JsonValue, Output extends JsonValue = JsonValue> = DispatchGraphCommand<Input> | PauseGraphCommand | CompleteGraphCommand<Output> | FailGraphCommand;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { JsonObject, JsonValue, Sha256Digest } from './json.js';
|
|
2
|
+
export type RunBrief = JsonObject;
|
|
3
|
+
export interface GraphValidationIssue {
|
|
4
|
+
readonly code: string;
|
|
5
|
+
readonly path: string;
|
|
6
|
+
readonly message: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class GraphValidationError extends Error {
|
|
9
|
+
readonly issues: readonly GraphValidationIssue[];
|
|
10
|
+
constructor(message: string, issues: readonly GraphValidationIssue[]);
|
|
11
|
+
}
|
|
12
|
+
export type GraphId = string;
|
|
13
|
+
export type NodeId = string;
|
|
14
|
+
export type EdgeId = string;
|
|
15
|
+
export interface GraphNode<Data extends JsonValue = JsonValue> extends JsonObject {
|
|
16
|
+
readonly id: NodeId;
|
|
17
|
+
readonly data: Data;
|
|
18
|
+
}
|
|
19
|
+
export interface GraphEdge<Data extends JsonValue = JsonValue> extends JsonObject {
|
|
20
|
+
readonly id: EdgeId;
|
|
21
|
+
readonly source: NodeId;
|
|
22
|
+
readonly target: NodeId;
|
|
23
|
+
readonly data: Data;
|
|
24
|
+
}
|
|
25
|
+
export interface GraphDefinition<NodeData extends JsonValue = JsonValue, EdgeData extends JsonValue = JsonValue, GraphData extends JsonValue = JsonValue> extends JsonObject {
|
|
26
|
+
readonly id: GraphId;
|
|
27
|
+
readonly definitionVersion: number;
|
|
28
|
+
readonly data: GraphData;
|
|
29
|
+
readonly nodes: readonly GraphNode<NodeData>[];
|
|
30
|
+
readonly edges: readonly GraphEdge<EdgeData>[];
|
|
31
|
+
}
|
|
32
|
+
export interface CompiledGraphDefinition<Definition extends GraphDefinition = GraphDefinition> extends JsonObject {
|
|
33
|
+
readonly value: Definition;
|
|
34
|
+
readonly canonicalJson: string;
|
|
35
|
+
readonly digest: Sha256Digest;
|
|
36
|
+
}
|
|
37
|
+
type DefinitionNode<Definition extends GraphDefinition> = Definition['nodes'][number];
|
|
38
|
+
type DefinitionEdge<Definition extends GraphDefinition> = Definition['edges'][number];
|
|
39
|
+
export interface GraphKernel<Definition extends GraphDefinition = GraphDefinition> {
|
|
40
|
+
readonly definition: CompiledGraphDefinition<Definition>;
|
|
41
|
+
node(id: NodeId): DefinitionNode<Definition> | undefined;
|
|
42
|
+
edge(id: EdgeId): DefinitionEdge<Definition> | undefined;
|
|
43
|
+
predecessors(id: NodeId): readonly NodeId[];
|
|
44
|
+
successors(id: NodeId): readonly NodeId[];
|
|
45
|
+
inboundEdges(id: NodeId): readonly DefinitionEdge<Definition>[];
|
|
46
|
+
outboundEdges(id: NodeId): readonly DefinitionEdge<Definition>[];
|
|
47
|
+
}
|
|
48
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Memory } from './memory-types.js';
|
|
2
|
+
import type { GraphCommand } from './graph-commands.js';
|
|
3
|
+
import type { CompiledGraphType } from './graph-type.js';
|
|
4
|
+
import type { JsonObject, JsonValue } from './json.js';
|
|
5
|
+
import type { ExecutionTarget, AgentResultPart, EngineSelectionRecord, Engine } from './contracts.js';
|
|
6
|
+
import type { AttemptBudgetPolicy, TokenBudget } from './budget.js';
|
|
7
|
+
import type { NodeDataContext } from './node-data-context.js';
|
|
8
|
+
import type { ResultContract } from './result-contract.js';
|
|
9
|
+
import type { RunStorageBinding } from './run-definition.js';
|
|
10
|
+
import type { NodeWorkspacePolicy } from './workspace/policy.js';
|
|
11
|
+
import type { ActionDecision } from './action-decision.js';
|
|
12
|
+
import type { PreflightPauseResult, PreflightFailureResult } from './preflight-result.js';
|
|
13
|
+
export type GraphExecutionErrorCode = 'ABORTED' | 'DUPLICATE_POSITION' | 'EMPTY_DECISION' | 'ENGINE_IDENTITY_UNRESOLVED' | 'INVALID_EVENT' | 'INVALID_PREFLIGHT_CONFIG' | 'MISSING_ENGINE_BINDING' | 'MISSING_MEMORY' | 'MISSING_NODE_BINDING' | 'PROTOCOL' | 'RESUME_EVENT_MISMATCH' | 'STORED_GRAPH_MISMATCH';
|
|
14
|
+
export declare class GraphExecutionError extends Error {
|
|
15
|
+
readonly code: GraphExecutionErrorCode;
|
|
16
|
+
constructor(code: GraphExecutionErrorCode, message: string, options?: ErrorOptions);
|
|
17
|
+
}
|
|
18
|
+
export interface GraphNodeBinding {
|
|
19
|
+
readonly prompt: ((input: JsonValue) => string) | null;
|
|
20
|
+
readonly scratchDirectory: string;
|
|
21
|
+
readonly workspace: NodeWorkspacePolicy;
|
|
22
|
+
readonly trustedCaller: JsonObject;
|
|
23
|
+
readonly permissions: readonly string[];
|
|
24
|
+
readonly policy: AttemptBudgetPolicy;
|
|
25
|
+
readonly resultContract: ResultContract | null;
|
|
26
|
+
readonly runData: ((context: NodeDataContext) => Promise<JsonValue>) | null;
|
|
27
|
+
readonly parseResult: ((part: AgentResultPart, parts: readonly AgentResultPart[]) => JsonValue) | null;
|
|
28
|
+
readonly tokenBudget: TokenBudget | null;
|
|
29
|
+
/** Whether node code may run again after a crash leaves its outcome unknown. */
|
|
30
|
+
readonly retrySafe?: boolean;
|
|
31
|
+
decideAction(): Promise<ActionDecision>;
|
|
32
|
+
}
|
|
33
|
+
export interface GraphEngineBinding {
|
|
34
|
+
readonly target: ExecutionTarget;
|
|
35
|
+
readonly selection: EngineSelectionRecord;
|
|
36
|
+
readonly engine: Engine;
|
|
37
|
+
readonly hardTokenLimitEnforceable: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface GraphExecutorOptions {
|
|
40
|
+
readonly runId: string;
|
|
41
|
+
readonly graph: CompiledGraphType;
|
|
42
|
+
readonly storage: RunStorageBinding;
|
|
43
|
+
readonly nodes: Readonly<Record<string, GraphNodeBinding>>;
|
|
44
|
+
readonly engines: readonly GraphEngineBinding[];
|
|
45
|
+
readonly preflightScratchDirectory?: string;
|
|
46
|
+
readonly bindings?: {
|
|
47
|
+
readonly memory?: Memory;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export type GraphExecutorResult = Extract<GraphCommand, {
|
|
51
|
+
readonly kind: 'pause' | 'complete' | 'fail';
|
|
52
|
+
}> | PreflightPauseResult | PreflightFailureResult | {
|
|
53
|
+
readonly kind: 'waiting';
|
|
54
|
+
readonly positions: readonly string[];
|
|
55
|
+
};
|
|
56
|
+
export interface GraphExecutor {
|
|
57
|
+
run(signal: AbortSignal): Promise<GraphExecutorResult>;
|
|
58
|
+
resume(target: string | {
|
|
59
|
+
readonly preflightEventId: string;
|
|
60
|
+
}, signal: AbortSignal): Promise<GraphExecutorResult>;
|
|
61
|
+
}
|