ocpipe 0.3.0 → 0.3.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,5 +1,6 @@
1
1
  <p align="center"><strong>ocpipe</strong></p>
2
- <p align="center">SDK for LLM pipelines with <a href="https://github.com/sst/opencode">OpenCode</a> and <a href="https://zod.dev">Zod</a>.</p>
2
+ <p align="center">Build LLM pipelines with <a href="https://github.com/sst/opencode">OpenCode</a> and <a href="https://zod.dev">Zod</a>.</p>
3
+ <p align="center">Inspired by <a href="https://github.com/stanfordnlp/dspy">DSPy</a>.</p>
3
4
  <p align="center">
4
5
  <a href="https://www.npmjs.com/package/ocpipe"><img alt="npm" src="https://img.shields.io/npm/v/ocpipe?style=flat-square" /></a>
5
6
  <a href="https://github.com/s4wave/ocpipe/actions"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/s4wave/ocpipe/tests.yml?style=flat-square&branch=master" /></a>
@@ -7,20 +8,25 @@
7
8
 
8
9
  ---
9
10
 
11
+ - **Type-safe** Define inputs and outputs with Zod schemas
12
+ - **Modular** Compose modules into complex pipelines
13
+ - **Checkpoints** Resume from any step
14
+ - **Multi-model** Works with 75+ providers through OpenCode
15
+ - **Auto-correction** Fixes schema mismatches automatically
16
+
10
17
  ### Quick Start
11
18
 
19
+ ```bash
20
+ bun add ocpipe
21
+ ```
22
+
12
23
  ```typescript
13
24
  import { signature, field, module, Pipeline, createBaseState } from 'ocpipe'
14
25
 
15
26
  const Greet = signature({
16
27
  doc: 'Generate a friendly greeting for the given name.',
17
- inputs: {
18
- name: field.string('The name of the person to greet'),
19
- },
20
- outputs: {
21
- greeting: field.string('A friendly greeting message'),
22
- emoji: field.string('An appropriate emoji for the greeting'),
23
- },
28
+ inputs: { name: field.string('The name of the person to greet') },
29
+ outputs: { greeting: field.string('A friendly greeting message') },
24
30
  })
25
31
 
26
32
  const pipeline = new Pipeline(
@@ -28,26 +34,20 @@ const pipeline = new Pipeline(
28
34
  name: 'hello-world',
29
35
  defaultModel: { providerID: 'anthropic', modelID: 'claude-haiku-4-5' },
30
36
  defaultAgent: 'code',
31
- checkpointDir: './ckpt',
32
- logDir: './logs',
33
37
  },
34
38
  createBaseState,
35
39
  )
36
40
 
37
41
  const result = await pipeline.run(module(Greet), { name: 'World' })
38
- console.log(result.data.greeting) // "Hello, World! It's wonderful to meet you!"
39
- ```
40
-
41
- ### Installation
42
+ console.log(result.data.greeting)
42
43
 
43
- ```bash
44
- bun init
45
- bun add ocpipe
44
+ // Extract types from signatures
45
+ import { InferInputs, InferOutputs } from 'ocpipe'
46
+ type GreetIn = InferInputs<typeof Greet> // { name: string }
47
+ type GreetOut = InferOutputs<typeof Greet> // { greeting: string }
46
48
  ```
47
49
 
48
- OpenCode CLI is bundled — run `bun run opencode` or use your system `opencode` if installed (preferred).
49
-
50
- See [example/](./example) for a complete example.
50
+ OpenCode CLI is bundled — run `bun run opencode` or use your system `opencode` if installed.
51
51
 
52
52
  ### Documentation
53
53
 
@@ -55,6 +55,10 @@ See [example/](./example) for a complete example.
55
55
  - [Design](./DESIGN.md) - Architecture and concepts
56
56
  - [Contributing](./CONTRIBUTING.md) - Development setup
57
57
 
58
+ <!-- This code has been tested on animals. They didn't understand it either. -->
59
+
58
60
  ---
59
61
 
60
- **Join the OpenCode community** [Discord](https://opencode.ai/discord) | follow on [X.com](https://x.com/opencode)
62
+ [Discord](https://discord.gg/opencode) · [OpenCode](https://github.com/sst/opencode)
63
+
64
+ <sub>An [Aperture Robotics](https://github.com/aperturerobotics) project.</sub>
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * Auto-correction example.
3
3
  *
4
- * Demonstrates DSTS's automatic schema correction.
4
+ * Demonstrates ocpipe's automatic schema correction.
5
5
  * This example uses a schema with specific field names that LLMs
6
6
  * sometimes get wrong (e.g., "type" instead of "issue_type").
7
7
  *
8
- * DSTS supports two correction methods:
8
+ * ocpipe supports two correction methods:
9
9
  * - 'json-patch' (default): RFC 6902 JSON Patch, no external dependencies
10
10
  * - 'jq': jq-style expressions, requires jq binary installed
11
11
  *
package/example/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Hello World example runner.
3
3
  *
4
- * Demonstrates running a DSTS module in a pipeline.
4
+ * Demonstrates running an ocpipe module in a pipeline.
5
5
  */
6
6
 
7
7
  import { Pipeline, createBaseState } from '../src/index.js'
package/llms.txt ADDED
@@ -0,0 +1,200 @@
1
+ # ocpipe
2
+
3
+ > ocpipe is a TypeScript library for building type-safe LLM pipelines with OpenCode and Zod. Inspired by DSPy, it provides modular, checkpointable workflows with automatic schema correction.
4
+
5
+ Important notes:
6
+
7
+ - Requires Bun runtime and OpenCode CLI installed and configured
8
+ - Uses Zod v4 for schema validation
9
+ - Unlike DSPy, does NOT provide ChainOfThought or ReAct - OpenCode agents already handle reasoning and tool access
10
+ - Session continuity is maintained by default across pipeline steps
11
+
12
+ ## Core Concepts
13
+
14
+ ocpipe separates concerns into three layers:
15
+ - **Signatures**: Declare input/output contracts (the "what")
16
+ - **Modules**: Compose predictors with execution logic (the "how")
17
+ - **Pipelines**: Orchestrate execution with checkpointing and retries (the "when")
18
+
19
+ ## Quick Start
20
+
21
+ ```bash
22
+ bun add ocpipe zod
23
+ ```
24
+
25
+ ```typescript
26
+ import { signature, field, module, Pipeline, createBaseState } from 'ocpipe'
27
+
28
+ const Greet = signature({
29
+ doc: 'Generate a friendly greeting for the given name.',
30
+ inputs: { name: field.string('The name of the person to greet') },
31
+ outputs: { greeting: field.string('A friendly greeting message') },
32
+ })
33
+
34
+ const pipeline = new Pipeline(
35
+ {
36
+ name: 'hello-world',
37
+ defaultModel: { providerID: 'anthropic', modelID: 'claude-haiku-4-5' },
38
+ defaultAgent: 'code',
39
+ checkpointDir: './ckpt',
40
+ logDir: './logs',
41
+ },
42
+ createBaseState,
43
+ )
44
+
45
+ const result = await pipeline.run(module(Greet), { name: 'World' })
46
+ console.log(result.data.greeting)
47
+ ```
48
+
49
+ ## Field Helpers
50
+
51
+ - `field.string(desc?)` - String field
52
+ - `field.number(desc?)` - Number field
53
+ - `field.boolean(desc?)` - Boolean field
54
+ - `field.array(itemType, desc?)` - Array with Zod item type
55
+ - `field.object(shape, desc?)` - Object with Zod shape
56
+ - `field.enum(values, desc?)` - Enum from const array
57
+ - `field.optional(field)` - Optional wrapper
58
+ - `field.nullable(field)` - Nullable wrapper
59
+ - `field.custom(zodType, desc?)` - Custom Zod type
60
+
61
+ ## Docs
62
+
63
+ - [Getting Started](https://github.com/s4wave/ocpipe/blob/master/GETTING_STARTED.md): Tutorial with examples for building hello world and extending with multiple modules
64
+ - [Design](https://github.com/s4wave/ocpipe/blob/master/DESIGN.md): Architecture, core concepts, and advanced patterns
65
+ - [README](https://github.com/s4wave/ocpipe/blob/master/README.md): Quick start and feature overview
66
+
67
+ ## Source Files
68
+
69
+ - [src/index.ts](https://github.com/s4wave/ocpipe/blob/master/src/index.ts): Main exports - signature, field, module, Pipeline, Predict, state helpers, parsing utilities
70
+ - [src/signature.ts](https://github.com/s4wave/ocpipe/blob/master/src/signature.ts): Signature definition and field helpers using Zod
71
+ - [src/module.ts](https://github.com/s4wave/ocpipe/blob/master/src/module.ts): Module, SignatureModule, and simple module() factory
72
+ - [src/pipeline.ts](https://github.com/s4wave/ocpipe/blob/master/src/pipeline.ts): Pipeline orchestrator with checkpointing, retries, and sub-pipelines
73
+ - [src/predict.ts](https://github.com/s4wave/ocpipe/blob/master/src/predict.ts): Predict class - prompt generation, LLM execution, response parsing, auto-correction
74
+ - [src/types.ts](https://github.com/s4wave/ocpipe/blob/master/src/types.ts): TypeScript interfaces - ModelConfig, ExecutionContext, SignatureDef, PipelineConfig, etc.
75
+ - [src/agent.ts](https://github.com/s4wave/ocpipe/blob/master/src/agent.ts): OpenCode CLI integration - runAgent(), session management
76
+ - [src/parsing.ts](https://github.com/s4wave/ocpipe/blob/master/src/parsing.ts): JSON extraction, Zod validation, JSON Patch and jq-style correction
77
+ - [src/state.ts](https://github.com/s4wave/ocpipe/blob/master/src/state.ts): State management - createBaseState(), createSessionId(), extendBaseState()
78
+ - [src/testing.ts](https://github.com/s4wave/ocpipe/blob/master/src/testing.ts): MockAgentBackend, createMockContext(), generateMockOutputs() for unit testing
79
+
80
+ ## Examples
81
+
82
+ - [example/index.ts](https://github.com/s4wave/ocpipe/blob/master/example/index.ts): Hello world pipeline runner
83
+ - [example/signature.ts](https://github.com/s4wave/ocpipe/blob/master/example/signature.ts): Greet signature definition
84
+ - [example/module.ts](https://github.com/s4wave/ocpipe/blob/master/example/module.ts): Greeter SignatureModule implementation
85
+ - [example/correction.ts](https://github.com/s4wave/ocpipe/blob/master/example/correction.ts): Auto-correction demonstration
86
+
87
+ ## Key Types
88
+
89
+ ```typescript
90
+ interface PipelineConfig {
91
+ name: string
92
+ defaultModel: { providerID: string; modelID: string }
93
+ defaultAgent: string
94
+ checkpointDir: string
95
+ logDir: string
96
+ retry?: { maxAttempts: number; onParseError?: boolean }
97
+ timeoutSec?: number
98
+ }
99
+
100
+ interface SignatureDef<I, O> {
101
+ doc: string // Instructions for the LLM
102
+ inputs: I // Record<string, FieldConfig>
103
+ outputs: O // Record<string, FieldConfig>
104
+ }
105
+
106
+ interface FieldConfig<T extends z.ZodType = z.ZodType> {
107
+ type: T // Zod type for validation
108
+ desc?: string // Description for prompt generation
109
+ }
110
+ ```
111
+
112
+ ## Patterns
113
+
114
+ ### Simple Module (one signature)
115
+ ```typescript
116
+ const result = await pipeline.run(module(MySignature), inputs)
117
+ ```
118
+
119
+ ### Custom Module Class
120
+ ```typescript
121
+ class MyModule extends SignatureModule<typeof MySignature> {
122
+ constructor() { super(MySignature) }
123
+ async forward(input, ctx) {
124
+ const result = await this.predictor.execute(input, ctx)
125
+ return result.data
126
+ }
127
+ }
128
+ ```
129
+
130
+ ### Multi-Predictor Module
131
+ ```typescript
132
+ class ComplexModule extends Module<InputType, OutputType> {
133
+ private step1 = this.predict(Signature1)
134
+ private step2 = this.predict(Signature2, { agent: 'specialist' })
135
+
136
+ async forward(input, ctx) {
137
+ const r1 = await this.step1.execute(input, ctx)
138
+ const r2 = await this.step2.execute({ data: r1.data }, ctx)
139
+ return { result: r2.data.output, metadata: r1.data }
140
+ }
141
+ }
142
+ ```
143
+
144
+ ### Session Control
145
+ ```typescript
146
+ // New session for this step
147
+ await pipeline.run(module, input, { newSession: true })
148
+
149
+ // Model override for this step
150
+ await pipeline.run(module, input, {
151
+ model: { providerID: 'anthropic', modelID: 'claude-opus-4-5' }
152
+ })
153
+ ```
154
+
155
+ ### Checkpointing
156
+ ```typescript
157
+ // Resume from checkpoint
158
+ const resumed = await Pipeline.loadCheckpoint(config, sessionId)
159
+
160
+ // List available checkpoints
161
+ const files = await Pipeline.listCheckpoints(config)
162
+ ```
163
+
164
+ ### Auto-Correction Configuration
165
+ ```typescript
166
+ // Default: json-patch with 3 rounds
167
+ super(MySignature)
168
+
169
+ // Custom configuration
170
+ super(MySignature, {
171
+ correction: {
172
+ method: 'json-patch', // or 'jq' (requires jq binary)
173
+ maxFields: 5,
174
+ maxRounds: 3,
175
+ }
176
+ })
177
+
178
+ // Disable correction
179
+ super(MySignature, { correction: false })
180
+ ```
181
+
182
+ ### Testing Without LLM
183
+ ```typescript
184
+ import { MockAgentBackend, createMockContext } from 'ocpipe'
185
+ import { vi } from 'vitest'
186
+
187
+ const mock = new MockAgentBackend()
188
+ mock.addJsonResponse({ greeting: 'Hello!', emoji: ':wave:' })
189
+
190
+ vi.mock('./agent.js', () => ({ runAgent: mock.createRunner() }))
191
+
192
+ const ctx = createMockContext()
193
+ const result = await predictor.execute({ name: 'Test' }, ctx)
194
+ ```
195
+
196
+ ## Optional
197
+
198
+ - [CONTRIBUTING.md](https://github.com/s4wave/ocpipe/blob/master/CONTRIBUTING.md): Development setup and contribution guidelines
199
+ - [src/integration.test.ts](https://github.com/s4wave/ocpipe/blob/master/src/integration.test.ts): Integration tests showing real usage patterns
200
+ - [src/parsing.test.ts](https://github.com/s4wave/ocpipe/blob/master/src/parsing.test.ts): Tests for JSON parsing and correction logic
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ocpipe",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "SDK for LLM pipelines with OpenCode and Zod",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -35,12 +35,18 @@
35
35
  "zod": "^4.0.0"
36
36
  },
37
37
  "devDependencies": {
38
+ "@eslint/js": "^9.39.2",
38
39
  "bun-types": "^1.3.5",
40
+ "eslint": "^9.39.2",
41
+ "globals": "^16.5.0",
42
+ "jiti": "^2.6.1",
39
43
  "prettier": "^3.7.4",
40
44
  "typescript": "^5.0.0",
45
+ "typescript-eslint": "^8.50.1",
41
46
  "vitest": "^4.0.0"
42
47
  },
43
48
  "scripts": {
49
+ "lint": "eslint .",
44
50
  "format": "bun run prettier --write .",
45
51
  "typecheck": "tsc --noEmit",
46
52
  "test": "vitest run",
@@ -55,6 +61,11 @@
55
61
  "files": [
56
62
  "src/",
57
63
  "!src/*.test.ts",
58
- "example/"
64
+ "example/",
65
+ "llms.txt",
66
+ "README.md",
67
+ "LICENSE",
68
+ "GETTING_STARTED.md",
69
+ "DESIGN.md"
59
70
  ]
60
71
  }
@@ -0,0 +1,55 @@
1
+ {
2
+ "sessionId": "20251231_092022",
3
+ "startedAt": "2025-12-31T09:20:22.199Z",
4
+ "phase": "init",
5
+ "steps": [
6
+ {
7
+ "stepName": "MoodAnalyzer",
8
+ "timestamp": "2025-12-31T09:20:25.808Z",
9
+ "result": {
10
+ "data": {
11
+ "mood": "happy",
12
+ "keywords": [
13
+ "happy",
14
+ "so",
15
+ "today"
16
+ ]
17
+ },
18
+ "stepName": "MoodAnalyzer",
19
+ "duration": 3608,
20
+ "sessionId": "ses_48c4aa762ffeP1pxFsOURK4cw2",
21
+ "model": {
22
+ "providerID": "github-copilot",
23
+ "modelID": "grok-code-fast-1"
24
+ },
25
+ "attempt": 1
26
+ }
27
+ },
28
+ {
29
+ "stepName": "ResponseSuggester",
30
+ "timestamp": "2025-12-31T09:20:30.186Z",
31
+ "result": {
32
+ "data": {
33
+ "suggestion": "That's wonderful! What's making you so happy today?"
34
+ },
35
+ "stepName": "ResponseSuggester",
36
+ "duration": 4377,
37
+ "sessionId": "ses_48c4aa762ffeP1pxFsOURK4cw2",
38
+ "model": {
39
+ "providerID": "github-copilot",
40
+ "modelID": "grok-code-fast-1"
41
+ },
42
+ "attempt": 1
43
+ }
44
+ }
45
+ ],
46
+ "subPipelines": [],
47
+ "inputText": "I am so happy today!",
48
+ "opencodeSessionId": "ses_48c4aa762ffeP1pxFsOURK4cw2",
49
+ "mood": "happy",
50
+ "keywords": [
51
+ "happy",
52
+ "so",
53
+ "today"
54
+ ]
55
+ }
package/src/agent.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * DSTS SDK OpenCode agent integration.
2
+ * ocpipe OpenCode agent integration.
3
3
  *
4
4
  * Wraps the OpenCode CLI for running LLM agents with session management.
5
5
  */
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
- * DSTS: Declarative Self-Improving TypeScript
2
+ * ocpipe: LLM pipelines with OpenCode and Zod.
3
3
  *
4
- * A DSPy-inspired SDK for building LLM workflow pipelines with OpenCode.
4
+ * Inspired by DSPy.
5
5
  *
6
6
  * @example
7
7
  * ```typescript
package/src/module.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  /**
2
- * DSTS SDK Module base class.
2
+ * ocpipe Module base class.
3
3
  *
4
4
  * Modules encapsulate logical units of work that use one or more Predictors.
5
5
  */
6
6
 
7
7
  import type {
8
8
  ExecutionContext,
9
+ FieldConfig,
9
10
  InferInputs,
10
11
  InferOutputs,
11
12
  SignatureDef,
@@ -13,17 +14,22 @@ import type {
13
14
  export type { ExecutionContext } from './types.js'
14
15
  import { Predict, type PredictConfig } from './predict.js'
15
16
 
17
+ type AnySignature = SignatureDef<
18
+ Record<string, FieldConfig>,
19
+ Record<string, FieldConfig>
20
+ >
21
+
16
22
  /** Module is the abstract base class for composable workflow units. */
17
23
  export abstract class Module<I, O> {
18
- private predictors: Predict<any>[] = []
24
+ private predictors: Predict<AnySignature>[] = []
19
25
 
20
26
  /** predict creates and registers a Predict instance for a signature. */
21
- protected predict<S extends SignatureDef<any, any>>(
27
+ protected predict<S extends AnySignature>(
22
28
  sig: S,
23
29
  config?: PredictConfig,
24
30
  ): Predict<S> {
25
31
  const p = new Predict(sig, config)
26
- this.predictors.push(p)
32
+ this.predictors.push(p as Predict<AnySignature>)
27
33
  return p
28
34
  }
29
35
 
@@ -31,15 +37,16 @@ export abstract class Module<I, O> {
31
37
  abstract forward(input: I, ctx: ExecutionContext): Promise<O>
32
38
 
33
39
  /** getPredictors returns all registered predictors (for future optimization). */
34
- getPredictors(): Predict<any>[] {
40
+ getPredictors(): Predict<AnySignature>[] {
35
41
  return this.predictors
36
42
  }
37
43
  }
38
44
 
39
45
  /** SignatureModule is a Module whose types are derived from a Signature. */
40
- export abstract class SignatureModule<
41
- S extends SignatureDef<any, any>,
42
- > extends Module<InferInputs<S>, InferOutputs<S>> {
46
+ export abstract class SignatureModule<S extends AnySignature> extends Module<
47
+ InferInputs<S>,
48
+ InferOutputs<S>
49
+ > {
43
50
  protected readonly sig: S
44
51
  protected readonly predictor: Predict<S>
45
52
 
@@ -51,9 +58,7 @@ export abstract class SignatureModule<
51
58
  }
52
59
 
53
60
  /** SimpleModule is a SignatureModule that just executes the predictor. */
54
- class SimpleModule<
55
- S extends SignatureDef<any, any>,
56
- > extends SignatureModule<S> {
61
+ class SimpleModule<S extends AnySignature> extends SignatureModule<S> {
57
62
  constructor(sig: S, config?: PredictConfig) {
58
63
  super(sig, config)
59
64
  }
@@ -67,7 +72,7 @@ class SimpleModule<
67
72
  }
68
73
 
69
74
  /** module creates a simple Module from a Signature (syntactic sugar). */
70
- export function module<S extends SignatureDef<any, any>>(
75
+ export function module<S extends AnySignature>(
71
76
  sig: S,
72
77
  config?: PredictConfig,
73
78
  ): Module<InferInputs<S>, InferOutputs<S>> {