ocpipe 0.1.0 → 0.2.1
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/LICENSE +21 -0
- package/README.md +24 -298
- package/example/correction.ts +3 -3
- package/example/index.ts +1 -1
- package/example/module.ts +2 -2
- package/example/signature.ts +1 -1
- package/package.json +19 -12
- package/{agent.ts → src/agent.ts} +1 -1
- package/{index.ts → src/index.ts} +3 -16
- package/{module.ts → src/module.ts} +20 -0
- package/{parsing.ts → src/parsing.ts} +1 -1
- package/src/paths.ts +4 -0
- package/{predict.ts → src/predict.ts} +1 -1
- package/{signature.ts → src/signature.ts} +1 -1
- package/{types.ts → src/types.ts} +1 -1
- /package/{pipeline.ts → src/pipeline.ts} +0 -0
- /package/{state.ts → src/state.ts} +0 -0
- /package/{testing.ts → src/testing.ts} +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Christian Stewart <christian@aperture.us>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
# DSTS
|
|
2
|
-
|
|
3
1
|
<div align="center">
|
|
4
|
-
<h3>
|
|
5
|
-
<p>
|
|
6
|
-
<p>
|
|
7
|
-
<a href="https://github.com/s4wave/dsts">GitHub</a> |
|
|
8
|
-
<a href="https://github.com/s4wave/dsts/blob/main/GETTING_STARTED.md">Getting Started</a> |
|
|
9
|
-
<a href="https://github.com/s4wave/dsts/blob/main/LICENSE">MIT License</a>
|
|
10
|
-
</p>
|
|
2
|
+
<h3>OpenCode Pipeline</h3>
|
|
3
|
+
<p>SDK for LLM pipelines with <a href="https://opencode.ai">OpenCode</a> and <a href="https://zod.dev">Zod</a>.</p>
|
|
11
4
|
</div>
|
|
12
5
|
|
|
13
6
|
<div align="center">
|
|
@@ -20,315 +13,48 @@ Signature → Predict → Module → Pipeline
|
|
|
20
13
|
|
|
21
14
|
</div>
|
|
22
15
|
|
|
23
|
-
DSTS separates the **what** (Signatures declare input/output contracts), the **how** (Modules compose predictors), and the **when** (Pipelines orchestrate execution). This separation enables clean composition, rich debugging, and maintainable LLM workflow code.
|
|
24
|
-
|
|
25
|
-
## Features
|
|
26
|
-
|
|
27
|
-
- **Type-safe signatures** - Define input/output contracts with Zod schemas
|
|
28
|
-
- **Automatic prompt generation** - Signatures become structured prompts
|
|
29
|
-
- **JSON output parsing** - Automatic extraction and validation of JSON responses
|
|
30
|
-
- **Session continuity** - Reuse OpenCode sessions across steps
|
|
31
|
-
- **Checkpointing** - Automatic state persistence after each step
|
|
32
|
-
- **Retry logic** - Configurable retries with parse error handling
|
|
33
|
-
- **Sub-pipelines** - Compose complex workflows from smaller pieces
|
|
34
|
-
- **Testing utilities** - Mock backends for unit testing
|
|
35
|
-
|
|
36
|
-
## Quick Start
|
|
37
|
-
|
|
38
16
|
```typescript
|
|
39
|
-
import { signature, field,
|
|
40
|
-
import { z } from 'zod'
|
|
17
|
+
import { signature, field, module, Pipeline, createBaseState } from 'ocpipe'
|
|
41
18
|
|
|
42
|
-
//
|
|
43
|
-
const
|
|
44
|
-
doc: '
|
|
19
|
+
// Define a signature
|
|
20
|
+
const Greet = signature({
|
|
21
|
+
doc: 'Generate a friendly greeting for the given name.',
|
|
45
22
|
inputs: {
|
|
46
|
-
|
|
23
|
+
name: field.string('The name of the person to greet'),
|
|
47
24
|
},
|
|
48
25
|
outputs: {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
keywords: field.array(z.string(), 'Extracted keywords'),
|
|
26
|
+
greeting: field.string('A friendly greeting message'),
|
|
27
|
+
emoji: field.string('An appropriate emoji for the greeting'),
|
|
52
28
|
},
|
|
53
29
|
})
|
|
54
30
|
|
|
55
|
-
//
|
|
56
|
-
class IntentParser extends SignatureModule<typeof ParseIntent> {
|
|
57
|
-
constructor() {
|
|
58
|
-
super(ParseIntent)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async forward(input, ctx) {
|
|
62
|
-
const result = await this.predictor.execute(input, ctx)
|
|
63
|
-
return result.data // Full signature output
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// 3. Run in a pipeline (the orchestration)
|
|
68
|
-
const pipeline = new Pipeline({
|
|
69
|
-
name: 'my-workflow',
|
|
70
|
-
defaultModel: { providerID: 'anthropic', modelID: 'claude-sonnet-4-5' },
|
|
71
|
-
defaultAgent: 'general',
|
|
72
|
-
checkpointDir: './ckpt',
|
|
73
|
-
logDir: './logs',
|
|
74
|
-
}, createBaseState)
|
|
75
|
-
|
|
76
|
-
const result = await pipeline.run(new IntentParser(), { description: 'Hello world' })
|
|
77
|
-
console.log(result.data.intent)
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## Core Concepts
|
|
81
|
-
|
|
82
|
-
### Signatures
|
|
83
|
-
|
|
84
|
-
A Signature declares **what** an LLM interaction does - its inputs, outputs, and purpose. This is separate from *how* it executes.
|
|
85
|
-
|
|
86
|
-
```typescript
|
|
87
|
-
import { signature, field } from 'dsts'
|
|
88
|
-
import { z } from 'zod'
|
|
89
|
-
|
|
90
|
-
const AnalyzeCode = signature({
|
|
91
|
-
doc: 'Analyze code for potential issues and improvements.',
|
|
92
|
-
inputs: {
|
|
93
|
-
code: field.string('Source code to analyze'),
|
|
94
|
-
language: field.enum(['typescript', 'python', 'rust'] as const),
|
|
95
|
-
},
|
|
96
|
-
outputs: {
|
|
97
|
-
issues: field.array(z.object({
|
|
98
|
-
severity: z.enum(['error', 'warning', 'info']),
|
|
99
|
-
message: z.string(),
|
|
100
|
-
line: z.number(),
|
|
101
|
-
}), 'List of issues found'),
|
|
102
|
-
suggestions: field.array(z.string(), 'Improvement suggestions'),
|
|
103
|
-
score: field.number('Code quality score 0-100'),
|
|
104
|
-
},
|
|
105
|
-
})
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
**Field helpers:**
|
|
109
|
-
- `field.string(desc?)` - String field
|
|
110
|
-
- `field.number(desc?)` - Number field
|
|
111
|
-
- `field.boolean(desc?)` - Boolean field
|
|
112
|
-
- `field.array(itemType, desc?)` - Array field
|
|
113
|
-
- `field.object(shape, desc?)` - Object field
|
|
114
|
-
- `field.enum(values, desc?)` - Enum field
|
|
115
|
-
- `field.optional(field)` - Optional wrapper
|
|
116
|
-
- `field.nullable(field)` - Nullable wrapper
|
|
117
|
-
- `field.custom(zodType, desc?)` - Custom Zod type
|
|
118
|
-
|
|
119
|
-
### Predict
|
|
120
|
-
|
|
121
|
-
`Predict` is the bridge between a Signature (the contract) and OpenCode (the execution). It handles prompt generation, response parsing, and validation.
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
import { Predict } from 'dsts'
|
|
125
|
-
|
|
126
|
-
// Basic usage
|
|
127
|
-
const predict = new Predict(AnalyzeCode)
|
|
128
|
-
const result = await predict.execute({ code: '...', language: 'typescript' }, ctx)
|
|
129
|
-
|
|
130
|
-
// With configuration
|
|
131
|
-
const predict = new Predict(AnalyzeCode, {
|
|
132
|
-
agent: 'code-reviewer', // Override default agent
|
|
133
|
-
model: { providerID: 'anthropic', modelID: 'claude-opus-4-5' },
|
|
134
|
-
newSession: true, // Don't reuse existing session
|
|
135
|
-
template: (inputs) => `...`, // Custom prompt template
|
|
136
|
-
})
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
**Output format:**
|
|
140
|
-
|
|
141
|
-
The LLM is prompted to return a JSON object:
|
|
142
|
-
```
|
|
143
|
-
OUTPUT FORMAT:
|
|
144
|
-
Return a JSON object with EXACTLY these field names and types.
|
|
145
|
-
|
|
146
|
-
```json
|
|
147
|
-
{
|
|
148
|
-
"issues": <array<object{severity, message, line}>>, // List of issues found
|
|
149
|
-
"suggestions": <array<string>>, // Improvement suggestions
|
|
150
|
-
"score": <number> // Code quality score 0-100
|
|
151
|
-
}
|
|
152
|
-
```
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### Module
|
|
156
|
-
|
|
157
|
-
A Module encapsulates a logical unit of work that may use one or more Predictors. Modules can call other Modules, enabling composition.
|
|
158
|
-
|
|
159
|
-
**SignatureModule** - For simple modules that wrap a single signature with pass-through types:
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
import { SignatureModule } from 'dsts'
|
|
163
|
-
|
|
164
|
-
class IntentParser extends SignatureModule<typeof ParseIntent> {
|
|
165
|
-
constructor() {
|
|
166
|
-
super(ParseIntent)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
async forward(input, ctx) {
|
|
170
|
-
const result = await this.predictor.execute(input, ctx)
|
|
171
|
-
return result.data // Types inferred from ParseIntent
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**Module** - For complex modules with multiple predictors or transformed outputs:
|
|
177
|
-
|
|
178
|
-
```typescript
|
|
179
|
-
import { Module } from 'dsts'
|
|
180
|
-
|
|
181
|
-
class CodeAnalyzer extends Module<
|
|
182
|
-
{ code: string; language: string },
|
|
183
|
-
{ issues: Issue[]; score: number }
|
|
184
|
-
> {
|
|
185
|
-
private analyze = this.predict(AnalyzeCode)
|
|
186
|
-
private suggest = this.predict(SuggestFixes, { agent: 'code-fixer' })
|
|
187
|
-
|
|
188
|
-
async forward(input: { code: string; language: string }, ctx: ExecutionContext) {
|
|
189
|
-
// First, analyze the code
|
|
190
|
-
const analysis = await this.analyze.execute(input, ctx)
|
|
191
|
-
|
|
192
|
-
// If there are critical issues, get fix suggestions
|
|
193
|
-
if (analysis.data.issues.some(i => i.severity === 'error')) {
|
|
194
|
-
const fixes = await this.suggest.execute({
|
|
195
|
-
code: input.code,
|
|
196
|
-
issues: analysis.data.issues,
|
|
197
|
-
}, ctx)
|
|
198
|
-
|
|
199
|
-
return {
|
|
200
|
-
issues: analysis.data.issues,
|
|
201
|
-
fixes: fixes.data.suggestions,
|
|
202
|
-
score: analysis.data.score,
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return {
|
|
207
|
-
issues: analysis.data.issues,
|
|
208
|
-
score: analysis.data.score,
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### Pipeline
|
|
215
|
-
|
|
216
|
-
Pipeline is the top-level orchestrator. It manages execution context, state, checkpointing, logging, and retry logic.
|
|
217
|
-
|
|
218
|
-
```typescript
|
|
219
|
-
import { Pipeline, createBaseState } from 'dsts'
|
|
220
|
-
|
|
221
|
-
// Create pipeline with configuration
|
|
31
|
+
// Run in a pipeline
|
|
222
32
|
const pipeline = new Pipeline({
|
|
223
|
-
name: '
|
|
224
|
-
defaultModel: { providerID: 'anthropic', modelID: 'claude-
|
|
225
|
-
defaultAgent: '
|
|
33
|
+
name: 'hello-world',
|
|
34
|
+
defaultModel: { providerID: 'anthropic', modelID: 'claude-haiku-4-5' },
|
|
35
|
+
defaultAgent: 'code',
|
|
226
36
|
checkpointDir: './ckpt',
|
|
227
37
|
logDir: './logs',
|
|
228
|
-
retry: { maxAttempts: 2, onParseError: true },
|
|
229
|
-
timeoutSec: 300,
|
|
230
38
|
}, createBaseState)
|
|
231
39
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
code: sourceCode,
|
|
235
|
-
language: 'typescript',
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
// Run with step options
|
|
239
|
-
const result = await pipeline.run(new CodeAnalyzer(), input, {
|
|
240
|
-
name: 'analyze-main', // Custom step name
|
|
241
|
-
model: { providerID: 'anthropic', modelID: 'claude-opus-4-5' }, // Override model
|
|
242
|
-
newSession: true, // Fresh session
|
|
243
|
-
retry: { maxAttempts: 3 }, // Override retry
|
|
244
|
-
})
|
|
245
|
-
|
|
246
|
-
// Access state
|
|
247
|
-
console.log(pipeline.state.steps) // Completed steps
|
|
248
|
-
console.log(pipeline.getSessionId()) // Current OpenCode session
|
|
249
|
-
|
|
250
|
-
// Resume from checkpoint
|
|
251
|
-
const resumed = await Pipeline.loadCheckpoint(config, sessionId)
|
|
40
|
+
const result = await pipeline.run(module(Greet), { name: 'World' })
|
|
41
|
+
console.log(result.data.greeting) // "Hello, World! It's wonderful to meet you!"
|
|
252
42
|
```
|
|
253
43
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
DSTS automatically checkpoints state after each step:
|
|
257
|
-
|
|
258
|
-
```typescript
|
|
259
|
-
import { createBaseState, extendBaseState } from 'dsts'
|
|
44
|
+
## Install
|
|
260
45
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
// { sessionId, startedAt, phase, steps, subPipelines }
|
|
264
|
-
|
|
265
|
-
// Extended state for your workflow
|
|
266
|
-
interface MyState extends BaseState {
|
|
267
|
-
inputPath: string
|
|
268
|
-
results: AnalysisResult[]
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const pipeline = new Pipeline(config, () => ({
|
|
272
|
-
...createBaseState(),
|
|
273
|
-
inputPath: '/path/to/input',
|
|
274
|
-
results: [],
|
|
275
|
-
}))
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
## Testing
|
|
279
|
-
|
|
280
|
-
DSTS provides testing utilities for unit testing without hitting real LLMs:
|
|
281
|
-
|
|
282
|
-
```typescript
|
|
283
|
-
import { MockAgentBackend, createMockContext, generateMockOutputs } from 'dsts'
|
|
284
|
-
import { vi } from 'vitest'
|
|
285
|
-
|
|
286
|
-
// Create mock backend
|
|
287
|
-
const mock = new MockAgentBackend()
|
|
288
|
-
|
|
289
|
-
// Add mock responses
|
|
290
|
-
mock.addJsonResponse({
|
|
291
|
-
intent: 'greeting',
|
|
292
|
-
confidence: 0.95,
|
|
293
|
-
keywords: ['hello', 'world'],
|
|
294
|
-
})
|
|
295
|
-
|
|
296
|
-
// Mock the agent module
|
|
297
|
-
vi.mock('./agent.js', () => ({
|
|
298
|
-
runAgent: mock.createRunner(),
|
|
299
|
-
}))
|
|
300
|
-
|
|
301
|
-
// Create test context
|
|
302
|
-
const ctx = createMockContext({
|
|
303
|
-
defaultModel: { providerID: 'anthropic', modelID: 'claude-sonnet-4-5' },
|
|
304
|
-
})
|
|
305
|
-
|
|
306
|
-
// Auto-generate mock outputs from schema
|
|
307
|
-
const mockData = generateMockOutputs(ParseIntent.outputs)
|
|
46
|
+
```bash
|
|
47
|
+
bun add ocpipe zod
|
|
308
48
|
```
|
|
309
49
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
Unlike DSPy, DSTS does not provide `ChainOfThought` or `ReAct` variants. This is intentional:
|
|
313
|
-
|
|
314
|
-
- **OpenCode agents already do chain-of-thought reasoning** - they think before acting
|
|
315
|
-
- **OpenCode agents already do ReAct** - they have access to tools and use them iteratively
|
|
316
|
-
- **Adding these would duplicate functionality** and create confusion
|
|
50
|
+
Requires [Bun](https://bun.sh) and [OpenCode](https://opencode.ai) CLI.
|
|
317
51
|
|
|
318
|
-
|
|
52
|
+
## Documentation
|
|
319
53
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
- [
|
|
323
|
-
- [OpenCode](https://opencode.ai) CLI installed and configured
|
|
324
|
-
- [Zod](https://zod.dev) for schema validation
|
|
325
|
-
|
|
326
|
-
## Installation
|
|
327
|
-
|
|
328
|
-
```bash
|
|
329
|
-
bun add dsts zod
|
|
330
|
-
```
|
|
54
|
+
- [Getting Started](./GETTING_STARTED.md) - Tutorial with examples
|
|
55
|
+
- [Design](./DESIGN.md) - Architecture and concepts
|
|
56
|
+
- [Contributing](./CONTRIBUTING.md) - Development setup
|
|
331
57
|
|
|
332
58
|
## License
|
|
333
59
|
|
|
334
|
-
MIT
|
|
60
|
+
[MIT](./LICENSE)
|
package/example/correction.ts
CHANGED
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
* bun run example/correction.ts --jq # Uses jq method
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { z } from 'zod'
|
|
18
|
-
import { Pipeline, createBaseState, signature, field, SignatureModule } from '../index.js'
|
|
19
|
-
import type { CorrectionMethod, ExecutionContext } from '../types.js'
|
|
17
|
+
import { z } from 'zod/v4'
|
|
18
|
+
import { Pipeline, createBaseState, signature, field, SignatureModule } from '../src/index.js'
|
|
19
|
+
import type { CorrectionMethod, ExecutionContext } from '../src/types.js'
|
|
20
20
|
|
|
21
21
|
// A signature with field names that LLMs often get wrong
|
|
22
22
|
const AnalyzeIssue = signature({
|
package/example/index.ts
CHANGED
package/example/module.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Wraps the Greet signature with execution logic.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { SignatureModule } from '../index.js'
|
|
8
|
-
import type { ExecutionContext } from '../types.js'
|
|
7
|
+
import { SignatureModule } from '../src/index.js'
|
|
8
|
+
import type { ExecutionContext } from '../src/types.js'
|
|
9
9
|
import { Greet } from './signature.js'
|
|
10
10
|
|
|
11
11
|
export class Greeter extends SignatureModule<typeof Greet> {
|
package/example/signature.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Defines the input/output contract for greeting generation.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { signature, field } from '../index.js'
|
|
7
|
+
import { signature, field } from '../src/index.js'
|
|
8
8
|
|
|
9
9
|
export const Greet = signature({
|
|
10
10
|
doc: 'Generate a friendly greeting for the given name.',
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ocpipe",
|
|
3
|
-
"version": "0.1
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "SDK for LLM pipelines with OpenCode and Zod",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "index.ts",
|
|
7
|
-
"types": "index.ts",
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"types": "src/index.ts",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/s4wave/
|
|
10
|
+
"url": "git+https://github.com/s4wave/ocpipe.git"
|
|
11
11
|
},
|
|
12
|
-
"homepage": "https://github.com/s4wave/
|
|
12
|
+
"homepage": "https://github.com/s4wave/ocpipe",
|
|
13
13
|
"bugs": {
|
|
14
|
-
"url": "https://github.com/s4wave/
|
|
14
|
+
"url": "https://github.com/s4wave/ocpipe/issues"
|
|
15
15
|
},
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"author": "s4wave",
|
|
@@ -29,20 +29,27 @@
|
|
|
29
29
|
"bun": ">=1.0.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"zod": "^
|
|
32
|
+
"zod": "^4.0.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
+
"bun-types": "^1.3.5",
|
|
35
36
|
"typescript": "^5.0.0",
|
|
36
|
-
"vitest": "^
|
|
37
|
+
"vitest": "^4.0.0"
|
|
37
38
|
},
|
|
38
39
|
"scripts": {
|
|
39
40
|
"typecheck": "tsc --noEmit",
|
|
40
41
|
"test": "vitest run",
|
|
41
|
-
"test:watch": "vitest"
|
|
42
|
+
"test:watch": "vitest",
|
|
43
|
+
"release": "npm run release:version && npm run release:commit",
|
|
44
|
+
"release:minor": "npm run release:version:minor && npm run release:commit",
|
|
45
|
+
"release:version": "npm version patch -m \"release: v%s\" --no-git-tag-version",
|
|
46
|
+
"release:version:minor": "npm version minor -m \"release: v%s\" --no-git-tag-version",
|
|
47
|
+
"release:commit": "git reset && git add package.json && git commit -s -m \"release: v$(node -p \"require('./package.json').version\")\" && git tag v$(node -p \"require('./package.json').version\")",
|
|
48
|
+
"release:publish": "git push && git push --tags && npm publish"
|
|
42
49
|
},
|
|
43
50
|
"files": [
|
|
44
|
-
"
|
|
45
|
-
"
|
|
51
|
+
"src/",
|
|
52
|
+
"!src/*.test.ts",
|
|
46
53
|
"example/"
|
|
47
54
|
]
|
|
48
55
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { spawn } from 'child_process'
|
|
8
8
|
import { mkdir } from 'fs/promises'
|
|
9
|
-
import { PROJECT_ROOT, TMP_DIR } from '
|
|
9
|
+
import { PROJECT_ROOT, TMP_DIR } from './paths.js'
|
|
10
10
|
import type { RunAgentOptions, RunAgentResult } from './types.js'
|
|
11
11
|
|
|
12
12
|
/** runAgent executes an OpenCode agent with a prompt, streaming output in real-time. */
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @example
|
|
7
7
|
* ```typescript
|
|
8
|
-
* import { signature, field,
|
|
9
|
-
* import { z } from 'zod'
|
|
8
|
+
* import { signature, field, module, Pipeline, createBaseState } from 'ocpipe'
|
|
10
9
|
*
|
|
11
10
|
* // Define a signature
|
|
12
11
|
* const ParseIntent = signature({
|
|
@@ -20,18 +19,6 @@
|
|
|
20
19
|
* },
|
|
21
20
|
* })
|
|
22
21
|
*
|
|
23
|
-
* // Create a module (types inferred from signature)
|
|
24
|
-
* class IntentParser extends SignatureModule<typeof ParseIntent> {
|
|
25
|
-
* constructor() {
|
|
26
|
-
* super(ParseIntent)
|
|
27
|
-
* }
|
|
28
|
-
*
|
|
29
|
-
* async forward(input, ctx) {
|
|
30
|
-
* const result = await this.predictor.execute(input, ctx)
|
|
31
|
-
* return result.data
|
|
32
|
-
* }
|
|
33
|
-
* }
|
|
34
|
-
*
|
|
35
22
|
* // Run in a pipeline
|
|
36
23
|
* const pipeline = new Pipeline({
|
|
37
24
|
* name: 'my-workflow',
|
|
@@ -41,7 +28,7 @@
|
|
|
41
28
|
* logDir: './logs',
|
|
42
29
|
* }, createBaseState)
|
|
43
30
|
*
|
|
44
|
-
* const result = await pipeline.run(
|
|
31
|
+
* const result = await pipeline.run(module(ParseIntent), { description: 'Hello world' })
|
|
45
32
|
* ```
|
|
46
33
|
*/
|
|
47
34
|
|
|
@@ -53,7 +40,7 @@ export { Predict } from './predict.js'
|
|
|
53
40
|
export type { PredictConfig } from './predict.js'
|
|
54
41
|
|
|
55
42
|
// Module base class
|
|
56
|
-
export { Module, SignatureModule } from './module.js'
|
|
43
|
+
export { Module, SignatureModule, module } from './module.js'
|
|
57
44
|
|
|
58
45
|
// Pipeline orchestrator
|
|
59
46
|
export { Pipeline } from './pipeline.js'
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
InferOutputs,
|
|
11
11
|
SignatureDef,
|
|
12
12
|
} from './types.js'
|
|
13
|
+
export type { ExecutionContext } from './types.js'
|
|
13
14
|
import { Predict, type PredictConfig } from './predict.js'
|
|
14
15
|
|
|
15
16
|
/** Module is the abstract base class for composable workflow units. */
|
|
@@ -48,3 +49,22 @@ export abstract class SignatureModule<
|
|
|
48
49
|
this.predictor = this.predict(sig, config)
|
|
49
50
|
}
|
|
50
51
|
}
|
|
52
|
+
|
|
53
|
+
/** SimpleModule is a SignatureModule that just executes the predictor. */
|
|
54
|
+
class SimpleModule<S extends SignatureDef<any, any>> extends SignatureModule<S> {
|
|
55
|
+
constructor(sig: S, config?: PredictConfig) {
|
|
56
|
+
super(sig, config)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async forward(input: InferInputs<S>, ctx: ExecutionContext): Promise<InferOutputs<S>> {
|
|
60
|
+
return (await this.predictor.execute(input, ctx)).data
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** module creates a simple Module from a Signature (syntactic sugar). */
|
|
65
|
+
export function module<S extends SignatureDef<any, any>>(
|
|
66
|
+
sig: S,
|
|
67
|
+
config?: PredictConfig,
|
|
68
|
+
): Module<InferInputs<S>, InferOutputs<S>> {
|
|
69
|
+
return new SimpleModule(sig, config)
|
|
70
|
+
}
|
package/src/paths.ts
ADDED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Signatures declare input/output contracts for LLM interactions using Zod for validation.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { z } from 'zod'
|
|
7
|
+
import { z } from 'zod/v4'
|
|
8
8
|
import type { FieldConfig, SignatureDef } from './types.js'
|
|
9
9
|
|
|
10
10
|
/** signature creates a new signature definition. */
|
|
File without changes
|
|
File without changes
|
|
File without changes
|