taskflow-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/analyst.md +30 -0
- package/dist/agents/critic.md +31 -0
- package/dist/agents/doc-writer.md +43 -0
- package/dist/agents/executor-code.md +36 -0
- package/dist/agents/executor-fast.md +26 -0
- package/dist/agents/executor-ui.md +35 -0
- package/dist/agents/executor.md +29 -0
- package/dist/agents/final-arbiter.md +29 -0
- package/dist/agents/plan-arbiter.md +35 -0
- package/dist/agents/planner.md +30 -0
- package/dist/agents/recover.md +28 -0
- package/dist/agents/reviewer.md +37 -0
- package/dist/agents/risk-reviewer.md +37 -0
- package/dist/agents/scout.md +51 -0
- package/dist/agents/security-reviewer.md +39 -0
- package/dist/agents/test-engineer.md +31 -0
- package/dist/agents/verifier.md +29 -0
- package/dist/agents/visual-explorer.md +32 -0
- package/dist/agents.d.ts +55 -0
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +265 -0
- package/dist/agents.js.map +1 -0
- package/dist/cache.d.ts +57 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +256 -0
- package/dist/cache.js.map +1 -0
- package/dist/compile.d.ts +37 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +324 -0
- package/dist/compile.js.map +1 -0
- package/dist/context-store.d.ts +142 -0
- package/dist/context-store.d.ts.map +1 -0
- package/dist/context-store.js +383 -0
- package/dist/context-store.js.map +1 -0
- package/dist/detached-runner.d.ts +12 -0
- package/dist/detached-runner.d.ts.map +1 -0
- package/dist/detached-runner.js +68 -0
- package/dist/detached-runner.js.map +1 -0
- package/dist/flowir/hash.d.ts +51 -0
- package/dist/flowir/hash.d.ts.map +1 -0
- package/dist/flowir/hash.js +90 -0
- package/dist/flowir/hash.js.map +1 -0
- package/dist/flowir/index.d.ts +43 -0
- package/dist/flowir/index.d.ts.map +1 -0
- package/dist/flowir/index.js +62 -0
- package/dist/flowir/index.js.map +1 -0
- package/dist/flowir/meta.d.ts +103 -0
- package/dist/flowir/meta.d.ts.map +1 -0
- package/dist/flowir/meta.js +19 -0
- package/dist/flowir/meta.js.map +1 -0
- package/dist/flowir/phasefp.d.ts +55 -0
- package/dist/flowir/phasefp.d.ts.map +1 -0
- package/dist/flowir/phasefp.js +123 -0
- package/dist/flowir/phasefp.js.map +1 -0
- package/dist/flowir/translate.d.ts +37 -0
- package/dist/flowir/translate.d.ts.map +1 -0
- package/dist/flowir/translate.js +137 -0
- package/dist/flowir/translate.js.map +1 -0
- package/dist/frontmatter.d.ts +21 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +107 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/host/runner-types.d.ts +98 -0
- package/dist/host/runner-types.d.ts.map +1 -0
- package/dist/host/runner-types.js +21 -0
- package/dist/host/runner-types.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/interpolate.d.ts +52 -0
- package/dist/interpolate.d.ts.map +1 -0
- package/dist/interpolate.js +418 -0
- package/dist/interpolate.js.map +1 -0
- package/dist/paths.d.ts +23 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +43 -0
- package/dist/paths.js.map +1 -0
- package/dist/runner-core.d.ts +49 -0
- package/dist/runner-core.d.ts.map +1 -0
- package/dist/runner-core.js +208 -0
- package/dist/runner-core.js.map +1 -0
- package/dist/runtime.d.ts +234 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +2284 -0
- package/dist/runtime.js.map +1 -0
- package/dist/schema.d.ts +257 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +795 -0
- package/dist/schema.js.map +1 -0
- package/dist/stale.d.ts +72 -0
- package/dist/stale.d.ts.map +1 -0
- package/dist/stale.js +179 -0
- package/dist/stale.js.map +1 -0
- package/dist/store.d.ts +237 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +761 -0
- package/dist/store.js.map +1 -0
- package/dist/typebox-helpers.d.ts +15 -0
- package/dist/typebox-helpers.d.ts.map +1 -0
- package/dist/typebox-helpers.js +19 -0
- package/dist/typebox-helpers.js.map +1 -0
- package/dist/usage.d.ts +21 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +33 -0
- package/dist/usage.js.map +1 -0
- package/dist/verify.d.ts +38 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +324 -0
- package/dist/verify.js.map +1 -0
- package/dist/workspace.d.ts +64 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +178 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public entry point for the FlowIR compile seam.
|
|
3
|
+
*
|
|
4
|
+
* `compileTaskflowToIR` is the read-only, content-addressed IR projection used
|
|
5
|
+
* by:
|
|
6
|
+
* - `/tf ir <flow>` / `action=ir` — render the compiled IR + hash (0 tokens)
|
|
7
|
+
* - the runtime (`runTaskflowLayers`) — fold `ir.hash` into the cache key
|
|
8
|
+
* (== `flowDefHash` in the stub; the overstory-canonical hash once the
|
|
9
|
+
* genuine compiler is vendored) and persist `ir.meta.declaredDeps` to
|
|
10
|
+
* `RunState` (M2 declared plane).
|
|
11
|
+
*
|
|
12
|
+
* The stub hash reuses the already-vendored overstory `flowDefHash` algorithm
|
|
13
|
+
* (./hash.ts) so pi-taskflow and overstory share one byte-identical hashing
|
|
14
|
+
* contract today. `usedFallbackHash` is `true` in the stub (the genuine
|
|
15
|
+
* overstory `hashIR` is not yet wired); it flips to `false` once the compiler
|
|
16
|
+
* is vendored, at which point the cache key's `v2:` prefix advances to `v3:`
|
|
17
|
+
* (see docs/internal/cache-migration.md).
|
|
18
|
+
*
|
|
19
|
+
* Pure + async (Web Crypto). Never throws — a hash failure leaves `hash`
|
|
20
|
+
* unset and `usedFallbackHash` true; the runtime degrades to the safe
|
|
21
|
+
* flowName-only cache key (cross-run disabled for that run).
|
|
22
|
+
*
|
|
23
|
+
* @see docs/internal/overstory-convergence-roadmap.md §3 (M1)
|
|
24
|
+
* @see docs/internal/rfc-flowir-compilation.md
|
|
25
|
+
*/
|
|
26
|
+
import type { Taskflow } from "../schema.ts";
|
|
27
|
+
import type { TaskflowIR } from "./meta.ts";
|
|
28
|
+
/**
|
|
29
|
+
* Compile a (desugared) `Taskflow` into its content-addressed IR.
|
|
30
|
+
*
|
|
31
|
+
* The returned `hash` is, in the stub, exactly `flowDefHash(def)` — the
|
|
32
|
+
* overstory-vendored canonical-JSON + SHA-256-truncation contract. The
|
|
33
|
+
* `usedFallbackHash` flag records that this is the *fallback* hash (non-IR-
|
|
34
|
+
* canonical): it is `true` whenever the stub cannot guarantee IR-canonicity
|
|
35
|
+
* (any phase with a `when`, or any hash-compute failure).
|
|
36
|
+
*
|
|
37
|
+
* Never throws. Returns structured diagnostics so `/tf ir` on a broken flow
|
|
38
|
+
* yields a clean error table instead of crashing.
|
|
39
|
+
*/
|
|
40
|
+
export declare function compileTaskflowToIR(def: Taskflow): Promise<TaskflowIR>;
|
|
41
|
+
export type { CompileError, CompileWarning, DeclaredDeps, FlowIR, FlowIRNode, TaskflowIR, TaskflowIRMeta, } from "./meta.ts";
|
|
42
|
+
export { phaseFingerprint } from "./phasefp.ts";
|
|
43
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/flowir/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAmB5E;AAED,YAAY,EACX,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,MAAM,EACN,UAAU,EACV,UAAU,EACV,cAAc,GACd,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public entry point for the FlowIR compile seam.
|
|
3
|
+
*
|
|
4
|
+
* `compileTaskflowToIR` is the read-only, content-addressed IR projection used
|
|
5
|
+
* by:
|
|
6
|
+
* - `/tf ir <flow>` / `action=ir` — render the compiled IR + hash (0 tokens)
|
|
7
|
+
* - the runtime (`runTaskflowLayers`) — fold `ir.hash` into the cache key
|
|
8
|
+
* (== `flowDefHash` in the stub; the overstory-canonical hash once the
|
|
9
|
+
* genuine compiler is vendored) and persist `ir.meta.declaredDeps` to
|
|
10
|
+
* `RunState` (M2 declared plane).
|
|
11
|
+
*
|
|
12
|
+
* The stub hash reuses the already-vendored overstory `flowDefHash` algorithm
|
|
13
|
+
* (./hash.ts) so pi-taskflow and overstory share one byte-identical hashing
|
|
14
|
+
* contract today. `usedFallbackHash` is `true` in the stub (the genuine
|
|
15
|
+
* overstory `hashIR` is not yet wired); it flips to `false` once the compiler
|
|
16
|
+
* is vendored, at which point the cache key's `v2:` prefix advances to `v3:`
|
|
17
|
+
* (see docs/internal/cache-migration.md).
|
|
18
|
+
*
|
|
19
|
+
* Pure + async (Web Crypto). Never throws — a hash failure leaves `hash`
|
|
20
|
+
* unset and `usedFallbackHash` true; the runtime degrades to the safe
|
|
21
|
+
* flowName-only cache key (cross-run disabled for that run).
|
|
22
|
+
*
|
|
23
|
+
* @see docs/internal/overstory-convergence-roadmap.md §3 (M1)
|
|
24
|
+
* @see docs/internal/rfc-flowir-compilation.md
|
|
25
|
+
*/
|
|
26
|
+
import { flowDefHash } from "./hash.js";
|
|
27
|
+
import { translateTaskflow } from "./translate.js";
|
|
28
|
+
/**
|
|
29
|
+
* Compile a (desugared) `Taskflow` into its content-addressed IR.
|
|
30
|
+
*
|
|
31
|
+
* The returned `hash` is, in the stub, exactly `flowDefHash(def)` — the
|
|
32
|
+
* overstory-vendored canonical-JSON + SHA-256-truncation contract. The
|
|
33
|
+
* `usedFallbackHash` flag records that this is the *fallback* hash (non-IR-
|
|
34
|
+
* canonical): it is `true` whenever the stub cannot guarantee IR-canonicity
|
|
35
|
+
* (any phase with a `when`, or any hash-compute failure).
|
|
36
|
+
*
|
|
37
|
+
* Never throws. Returns structured diagnostics so `/tf ir` on a broken flow
|
|
38
|
+
* yields a clean error table instead of crashing.
|
|
39
|
+
*/
|
|
40
|
+
export async function compileTaskflowToIR(def) {
|
|
41
|
+
const t = translateTaskflow(def);
|
|
42
|
+
let hash;
|
|
43
|
+
try {
|
|
44
|
+
hash = await flowDefHash(def);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
hash = undefined;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
ir: t.ir,
|
|
51
|
+
meta: t.meta,
|
|
52
|
+
hash,
|
|
53
|
+
warnings: t.warnings,
|
|
54
|
+
errors: t.errors,
|
|
55
|
+
// Stub: the fallback hash is used whenever (a) any phase has a `when`
|
|
56
|
+
// (translateTaskflow flags it) OR (b) the hash computation itself failed.
|
|
57
|
+
// Once the genuine overstory compiler is vendored, condition (a) drops.
|
|
58
|
+
usedFallbackHash: t.usedFallbackHash || hash === undefined,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export { phaseFingerprint } from "./phasefp.js";
|
|
62
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/flowir/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGnD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAAa;IACtD,MAAM,CAAC,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,IAAwB,CAAC;IAC7B,IAAI,CAAC;QACJ,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACR,IAAI,GAAG,SAAS,CAAC;IAClB,CAAC;IACD,OAAO;QACN,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,IAAI;QACJ,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,sEAAsE;QACtE,0EAA0E;QAC1E,wEAAwE;QACxE,gBAAgB,EAAE,CAAC,CAAC,gBAAgB,IAAI,IAAI,KAAK,SAAS;KAC1D,CAAC;AACH,CAAC;AAYD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the FlowIR compile seam.
|
|
3
|
+
*
|
|
4
|
+
* This is the **stub/projection** layer of the overstory-convergence roadmap's
|
|
5
|
+
* M1 slice: we project a pi-taskflow `Taskflow` into a `FlowIR` shape that
|
|
6
|
+
* mirrors overstory's IR contract *structurally* (nodes with `inject`/`emits`)
|
|
7
|
+
* without yet compiling to overstory's native inject/emits model. The hash
|
|
8
|
+
* contract (overstory's `hashIR` algorithm) is shared via `flowDefHash` — see
|
|
9
|
+
* `./hash.ts`. When the genuine overstory compiler is vendored later, the
|
|
10
|
+
* `usedFallbackHash` flag flips to `false` and `ir` becomes the canonical IR;
|
|
11
|
+
* until then this seam is read-only, pure, and never throws.
|
|
12
|
+
*
|
|
13
|
+
* Pure module: no IO, no Date, no randomness. Type-only where possible.
|
|
14
|
+
*
|
|
15
|
+
* @see docs/internal/overstory-convergence-roadmap.md §3 (M1)
|
|
16
|
+
* @see docs/internal/rfc-flowir-compilation.md
|
|
17
|
+
*/
|
|
18
|
+
import type { Budget, Taskflow } from "../schema.ts";
|
|
19
|
+
/**
|
|
20
|
+
* A phase's *declared* (static) dependency footprint, synthesized at compile
|
|
21
|
+
* time from `{steps.X}` interpolation refs (via `collectRefs`) plus `dependsOn`.
|
|
22
|
+
* `reads` = the upstream step ids this phase's task/when/branches/with/context
|
|
23
|
+
* statically reference; `writes` = the step id this phase emits (itself).
|
|
24
|
+
*
|
|
25
|
+
* This is the *declared* plane — distinct from the *observed* readSet captured
|
|
26
|
+
* at runtime (M3 `PhaseState.reads`). The two are reconciled by a **union**
|
|
27
|
+
* (`observed ∪ declared`) in `computeStaleFrontier` / `recomputeTaskflow` so a
|
|
28
|
+
* declared-but-unobserved edge (e.g. a `when` ref that never fired) is still
|
|
29
|
+
* treated as a dependency for staleness propagation. JSON-safe `Record` shape
|
|
30
|
+
* (not `Map`) so it round-trips through `RunState` persistence.
|
|
31
|
+
*/
|
|
32
|
+
export interface DeclaredDeps {
|
|
33
|
+
/** Upstream step ids statically referenced by this phase's interpolation. */
|
|
34
|
+
reads: string[];
|
|
35
|
+
/** Step id(s) this phase emits — currently `[phase.id]` (1:1 projection). */
|
|
36
|
+
writes: string[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A single IR node — one per pi-taskflow phase. `kind` is the native phase type
|
|
40
|
+
* (a 1:1 projection; the overstory-native kind lowering is deferred per roadmap
|
|
41
|
+
* §6.1). `inject`/`emits` mirror overstory's contract: a node *injects*
|
|
42
|
+
* (reads) the outputs of its upstream nodes and *emits* (writes) its own.
|
|
43
|
+
*/
|
|
44
|
+
export interface FlowIRNode {
|
|
45
|
+
id: string;
|
|
46
|
+
/** pi-taskflow phase type (1:1 projection; `agent`|`parallel`|`map`|…). */
|
|
47
|
+
kind: string;
|
|
48
|
+
/** Synthesized declared reads: the `{steps.X}` refs this node's task
|
|
49
|
+
* interpolates. (overstory-native `inject` lowering is deferred.) */
|
|
50
|
+
inject: string[];
|
|
51
|
+
/** What this node emits — currently `[id]` (1:1 projection). */
|
|
52
|
+
emits: string[];
|
|
53
|
+
/** Raw `when` guard passthrough (stub: not rewritten to IR conditions). */
|
|
54
|
+
when?: string;
|
|
55
|
+
}
|
|
56
|
+
/** The compiled IR: a flat list of nodes plus flow-level metadata. */
|
|
57
|
+
export interface FlowIR {
|
|
58
|
+
name: string;
|
|
59
|
+
nodes: FlowIRNode[];
|
|
60
|
+
args?: Taskflow["args"];
|
|
61
|
+
budget?: Budget;
|
|
62
|
+
concurrency?: number;
|
|
63
|
+
}
|
|
64
|
+
/** A hard compile error (none in the stub; reserved for the genuine compiler). */
|
|
65
|
+
export interface CompileError {
|
|
66
|
+
phaseId?: string;
|
|
67
|
+
code: string;
|
|
68
|
+
message: string;
|
|
69
|
+
}
|
|
70
|
+
/** A non-fatal advisory (e.g. a `{steps.X}` ref not reachable via dependsOn). */
|
|
71
|
+
export interface CompileWarning {
|
|
72
|
+
phaseId?: string;
|
|
73
|
+
message: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Compile-time metadata attached to the IR. `declaredDeps` is the M2 declared
|
|
77
|
+
* plane (per-phase `DeclaredDeps`); `sidecar` carries every pi-taskflow-specific
|
|
78
|
+
* field not represented in `FlowIRNode` so the projection is lossless and can
|
|
79
|
+
* round-trip back to a runnable `Taskflow`.
|
|
80
|
+
*/
|
|
81
|
+
export interface TaskflowIRMeta {
|
|
82
|
+
sourceFlowName: string;
|
|
83
|
+
/** Per-phase declared dependency footprint (M2). JSON-safe. */
|
|
84
|
+
declaredDeps: Record<string, DeclaredDeps>;
|
|
85
|
+
/** Pi-taskflow-specific fields preserved verbatim for round-trip. */
|
|
86
|
+
sidecar: Record<string, unknown>;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The composite compile result (RFC §5). `ir`/`hash` are present unless
|
|
90
|
+
* synthesis failed (stub never fails). `usedFallbackHash` is `true` whenever
|
|
91
|
+
* the stub cannot produce an overstory-canonical hash (always, in the stub:
|
|
92
|
+
* the hash is the `flowDefHash` fallback; flips to `false` once the genuine
|
|
93
|
+
* compiler is vendored).
|
|
94
|
+
*/
|
|
95
|
+
export interface TaskflowIR {
|
|
96
|
+
ir?: FlowIR;
|
|
97
|
+
meta: TaskflowIRMeta;
|
|
98
|
+
hash?: string;
|
|
99
|
+
warnings: CompileWarning[];
|
|
100
|
+
errors: CompileError[];
|
|
101
|
+
usedFallbackHash: boolean;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=meta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../src/flowir/meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAMrD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,YAAY;IAC5B,6EAA6E;IAC7E,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,EAAE,CAAC;CACjB;AAMD;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb;0EACsE;IACtE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,gEAAgE;IAChE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,sEAAsE;AACtE,MAAM,WAAW,MAAM;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CAChB;AAMD;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC3C,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;CAC1B"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the FlowIR compile seam.
|
|
3
|
+
*
|
|
4
|
+
* This is the **stub/projection** layer of the overstory-convergence roadmap's
|
|
5
|
+
* M1 slice: we project a pi-taskflow `Taskflow` into a `FlowIR` shape that
|
|
6
|
+
* mirrors overstory's IR contract *structurally* (nodes with `inject`/`emits`)
|
|
7
|
+
* without yet compiling to overstory's native inject/emits model. The hash
|
|
8
|
+
* contract (overstory's `hashIR` algorithm) is shared via `flowDefHash` — see
|
|
9
|
+
* `./hash.ts`. When the genuine overstory compiler is vendored later, the
|
|
10
|
+
* `usedFallbackHash` flag flips to `false` and `ir` becomes the canonical IR;
|
|
11
|
+
* until then this seam is read-only, pure, and never throws.
|
|
12
|
+
*
|
|
13
|
+
* Pure module: no IO, no Date, no randomness. Type-only where possible.
|
|
14
|
+
*
|
|
15
|
+
* @see docs/internal/overstory-convergence-roadmap.md §3 (M1)
|
|
16
|
+
* @see docs/internal/rfc-flowir-compilation.md
|
|
17
|
+
*/
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=meta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../../src/flowir/meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-phase structural sub-fingerprint (M6).
|
|
3
|
+
*
|
|
4
|
+
* `phaseFingerprint` produces a content-addressed hash of ONLY the subset of
|
|
5
|
+
* the flow definition that can affect a single phase's subagent output: the
|
|
6
|
+
* phase itself plus its transitive dependency closure. Folding this into the
|
|
7
|
+
* cross-run cache key (instead of the whole-flow `flowDefHash`) means editing
|
|
8
|
+
* phase B invalidates only B and its transitive dependents — independent
|
|
9
|
+
* sibling phase A keeps its cache hit.
|
|
10
|
+
*
|
|
11
|
+
* ## Soundness (the fallback gate)
|
|
12
|
+
*
|
|
13
|
+
* Per-phase invalidation is only sound when a phase's *real* dependencies are
|
|
14
|
+
* fully captured by the static `dependsOn ∪ from` closure. Three cases break
|
|
15
|
+
* that guarantee, so `phaseFingerprint` returns `undefined` for them and the
|
|
16
|
+
* caller falls back to the whole-flow `flowDefHash` (safe, = pre-M6 behavior):
|
|
17
|
+
*
|
|
18
|
+
* 1. **Shared Context Tree** (`def.contextSharing === true` or any closure
|
|
19
|
+
* member has `shareContext === true`): a sharing phase can read sibling
|
|
20
|
+
* blackboard writes OUTSIDE its declared deps, so the static closure
|
|
21
|
+
* under-approximates real reads.
|
|
22
|
+
* 2. **`flow` phase in the closure** (`type === "flow"`): a `flow` phase's
|
|
23
|
+
* sub-structure is resolved at runtime (inline `def`) or from a saved
|
|
24
|
+
* flow (`use`) and is not statically visible here. Editing the saved
|
|
25
|
+
* sub-flow would not move this phase's sub-fingerprint.
|
|
26
|
+
* 3. **`join: "any"` phase** (`phase.join === "any"`): validation exempts it
|
|
27
|
+
* from the `{steps.X}`-must-be-in-`dependsOn` check, so it may read
|
|
28
|
+
* phases outside its static closure. The closure under-approximates its
|
|
29
|
+
* real reads, so fall back to whole-flow invalidation.
|
|
30
|
+
*
|
|
31
|
+
* `cache`, `retry`, `concurrency`, and `final` are stripped from each phase
|
|
32
|
+
* before hashing: none of them changes the subagent's OUTPUT (they are policy,
|
|
33
|
+
* execution mechanics, or result selection). `cache`'s sub-fields
|
|
34
|
+
* (`scope`/`ttl`/`fingerprint`) reach the cache key through other paths
|
|
35
|
+
* (`cc.scope` gates the lookup, `cc.ttlMs` governs expiry, `cc.fingerprint` is
|
|
36
|
+
* in the key tail). Every other `Phase` field is hashed. `PhaseSchema` uses
|
|
37
|
+
* `additionalProperties: false`, so no surprise field can be missed.
|
|
38
|
+
*
|
|
39
|
+
* Pure + async (Web Crypto via `hashCanonical`). Reuses the vendored
|
|
40
|
+
* `canonicalJson`/`hashCanonical` (byte-identical to overstory's contract) so
|
|
41
|
+
* the sub-fingerprint shares one hashing contract with `flowDefHash`. Never
|
|
42
|
+
* throws — callers wrap in try/catch and degrade to `flowDefHash`.
|
|
43
|
+
*
|
|
44
|
+
* @see docs/internal/cache-migration.md (v3:phasefp tier)
|
|
45
|
+
*/
|
|
46
|
+
import { type Taskflow } from "../schema.ts";
|
|
47
|
+
/**
|
|
48
|
+
* Per-phase structural sub-fingerprint.
|
|
49
|
+
*
|
|
50
|
+
* @returns the hex hash, or `undefined` when per-phase soundness cannot be
|
|
51
|
+
* guaranteed (caller falls back to the whole-flow `flowDefHash`). Never
|
|
52
|
+
* throws.
|
|
53
|
+
*/
|
|
54
|
+
export declare function phaseFingerprint(def: Taskflow, phaseId: string): Promise<string | undefined>;
|
|
55
|
+
//# sourceMappingURL=phasefp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phasefp.d.ts","sourceRoot":"","sources":["../../src/flowir/phasefp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,OAAO,EAAsC,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AA0BjF;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAyClG"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-phase structural sub-fingerprint (M6).
|
|
3
|
+
*
|
|
4
|
+
* `phaseFingerprint` produces a content-addressed hash of ONLY the subset of
|
|
5
|
+
* the flow definition that can affect a single phase's subagent output: the
|
|
6
|
+
* phase itself plus its transitive dependency closure. Folding this into the
|
|
7
|
+
* cross-run cache key (instead of the whole-flow `flowDefHash`) means editing
|
|
8
|
+
* phase B invalidates only B and its transitive dependents — independent
|
|
9
|
+
* sibling phase A keeps its cache hit.
|
|
10
|
+
*
|
|
11
|
+
* ## Soundness (the fallback gate)
|
|
12
|
+
*
|
|
13
|
+
* Per-phase invalidation is only sound when a phase's *real* dependencies are
|
|
14
|
+
* fully captured by the static `dependsOn ∪ from` closure. Three cases break
|
|
15
|
+
* that guarantee, so `phaseFingerprint` returns `undefined` for them and the
|
|
16
|
+
* caller falls back to the whole-flow `flowDefHash` (safe, = pre-M6 behavior):
|
|
17
|
+
*
|
|
18
|
+
* 1. **Shared Context Tree** (`def.contextSharing === true` or any closure
|
|
19
|
+
* member has `shareContext === true`): a sharing phase can read sibling
|
|
20
|
+
* blackboard writes OUTSIDE its declared deps, so the static closure
|
|
21
|
+
* under-approximates real reads.
|
|
22
|
+
* 2. **`flow` phase in the closure** (`type === "flow"`): a `flow` phase's
|
|
23
|
+
* sub-structure is resolved at runtime (inline `def`) or from a saved
|
|
24
|
+
* flow (`use`) and is not statically visible here. Editing the saved
|
|
25
|
+
* sub-flow would not move this phase's sub-fingerprint.
|
|
26
|
+
* 3. **`join: "any"` phase** (`phase.join === "any"`): validation exempts it
|
|
27
|
+
* from the `{steps.X}`-must-be-in-`dependsOn` check, so it may read
|
|
28
|
+
* phases outside its static closure. The closure under-approximates its
|
|
29
|
+
* real reads, so fall back to whole-flow invalidation.
|
|
30
|
+
*
|
|
31
|
+
* `cache`, `retry`, `concurrency`, and `final` are stripped from each phase
|
|
32
|
+
* before hashing: none of them changes the subagent's OUTPUT (they are policy,
|
|
33
|
+
* execution mechanics, or result selection). `cache`'s sub-fields
|
|
34
|
+
* (`scope`/`ttl`/`fingerprint`) reach the cache key through other paths
|
|
35
|
+
* (`cc.scope` gates the lookup, `cc.ttlMs` governs expiry, `cc.fingerprint` is
|
|
36
|
+
* in the key tail). Every other `Phase` field is hashed. `PhaseSchema` uses
|
|
37
|
+
* `additionalProperties: false`, so no surprise field can be missed.
|
|
38
|
+
*
|
|
39
|
+
* Pure + async (Web Crypto via `hashCanonical`). Reuses the vendored
|
|
40
|
+
* `canonicalJson`/`hashCanonical` (byte-identical to overstory's contract) so
|
|
41
|
+
* the sub-fingerprint shares one hashing contract with `flowDefHash`. Never
|
|
42
|
+
* throws — callers wrap in try/catch and degrade to `flowDefHash`.
|
|
43
|
+
*
|
|
44
|
+
* @see docs/internal/cache-migration.md (v3:phasefp tier)
|
|
45
|
+
*/
|
|
46
|
+
import { transitiveDependencies } from "../schema.js";
|
|
47
|
+
import { canonicalJson, hashCanonical } from "./hash.js";
|
|
48
|
+
/** Fields stripped before hashing because they do NOT affect a phase's
|
|
49
|
+
* subagent OUTPUT, only execution mechanics or result selection — folding
|
|
50
|
+
* them in would cause false cache invalidation on a no-op config change:
|
|
51
|
+
* - `cache`: policy object; its sub-fields reach the key via
|
|
52
|
+
* `cc.scope`/`cc.ttlMs`/`cc.fingerprint`.
|
|
53
|
+
* - `retry`: retry/backoff is execution mechanics; a successful phase
|
|
54
|
+
* produces the same output regardless of how many attempts it took.
|
|
55
|
+
* - `concurrency`: fan-out parallelism; does not change any item's output.
|
|
56
|
+
* - `final`: marks which phase's output is the flow result; does not change
|
|
57
|
+
* the phase's own output. */
|
|
58
|
+
const PHASE_FP_STRIP = ["cache", "retry", "concurrency", "final"];
|
|
59
|
+
/** Clone a phase into a plain record with policy fields removed. */
|
|
60
|
+
function stripPolicy(phase) {
|
|
61
|
+
const rec = phase;
|
|
62
|
+
const out = {};
|
|
63
|
+
for (const k of Object.keys(rec)) {
|
|
64
|
+
if (PHASE_FP_STRIP.includes(k))
|
|
65
|
+
continue;
|
|
66
|
+
out[k] = rec[k];
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Per-phase structural sub-fingerprint.
|
|
72
|
+
*
|
|
73
|
+
* @returns the hex hash, or `undefined` when per-phase soundness cannot be
|
|
74
|
+
* guaranteed (caller falls back to the whole-flow `flowDefHash`). Never
|
|
75
|
+
* throws.
|
|
76
|
+
*/
|
|
77
|
+
export async function phaseFingerprint(def, phaseId) {
|
|
78
|
+
const phases = def.phases;
|
|
79
|
+
const byId = new Map(phases.map((p) => [p.id, p]));
|
|
80
|
+
const phase = byId.get(phaseId);
|
|
81
|
+
if (!phase)
|
|
82
|
+
return undefined;
|
|
83
|
+
// --- Soundness gate: fall back to whole-flow when static closure is unsafe. ---
|
|
84
|
+
// Flow-wide context sharing enables cross-sibling reads outside declared deps.
|
|
85
|
+
if (def.contextSharing === true)
|
|
86
|
+
return undefined;
|
|
87
|
+
// A `join: "any"` phase may interpolate `{steps.X.*}` refs to phases OUTSIDE
|
|
88
|
+
// its declared dependsOn (validation deliberately exempts it — schema.ts), so
|
|
89
|
+
// the static closure under-approximates its real reads. Fall back to
|
|
90
|
+
// whole-flow invalidation rather than rely on the key tail alone (which would
|
|
91
|
+
// be an undocumented coupling). Safe, = pre-M6 behavior.
|
|
92
|
+
if (phase.join === "any")
|
|
93
|
+
return undefined;
|
|
94
|
+
const closureIds = transitiveDependencies(phases, phaseId);
|
|
95
|
+
const closurePhases = [];
|
|
96
|
+
for (const id of closureIds) {
|
|
97
|
+
const p = byId.get(id);
|
|
98
|
+
if (!p)
|
|
99
|
+
continue; // unknown dep — validation reports elsewhere
|
|
100
|
+
// Per-phase sharing: this closure member can read sibling blackboard
|
|
101
|
+
// writes outside its own declared deps.
|
|
102
|
+
if (p.shareContext === true)
|
|
103
|
+
return undefined;
|
|
104
|
+
// A flow phase's sub-structure is runtime/saved-flow-resolved and not
|
|
105
|
+
// statically visible — editing it would not move the sub-fingerprint.
|
|
106
|
+
if ((p.type ?? "agent") === "flow")
|
|
107
|
+
return undefined;
|
|
108
|
+
closurePhases.push(p);
|
|
109
|
+
}
|
|
110
|
+
// The self phase's own sharing/type is part of the closure too.
|
|
111
|
+
if (phase.shareContext === true)
|
|
112
|
+
return undefined;
|
|
113
|
+
if ((phase.type ?? "agent") === "flow")
|
|
114
|
+
return undefined;
|
|
115
|
+
// --- Build the canonical payload. ---
|
|
116
|
+
// `deps` is the SORTED transitive closure (self excluded). canonicalJson
|
|
117
|
+
// sorts OBJECT keys but preserves ARRAY order, so we sort the array
|
|
118
|
+
// explicitly for determinism independent of dependency walk order.
|
|
119
|
+
const depsPayload = closurePhases.map((p) => ({ id: p.id, def: stripPolicy(p) }));
|
|
120
|
+
const payload = { self: stripPolicy(phase), deps: depsPayload };
|
|
121
|
+
return hashCanonical(canonicalJson(payload));
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=phasefp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phasefp.js","sourceRoot":"","sources":["../../src/flowir/phasefp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowIR translation — the 1:1 projection of a pi-taskflow `Taskflow` into the
|
|
3
|
+
* `FlowIR` shape.
|
|
4
|
+
*
|
|
5
|
+
* **Stub/projection** (M1): this is a *structural* mirror, NOT a compile to
|
|
6
|
+
* overstory's native inject/emits model (which expects an explicit emit
|
|
7
|
+
* declaration pi-taskflow doesn't have — see roadmap §6.1). Each phase becomes
|
|
8
|
+
* one `FlowIRNode`; `inject` is synthesized from `{steps.X}` interpolation refs
|
|
9
|
+
* (`collectRefs`), `emits` is `[phase.id]`. The overstory-native `kind` lowering
|
|
10
|
+
* is deliberately deferred.
|
|
11
|
+
*
|
|
12
|
+
* Pure, synchronous, never throws. Used by `compileTaskflowToIR` (./index.ts).
|
|
13
|
+
*
|
|
14
|
+
* @see docs/internal/overstory-convergence-roadmap.md §3 (M1)
|
|
15
|
+
*/
|
|
16
|
+
import { type Taskflow } from "../schema.ts";
|
|
17
|
+
import type { CompileError, CompileWarning, FlowIR, TaskflowIRMeta } from "./meta.ts";
|
|
18
|
+
/**
|
|
19
|
+
* Translate a desugared `Taskflow` into a 1:1 `FlowIR` projection + declared
|
|
20
|
+
* dependency metadata. Never throws: malformed input yields warnings/errors in
|
|
21
|
+
* the return value, not an exception (so `/tf ir` on a broken flow still
|
|
22
|
+
* produces a structured diagnostic rather than crashing the tool).
|
|
23
|
+
*
|
|
24
|
+
* `usedFallbackHash` is `true` unconditionally in the stub: the hash produced
|
|
25
|
+
* is `flowDefHash` (the definition fingerprint), NOT the overstory-IR-canonical
|
|
26
|
+
* hash, so callers can never mistake a stub hash for a canonical one. It flips
|
|
27
|
+
* to `false` only once the genuine overstory compiler is vendored and the hash
|
|
28
|
+
* is IR-canonical; a `when` guard remains a *future* fallback driver then.
|
|
29
|
+
*/
|
|
30
|
+
export declare function translateTaskflow(def: Taskflow): {
|
|
31
|
+
ir: FlowIR;
|
|
32
|
+
meta: TaskflowIRMeta;
|
|
33
|
+
warnings: CompileWarning[];
|
|
34
|
+
errors: CompileError[];
|
|
35
|
+
usedFallbackHash: boolean;
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=translate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../src/flowir/translate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAA2B,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,KAAK,EACX,YAAY,EACZ,cAAc,EAEd,MAAM,EAEN,cAAc,EACd,MAAM,WAAW,CAAC;AAwDnB;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,GAAG;IACjD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;CAC1B,CAgEA"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowIR translation — the 1:1 projection of a pi-taskflow `Taskflow` into the
|
|
3
|
+
* `FlowIR` shape.
|
|
4
|
+
*
|
|
5
|
+
* **Stub/projection** (M1): this is a *structural* mirror, NOT a compile to
|
|
6
|
+
* overstory's native inject/emits model (which expects an explicit emit
|
|
7
|
+
* declaration pi-taskflow doesn't have — see roadmap §6.1). Each phase becomes
|
|
8
|
+
* one `FlowIRNode`; `inject` is synthesized from `{steps.X}` interpolation refs
|
|
9
|
+
* (`collectRefs`), `emits` is `[phase.id]`. The overstory-native `kind` lowering
|
|
10
|
+
* is deliberately deferred.
|
|
11
|
+
*
|
|
12
|
+
* Pure, synchronous, never throws. Used by `compileTaskflowToIR` (./index.ts).
|
|
13
|
+
*
|
|
14
|
+
* @see docs/internal/overstory-convergence-roadmap.md §3 (M1)
|
|
15
|
+
*/
|
|
16
|
+
import { collectRefs } from "../schema.js";
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Sidecar: the pi-taskflow-specific fields not represented in FlowIRNode.
|
|
19
|
+
// Everything preserved verbatim so the projection is lossless and can
|
|
20
|
+
// round-trip back to a runnable Taskflow. Defined as a list so the sidecar
|
|
21
|
+
// never silently drops a field when the DSL grows (a new field is carried
|
|
22
|
+
// automatically through `Phase` indexing).
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
const SIDECAR_PHASE_FIELDS = [
|
|
25
|
+
"task",
|
|
26
|
+
"over",
|
|
27
|
+
"as",
|
|
28
|
+
"branches",
|
|
29
|
+
"from",
|
|
30
|
+
"use",
|
|
31
|
+
"def",
|
|
32
|
+
"with",
|
|
33
|
+
"until",
|
|
34
|
+
"maxIterations",
|
|
35
|
+
"convergence",
|
|
36
|
+
"variants",
|
|
37
|
+
"judge",
|
|
38
|
+
"judgeAgent",
|
|
39
|
+
"mode",
|
|
40
|
+
"dependsOn",
|
|
41
|
+
"join",
|
|
42
|
+
"when",
|
|
43
|
+
"retry",
|
|
44
|
+
"output",
|
|
45
|
+
"model",
|
|
46
|
+
"thinking",
|
|
47
|
+
"tools",
|
|
48
|
+
"cwd",
|
|
49
|
+
"context",
|
|
50
|
+
"contextLimit",
|
|
51
|
+
"onBlock",
|
|
52
|
+
"eval",
|
|
53
|
+
"cache",
|
|
54
|
+
"shareContext",
|
|
55
|
+
"optional",
|
|
56
|
+
"final",
|
|
57
|
+
"concurrency",
|
|
58
|
+
];
|
|
59
|
+
/** Build the per-phase sidecar record (verbatim copy of non-IR fields). */
|
|
60
|
+
function sidecarForPhase(phase) {
|
|
61
|
+
const out = {};
|
|
62
|
+
const rec = phase;
|
|
63
|
+
for (const k of SIDECAR_PHASE_FIELDS) {
|
|
64
|
+
if (k in rec && rec[k] !== undefined)
|
|
65
|
+
out[k] = rec[k];
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Translate a desugared `Taskflow` into a 1:1 `FlowIR` projection + declared
|
|
71
|
+
* dependency metadata. Never throws: malformed input yields warnings/errors in
|
|
72
|
+
* the return value, not an exception (so `/tf ir` on a broken flow still
|
|
73
|
+
* produces a structured diagnostic rather than crashing the tool).
|
|
74
|
+
*
|
|
75
|
+
* `usedFallbackHash` is `true` unconditionally in the stub: the hash produced
|
|
76
|
+
* is `flowDefHash` (the definition fingerprint), NOT the overstory-IR-canonical
|
|
77
|
+
* hash, so callers can never mistake a stub hash for a canonical one. It flips
|
|
78
|
+
* to `false` only once the genuine overstory compiler is vendored and the hash
|
|
79
|
+
* is IR-canonical; a `when` guard remains a *future* fallback driver then.
|
|
80
|
+
*/
|
|
81
|
+
export function translateTaskflow(def) {
|
|
82
|
+
const warnings = [];
|
|
83
|
+
const errors = [];
|
|
84
|
+
const declaredDeps = {};
|
|
85
|
+
const sidecarPhases = {};
|
|
86
|
+
// In the stub the hash is ALWAYS the fallback (flowDefHash — the definition
|
|
87
|
+
// fingerprint, not the overstory-IR-canonical hash). The `when` guard is a
|
|
88
|
+
// *future* driver (the genuine compiler can't lower conditions → fallback);
|
|
89
|
+
// today the stub unconditionally uses the fallback so callers can never
|
|
90
|
+
// mistake a stub hash for a canonical one. Flips to `false` only once the
|
|
91
|
+
// genuine overstory compiler is vendored and the hash is IR-canonical.
|
|
92
|
+
const usedFallbackHash = true;
|
|
93
|
+
const nodes = def.phases.map((phase) => {
|
|
94
|
+
const refs = collectRefs(phase);
|
|
95
|
+
// declared reads: the {steps.X} refs this phase statically references.
|
|
96
|
+
const reads = refs.steps.filter((id) => id !== phase.id);
|
|
97
|
+
declaredDeps[phase.id] = { reads, writes: [phase.id] };
|
|
98
|
+
// Advisory: a {steps.X} ref whose target doesn't exist (mirrors the
|
|
99
|
+
// validation check but non-fatal here — validation is the source of
|
|
100
|
+
// truth; this is a read-only diagnostic).
|
|
101
|
+
const knownIds = new Set(def.phases.map((p) => p.id));
|
|
102
|
+
for (const r of refs.steps) {
|
|
103
|
+
if (r !== phase.id && !knownIds.has(r)) {
|
|
104
|
+
warnings.push({
|
|
105
|
+
phaseId: phase.id,
|
|
106
|
+
message: `references {steps.${r}.*} but no phase '${r}' exists`,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (phase.when !== undefined) {
|
|
111
|
+
// `when` is a future fallback driver; today the stub is always fallback.
|
|
112
|
+
// (Kept as a structural marker on the node for round-trip.)
|
|
113
|
+
}
|
|
114
|
+
sidecarPhases[phase.id] = sidecarForPhase(phase);
|
|
115
|
+
return {
|
|
116
|
+
id: phase.id,
|
|
117
|
+
kind: phase.type ?? "agent",
|
|
118
|
+
inject: reads,
|
|
119
|
+
emits: [phase.id],
|
|
120
|
+
when: phase.when,
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
const ir = {
|
|
124
|
+
name: def.name,
|
|
125
|
+
nodes,
|
|
126
|
+
args: def.args,
|
|
127
|
+
budget: def.budget,
|
|
128
|
+
concurrency: def.concurrency,
|
|
129
|
+
};
|
|
130
|
+
const meta = {
|
|
131
|
+
sourceFlowName: def.name,
|
|
132
|
+
declaredDeps,
|
|
133
|
+
sidecar: { phases: sidecarPhases },
|
|
134
|
+
};
|
|
135
|
+
return { ir, meta, warnings, errors, usedFallbackHash };
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=translate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translate.js","sourceRoot":"","sources":["../../src/flowir/translate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal YAML-frontmatter parser for agent `.md` files.
|
|
3
|
+
*
|
|
4
|
+
* Vendored so taskflow-core stays dependency-free (the host SDK's
|
|
5
|
+
* `parseFrontmatter` pulls in the `yaml` package). Agent frontmatter is flat
|
|
6
|
+
* `key: value` — scalars, quoted strings, comma lists, or inline `[a, b]`
|
|
7
|
+
* sequences — which is all this parser needs to support. Anything it can't
|
|
8
|
+
* parse degrades to a string value (the caller already tolerates that).
|
|
9
|
+
*/
|
|
10
|
+
export interface Frontmatter {
|
|
11
|
+
frontmatter: Record<string, unknown>;
|
|
12
|
+
body: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Parse frontmatter from a markdown file. Returns `{ frontmatter, body }`.
|
|
16
|
+
* Lines that aren't `key: value` (e.g. block sequences) are skipped; the caller
|
|
17
|
+
* only relies on flat keys.
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseFrontmatter(content: string): Frontmatter;
|
|
20
|
+
export declare const stripFrontmatter: (content: string) => string;
|
|
21
|
+
//# sourceMappingURL=frontmatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,WAAW;IAC3B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;CACb;AAyCD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAuC7D;AAED,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,KAAG,MAAwC,CAAC"}
|