@relayflows/sdk 2.0.44 → 2.0.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authored-flow-error.d.ts +1 -1
- package/dist/authored-flow-error.d.ts.map +1 -1
- package/dist/authored-flow-error.js.map +1 -1
- package/dist/authored-helper-effect.d.ts.map +1 -1
- package/dist/authored-helper-effect.js +9 -0
- package/dist/authored-helper-effect.js.map +1 -1
- package/dist/authored-root.d.ts.map +1 -1
- package/dist/authored-root.js +17 -0
- package/dist/authored-root.js.map +1 -1
- package/dist/cli/direct-run.d.ts.map +1 -1
- package/dist/cli/direct-run.js +7 -0
- package/dist/cli/direct-run.js.map +1 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +31 -2
- package/dist/cli/run.js.map +1 -1
- package/dist/cloud-mirror-step.d.ts.map +1 -1
- package/dist/cloud-mirror-step.js +6 -1
- package/dist/cloud-mirror-step.js.map +1 -1
- package/dist/compile.d.ts +1 -0
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +2 -1
- package/dist/compile.js.map +1 -1
- package/dist/failure-kinds.d.ts +1 -1
- package/dist/failure-kinds.d.ts.map +1 -1
- package/dist/failure-kinds.js +1 -0
- package/dist/failure-kinds.js.map +1 -1
- package/dist/flow-tool-adapters.d.ts +56 -0
- package/dist/flow-tool-adapters.d.ts.map +1 -0
- package/dist/flow-tool-adapters.js +42 -0
- package/dist/flow-tool-adapters.js.map +1 -0
- package/dist/flow-tool-client.d.ts +38 -0
- package/dist/flow-tool-client.d.ts.map +1 -0
- package/dist/flow-tool-client.js +105 -0
- package/dist/flow-tool-client.js.map +1 -0
- package/dist/flow-tool-contract.d.ts +103 -0
- package/dist/flow-tool-contract.d.ts.map +1 -0
- package/dist/flow-tool-contract.js +75 -0
- package/dist/flow-tool-contract.js.map +1 -0
- package/dist/flow-tool-definitions.d.ts +19 -0
- package/dist/flow-tool-definitions.d.ts.map +1 -0
- package/dist/flow-tool-definitions.js +12 -0
- package/dist/flow-tool-definitions.js.map +1 -0
- package/dist/flow-tool-http.d.ts +14 -0
- package/dist/flow-tool-http.d.ts.map +1 -0
- package/dist/flow-tool-http.js +175 -0
- package/dist/flow-tool-http.js.map +1 -0
- package/dist/flow-tool-kernel.d.ts +27 -0
- package/dist/flow-tool-kernel.d.ts.map +1 -0
- package/dist/flow-tool-kernel.js +310 -0
- package/dist/flow-tool-kernel.js.map +1 -0
- package/dist/flow-tool-manifest.d.ts +30 -0
- package/dist/flow-tool-manifest.d.ts.map +1 -0
- package/dist/flow-tool-manifest.js +79 -0
- package/dist/flow-tool-manifest.js.map +1 -0
- package/dist/flow-tool-schema.d.ts +15 -0
- package/dist/flow-tool-schema.d.ts.map +1 -0
- package/dist/flow-tool-schema.js +70 -0
- package/dist/flow-tool-schema.js.map +1 -0
- package/dist/flow-tool-wire.d.ts +26 -0
- package/dist/flow-tool-wire.d.ts.map +1 -0
- package/dist/flow-tool-wire.js +195 -0
- package/dist/flow-tool-wire.js.map +1 -0
- package/dist/helper-park.d.ts +14 -0
- package/dist/helper-park.d.ts.map +1 -0
- package/dist/helper-park.js +40 -0
- package/dist/helper-park.js.map +1 -0
- package/dist/helper-receipt.d.ts +11 -0
- package/dist/helper-receipt.d.ts.map +1 -0
- package/dist/helper-receipt.js +100 -0
- package/dist/helper-receipt.js.map +1 -0
- package/dist/helper-writeback.d.ts.map +1 -1
- package/dist/helper-writeback.js +7 -2
- package/dist/helper-writeback.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/journal-client.d.ts +7 -0
- package/dist/journal-client.d.ts.map +1 -1
- package/dist/journal-client.js +22 -1
- package/dist/journal-client.js.map +1 -1
- package/dist/protocol.d.ts +7 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/yaml-helper-effect.d.ts.map +1 -1
- package/dist/yaml-helper-effect.js +32 -23
- package/dist/yaml-helper-effect.js.map +1 -1
- package/package.json +2 -2
- package/src/authored-flow-error.ts +1 -0
- package/src/authored-helper-effect.ts +9 -0
- package/src/authored-root.ts +17 -0
- package/src/cli/direct-run.ts +7 -0
- package/src/cli/run.ts +30 -2
- package/src/cloud-mirror-step.ts +6 -1
- package/src/compile.ts +2 -1
- package/src/failure-kinds.ts +1 -0
- package/src/flow-tool-adapters.ts +43 -0
- package/src/flow-tool-client.ts +115 -0
- package/src/flow-tool-contract.ts +153 -0
- package/src/flow-tool-definitions.ts +27 -0
- package/src/flow-tool-http.ts +134 -0
- package/src/flow-tool-kernel.ts +319 -0
- package/src/flow-tool-manifest.ts +104 -0
- package/src/flow-tool-schema.ts +66 -0
- package/src/flow-tool-wire.ts +152 -0
- package/src/helper-park.ts +45 -0
- package/src/helper-receipt.ts +90 -0
- package/src/helper-writeback.ts +8 -3
- package/src/index.ts +21 -0
- package/src/journal-client.ts +21 -1
- package/src/protocol.ts +7 -0
- package/src/yaml-helper-effect.ts +12 -5
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { canonicalize } from './canonical.js';
|
|
2
|
+
import { sha256 } from './bundle.js';
|
|
3
|
+
import { snapshotJsonValue } from './json-value.js';
|
|
4
|
+
import { FLOW_TOOL_LIMITS, FLOW_TOOL_SCHEMA_DIALECT, flowToolSchema, compileFlowToolSchema } from './flow-tool-schema.js';
|
|
5
|
+
const FIELDS = ['name', 'description', 'flow', 'inputSchema', 'resultSchema'];
|
|
6
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/;
|
|
7
|
+
const VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
8
|
+
function record(value, fields, at) {
|
|
9
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
10
|
+
throw new TypeError(`${at}: expected an object`);
|
|
11
|
+
if (Object.keys(value).some(key => !fields.includes(key)) || fields.some(key => !Object.hasOwn(value, key))) {
|
|
12
|
+
// Unknown field names may themselves be sensitive caller data; do not echo them.
|
|
13
|
+
throw new TypeError(`${at}: missing or unknown fields`);
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
function declaration(value) {
|
|
18
|
+
const data = record(snapshotJsonValue(value, 'flow tool', FLOW_TOOL_LIMITS), FIELDS, 'flow tool');
|
|
19
|
+
if (typeof data.name !== 'string' || !/^[A-Za-z_][A-Za-z0-9_-]{0,63}$/.test(data.name)) {
|
|
20
|
+
throw new TypeError('flow tool.name: expected a portable tool name (1–64 ASCII characters)');
|
|
21
|
+
}
|
|
22
|
+
if (typeof data.description !== 'string' || !data.description.trim() || data.description.length > 4096) {
|
|
23
|
+
throw new TypeError('flow tool.description: expected 1–4096 characters of operator-authored description');
|
|
24
|
+
}
|
|
25
|
+
const flow = record(data.flow, ['name', 'version', 'digest'], 'flow tool.flow');
|
|
26
|
+
if (typeof flow.name !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(flow.name)) {
|
|
27
|
+
throw new TypeError('flow tool.flow.name: expected a safe flow name');
|
|
28
|
+
}
|
|
29
|
+
if (typeof flow.version !== 'string' || flow.version.length > 128 || !VERSION.test(flow.version)
|
|
30
|
+
|| flow.version.split('+')[0].split('-').slice(1).join('-').split('.').some(id => /^0\d+$/.test(id))) {
|
|
31
|
+
throw new TypeError('flow tool.flow.version: expected a semantic version');
|
|
32
|
+
}
|
|
33
|
+
if (typeof flow.digest !== 'string' || !DIGEST.test(flow.digest))
|
|
34
|
+
throw new TypeError('flow tool.flow.digest: expected sha256 and 64 lowercase hex digits');
|
|
35
|
+
return Object.freeze({
|
|
36
|
+
name: data.name, description: data.description,
|
|
37
|
+
flow: Object.freeze({ name: flow.name, version: flow.version, digest: flow.digest }),
|
|
38
|
+
inputSchema: flowToolSchema(data.inputSchema, 'flow tool.inputSchema'),
|
|
39
|
+
resultSchema: flowToolSchema(data.resultSchema, 'flow tool.resultSchema'),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** Explicit runtime contract; TypeScript generics are never treated as schemas. */
|
|
43
|
+
export function createFlowToolManifest(value) {
|
|
44
|
+
const content = Object.freeze({ manifestVersion: 1, schemaDialect: FLOW_TOOL_SCHEMA_DIALECT, ...declaration(value) });
|
|
45
|
+
return snapshotJsonValue({ ...content, digest: `sha256:${sha256(canonicalize(content))}` }, 'flow tool manifest', FLOW_TOOL_LIMITS);
|
|
46
|
+
}
|
|
47
|
+
/** Verify untrusted JSON and optionally bind it to a caller-trusted catalog digest. */
|
|
48
|
+
export function parseFlowToolManifest(value, expectedDigest) {
|
|
49
|
+
const data = record(snapshotJsonValue(value, 'flow tool manifest', FLOW_TOOL_LIMITS), [...FIELDS, 'manifestVersion', 'schemaDialect', 'digest'], 'flow tool manifest');
|
|
50
|
+
if (data.manifestVersion !== 1 || data.schemaDialect !== FLOW_TOOL_SCHEMA_DIALECT) {
|
|
51
|
+
throw new TypeError('flow tool manifest: unsupported manifest version or schema dialect');
|
|
52
|
+
}
|
|
53
|
+
// Identity verification must never trim, case-fold or otherwise normalize metadata.
|
|
54
|
+
const parsed = createFlowToolManifest(Object.fromEntries(FIELDS.map(key => [key, data[key]])));
|
|
55
|
+
if (data.digest !== parsed.digest || (expectedDigest !== undefined && parsed.digest !== expectedDigest)) {
|
|
56
|
+
throw new TypeError('flow tool manifest: digest mismatch');
|
|
57
|
+
}
|
|
58
|
+
return parsed;
|
|
59
|
+
}
|
|
60
|
+
export function canonicalFlowToolManifest(value) {
|
|
61
|
+
return canonicalize(parseFlowToolManifest(value));
|
|
62
|
+
}
|
|
63
|
+
function validate(value, schema, at) {
|
|
64
|
+
const snapshot = snapshotJsonValue(value, at, FLOW_TOOL_LIMITS);
|
|
65
|
+
const validator = compileFlowToolSchema(schema);
|
|
66
|
+
if (!validator(snapshot)) {
|
|
67
|
+
// Report only the keyword: instance paths can contain sensitive caller keys.
|
|
68
|
+
throw new TypeError(`${at}: schema validation failed (${validator.errors?.[0]?.keyword ?? 'invalid'})`);
|
|
69
|
+
}
|
|
70
|
+
return snapshot;
|
|
71
|
+
}
|
|
72
|
+
export function validateFlowToolInput(manifest, input) {
|
|
73
|
+
return validate(input, parseFlowToolManifest(manifest).inputSchema, 'flow tool input');
|
|
74
|
+
}
|
|
75
|
+
/** Validates structure only, not business truth or successful execution. */
|
|
76
|
+
export function validateFlowToolResult(manifest, result) {
|
|
77
|
+
return validate(result, parseFlowToolManifest(manifest).resultSchema, 'flow tool result');
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=flow-tool-manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-tool-manifest.js","sourceRoot":"","sources":["../src/flow-tool-manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const FLOW_TOOL_SCHEMA_DIALECT: "https://json-schema.org/draft/2020-12/schema";
|
|
2
|
+
export type FlowToolJson = null | boolean | number | string | readonly FlowToolJson[] | {
|
|
3
|
+
readonly [key: string]: FlowToolJson;
|
|
4
|
+
};
|
|
5
|
+
export type FlowToolObjectSchema = Readonly<Record<string, FlowToolJson>> & {
|
|
6
|
+
readonly type: 'object';
|
|
7
|
+
};
|
|
8
|
+
export declare const FLOW_TOOL_LIMITS: Readonly<{
|
|
9
|
+
maxDepth: 64;
|
|
10
|
+
maxNodes: 4096;
|
|
11
|
+
maxBytes: 262144;
|
|
12
|
+
}>;
|
|
13
|
+
export declare function compileFlowToolSchema(schema: FlowToolObjectSchema): import("ajv").ValidateFunction<unknown>;
|
|
14
|
+
export declare function flowToolSchema(value: unknown, at: string): FlowToolObjectSchema;
|
|
15
|
+
//# sourceMappingURL=flow-tool-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-tool-schema.d.ts","sourceRoot":"","sources":["../src/flow-tool-schema.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,wBAAwB,EAAG,8CAAuD,CAAC;AAChG,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,YAAY,EAAE,GACjF;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAAA;CAAE,CAAC;AAC7C,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AACxG,eAAO,MAAM,gBAAgB;;;;EAAoE,CAAC;AAqClG,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,2CAMjE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,GAAG,oBAAoB,CAY/E"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import Ajv2020 from 'ajv/dist/2020.js';
|
|
2
|
+
import { jsonSchemaBoundError } from './json-schema-bound.js';
|
|
3
|
+
import { snapshotJsonValue } from './json-value.js';
|
|
4
|
+
export const FLOW_TOOL_SCHEMA_DIALECT = 'https://json-schema.org/draft/2020-12/schema';
|
|
5
|
+
export const FLOW_TOOL_LIMITS = Object.freeze({ maxDepth: 64, maxNodes: 4096, maxBytes: 262144 });
|
|
6
|
+
// A deliberately explicit portable v1 profile, not silently ignored JSON Schema.
|
|
7
|
+
const KEYWORDS = new Set([
|
|
8
|
+
'$schema', '$defs', '$ref', 'title', 'description', 'type', 'enum', 'const',
|
|
9
|
+
'properties', 'required', 'additionalProperties', 'items', 'minItems', 'maxItems',
|
|
10
|
+
'uniqueItems', 'minLength', 'maxLength', 'minimum', 'maximum', 'exclusiveMinimum',
|
|
11
|
+
'exclusiveMaximum', 'multipleOf', 'minProperties', 'maxProperties', 'anyOf', 'oneOf', 'allOf', 'not',
|
|
12
|
+
]);
|
|
13
|
+
function inspect(schema, at) {
|
|
14
|
+
if (typeof schema === 'boolean')
|
|
15
|
+
return;
|
|
16
|
+
if (schema === null || typeof schema !== 'object' || Array.isArray(schema)) {
|
|
17
|
+
throw new TypeError(`${at}: expected a JSON Schema object or boolean`);
|
|
18
|
+
}
|
|
19
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
20
|
+
if (!KEYWORDS.has(key))
|
|
21
|
+
throw new TypeError(`${at}: unsupported v1 schema keyword ${key}`);
|
|
22
|
+
if (key === '$schema' && value !== FLOW_TOOL_SCHEMA_DIALECT) {
|
|
23
|
+
throw new TypeError(`${at}: expected JSON Schema 2020-12`);
|
|
24
|
+
}
|
|
25
|
+
if (key === '$ref' && (typeof value !== 'string' || !value.startsWith('#/'))) {
|
|
26
|
+
throw new TypeError(`${at}: only document-local JSON Pointer references are supported`);
|
|
27
|
+
}
|
|
28
|
+
if (key === 'properties' || key === '$defs') {
|
|
29
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
30
|
+
throw new TypeError(`${at}.${key}: expected an object`);
|
|
31
|
+
}
|
|
32
|
+
for (const [name, child] of Object.entries(value))
|
|
33
|
+
inspect(child, `${at}.${key}.${name}`);
|
|
34
|
+
}
|
|
35
|
+
else if (key === 'items' || key === 'additionalProperties' || key === 'not') {
|
|
36
|
+
inspect(value, `${at}.${key}`);
|
|
37
|
+
}
|
|
38
|
+
else if (key === 'anyOf' || key === 'oneOf' || key === 'allOf') {
|
|
39
|
+
if (!Array.isArray(value))
|
|
40
|
+
throw new TypeError(`${at}.${key}: expected an array`);
|
|
41
|
+
value.forEach((child, i) => inspect(child, `${at}.${key}[${i}]`));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function compileFlowToolSchema(schema) {
|
|
46
|
+
// No coercion, defaults, removal of extras, network retrieval, or ignored formats.
|
|
47
|
+
// Deliberately revalidate each supplied manifest; no unbounded global schema cache.
|
|
48
|
+
// A future admitted catalog may own a bounded compiled-validator lifecycle.
|
|
49
|
+
return new Ajv2020({ strict: true, strictRequired: true, allowUnionTypes: true, allErrors: false })
|
|
50
|
+
.compile(schema);
|
|
51
|
+
}
|
|
52
|
+
export function flowToolSchema(value, at) {
|
|
53
|
+
const snapshot = snapshotJsonValue(value, at, FLOW_TOOL_LIMITS);
|
|
54
|
+
inspect(snapshot, at);
|
|
55
|
+
if (snapshot === null || typeof snapshot !== 'object' || Array.isArray(snapshot) || snapshot.type !== 'object') {
|
|
56
|
+
throw new TypeError(`${at}: tool schemas must explicitly have type "object"`);
|
|
57
|
+
}
|
|
58
|
+
const bounded = jsonSchemaBoundError(snapshot);
|
|
59
|
+
if (bounded !== undefined)
|
|
60
|
+
throw new TypeError(`${at}: ${bounded}`);
|
|
61
|
+
const schema = snapshot;
|
|
62
|
+
try {
|
|
63
|
+
compileFlowToolSchema(schema);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
throw new TypeError(`${at}: invalid or unsupported JSON Schema`);
|
|
67
|
+
}
|
|
68
|
+
return schema;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=flow-tool-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-tool-schema.js","sourceRoot":"","sources":["../src/flow-tool-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type FlowToolDigest } from './flow-tool-manifest.js';
|
|
2
|
+
import { type FlowToolCatalogV1, type FlowToolCatalogEntryV1, type FlowToolRunV1, type FlowToolEventV1, type FlowToolEvidenceV1, type FlowToolInvokeRequestV1 } from './flow-tool-contract.js';
|
|
3
|
+
export declare const FLOW_TOOL_ENVELOPE_LIMITS: Readonly<{
|
|
4
|
+
maxDepth: 64;
|
|
5
|
+
maxNodes: number;
|
|
6
|
+
maxBytes: number;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function toolId(value: unknown): asserts value is string;
|
|
9
|
+
export declare function flowToolInputDigest(value: unknown): FlowToolDigest;
|
|
10
|
+
export declare function parseFlowToolCatalog(value: unknown): FlowToolCatalogV1;
|
|
11
|
+
export declare function parseFlowToolEntry(value: unknown): FlowToolCatalogEntryV1;
|
|
12
|
+
/** Stable discovery serialization independent of input key or catalog ordering. */
|
|
13
|
+
export declare function canonicalFlowToolCatalog(value: unknown): string;
|
|
14
|
+
/** Shared admission validation; this proves a contract binding, not authorization. */
|
|
15
|
+
export declare function parseFlowToolInvocation(value: unknown, selected: FlowToolCatalogEntryV1): FlowToolInvokeRequestV1;
|
|
16
|
+
export declare function parseFlowToolEvidence(value: unknown, flowDigest: FlowToolDigest): FlowToolEvidenceV1;
|
|
17
|
+
export declare function flowToolRunLinks(runId: string): {
|
|
18
|
+
status_url: string;
|
|
19
|
+
events_url: string;
|
|
20
|
+
evidence_url: string;
|
|
21
|
+
cancel_url: string;
|
|
22
|
+
resume_url: string;
|
|
23
|
+
};
|
|
24
|
+
export declare function parseFlowToolRun(value: unknown, selected: FlowToolCatalogEntryV1, previous?: FlowToolRunV1): FlowToolRunV1;
|
|
25
|
+
export declare function parseFlowToolEvent(value: unknown, run: FlowToolRunV1, cursor: number): FlowToolEventV1;
|
|
26
|
+
//# sourceMappingURL=flow-tool-wire.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-tool-wire.d.ts","sourceRoot":"","sources":["../src/flow-tool-wire.ts"],"names":[],"mappings":"AAIA,OAAO,EAAwE,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpI,OAAO,EAEL,KAAK,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAE,KAAK,uBAAuB,EACrJ,MAAM,yBAAyB,CAAC;AAUjC,eAAO,MAAM,yBAAyB;;;;EAIpC,CAAC;AASH,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAE9D;AAOD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAElE;AACD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,CAkBtE;AACD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,sBAAsB,CAEzE;AACD,mFAAmF;AACnF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAI/D;AACD,sFAAsF;AACtF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,sBAAsB,GAAG,uBAAuB,CAUjH;AACD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,GAAG,kBAAkB,CAYpG;AACD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM;;;;;;EAI7C;AACD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,sBAAsB,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,aAAa,CAmC1H;AACD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,CActG"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { canonicalize } from './canonical.js';
|
|
2
|
+
import { sha256 } from './bundle.js';
|
|
3
|
+
import { snapshotJsonValue } from './json-value.js';
|
|
4
|
+
import { compileFlowToolSchema, FLOW_TOOL_LIMITS } from './flow-tool-schema.js';
|
|
5
|
+
import { parseFlowToolManifest, validateFlowToolInput, validateFlowToolResult } from './flow-tool-manifest.js';
|
|
6
|
+
import { FlowToolError, FLOW_TOOL_CATALOG_SCHEMA, FLOW_TOOL_RUN_SCHEMA, FLOW_TOOL_EVIDENCE_SCHEMA, FLOW_TOOL_EVENT_SCHEMA, FLOW_TOOL_INVOKE_SCHEMA, } from './flow-tool-contract.js';
|
|
7
|
+
// Compile only our fixed protocol schemas; never cache caller-controlled schemas globally.
|
|
8
|
+
const validators = new Map([FLOW_TOOL_CATALOG_SCHEMA, FLOW_TOOL_RUN_SCHEMA, FLOW_TOOL_EVIDENCE_SCHEMA, FLOW_TOOL_EVENT_SCHEMA, FLOW_TOOL_INVOKE_SCHEMA]
|
|
9
|
+
.map(schema => [schema, compileFlowToolSchema(schema)]));
|
|
10
|
+
// FLOW_TOOL_LIMITS bounds one manifest, input, or result. A catalog holds up
|
|
11
|
+
// to 64 of those documents, and a run or invoke envelope wraps one of them.
|
|
12
|
+
// Snapshotting the envelope with the single-document budget rejects a valid
|
|
13
|
+
// catalog or a near-limit result before that document is checked on its own.
|
|
14
|
+
const CATALOG_TOOL_CAP = 64;
|
|
15
|
+
export const FLOW_TOOL_ENVELOPE_LIMITS = Object.freeze({
|
|
16
|
+
maxDepth: FLOW_TOOL_LIMITS.maxDepth,
|
|
17
|
+
maxNodes: FLOW_TOOL_LIMITS.maxNodes * CATALOG_TOOL_CAP + FLOW_TOOL_LIMITS.maxNodes,
|
|
18
|
+
maxBytes: FLOW_TOOL_LIMITS.maxBytes * CATALOG_TOOL_CAP + FLOW_TOOL_LIMITS.maxBytes,
|
|
19
|
+
});
|
|
20
|
+
const ENVELOPE_SCHEMAS = new Set([FLOW_TOOL_CATALOG_SCHEMA, FLOW_TOOL_RUN_SCHEMA, FLOW_TOOL_INVOKE_SCHEMA]);
|
|
21
|
+
function wire(value, schema) {
|
|
22
|
+
try {
|
|
23
|
+
const snapshot = snapshotJsonValue(value, 'flow tool protocol', ENVELOPE_SCHEMAS.has(schema) ? FLOW_TOOL_ENVELOPE_LIMITS : FLOW_TOOL_LIMITS);
|
|
24
|
+
if (!validators.get(schema)(snapshot))
|
|
25
|
+
throw new FlowToolError('invalid_contract');
|
|
26
|
+
return snapshot;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
throw new FlowToolError('invalid_contract');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function toolId(value) {
|
|
33
|
+
if (typeof value !== 'string' || !/^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/.test(value))
|
|
34
|
+
throw new FlowToolError('invalid_contract');
|
|
35
|
+
}
|
|
36
|
+
function digest(value) {
|
|
37
|
+
if (typeof value !== 'string' || !/^sha256:[a-f0-9]{64}$/.test(value))
|
|
38
|
+
throw new FlowToolError('invalid_contract');
|
|
39
|
+
}
|
|
40
|
+
function decimal(value) {
|
|
41
|
+
if (!/^(0|[1-9][0-9]*)(\.[0-9]+)?$/.test(value))
|
|
42
|
+
throw new FlowToolError('invalid_contract');
|
|
43
|
+
}
|
|
44
|
+
export function flowToolInputDigest(value) {
|
|
45
|
+
return `sha256:${sha256(canonicalize(snapshotJsonValue(value, 'flow tool input', FLOW_TOOL_LIMITS)))}`;
|
|
46
|
+
}
|
|
47
|
+
export function parseFlowToolCatalog(value) {
|
|
48
|
+
const catalog = wire(value, FLOW_TOOL_CATALOG_SCHEMA);
|
|
49
|
+
const names = new Set();
|
|
50
|
+
for (const entry of catalog.tools) {
|
|
51
|
+
try {
|
|
52
|
+
parseFlowToolManifest(entry.manifest);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
throw new FlowToolError('invalid_contract');
|
|
56
|
+
}
|
|
57
|
+
toolId(entry.deployment_id);
|
|
58
|
+
if (names.has(entry.manifest.name))
|
|
59
|
+
throw new FlowToolError('invalid_contract');
|
|
60
|
+
names.add(entry.manifest.name);
|
|
61
|
+
for (const name of [...entry.business_verdicts, ...entry.requires_human])
|
|
62
|
+
toolId(name);
|
|
63
|
+
// Policy labels are not enforcement. The server must also bind read_only to
|
|
64
|
+
// effective capabilities; this v1 client will not accept a write-enabled entry.
|
|
65
|
+
if (entry.effects.some(effect => !/^[a-z][a-z0-9_-]*:read$/.test(effect)))
|
|
66
|
+
throw new FlowToolError('invalid_contract');
|
|
67
|
+
if (entry.budget.max_dollars !== null) {
|
|
68
|
+
if (entry.budget.max_dollars.length > 128)
|
|
69
|
+
throw new FlowToolError('invalid_contract');
|
|
70
|
+
decimal(entry.budget.max_dollars);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return catalog;
|
|
74
|
+
}
|
|
75
|
+
export function parseFlowToolEntry(value) {
|
|
76
|
+
return parseFlowToolCatalog({ api_version: 1, tools: [value] }).tools[0];
|
|
77
|
+
}
|
|
78
|
+
/** Stable discovery serialization independent of input key or catalog ordering. */
|
|
79
|
+
export function canonicalFlowToolCatalog(value) {
|
|
80
|
+
const catalog = parseFlowToolCatalog(value);
|
|
81
|
+
return canonicalize({ api_version: 1, tools: [...catalog.tools].sort((a, b) => a.manifest.name < b.manifest.name ? -1 : a.manifest.name > b.manifest.name ? 1 : 0) });
|
|
82
|
+
}
|
|
83
|
+
/** Shared admission validation; this proves a contract binding, not authorization. */
|
|
84
|
+
export function parseFlowToolInvocation(value, selected) {
|
|
85
|
+
const entry = parseFlowToolEntry(selected);
|
|
86
|
+
const request = wire(value, FLOW_TOOL_INVOKE_SCHEMA);
|
|
87
|
+
if (request.flow !== `${entry.manifest.flow.name}@${entry.manifest.flow.digest}`
|
|
88
|
+
|| request.deployment_id !== entry.deployment_id || request.manifest_digest !== entry.manifest.digest
|
|
89
|
+
|| (request.mode === 'async' && request.wait_ms !== 0))
|
|
90
|
+
throw new FlowToolError('invalid_contract');
|
|
91
|
+
let input;
|
|
92
|
+
try {
|
|
93
|
+
input = validateFlowToolInput(entry.manifest, request.input);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
throw new FlowToolError('invalid_contract');
|
|
97
|
+
}
|
|
98
|
+
if (flowToolInputDigest(input) !== request.input_digest)
|
|
99
|
+
throw new FlowToolError('invalid_contract');
|
|
100
|
+
return request;
|
|
101
|
+
}
|
|
102
|
+
export function parseFlowToolEvidence(value, flowDigest) {
|
|
103
|
+
const evidence = wire(value, FLOW_TOOL_EVIDENCE_SCHEMA);
|
|
104
|
+
digest(evidence.journal_digest);
|
|
105
|
+
if (evidence.flow_digest !== flowDigest)
|
|
106
|
+
throw new FlowToolError('invalid_contract');
|
|
107
|
+
const refs = new Set();
|
|
108
|
+
for (const artifact of evidence.artifacts) {
|
|
109
|
+
toolId(artifact.name);
|
|
110
|
+
toolId(artifact.ref);
|
|
111
|
+
if (refs.has(artifact.ref) || !/^[a-z0-9.+-]+\/[a-z0-9.+-]+$/.test(artifact.media_type))
|
|
112
|
+
throw new FlowToolError('invalid_contract');
|
|
113
|
+
refs.add(artifact.ref);
|
|
114
|
+
}
|
|
115
|
+
evidence.redacted_transcript_refs.forEach(toolId);
|
|
116
|
+
return evidence;
|
|
117
|
+
}
|
|
118
|
+
export function flowToolRunLinks(runId) {
|
|
119
|
+
toolId(runId);
|
|
120
|
+
const path = `/api/v1/flow-runs/${runId}`;
|
|
121
|
+
return { status_url: path, events_url: `${path}/events`, evidence_url: `${path}/evidence`, cancel_url: `${path}/cancel`, resume_url: `${path}/resume` };
|
|
122
|
+
}
|
|
123
|
+
export function parseFlowToolRun(value, selected, previous) {
|
|
124
|
+
const run = wire(value, FLOW_TOOL_RUN_SCHEMA);
|
|
125
|
+
toolId(run.run_id);
|
|
126
|
+
digest(run.input_digest);
|
|
127
|
+
if (run.tool_name !== selected.manifest.name || run.deployment_id !== selected.deployment_id
|
|
128
|
+
|| run.manifest_digest !== selected.manifest.digest || run.flow_digest !== selected.manifest.flow.digest)
|
|
129
|
+
throw new FlowToolError('invalid_contract');
|
|
130
|
+
for (const [key, url] of Object.entries(flowToolRunLinks(run.run_id))) {
|
|
131
|
+
if (run[key] !== url)
|
|
132
|
+
throw new FlowToolError('invalid_contract');
|
|
133
|
+
}
|
|
134
|
+
const terminal = ['completed', 'failed', 'cancelled'].includes(run.state);
|
|
135
|
+
if (terminal !== (run.terminal !== null))
|
|
136
|
+
throw new FlowToolError('invalid_contract');
|
|
137
|
+
if (run.terminal !== null) {
|
|
138
|
+
const result = run.terminal;
|
|
139
|
+
const success = result.terminal_reason === 'success';
|
|
140
|
+
if (success !== (run.state === 'completed') || (run.state === 'cancelled') !== (result.terminal_reason === 'canceled'))
|
|
141
|
+
throw new FlowToolError('invalid_contract');
|
|
142
|
+
if (success) {
|
|
143
|
+
if (result.business_verdict === null || !selected.business_verdicts.includes(result.business_verdict) || result.result === null)
|
|
144
|
+
throw new FlowToolError('invalid_contract');
|
|
145
|
+
try {
|
|
146
|
+
validateFlowToolResult(selected.manifest, result.result);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
throw new FlowToolError('invalid_contract');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else if (result.business_verdict !== null || result.result !== null)
|
|
153
|
+
throw new FlowToolError('invalid_contract');
|
|
154
|
+
const evidence = parseFlowToolEvidence(result.evidence, run.flow_digest);
|
|
155
|
+
const refs = new Set(evidence.artifacts.map(artifact => artifact.ref));
|
|
156
|
+
const gateNames = new Set();
|
|
157
|
+
for (const gate of result.gates) {
|
|
158
|
+
toolId(gate.name);
|
|
159
|
+
toolId(gate.evidence_ref);
|
|
160
|
+
if (!refs.has(gate.evidence_ref) || gateNames.has(gate.name))
|
|
161
|
+
throw new FlowToolError('invalid_contract');
|
|
162
|
+
gateNames.add(gate.name);
|
|
163
|
+
}
|
|
164
|
+
decimal(result.spend.dollars);
|
|
165
|
+
if (selected.budget.max_dollars !== null && result.spend.dollars_unmetered)
|
|
166
|
+
throw new FlowToolError('invalid_contract');
|
|
167
|
+
}
|
|
168
|
+
if (previous !== undefined) {
|
|
169
|
+
if (run.run_id !== previous.run_id || run.input_digest !== previous.input_digest || run.sequence < previous.sequence
|
|
170
|
+
|| (run.sequence === previous.sequence && canonicalize(run) !== canonicalize(previous))
|
|
171
|
+
|| (previous.terminal !== null && canonicalize(run) !== canonicalize(previous)))
|
|
172
|
+
throw new FlowToolError('invalid_contract');
|
|
173
|
+
}
|
|
174
|
+
return run;
|
|
175
|
+
}
|
|
176
|
+
export function parseFlowToolEvent(value, run, cursor) {
|
|
177
|
+
const event = wire(value, FLOW_TOOL_EVENT_SCHEMA);
|
|
178
|
+
if (event.run_id !== run.run_id || event.flow_digest !== run.flow_digest || event.sequence <= cursor)
|
|
179
|
+
throw new FlowToolError('invalid_contract');
|
|
180
|
+
if (event.step_id !== undefined)
|
|
181
|
+
toolId(event.step_id);
|
|
182
|
+
if (event.wait_id !== undefined)
|
|
183
|
+
toolId(event.wait_id);
|
|
184
|
+
const terminal = ['completed', 'failed', 'cancelled'].includes(event.state);
|
|
185
|
+
if ((event.type === 'run.terminal') !== terminal || terminal !== (event.terminal_reason !== undefined)
|
|
186
|
+
|| (event.type === 'run.accepted' && event.state !== 'accepted')
|
|
187
|
+
|| (event.type !== 'human.required' && event.wait_id !== undefined)
|
|
188
|
+
|| (event.type === 'human.required' && (event.wait_id === undefined || event.state !== 'parked'))
|
|
189
|
+
|| (event.type === 'step.completed' && event.step_id === undefined)
|
|
190
|
+
|| (terminal && ((event.state === 'completed') !== (event.terminal_reason === 'success')
|
|
191
|
+
|| (event.state === 'cancelled') !== (event.terminal_reason === 'canceled'))))
|
|
192
|
+
throw new FlowToolError('invalid_contract');
|
|
193
|
+
return event;
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=flow-tool-wire.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-tool-wire.js","sourceRoot":"","sources":["../src/flow-tool-wire.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { JournalClient } from './journal-client.js';
|
|
2
|
+
import type { StepDispatchEvent } from './protocol.js';
|
|
3
|
+
import { HelperWritebackPending } from './helper-receipt.js';
|
|
4
|
+
export declare function helperReceiptWaitId(stepId: string, attempt: number): string;
|
|
5
|
+
/** Journal a human-wait park before the worker connection closes.
|
|
6
|
+
* Closing without this is a transport failure, and the default budget is one
|
|
7
|
+
* extra retry: two receipt timeouts then fail the accepted write.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parkHelperReceipt(client: JournalClient, dispatch: StepDispatchEvent, error: HelperWritebackPending): Promise<void>;
|
|
10
|
+
/** Resume continues the same accepted write. Answering the park redispatches
|
|
11
|
+
* the attempt; it does not submit another provider draft.
|
|
12
|
+
*/
|
|
13
|
+
export declare function releaseHelperReceiptWaits(client: JournalClient, runId: string): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=helper-park.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helper-park.d.ts","sourceRoot":"","sources":["../src/helper-park.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,iBAAiB,EAAE,KAAK,EAAE,sBAAsB,GAChF,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;GAEG;AACH,wBAAsB,yBAAyB,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBnG"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export function helperReceiptWaitId(stepId, attempt) {
|
|
2
|
+
return `helper-receipt:${stepId}:${attempt}`;
|
|
3
|
+
}
|
|
4
|
+
/** Journal a human-wait park before the worker connection closes.
|
|
5
|
+
* Closing without this is a transport failure, and the default budget is one
|
|
6
|
+
* extra retry: two receipt timeouts then fail the accepted write.
|
|
7
|
+
*/
|
|
8
|
+
export async function parkHelperReceipt(client, dispatch, error) {
|
|
9
|
+
await client.stepWait(dispatch.run_id, dispatch.step_id, dispatch.attempt, dispatch.idempotency_key, {
|
|
10
|
+
wait_id: helperReceiptWaitId(dispatch.step_id, dispatch.attempt),
|
|
11
|
+
prompt: error.message,
|
|
12
|
+
requested_of: 'relayfile-receipt',
|
|
13
|
+
options: ['resume'],
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
/** Resume continues the same accepted write. Answering the park redispatches
|
|
17
|
+
* the attempt; it does not submit another provider draft.
|
|
18
|
+
*/
|
|
19
|
+
export async function releaseHelperReceiptWaits(client, runId) {
|
|
20
|
+
const entries = [];
|
|
21
|
+
let from = 1;
|
|
22
|
+
for (;;) {
|
|
23
|
+
const page = (await client.journalRead(runId, from, 1000)).entries;
|
|
24
|
+
if (page.length === 0)
|
|
25
|
+
break;
|
|
26
|
+
entries.push(...page);
|
|
27
|
+
const last = page[page.length - 1]?.seq;
|
|
28
|
+
if (last === undefined || page.length < 1000)
|
|
29
|
+
break;
|
|
30
|
+
from = last + 1;
|
|
31
|
+
}
|
|
32
|
+
const closed = new Set(entries.filter(entry => entry.entry_type === 'wait.completed').map(entry => entry.payload?.wait_id));
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
const waitId = entry.payload?.wait_id;
|
|
35
|
+
if (entry.entry_type !== 'wait.human' || waitId === undefined || !waitId.startsWith('helper-receipt:') || closed.has(waitId))
|
|
36
|
+
continue;
|
|
37
|
+
await client.eventEmit(runId, waitId, { answer: 'resume', answeredBy: 'flows-resume' });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=helper-park.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helper-park.js","sourceRoot":"","sources":["../src/helper-park.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,mBAAmB,CAAC,MAAc,EAAE,OAAe;IACjE,OAAO,kBAAkB,MAAM,IAAI,OAAO,EAAE,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAqB,EAAE,QAA2B,EAAE,KAA6B;IAEjF,MAAM,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,eAAe,EAAE;QACnG,OAAO,EAAE,mBAAmB,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC;QAChE,MAAM,EAAE,KAAK,CAAC,OAAO;QACrB,YAAY,EAAE,mBAAmB;QACjC,OAAO,EAAE,CAAC,QAAQ,CAAC;KACpB,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,MAAqB,EAAE,KAAa;IAElF,MAAM,OAAO,GAAgB,EAAE,CAAC;IAChC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,SAAS,CAAC;QACR,MAAM,IAAI,GAAG,CAAC,MAAM,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,OAAsB,CAAC;QAClF,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM;QAC7B,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC;QACxC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI;YAAE,MAAM;QACpD,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,KAAK,gBAAgB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5H,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC;QACtC,IAAI,KAAK,CAAC,UAAU,KAAK,YAAY,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,SAAS;QACvI,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC;IAC1F,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type WritebackResult } from '@relayfile/adapter-core/vfs-client';
|
|
2
|
+
import { AuthoredFlowExecutionError } from './authored-flow-error.js';
|
|
3
|
+
export declare class HelperWritebackPending extends AuthoredFlowExecutionError {
|
|
4
|
+
readonly writeId: string;
|
|
5
|
+
readonly path: string;
|
|
6
|
+
constructor(writeId: string, path: string, runId: string);
|
|
7
|
+
}
|
|
8
|
+
export declare function helperReceiptTimeoutMs(): number;
|
|
9
|
+
/** Persist intent before mount I/O: an interrupted submission is never blindly repeated. */
|
|
10
|
+
export declare function writeHelperDraft(mount: string, provider: string, operation: string, path: string, body: Record<string, unknown>, dataDir: string, runId: string, stepId: string, signal: AbortSignal): Promise<WritebackResult>;
|
|
11
|
+
//# sourceMappingURL=helper-receipt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helper-receipt.d.ts","sourceRoot":"","sources":["../src/helper-receipt.ts"],"names":[],"mappings":"AAGA,OAAO,EAAwC,KAAK,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAEhH,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAEtE,qBAAa,sBAAuB,SAAQ,0BAA0B;IACxD,QAAQ,CAAC,OAAO,EAAE,MAAM;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAAtC,OAAO,EAAE,MAAM,EAAW,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAG3E;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAM/C;AAED,4FAA4F;AAC5F,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EACvF,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAC3F,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAqC/C"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { resolve, relative, isAbsolute } from 'node:path';
|
|
3
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
4
|
+
import { writeJsonFile } from '@relayfile/adapter-core/vfs-client';
|
|
5
|
+
import { atomicJson, receiptPath, readHelperReceipt } from './helper-storage.js';
|
|
6
|
+
import { AuthoredFlowExecutionError } from './authored-flow-error.js';
|
|
7
|
+
export class HelperWritebackPending extends AuthoredFlowExecutionError {
|
|
8
|
+
writeId;
|
|
9
|
+
path;
|
|
10
|
+
constructor(writeId, path, runId) {
|
|
11
|
+
super('helper_writeback_pending', `write ${writeId} accepted or submission interrupted; delivery receipt pending at ${path}. Resume to wait; do not re-issue the write.`, undefined, runId);
|
|
12
|
+
this.writeId = writeId;
|
|
13
|
+
this.path = path;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function helperReceiptTimeoutMs() {
|
|
17
|
+
const value = process.env.RELAYFLOW_HELPER_RECEIPT_TIMEOUT_MS;
|
|
18
|
+
if (value === undefined || value.trim() === '')
|
|
19
|
+
return 60_000;
|
|
20
|
+
const timeout = Number(value);
|
|
21
|
+
if (!Number.isSafeInteger(timeout) || timeout <= 0)
|
|
22
|
+
throw new Error('RELAYFLOW_HELPER_RECEIPT_TIMEOUT_MS must be a positive integer');
|
|
23
|
+
return timeout;
|
|
24
|
+
}
|
|
25
|
+
/** Persist intent before mount I/O: an interrupted submission is never blindly repeated. */
|
|
26
|
+
export async function writeHelperDraft(mount, provider, operation, path, body, dataDir, runId, stepId, signal) {
|
|
27
|
+
const timeout = helperReceiptTimeoutMs();
|
|
28
|
+
const writeId = `${runId}:${stepId}`;
|
|
29
|
+
const file = receiptPath(dataDir, runId, stepId) + '.pending';
|
|
30
|
+
let intent;
|
|
31
|
+
try {
|
|
32
|
+
intent = await readHelperReceipt(file);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error.code !== 'ENOENT')
|
|
36
|
+
throw error;
|
|
37
|
+
const absolutePath = resolve(mount, path.replace(/^\/+/, ''));
|
|
38
|
+
const inside = relative(mount, absolutePath);
|
|
39
|
+
if (inside === '..' || inside.startsWith('../') || isAbsolute(inside))
|
|
40
|
+
throw new Error('Helper path escapes mount root');
|
|
41
|
+
intent = { path, absolutePath, body };
|
|
42
|
+
await atomicJson(file, intent);
|
|
43
|
+
signal.throwIfAborted();
|
|
44
|
+
const submitted = await writeJsonFile({ relayfileMountRoot: mount, writebackTimeoutMs: 0 }, provider, operation, path, body);
|
|
45
|
+
if (providerReceipt(submitted.receipt, intent.body)) {
|
|
46
|
+
return { ...submitted, deliveryStatus: 'confirmed', receipt: stringReceipt(submitted.receipt) };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const deadline = Date.now() + timeout;
|
|
50
|
+
do {
|
|
51
|
+
signal.throwIfAborted();
|
|
52
|
+
let receipt;
|
|
53
|
+
try {
|
|
54
|
+
receipt = JSON.parse(await readFile(intent.absolutePath, 'utf8'));
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error.code !== 'ENOENT' && !(error instanceof SyntaxError))
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
// Identity fields only. A path, timestamp, or error object written while
|
|
61
|
+
// the adapter is still flushing is not a provider delivery.
|
|
62
|
+
if (providerReceipt(receipt, intent.body)) {
|
|
63
|
+
return { path: intent.path, absolutePath: intent.absolutePath, deliveryStatus: 'confirmed', receipt: stringReceipt(receipt) };
|
|
64
|
+
}
|
|
65
|
+
const remaining = deadline - Date.now();
|
|
66
|
+
if (remaining <= 0)
|
|
67
|
+
break;
|
|
68
|
+
await delay(Math.min(250, remaining), undefined, { signal });
|
|
69
|
+
} while (Date.now() <= deadline);
|
|
70
|
+
throw new HelperWritebackPending(writeId, intent.path, runId);
|
|
71
|
+
}
|
|
72
|
+
/** A provider id the draft did not already carry. Path and created are not delivery. */
|
|
73
|
+
function providerReceipt(receipt, draft) {
|
|
74
|
+
if (receipt === undefined || typeof receipt !== 'object' || Array.isArray(receipt))
|
|
75
|
+
return false;
|
|
76
|
+
return ['id', 'externalId', 'ts'].some(key => {
|
|
77
|
+
const value = receiptIdentity(receipt[key]);
|
|
78
|
+
return value !== undefined && value !== receiptIdentity(draft[key]);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/** GitHub mount files store comment and issue ids as JSON numbers. */
|
|
82
|
+
function receiptIdentity(value) {
|
|
83
|
+
if (typeof value === 'string') {
|
|
84
|
+
const trimmed = value.trim();
|
|
85
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
86
|
+
}
|
|
87
|
+
if (typeof value === 'number' && Number.isSafeInteger(value))
|
|
88
|
+
return String(value);
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
function stringReceipt(receipt) {
|
|
92
|
+
const next = { ...receipt };
|
|
93
|
+
for (const key of ['id', 'externalId', 'ts']) {
|
|
94
|
+
const value = receiptIdentity(receipt[key]);
|
|
95
|
+
if (value !== undefined)
|
|
96
|
+
next[key] = value;
|
|
97
|
+
}
|
|
98
|
+
return next;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=helper-receipt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helper-receipt.js","sourceRoot":"","sources":["../src/helper-receipt.ts"],"names":[],"mappings":"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"}
|