@relayflows/surface 2.0.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 ADDED
@@ -0,0 +1,62 @@
1
+ # `@relayflows/surface`
2
+
3
+ The TypeScript authoring contract described by `docs/SURFACE.md`.
4
+
5
+ The package defines flows and the context that a future journal-backed runtime
6
+ will inject. A flow handle retains an immutable header and body behind the
7
+ `@relayflows/surface/runtime` bridge used by in-repository SDK inspection; the
8
+ public handle remains the frozen `{ name }` authoring value. This package never
9
+ constructs a context, executes a body, or contacts the kernel. The SDK has an
10
+ internal test seam proving an awaited plain `f.run(...)` can cross the existing
11
+ journal protocol, but it is intentionally not exported as a runner: authored
12
+ body progress does not yet have a durable root journal or crash-safe resume.
13
+ Within that seam, a root operation must participate in the asynchronous
14
+ continuation that reaches `done()`. Direct `await` is supported, including steps
15
+ constructed before they are awaited, and so are awaited `Promise.resolve`,
16
+ `Promise.all`, `Promise.allSettled`, `Promise.any` and `Promise.race`. Ignored
17
+ operations, manual `.then` callbacks, ignored combinators, callback failures that
18
+ are caught away, and derived work still in flight when the body returns are all
19
+ refused before the terminal journal step; callback source text is never treated
20
+ as lifecycle proof.
21
+
22
+ Note that executing an authored body replaces the global `Promise.all` for the
23
+ duration of the run. The reason, the scope, and the one documented limit of the
24
+ lifecycle contract are in `docs/SURFACE.md`, "The authored operation lifecycle".
25
+
26
+ This is an in-repository foundation, not a registry-published package. The
27
+ repository's `flows run` command can execute a directly authored `.flow.ts`
28
+ with required JSON input. Durable authored-root resume remains tracked in issue
29
+ #132. Resident trigger handlers (`flow.on(...)`) are gate-2 work and are not yet
30
+ part of this package.
31
+
32
+ The repository pins Bun through `surface/bun.lock`. From a fresh checkout:
33
+
34
+ ```sh
35
+ cd surface
36
+ bun install --frozen-lockfile --ignore-scripts
37
+ bun run build
38
+ bun run test
39
+ ```
40
+
41
+ ```ts
42
+ import { flow } from "@relayflows/surface";
43
+
44
+ export default flow<{ base: string }>("release-note", {}, async (f, input) => {
45
+ await f.run(`git diff ${input.base}`);
46
+ f.done("success");
47
+ });
48
+ ```
49
+
50
+ Run it with inline JSON or the path to a JSON file:
51
+
52
+ ```sh
53
+ flows run release-note.flow.ts --input '{"base":"main"}'
54
+ flows run release-note.flow.ts --input ./release-note.input.json
55
+ ```
56
+
57
+ Direct input is limited to 1,048,576 UTF-8 bytes. Missing, invalid, or
58
+ oversized input is refused before the daemon is contacted.
59
+
60
+ Direct runs use the same journal-backed executor as other authored flows, so
61
+ branches over step output observe the value recorded by `step.completed`.
62
+ Unsupported headers, verbs, and code predicate gates fail closed.
@@ -0,0 +1,92 @@
1
+ import type { Step } from "./step.js";
2
+ import type { CompletionReason, RunCompletionReason } from "./completion.js";
3
+ export interface WorkerSummary {
4
+ workerId: string;
5
+ status: string;
6
+ lastSeenAt: string | null;
7
+ }
8
+ export interface Heartbeat extends WorkerSummary {
9
+ }
10
+ export interface EnrollmentReceipt {
11
+ /** Mount path for the token. The credential itself never enters the journal. */
12
+ tokenPath: string;
13
+ expiresAt: string;
14
+ registerCommand: string;
15
+ }
16
+ export interface ScheduleState {
17
+ id: string;
18
+ lastTriggerStatus: string | null;
19
+ lastTriggeredRunId: string | null;
20
+ lastTriggerError: string | null;
21
+ }
22
+ export interface JournalStep {
23
+ id: string;
24
+ type: "deterministic" | "llm" | "agent";
25
+ completionReason: CompletionReason | null;
26
+ }
27
+ export interface RunJournal {
28
+ runId: string;
29
+ steps: JournalStep[];
30
+ completionReason: RunCompletionReason | null;
31
+ }
32
+ /** AgentWorkforce Cloud helper contract generated from its relayfile adapter. */
33
+ export interface CloudHelper {
34
+ workers: {
35
+ mintEnrollmentToken(input: {
36
+ workspaceId: string;
37
+ name: string;
38
+ /** Principal resolved at `<mount>/principals/<as>`. */
39
+ as: string;
40
+ }): Step<EnrollmentReceipt>;
41
+ list(input: {
42
+ workspaceId: string;
43
+ as: string;
44
+ }): Step<{
45
+ online: WorkerSummary[];
46
+ all: WorkerSummary[];
47
+ }>;
48
+ heartbeat(input: {
49
+ workerId: string;
50
+ as: string;
51
+ }): Step<Heartbeat>;
52
+ awaitHeartbeat(input: {
53
+ workerId: string;
54
+ as: string;
55
+ within: string;
56
+ }): Step<Heartbeat>;
57
+ };
58
+ schedules: {
59
+ create(input: {
60
+ workspaceId: string;
61
+ workflow: string;
62
+ cron: string;
63
+ name: string;
64
+ as: string;
65
+ }): Step<{
66
+ id: string;
67
+ }>;
68
+ fire(input: {
69
+ scheduleId: string;
70
+ as: string;
71
+ }): Step<{
72
+ accepted: boolean;
73
+ }>;
74
+ get(input: {
75
+ scheduleId: string;
76
+ as: string;
77
+ }): Step<ScheduleState>;
78
+ remove(input: {
79
+ scheduleId: string;
80
+ as: string;
81
+ }): Step<{
82
+ deleted: boolean;
83
+ }>;
84
+ };
85
+ runs: {
86
+ journal(input: {
87
+ runId: string;
88
+ as: string;
89
+ }): Step<RunJournal>;
90
+ };
91
+ }
92
+ //# sourceMappingURL=cloud.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["../src/cloud.ts"],"names":[],"mappings":"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"}
package/dist/cloud.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cloud.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud.js","sourceRoot":"","sources":["../src/cloud.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ /** The closed step completion vocabulary from the journal protocol. */
2
+ export declare const COMPLETION_REASONS: readonly ["success", "verification_failed", "retries_exhausted", "lease_expired", "crashed", "timeout", "worker_error", "budget_exceeded", "canceled"];
3
+ export type CompletionReason = (typeof COMPLETION_REASONS)[number];
4
+ /** The closed run completion vocabulary from the journal protocol. */
5
+ export declare const RUN_COMPLETION_REASONS: readonly ["success", "step_failed", "canceled", "budget_exceeded"];
6
+ export type RunCompletionReason = (typeof RUN_COMPLETION_REASONS)[number];
7
+ //# sourceMappingURL=completion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,eAAO,MAAM,kBAAkB,wJAUrB,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnE,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,oEAKzB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC"}
@@ -0,0 +1,20 @@
1
+ /** The closed step completion vocabulary from the journal protocol. */
2
+ export const COMPLETION_REASONS = [
3
+ "success",
4
+ "verification_failed",
5
+ "retries_exhausted",
6
+ "lease_expired",
7
+ "crashed",
8
+ "timeout",
9
+ "worker_error",
10
+ "budget_exceeded",
11
+ "canceled",
12
+ ];
13
+ /** The closed run completion vocabulary from the journal protocol. */
14
+ export const RUN_COMPLETION_REASONS = [
15
+ "success",
16
+ "step_failed",
17
+ "canceled",
18
+ "budget_exceeded",
19
+ ];
20
+ //# sourceMappingURL=completion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.js","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,SAAS;IACT,qBAAqB;IACrB,mBAAmB;IACnB,eAAe;IACf,SAAS;IACT,SAAS;IACT,cAAc;IACd,iBAAiB;IACjB,UAAU;CACF,CAAC;AAIX,sEAAsE;AACtE,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,SAAS;IACT,aAAa;IACb,UAAU;IACV,iBAAiB;CACT,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { CloudHelper } from "./cloud.js";
2
+ import type { RunCompletionReason } from "./completion.js";
3
+ import type { Step } from "./step.js";
4
+ export interface AgentResult {
5
+ summary: string;
6
+ artifacts: string[];
7
+ }
8
+ export interface AgentOptions {
9
+ task: string;
10
+ workspace?: string;
11
+ }
12
+ /**
13
+ * The context a journal-backed runtime injects into a flow body.
14
+ *
15
+ * This package declares the authoring contract only. It cannot construct a
16
+ * context or execute a step, so all effects remain behind the journal client.
17
+ */
18
+ export interface Ctx {
19
+ run(command: string): Step<string>;
20
+ llm(strings: TemplateStringsArray, ...values: unknown[]): Step<string>;
21
+ agent(name: string, options: AgentOptions): Step<AgentResult>;
22
+ human(question: string, options: {
23
+ to: string;
24
+ }): Promise<boolean>;
25
+ dispatch<T>(flow: string, input: unknown): Promise<T>;
26
+ done(reason: RunCompletionReason): void;
27
+ cloud: CloudHelper;
28
+ }
29
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,GAAG;IAClB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,GAAG,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IACvE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;IAC9D,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnE,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACtD,IAAI,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACxC,KAAK,EAAE,WAAW,CAAC;CACpB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":""}
package/dist/flow.d.ts ADDED
@@ -0,0 +1,47 @@
1
+ import type { Ctx } from "./context.js";
2
+ /** Optional escalation header; the empty header is the common case. */
3
+ export interface FlowHeader {
4
+ identity?: string;
5
+ memory?: {
6
+ script?: boolean;
7
+ agent?: boolean;
8
+ };
9
+ budget?: string;
10
+ tools?: {
11
+ relayfile?: string[];
12
+ mcp?: string[];
13
+ };
14
+ workspace?: string;
15
+ }
16
+ export type FlowBody<Input = unknown> = (f: Ctx, input: Input) => Promise<void>;
17
+ export interface ReadonlyFlowHeader {
18
+ readonly identity?: string;
19
+ readonly memory?: Readonly<{
20
+ script?: boolean;
21
+ agent?: boolean;
22
+ }>;
23
+ readonly budget?: string;
24
+ readonly tools?: Readonly<{
25
+ relayfile?: readonly string[];
26
+ mcp?: readonly string[];
27
+ }>;
28
+ readonly workspace?: string;
29
+ }
30
+ /** Immutable definition retained for the SDK's journal-backed runtime. */
31
+ export interface AuthoredFlowDefinition<Input = unknown> {
32
+ readonly name: string;
33
+ readonly header: ReadonlyFlowHeader;
34
+ readonly body: FlowBody<Input>;
35
+ }
36
+ /** Opaque authored-flow handle. Execution stays behind the journal runtime. */
37
+ export interface FlowHandle {
38
+ readonly name: string;
39
+ }
40
+ export declare function flow<Input = unknown>(name: string, body: FlowBody<Input>): FlowHandle;
41
+ export declare function flow<Input = unknown>(name: string, header: FlowHeader, body: FlowBody<Input>): FlowHandle;
42
+ /**
43
+ * Runtime bridge used by the SDK after it imports an authored `.flow.ts`.
44
+ * The root package deliberately does not re-export this accessor.
45
+ */
46
+ export declare function getFlowDefinition<Input = unknown>(handle: FlowHandle): AuthoredFlowDefinition<Input>;
47
+ //# sourceMappingURL=flow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow.d.ts","sourceRoot":"","sources":["../src/flow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAExC,uEAAuE;AACvE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,QAAQ,CAAC,KAAK,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEhF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;QACxB,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC9B,GAAG,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;KACzB,CAAC,CAAC;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,0EAA0E;AAC1E,MAAM,WAAW,sBAAsB,CAAC,KAAK,GAAG,OAAO;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;CAChC;AAED,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAID,wBAAgB,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC;AACvF,wBAAgB,IAAI,CAAC,KAAK,GAAG,OAAO,EAClC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,GACpB,UAAU,CAAC;AAkCd;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAapG"}
package/dist/flow.js ADDED
@@ -0,0 +1,148 @@
1
+ const definitions = new WeakMap();
2
+ export function flow(name, headerOrBody, body) {
3
+ const flowBody = typeof headerOrBody === "function" ? headerOrBody : body;
4
+ const header = typeof headerOrBody === "function" ? {} : headerOrBody;
5
+ if (name.trim().length === 0) {
6
+ throw new TypeError("flow name must not be empty");
7
+ }
8
+ if (typeof flowBody !== "function") {
9
+ throw new TypeError(`flow "${name}" requires a body`);
10
+ }
11
+ assertFlowHeader(header, name);
12
+ const definition = Object.freeze({
13
+ name,
14
+ header: freezeHeader(header),
15
+ body: flowBody,
16
+ });
17
+ const handle = Object.freeze({ name });
18
+ // One map holds definitions of many input types, so it is stored at the
19
+ // default parameterisation and `getFlowDefinition<Input>` re-parameterises on
20
+ // the way out. The cast is needed because `body` puts `Input` in a parameter
21
+ // position, making the type invariant: `AuthoredFlowDefinition<Input>` is not
22
+ // assignable to `AuthoredFlowDefinition<unknown>` even though every read
23
+ // recovers the author's own type. Sound here because the handle-to-definition
24
+ // pairing is 1:1 and both sides are keyed by the same authored flow.
25
+ definitions.set(handle, definition);
26
+ return handle;
27
+ }
28
+ /**
29
+ * Runtime bridge used by the SDK after it imports an authored `.flow.ts`.
30
+ * The root package deliberately does not re-export this accessor.
31
+ */
32
+ export function getFlowDefinition(handle) {
33
+ if ((typeof handle !== "object" && typeof handle !== "function") || handle === null) {
34
+ throw new TypeError("expected an @relayflows/surface flow handle");
35
+ }
36
+ const definition = definitions.get(handle);
37
+ if (definition === undefined
38
+ || !isStoredDefinition(definition, definition.name)
39
+ || handle.name !== definition.name) {
40
+ throw new TypeError("expected an @relayflows/surface flow handle");
41
+ }
42
+ return definition;
43
+ }
44
+ function isStoredDefinition(value, handleName) {
45
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
46
+ return false;
47
+ }
48
+ const candidate = value;
49
+ return typeof handleName === "string"
50
+ && candidate.name === handleName
51
+ && typeof candidate.body === "function"
52
+ && typeof candidate.header === "object"
53
+ && candidate.header !== null
54
+ && !Array.isArray(candidate.header)
55
+ && Object.isFrozen(candidate.header)
56
+ && Object.isFrozen(value);
57
+ }
58
+ function freezeHeader(header) {
59
+ const unknownFields = Object.keys(header).filter((field) => ![
60
+ "identity",
61
+ "memory",
62
+ "budget",
63
+ "tools",
64
+ "workspace",
65
+ ].includes(field));
66
+ if (unknownFields.length > 0) {
67
+ throw new TypeError(`flow header has unknown fields: ${unknownFields.join(", ")}`);
68
+ }
69
+ const memory = header.memory === undefined
70
+ ? undefined
71
+ : Object.freeze({ ...header.memory });
72
+ const tools = header.tools === undefined
73
+ ? undefined
74
+ : Object.freeze({
75
+ ...(header.tools.relayfile === undefined
76
+ ? {}
77
+ : { relayfile: Object.freeze([...header.tools.relayfile]) }),
78
+ ...(header.tools.mcp === undefined
79
+ ? {}
80
+ : { mcp: Object.freeze([...header.tools.mcp]) }),
81
+ });
82
+ return Object.freeze({
83
+ ...(header.identity === undefined ? {} : { identity: header.identity }),
84
+ ...(memory === undefined ? {} : { memory }),
85
+ ...(header.budget === undefined ? {} : { budget: header.budget }),
86
+ ...(tools === undefined ? {} : { tools }),
87
+ ...(header.workspace === undefined ? {} : { workspace: header.workspace }),
88
+ });
89
+ }
90
+ function assertFlowHeader(value, flowName) {
91
+ const at = `unsupported_header: flow "${flowName}" header`;
92
+ assertHeaderObject(value, at);
93
+ assertKnownKeys(value, ["identity", "memory", "budget", "tools", "workspace"], at);
94
+ assertOptionalString(value, "identity", at);
95
+ assertOptionalString(value, "budget", at);
96
+ assertOptionalString(value, "workspace", at);
97
+ if (value.memory !== undefined) {
98
+ assertHeaderObject(value.memory, `${at}.memory`);
99
+ assertKnownKeys(value.memory, ["script", "agent"], `${at}.memory`);
100
+ assertOptionalBoolean(value.memory, "script", `${at}.memory`);
101
+ assertOptionalBoolean(value.memory, "agent", `${at}.memory`);
102
+ }
103
+ if (value.tools !== undefined) {
104
+ assertHeaderObject(value.tools, `${at}.tools`);
105
+ assertKnownKeys(value.tools, ["relayfile", "mcp"], `${at}.tools`);
106
+ assertOptionalStringArray(value.tools, "relayfile", `${at}.tools`);
107
+ assertOptionalStringArray(value.tools, "mcp", `${at}.tools`);
108
+ }
109
+ }
110
+ function assertHeaderObject(value, at) {
111
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
112
+ throw new TypeError(`${at}: expected an object`);
113
+ }
114
+ const prototype = Object.getPrototypeOf(value);
115
+ if (prototype !== Object.prototype && prototype !== null) {
116
+ throw new TypeError(`${at}: expected a plain object`);
117
+ }
118
+ }
119
+ function assertKnownKeys(value, allowed, at) {
120
+ const allowedKeys = new Set(allowed);
121
+ for (const key of Reflect.ownKeys(value)) {
122
+ if (!allowedKeys.has(key)) {
123
+ throw new TypeError(`${at}: unknown field ${JSON.stringify(String(key))}`);
124
+ }
125
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
126
+ if (descriptor === undefined || !('value' in descriptor)) {
127
+ throw new TypeError(`${at}.${String(key)}: expected a data property`);
128
+ }
129
+ }
130
+ }
131
+ function assertOptionalString(value, key, at) {
132
+ if (value[key] !== undefined && typeof value[key] !== "string") {
133
+ throw new TypeError(`${at}.${key}: expected a string`);
134
+ }
135
+ }
136
+ function assertOptionalBoolean(value, key, at) {
137
+ if (value[key] !== undefined && typeof value[key] !== "boolean") {
138
+ throw new TypeError(`${at}.${key}: expected a boolean`);
139
+ }
140
+ }
141
+ function assertOptionalStringArray(value, key, at) {
142
+ const candidate = value[key];
143
+ if (candidate !== undefined
144
+ && (!Array.isArray(candidate) || candidate.some((item) => typeof item !== "string"))) {
145
+ throw new TypeError(`${at}.${key}: expected an array of strings`);
146
+ }
147
+ }
148
+ //# sourceMappingURL=flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow.js","sourceRoot":"","sources":["../src/flow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export type { EnrollmentReceipt, Heartbeat, JournalStep, RunJournal, ScheduleState, WorkerSummary, CloudHelper, } from "./cloud.js";
2
+ export type { AgentOptions, AgentResult, Ctx } from "./context.js";
3
+ export { COMPLETION_REASONS, RUN_COMPLETION_REASONS, type CompletionReason, type RunCompletionReason, } from "./completion.js";
4
+ export type { Step } from "./step.js";
5
+ export { flow, type FlowHandle, type FlowHeader, } from "./flow.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,UAAU,EACV,aAAa,EACb,aAAa,EACb,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,IAAI,EACJ,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { COMPLETION_REASONS, RUN_COMPLETION_REASONS, } from "./completion.js";
2
+ export { flow, } from "./flow.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,kBAAkB,EAClB,sBAAsB,GAGvB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,IAAI,GAGL,MAAM,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { getFlowDefinition, type AuthoredFlowDefinition, type FlowBody, type FlowHandle, type ReadonlyFlowHeader, } from "./flow.js";
2
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,kBAAkB,GACxB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { getFlowDefinition, } from "./flow.js";
2
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,GAKlB,MAAM,WAAW,CAAC"}
package/dist/step.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /** A journal-backed step result with its postfix verification gate. */
2
+ export interface Step<T> extends PromiseLike<T> {
3
+ /** Fail the step with `verification_failed` when the predicate is false. */
4
+ gate(predicate: (value: T) => boolean, because?: string): Step<T>;
5
+ }
6
+ //# sourceMappingURL=step.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../src/step.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,MAAM,WAAW,IAAI,CAAC,CAAC,CAAE,SAAQ,WAAW,CAAC,CAAC,CAAC;IAC7C,4EAA4E;IAC5E,IAAI,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;CACnE"}
package/dist/step.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=step.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step.js","sourceRoot":"","sources":["../src/step.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@relayflows/surface",
3
+ "version": "2.0.0",
4
+ "description": "TypeScript authoring surface for Relayflows.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./runtime": {
14
+ "types": "./dist/runtime.d.ts",
15
+ "import": "./dist/runtime.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "src"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "prepare": "bun run build",
25
+ "typecheck": "tsc --noEmit",
26
+ "typecheck:regressions": "tsc -p ../../regressions/tsconfig.json",
27
+ "test": "bun run build && tsc -p tsconfig.test.json && vitest run"
28
+ },
29
+ "license": "Apache-2.0",
30
+ "devDependencies": {
31
+ "typescript": "^5.6.0",
32
+ "vitest": "^2.1.0"
33
+ },
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/AgentWorkforce/flows.git",
37
+ "directory": "packages/surface"
38
+ }
39
+ }
package/src/cloud.ts ADDED
@@ -0,0 +1,76 @@
1
+ import type { Step } from "./step.js";
2
+ import type {
3
+ CompletionReason,
4
+ RunCompletionReason,
5
+ } from "./completion.js";
6
+
7
+ export interface WorkerSummary {
8
+ workerId: string;
9
+ status: string;
10
+ lastSeenAt: string | null;
11
+ }
12
+
13
+ export interface Heartbeat extends WorkerSummary {}
14
+
15
+ export interface EnrollmentReceipt {
16
+ /** Mount path for the token. The credential itself never enters the journal. */
17
+ tokenPath: string;
18
+ expiresAt: string;
19
+ registerCommand: string;
20
+ }
21
+
22
+ export interface ScheduleState {
23
+ id: string;
24
+ lastTriggerStatus: string | null;
25
+ lastTriggeredRunId: string | null;
26
+ lastTriggerError: string | null;
27
+ }
28
+
29
+ export interface JournalStep {
30
+ id: string;
31
+ type: "deterministic" | "llm" | "agent";
32
+ completionReason: CompletionReason | null;
33
+ }
34
+
35
+ export interface RunJournal {
36
+ runId: string;
37
+ steps: JournalStep[];
38
+ completionReason: RunCompletionReason | null;
39
+ }
40
+
41
+ /** AgentWorkforce Cloud helper contract generated from its relayfile adapter. */
42
+ export interface CloudHelper {
43
+ workers: {
44
+ mintEnrollmentToken(input: {
45
+ workspaceId: string;
46
+ name: string;
47
+ /** Principal resolved at `<mount>/principals/<as>`. */
48
+ as: string;
49
+ }): Step<EnrollmentReceipt>;
50
+ list(input: { workspaceId: string; as: string }): Step<{
51
+ online: WorkerSummary[];
52
+ all: WorkerSummary[];
53
+ }>;
54
+ heartbeat(input: { workerId: string; as: string }): Step<Heartbeat>;
55
+ awaitHeartbeat(input: {
56
+ workerId: string;
57
+ as: string;
58
+ within: string;
59
+ }): Step<Heartbeat>;
60
+ };
61
+ schedules: {
62
+ create(input: {
63
+ workspaceId: string;
64
+ workflow: string;
65
+ cron: string;
66
+ name: string;
67
+ as: string;
68
+ }): Step<{ id: string }>;
69
+ fire(input: { scheduleId: string; as: string }): Step<{ accepted: boolean }>;
70
+ get(input: { scheduleId: string; as: string }): Step<ScheduleState>;
71
+ remove(input: { scheduleId: string; as: string }): Step<{ deleted: boolean }>;
72
+ };
73
+ runs: {
74
+ journal(input: { runId: string; as: string }): Step<RunJournal>;
75
+ };
76
+ }
@@ -0,0 +1,24 @@
1
+ /** The closed step completion vocabulary from the journal protocol. */
2
+ export const COMPLETION_REASONS = [
3
+ "success",
4
+ "verification_failed",
5
+ "retries_exhausted",
6
+ "lease_expired",
7
+ "crashed",
8
+ "timeout",
9
+ "worker_error",
10
+ "budget_exceeded",
11
+ "canceled",
12
+ ] as const;
13
+
14
+ export type CompletionReason = (typeof COMPLETION_REASONS)[number];
15
+
16
+ /** The closed run completion vocabulary from the journal protocol. */
17
+ export const RUN_COMPLETION_REASONS = [
18
+ "success",
19
+ "step_failed",
20
+ "canceled",
21
+ "budget_exceeded",
22
+ ] as const;
23
+
24
+ export type RunCompletionReason = (typeof RUN_COMPLETION_REASONS)[number];
package/src/context.ts ADDED
@@ -0,0 +1,29 @@
1
+ import type { CloudHelper } from "./cloud.js";
2
+ import type { RunCompletionReason } from "./completion.js";
3
+ import type { Step } from "./step.js";
4
+
5
+ export interface AgentResult {
6
+ summary: string;
7
+ artifacts: string[];
8
+ }
9
+
10
+ export interface AgentOptions {
11
+ task: string;
12
+ workspace?: string;
13
+ }
14
+
15
+ /**
16
+ * The context a journal-backed runtime injects into a flow body.
17
+ *
18
+ * This package declares the authoring contract only. It cannot construct a
19
+ * context or execute a step, so all effects remain behind the journal client.
20
+ */
21
+ export interface Ctx {
22
+ run(command: string): Step<string>;
23
+ llm(strings: TemplateStringsArray, ...values: unknown[]): Step<string>;
24
+ agent(name: string, options: AgentOptions): Step<AgentResult>;
25
+ human(question: string, options: { to: string }): Promise<boolean>;
26
+ dispatch<T>(flow: string, input: unknown): Promise<T>;
27
+ done(reason: RunCompletionReason): void;
28
+ cloud: CloudHelper;
29
+ }
package/src/flow.ts ADDED
@@ -0,0 +1,245 @@
1
+ import type { Ctx } from "./context.js";
2
+
3
+ /** Optional escalation header; the empty header is the common case. */
4
+ export interface FlowHeader {
5
+ identity?: string;
6
+ memory?: { script?: boolean; agent?: boolean };
7
+ budget?: string;
8
+ tools?: { relayfile?: string[]; mcp?: string[] };
9
+ workspace?: string;
10
+ }
11
+
12
+ export type FlowBody<Input = unknown> = (f: Ctx, input: Input) => Promise<void>;
13
+
14
+ export interface ReadonlyFlowHeader {
15
+ readonly identity?: string;
16
+ readonly memory?: Readonly<{ script?: boolean; agent?: boolean }>;
17
+ readonly budget?: string;
18
+ readonly tools?: Readonly<{
19
+ relayfile?: readonly string[];
20
+ mcp?: readonly string[];
21
+ }>;
22
+ readonly workspace?: string;
23
+ }
24
+
25
+ /** Immutable definition retained for the SDK's journal-backed runtime. */
26
+ export interface AuthoredFlowDefinition<Input = unknown> {
27
+ readonly name: string;
28
+ readonly header: ReadonlyFlowHeader;
29
+ readonly body: FlowBody<Input>;
30
+ }
31
+
32
+ /** Opaque authored-flow handle. Execution stays behind the journal runtime. */
33
+ export interface FlowHandle {
34
+ readonly name: string;
35
+ }
36
+
37
+ const definitions = new WeakMap<object, AuthoredFlowDefinition>();
38
+
39
+ export function flow<Input = unknown>(name: string, body: FlowBody<Input>): FlowHandle;
40
+ export function flow<Input = unknown>(
41
+ name: string,
42
+ header: FlowHeader,
43
+ body: FlowBody<Input>,
44
+ ): FlowHandle;
45
+ export function flow<Input = unknown>(
46
+ name: string,
47
+ headerOrBody: FlowHeader | FlowBody<Input>,
48
+ body?: FlowBody<Input>,
49
+ ): FlowHandle {
50
+ const flowBody = typeof headerOrBody === "function" ? headerOrBody : body;
51
+ const header = typeof headerOrBody === "function" ? {} : headerOrBody;
52
+
53
+ if (name.trim().length === 0) {
54
+ throw new TypeError("flow name must not be empty");
55
+ }
56
+ if (typeof flowBody !== "function") {
57
+ throw new TypeError(`flow "${name}" requires a body`);
58
+ }
59
+ assertFlowHeader(header, name);
60
+
61
+ const definition: AuthoredFlowDefinition<Input> = Object.freeze({
62
+ name,
63
+ header: freezeHeader(header),
64
+ body: flowBody,
65
+ });
66
+ const handle: FlowHandle = Object.freeze({ name });
67
+ // One map holds definitions of many input types, so it is stored at the
68
+ // default parameterisation and `getFlowDefinition<Input>` re-parameterises on
69
+ // the way out. The cast is needed because `body` puts `Input` in a parameter
70
+ // position, making the type invariant: `AuthoredFlowDefinition<Input>` is not
71
+ // assignable to `AuthoredFlowDefinition<unknown>` even though every read
72
+ // recovers the author's own type. Sound here because the handle-to-definition
73
+ // pairing is 1:1 and both sides are keyed by the same authored flow.
74
+ definitions.set(handle, definition as AuthoredFlowDefinition);
75
+ return handle;
76
+ }
77
+
78
+ /**
79
+ * Runtime bridge used by the SDK after it imports an authored `.flow.ts`.
80
+ * The root package deliberately does not re-export this accessor.
81
+ */
82
+ export function getFlowDefinition<Input = unknown>(handle: FlowHandle): AuthoredFlowDefinition<Input> {
83
+ if ((typeof handle !== "object" && typeof handle !== "function") || handle === null) {
84
+ throw new TypeError("expected an @relayflows/surface flow handle");
85
+ }
86
+ const definition = definitions.get(handle);
87
+ if (
88
+ definition === undefined
89
+ || !isStoredDefinition(definition, definition.name)
90
+ || handle.name !== definition.name
91
+ ) {
92
+ throw new TypeError("expected an @relayflows/surface flow handle");
93
+ }
94
+ return definition;
95
+ }
96
+
97
+ function isStoredDefinition(
98
+ value: unknown,
99
+ handleName: unknown,
100
+ ): value is AuthoredFlowDefinition {
101
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
102
+ return false;
103
+ }
104
+ const candidate = value as Partial<AuthoredFlowDefinition>;
105
+ return typeof handleName === "string"
106
+ && candidate.name === handleName
107
+ && typeof candidate.body === "function"
108
+ && typeof candidate.header === "object"
109
+ && candidate.header !== null
110
+ && !Array.isArray(candidate.header)
111
+ && Object.isFrozen(candidate.header)
112
+ && Object.isFrozen(value);
113
+ }
114
+
115
+ function freezeHeader(header: FlowHeader): ReadonlyFlowHeader {
116
+ const unknownFields = Object.keys(header).filter((field) => ![
117
+ "identity",
118
+ "memory",
119
+ "budget",
120
+ "tools",
121
+ "workspace",
122
+ ].includes(field));
123
+ if (unknownFields.length > 0) {
124
+ throw new TypeError(`flow header has unknown fields: ${unknownFields.join(", ")}`);
125
+ }
126
+ const memory = header.memory === undefined
127
+ ? undefined
128
+ : Object.freeze({ ...header.memory });
129
+ const tools = header.tools === undefined
130
+ ? undefined
131
+ : Object.freeze({
132
+ ...(header.tools.relayfile === undefined
133
+ ? {}
134
+ : { relayfile: Object.freeze([...header.tools.relayfile]) }),
135
+ ...(header.tools.mcp === undefined
136
+ ? {}
137
+ : { mcp: Object.freeze([...header.tools.mcp]) }),
138
+ });
139
+ return Object.freeze({
140
+ ...(header.identity === undefined ? {} : { identity: header.identity }),
141
+ ...(memory === undefined ? {} : { memory }),
142
+ ...(header.budget === undefined ? {} : { budget: header.budget }),
143
+ ...(tools === undefined ? {} : { tools }),
144
+ ...(header.workspace === undefined ? {} : { workspace: header.workspace }),
145
+ });
146
+ }
147
+
148
+ function assertFlowHeader(value: unknown, flowName: string): asserts value is FlowHeader {
149
+ const at = `unsupported_header: flow "${flowName}" header`;
150
+ assertHeaderObject(value, at);
151
+ assertKnownKeys(
152
+ value,
153
+ ["identity", "memory", "budget", "tools", "workspace"],
154
+ at,
155
+ );
156
+ assertOptionalString(value, "identity", at);
157
+ assertOptionalString(value, "budget", at);
158
+ assertOptionalString(value, "workspace", at);
159
+
160
+ if (value.memory !== undefined) {
161
+ assertHeaderObject(value.memory, `${at}.memory`);
162
+ assertKnownKeys(
163
+ value.memory,
164
+ ["script", "agent"],
165
+ `${at}.memory`,
166
+ );
167
+ assertOptionalBoolean(value.memory, "script", `${at}.memory`);
168
+ assertOptionalBoolean(value.memory, "agent", `${at}.memory`);
169
+ }
170
+
171
+ if (value.tools !== undefined) {
172
+ assertHeaderObject(value.tools, `${at}.tools`);
173
+ assertKnownKeys(
174
+ value.tools,
175
+ ["relayfile", "mcp"],
176
+ `${at}.tools`,
177
+ );
178
+ assertOptionalStringArray(value.tools, "relayfile", `${at}.tools`);
179
+ assertOptionalStringArray(value.tools, "mcp", `${at}.tools`);
180
+ }
181
+ }
182
+
183
+ function assertHeaderObject(
184
+ value: unknown,
185
+ at: string,
186
+ ): asserts value is Record<string, unknown> {
187
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
188
+ throw new TypeError(`${at}: expected an object`);
189
+ }
190
+ const prototype = Object.getPrototypeOf(value);
191
+ if (prototype !== Object.prototype && prototype !== null) {
192
+ throw new TypeError(`${at}: expected a plain object`);
193
+ }
194
+ }
195
+
196
+ function assertKnownKeys(
197
+ value: Record<string, unknown>,
198
+ allowed: readonly string[],
199
+ at: string,
200
+ ): void {
201
+ const allowedKeys = new Set<PropertyKey>(allowed);
202
+ for (const key of Reflect.ownKeys(value)) {
203
+ if (!allowedKeys.has(key)) {
204
+ throw new TypeError(`${at}: unknown field ${JSON.stringify(String(key))}`);
205
+ }
206
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
207
+ if (descriptor === undefined || !('value' in descriptor)) {
208
+ throw new TypeError(`${at}.${String(key)}: expected a data property`);
209
+ }
210
+ }
211
+ }
212
+
213
+ function assertOptionalString(
214
+ value: Record<string, unknown>,
215
+ key: string,
216
+ at: string,
217
+ ): void {
218
+ if (value[key] !== undefined && typeof value[key] !== "string") {
219
+ throw new TypeError(`${at}.${key}: expected a string`);
220
+ }
221
+ }
222
+
223
+ function assertOptionalBoolean(
224
+ value: Record<string, unknown>,
225
+ key: string,
226
+ at: string,
227
+ ): void {
228
+ if (value[key] !== undefined && typeof value[key] !== "boolean") {
229
+ throw new TypeError(`${at}.${key}: expected a boolean`);
230
+ }
231
+ }
232
+
233
+ function assertOptionalStringArray(
234
+ value: Record<string, unknown>,
235
+ key: string,
236
+ at: string,
237
+ ): void {
238
+ const candidate = value[key];
239
+ if (
240
+ candidate !== undefined
241
+ && (!Array.isArray(candidate) || candidate.some((item) => typeof item !== "string"))
242
+ ) {
243
+ throw new TypeError(`${at}.${key}: expected an array of strings`);
244
+ }
245
+ }
package/src/index.ts ADDED
@@ -0,0 +1,22 @@
1
+ export type {
2
+ EnrollmentReceipt,
3
+ Heartbeat,
4
+ JournalStep,
5
+ RunJournal,
6
+ ScheduleState,
7
+ WorkerSummary,
8
+ CloudHelper,
9
+ } from "./cloud.js";
10
+ export type { AgentOptions, AgentResult, Ctx } from "./context.js";
11
+ export {
12
+ COMPLETION_REASONS,
13
+ RUN_COMPLETION_REASONS,
14
+ type CompletionReason,
15
+ type RunCompletionReason,
16
+ } from "./completion.js";
17
+ export type { Step } from "./step.js";
18
+ export {
19
+ flow,
20
+ type FlowHandle,
21
+ type FlowHeader,
22
+ } from "./flow.js";
package/src/runtime.ts ADDED
@@ -0,0 +1,7 @@
1
+ export {
2
+ getFlowDefinition,
3
+ type AuthoredFlowDefinition,
4
+ type FlowBody,
5
+ type FlowHandle,
6
+ type ReadonlyFlowHeader,
7
+ } from "./flow.js";
package/src/step.ts ADDED
@@ -0,0 +1,5 @@
1
+ /** A journal-backed step result with its postfix verification gate. */
2
+ export interface Step<T> extends PromiseLike<T> {
3
+ /** Fail the step with `verification_failed` when the predicate is false. */
4
+ gate(predicate: (value: T) => boolean, because?: string): Step<T>;
5
+ }