@studio-foundation/contracts 0.3.0-beta.6 → 0.5.2

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 CHANGED
@@ -1,18 +1,56 @@
1
1
  # @studio-foundation/contracts
2
2
 
3
- Shared TypeScript types and interfaces for the Studio monorepo. Zero dependencies, zero logic.
3
+ **Studio** is a declarative YAML runtime for AI agents. It orchestrates multi-stage agent workflows with structured output validation and automatic retry. This package is **contracts**: the shared TypeScript types and interfaces that every other Studio package imports. Zero dependencies, zero logic.
4
4
 
5
- ## Role
5
+ `contracts` is the leaf of the dependency graph. It defines the language all Studio packages speak: `PipelineDefinition`, `StageRun`, `OutputContract`, `AgentConfig`, `LLMRequest`, and the rest. Install it if you're writing tooling that reads or produces Studio configs, or if you're embedding Studio packages into your own code and need the types.
6
6
 
7
- `contracts` is the leaf package — every other Studio package imports from it, nothing imports it back. It defines the language that all packages speak.
7
+ - Homepage: https://github.com/studio-foundation/studio
8
+ - Full docs: [README](https://github.com/studio-foundation/studio#readme) · [INVARIANTS](https://github.com/studio-foundation/studio/blob/main/INVARIANTS.md)
9
+ - Use via the CLI: [`@studio-foundation/cli`](https://www.npmjs.com/package/@studio-foundation/cli)
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install @studio-foundation/contracts
15
+ # or
16
+ pnpm add @studio-foundation/contracts
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```typescript
22
+ import type {
23
+ PipelineDefinition,
24
+ StageDefinition,
25
+ OutputContract,
26
+ AgentConfig,
27
+ StageStatus,
28
+ } from '@studio-foundation/contracts';
29
+
30
+ import { isStageGroup } from '@studio-foundation/contracts'; // the only runtime export
31
+
32
+ for (const stage of pipeline.stages) {
33
+ if (isStageGroup(stage)) {
34
+ // handle a group
35
+ } else {
36
+ // handle a plain stage
37
+ }
38
+ }
39
+ ```
40
+
41
+ ## Dependency position
8
42
 
9
43
  ```
10
44
  contracts ← ralph
11
45
  contracts ← runner
46
+ contracts ← anonymizer
12
47
  contracts ← engine
13
48
  contracts ← cli
49
+ contracts ← api
14
50
  ```
15
51
 
52
+ Nothing imports upward. If you find yourself adding a dep here, you're solving the wrong problem.
53
+
16
54
  ## What's in here
17
55
 
18
56
  | Module | Purpose |
@@ -98,9 +136,15 @@ interface SpawnConfig {
98
136
 
99
137
  Used by the `studio_run` builtin tool to spawn sub-pipelines from within an agent run.
100
138
 
101
- ## Rules
139
+ ## For contributors
102
140
 
103
- - **Zero dependencies** no imports from other `@studio/*` packages, ever.
104
- - **Zero logic** — types and interfaces only. The one exception: `isStageGroup()` in `pipeline.ts` is a pure type guard function (no side effects, no state).
141
+ Internal rules that govern this package:
142
+
143
+ - **Zero dependencies**: no imports from other `@studio-foundation/*` packages, ever.
144
+ - **Zero logic**: types and interfaces only. The one exception: `isStageGroup()` in `pipeline.ts` is a pure type guard function (no side effects, no state).
105
145
  - If you need to add a type used by two packages, put it here.
106
146
  - If you're adding logic, you're in the wrong package.
147
+
148
+ ## License
149
+
150
+ AGPL-3.0-only
@@ -67,7 +67,7 @@ export interface StageDefinition {
67
67
  };
68
68
  hooks?: StageHooks;
69
69
  }
70
- export type PipelineEntry = StageDefinition | StageGroup;
70
+ export type PipelineEntry = StageDefinition | StageGroup | MapStage | CallStage;
71
71
  export interface StageGroup {
72
72
  group: string;
73
73
  max_iterations: number;
@@ -75,5 +75,50 @@ export interface StageGroup {
75
75
  on_failure?: 'fail-fast' | 'collect-all';
76
76
  stages: StageDefinition[];
77
77
  }
78
+ /**
79
+ * A fan-out / map stage: run a sub-pipeline once per item of a list, then
80
+ * collect the structured outputs. Replaces the "shell `studio run` per item +
81
+ * scrape the log" glue — the child runs are spawned in-process via the engine's
82
+ * RunSpawner and their last-stage output is returned directly (no scraping).
83
+ */
84
+ export interface MapStage {
85
+ map: string;
86
+ condition?: string;
87
+ over: string;
88
+ pipeline: string;
89
+ /**
90
+ * Per-item input template. Each value may reference the current item and the
91
+ * pipeline input via {{item}}, {{item.<path>}}, {{index}}, {{input.<path>}}.
92
+ * A value that is exactly "{{item}}" (or "{{input.x}}") keeps the resolved
93
+ * value's native type; mixed strings interpolate to text.
94
+ */
95
+ input?: Record<string, unknown>;
96
+ as?: string;
97
+ concurrency?: number;
98
+ on_item_failure?: 'fail-fast' | 'collect-all';
99
+ }
100
+ /**
101
+ * A call stage: run a named pipeline once, inline, and expose its output to
102
+ * later parent stages under the stage name. This is `map` with the iteration
103
+ * removed — same RunSpawner machinery, structured output, no log scraping — for
104
+ * when the shape is a sequence, not a fan-out (e.g. chaining wiki-extraction →
105
+ * wiki-resolution → wiki-preparation → pages-export in one top-level pipeline).
106
+ */
107
+ export interface CallStage {
108
+ call: string;
109
+ condition?: string;
110
+ pipeline?: string;
111
+ /**
112
+ * Input for the child run. Each value may reference the parent context via
113
+ * {{input}}, {{input.<path>}}, {{stages.<name>.output.<path>}} — the same
114
+ * substitution as `map`'s `input`, minus the per-item {{item}}/{{index}}. A
115
+ * value that is exactly one {{ref}} keeps the resolved value's native type;
116
+ * any other string interpolates to text. Omitted → the parent input is
117
+ * forwarded to the child unchanged.
118
+ */
119
+ input?: Record<string, unknown>;
120
+ }
78
121
  export declare function isStageGroup(entry: PipelineEntry): entry is StageGroup;
122
+ export declare function isMapStage(entry: PipelineEntry): entry is MapStage;
123
+ export declare function isCallStage(entry: PipelineEntry): entry is CallStage;
79
124
  //# sourceMappingURL=pipeline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
package/dist/pipeline.js CHANGED
@@ -2,4 +2,10 @@
2
2
  export function isStageGroup(entry) {
3
3
  return 'group' in entry && 'stages' in entry;
4
4
  }
5
+ export function isMapStage(entry) {
6
+ return 'map' in entry && 'over' in entry;
7
+ }
8
+ export function isCallStage(entry) {
9
+ return 'call' in entry;
10
+ }
5
11
  //# sourceMappingURL=pipeline.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA,iCAAiC;AA8FjC,MAAM,UAAU,YAAY,CAAC,KAAoB;IAC/C,OAAO,OAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,KAAK,CAAC;AAC/C,CAAC"}
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA,iCAAiC;AA4IjC,MAAM,UAAU,YAAY,CAAC,KAAoB;IAC/C,OAAO,OAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,KAAK,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAoB;IAC7C,OAAO,KAAK,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAoB;IAC9C,OAAO,MAAM,IAAI,KAAK,CAAC;AACzB,CAAC"}
package/dist/task.d.ts CHANGED
@@ -1,2 +1,27 @@
1
1
  export type TaskStatus = 'pending' | 'running' | 'success' | 'failed';
2
+ /**
3
+ * Input contract for a single agent run, carried from the engine to the runner.
4
+ *
5
+ * `description` is the default flat task text — most pipelines have only this.
6
+ * `fields`, when present, SUPERSEDES `description`: named fields are preserved
7
+ * structurally so anonymization can tokenize each independently (run-level
8
+ * shared keymap) BEFORE the prompt is assembled, and prompt assembly renders
9
+ * the fields. Field names are OPAQUE to the kernel — it imposes no domain
10
+ * meaning on them; an input opts into field-addressing, the kernel never
11
+ * requires it. One documented branch: `fields` present → field path; absent →
12
+ * flat-description path unchanged.
13
+ */
14
+ export interface TaskInput {
15
+ description: string;
16
+ fields?: Record<string, string>;
17
+ /**
18
+ * Opaque scope: names of `fields` to anonymize. Treated as opaque strings —
19
+ * the kernel imposes no domain meaning (INV-04). Undefined → anonymize all
20
+ * fields (fail-safe); [] → anonymize none; ['a'] → only field `a`. Ignored
21
+ * when `fields` is absent.
22
+ */
23
+ anonymize_fields?: string[];
24
+ expected_output?: string;
25
+ contract_name?: string;
26
+ }
2
27
  //# sourceMappingURL=task.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC"}
1
+ {"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEtE;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
@@ -5,14 +5,85 @@ export interface ToolCallRequirements {
5
5
  required_tool_groups?: string[][];
6
6
  counted_tools?: string[];
7
7
  }
8
+ /**
9
+ * An external validator: a shell command that receives the stage output as JSON
10
+ * on stdin and prints `{ "valid": boolean, "errors": string[] }` to stdout.
11
+ *
12
+ * This is the escape hatch for validation the declarative schema cannot express
13
+ * (cross-field rules, computed constraints) and for validators written in another
14
+ * language. Field-level shape — types, enums, nested required fields — now lives
15
+ * declaratively in `schema.fields` (see FieldSpec); reach for an external validator
16
+ * only when a rule spans multiple fields or needs real code. Unlike a required tool,
17
+ * it runs against the ACTUAL stage output, so the agent cannot satisfy it by
18
+ * reporting different arguments than it emits.
19
+ */
20
+ export interface ExternalValidator {
21
+ name: string;
22
+ /** Shell command. Receives the output JSON on stdin; prints {valid, errors} on stdout. */
23
+ command: string;
24
+ /** Optional timeout in milliseconds (default 30000). */
25
+ timeout_ms?: number;
26
+ }
27
+ /**
28
+ * Post-execution filesystem check: the files/artifacts a stage MUST leave on
29
+ * disk to be considered done. A "success" return code doesn't prove the agent
30
+ * actually produced its outputs — this closes that gap. Each entry is a path or
31
+ * glob (relative to the repo workspace); a stage fails if any entry matches no
32
+ * existing file. Runs inside the RALPH loop, so a miss enriches the retry
33
+ * feedback before the stage is finally failed.
34
+ */
35
+ export interface ExpectedOutputs {
36
+ /** Paths or glob patterns (relative to the repo workspace). Each must match ≥1 existing file. */
37
+ files: string[];
38
+ }
39
+ /**
40
+ * The JSON type a field is expected to hold. `integer` is `number` narrowed to
41
+ * whole values; `object` excludes arrays and null (use `array` for lists).
42
+ */
43
+ export type FieldType = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array';
44
+ /**
45
+ * Declarative shape of a single field — the piece that lifts contract validation
46
+ * beyond "the key is present" (required_fields) to "the value is the right type,
47
+ * one of the allowed values, and structurally sound".
48
+ *
49
+ * Every check is optional and only fires when the field is actually present;
50
+ * presence is still governed by `required_fields`. This keeps the two orthogonal:
51
+ * `required_fields` says a field must exist, `fields` says what it must look like.
52
+ *
53
+ * Recursion covers nested structures the PoC contracts need:
54
+ * - `type: object` + `required_fields`/`fields` validates a sub-object
55
+ * - `type: array` + `items` validates every element (e.g. each `pages[]` entry)
56
+ */
57
+ export interface FieldSpec {
58
+ /** Expected JSON type. On mismatch the field fails and nested checks are skipped. */
59
+ type?: FieldType;
60
+ /** Allowed values (enumeration), compared with strict equality. */
61
+ enum?: Array<string | number | boolean>;
62
+ /** For objects: names of nested fields that must be present. */
63
+ required_fields?: string[];
64
+ /** For objects: per-field specs applied to nested fields that are present. */
65
+ fields?: Record<string, FieldSpec>;
66
+ /** For arrays: the spec every element must satisfy. */
67
+ items?: FieldSpec;
68
+ }
69
+ /**
70
+ * A stage's output schema. `required_fields` checks top-level presence; `fields`
71
+ * adds declarative type/enum/nested validation for the fields it names. Both are
72
+ * optional and compose — a contract can use either, both, or neither.
73
+ */
74
+ export interface OutputSchema {
75
+ required_fields?: string[];
76
+ fields?: Record<string, FieldSpec>;
77
+ }
8
78
  export interface OutputContract {
9
79
  name: string;
10
80
  version: number;
11
- schema?: {
12
- required_fields?: string[];
13
- [key: string]: unknown;
14
- };
81
+ schema?: OutputSchema;
15
82
  tool_calls?: ToolCallRequirements;
83
+ /** External validators run against the real output inside the RALPH loop. */
84
+ validators?: ExternalValidator[];
85
+ /** Files/artifacts the stage must leave on disk. Checked post-execution. */
86
+ expected_outputs?: ExpectedOutputs;
16
87
  custom_rules?: ValidationRule[];
17
88
  post_validation?: {
18
89
  rejection_detection: {
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE;QACP,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,YAAY,CAAC,EAAE,cAAc,EAAE,CAAC;IAChC,eAAe,CAAC,EAAE;QAChB,mBAAmB,EAAE;YACnB,KAAK,EAAE,MAAM,CAAC;YACd,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;YAC3B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;YAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;SAC9B,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,0FAA0F;IAC1F,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,iGAAiG;IACjG,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEzF;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,SAAS;IACxB,qFAAqF;IACrF,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,mEAAmE;IACnE,IAAI,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACxC,gEAAgE;IAChE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACnC,uDAAuD;IACvD,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACjC,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,eAAe,CAAC;IACnC,YAAY,CAAC,EAAE,cAAc,EAAE,CAAC;IAChC,eAAe,CAAC,EAAE;QAChB,mBAAmB,EAAE;YACnB,KAAK,EAAE,MAAM,CAAC;YACd,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;YAC3B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;YAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;SAC9B,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@studio-foundation/contracts",
3
- "version": "0.3.0-beta.6",
4
- "description": "Shared TypeScript types and interfaces for Studio v7",
3
+ "version": "0.5.2",
4
+ "description": "Shared TypeScript types and interfaces for Studio packages",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",