@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 +62 -0
- package/dist/cloud.d.ts +92 -0
- package/dist/cloud.d.ts.map +1 -0
- package/dist/cloud.js +2 -0
- package/dist/cloud.js.map +1 -0
- package/dist/completion.d.ts +7 -0
- package/dist/completion.d.ts.map +1 -0
- package/dist/completion.js +20 -0
- package/dist/completion.js.map +1 -0
- package/dist/context.d.ts +29 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +2 -0
- package/dist/context.js.map +1 -0
- package/dist/flow.d.ts +47 -0
- package/dist/flow.d.ts.map +1 -0
- package/dist/flow.js +148 -0
- package/dist/flow.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime.d.ts +2 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +2 -0
- package/dist/runtime.js.map +1 -0
- package/dist/step.d.ts +6 -0
- package/dist/step.d.ts.map +1 -0
- package/dist/step.js +2 -0
- package/dist/step.js.map +1 -0
- package/package.json +39 -0
- package/src/cloud.ts +76 -0
- package/src/completion.ts +24 -0
- package/src/context.ts +29 -0
- package/src/flow.ts +245 -0
- package/src/index.ts +22 -0
- package/src/runtime.ts +7 -0
- package/src/step.ts +5 -0
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.
|
package/dist/cloud.d.ts
ADDED
|
@@ -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 @@
|
|
|
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"}
|
package/dist/context.js
ADDED
|
@@ -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
|
package/dist/flow.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.js","sourceRoot":"","sources":["../src/flow.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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"}
|
package/dist/runtime.js
ADDED
|
@@ -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
package/dist/step.js.map
ADDED
|
@@ -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
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
|
+
}
|