@output.ai/cli 0.4.2 → 0.5.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/README.md +6 -8
- package/dist/assets/docker/docker-compose-dev.yml +9 -1
- package/dist/services/coding_agents.js +180 -8
- package/dist/services/coding_agents.spec.js +54 -11
- package/dist/templates/agent_instructions/AGENTS.md.template +20 -14
- package/dist/templates/agent_instructions/agents/{context_fetcher.md.template → workflow_context_fetcher.md.template} +1 -1
- package/dist/templates/agent_instructions/agents/workflow_debugger.md.template +98 -0
- package/dist/templates/agent_instructions/agents/workflow_planner.md.template +3 -3
- package/dist/templates/agent_instructions/agents/{prompt_writer.md.template → workflow_prompt_writer.md.template} +1 -1
- package/dist/templates/agent_instructions/agents/workflow_quality.md.template +2 -2
- package/dist/templates/agent_instructions/commands/build_workflow.md.template +2 -2
- package/dist/templates/agent_instructions/commands/debug_workflow.md.template +198 -0
- package/dist/templates/agent_instructions/commands/plan_workflow.md.template +3 -3
- package/dist/templates/agent_instructions/skills/output-error-direct-io/SKILL.md.template +249 -0
- package/dist/templates/agent_instructions/skills/output-error-http-client/SKILL.md.template +298 -0
- package/dist/templates/agent_instructions/skills/output-error-missing-schemas/SKILL.md.template +265 -0
- package/dist/templates/agent_instructions/skills/output-error-nondeterminism/SKILL.md.template +252 -0
- package/dist/templates/agent_instructions/skills/output-error-try-catch/SKILL.md.template +226 -0
- package/dist/templates/agent_instructions/skills/output-error-zod-import/SKILL.md.template +209 -0
- package/dist/templates/agent_instructions/skills/output-services-check/SKILL.md.template +128 -0
- package/dist/templates/agent_instructions/skills/output-workflow-list/SKILL.md.template +117 -0
- package/dist/templates/agent_instructions/skills/output-workflow-result/SKILL.md.template +199 -0
- package/dist/templates/agent_instructions/skills/output-workflow-run/SKILL.md.template +228 -0
- package/dist/templates/agent_instructions/skills/output-workflow-runs-list/SKILL.md.template +141 -0
- package/dist/templates/agent_instructions/skills/output-workflow-start/SKILL.md.template +201 -0
- package/dist/templates/agent_instructions/skills/output-workflow-status/SKILL.md.template +151 -0
- package/dist/templates/agent_instructions/skills/output-workflow-stop/SKILL.md.template +164 -0
- package/dist/templates/agent_instructions/skills/output-workflow-trace/SKILL.md.template +134 -0
- package/dist/templates/project/README.md.template +2 -2
- package/dist/templates/project/package.json.template +3 -2
- package/package.json +1 -1
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
argument-hint: [problem-description-and-optional-workflow-id]
|
|
3
|
+
description: Debug Output SDK workflow issues
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
model: claude-opus-4-1
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Your task is to systematically debug an Output SDK workflow issue in a local development environment.
|
|
9
|
+
|
|
10
|
+
The first argument is a textual description of the problem you're experiencing. If you have a specific workflow ID, include it in your description.
|
|
11
|
+
|
|
12
|
+
Use the todo tool to track your progress through the debugging process.
|
|
13
|
+
|
|
14
|
+
# Debugging Process
|
|
15
|
+
|
|
16
|
+
## Overview
|
|
17
|
+
|
|
18
|
+
Follow a systematic approach to identify and resolve workflow execution issues: verify infrastructure, gather evidence, analyze traces, and apply targeted fixes.
|
|
19
|
+
|
|
20
|
+
<pre_flight_check>
|
|
21
|
+
EXECUTE: @.outputai/instructions/meta/pre_flight.md
|
|
22
|
+
</pre_flight_check>
|
|
23
|
+
|
|
24
|
+
<process_flow>
|
|
25
|
+
|
|
26
|
+
<step number="1" name="verify_services">
|
|
27
|
+
|
|
28
|
+
### Step 1: Verify Services Running
|
|
29
|
+
|
|
30
|
+
Before debugging, confirm that all required services are operational. The `output-services-check` skill provides comprehensive guidance.
|
|
31
|
+
|
|
32
|
+
<verification_commands>
|
|
33
|
+
```bash
|
|
34
|
+
# Check Docker containers are running
|
|
35
|
+
docker ps | grep output
|
|
36
|
+
|
|
37
|
+
# Verify Output services respond
|
|
38
|
+
curl -s http://localhost:3001/health || echo "API not responding"
|
|
39
|
+
|
|
40
|
+
# Check Temporal UI is accessible
|
|
41
|
+
curl -s http://localhost:8080 > /dev/null && echo "Temporal UI accessible" || echo "Temporal UI not accessible"
|
|
42
|
+
```
|
|
43
|
+
</verification_commands>
|
|
44
|
+
|
|
45
|
+
<decision_tree>
|
|
46
|
+
IF docker_not_running:
|
|
47
|
+
RUN: docker compose up -d
|
|
48
|
+
WAIT: for services to start (30-60 seconds)
|
|
49
|
+
IF output_dev_not_running:
|
|
50
|
+
RUN: npx output dev
|
|
51
|
+
WAIT: for services to initialize
|
|
52
|
+
IF all_services_running:
|
|
53
|
+
PROCEED: to step 2
|
|
54
|
+
</decision_tree>
|
|
55
|
+
|
|
56
|
+
**Expected State**:
|
|
57
|
+
- Docker containers for `output` are running
|
|
58
|
+
- API server responds at `http://localhost:3001`
|
|
59
|
+
- Temporal UI accessible at `http://localhost:8080`
|
|
60
|
+
|
|
61
|
+
</step>
|
|
62
|
+
|
|
63
|
+
<step number="2" name="list_workflow_runs">
|
|
64
|
+
|
|
65
|
+
### Step 2: List Workflow Runs
|
|
66
|
+
|
|
67
|
+
Identify the failing workflow execution by listing recent runs. The `output-workflow-runs-list` skill provides detailed filtering guidance.
|
|
68
|
+
|
|
69
|
+
<list_commands>
|
|
70
|
+
```bash
|
|
71
|
+
# List all recent workflow runs
|
|
72
|
+
npx output workflow runs list
|
|
73
|
+
|
|
74
|
+
# Filter by specific workflow type (if known)
|
|
75
|
+
npx output workflow runs list <workflowName>
|
|
76
|
+
|
|
77
|
+
# Get detailed JSON output for analysis
|
|
78
|
+
npx output workflow runs list --format json
|
|
79
|
+
|
|
80
|
+
# Limit results to most recent
|
|
81
|
+
npx output workflow runs list --limit 10
|
|
82
|
+
```
|
|
83
|
+
</list_commands>
|
|
84
|
+
|
|
85
|
+
<identification_criteria>
|
|
86
|
+
Look for:
|
|
87
|
+
- Status: FAILED or TERMINATED
|
|
88
|
+
- Recent timestamp matching when the issue occurred
|
|
89
|
+
- Workflow type matching the problem description
|
|
90
|
+
</identification_criteria>
|
|
91
|
+
|
|
92
|
+
<decision_tree>
|
|
93
|
+
IF user_provided_workflow_id:
|
|
94
|
+
USE: provided workflow ID
|
|
95
|
+
PROCEED: to step 3
|
|
96
|
+
IF failed_runs_found:
|
|
97
|
+
SELECT: most recent failed run
|
|
98
|
+
NOTE: workflow ID from output
|
|
99
|
+
PROCEED: to step 3
|
|
100
|
+
IF no_runs_found:
|
|
101
|
+
CHECK: workflow exists with `npx output workflow list`
|
|
102
|
+
IF workflow_not_found:
|
|
103
|
+
REPORT: workflow doesn't exist
|
|
104
|
+
SUGGEST: verify workflow name and location
|
|
105
|
+
ELSE:
|
|
106
|
+
SUGGEST: run the workflow with `npx output workflow run <name>`
|
|
107
|
+
</decision_tree>
|
|
108
|
+
|
|
109
|
+
</step>
|
|
110
|
+
|
|
111
|
+
<step number="3" name="debug_workflow" subagent="workflow-debugger">
|
|
112
|
+
|
|
113
|
+
### Step 3: Debug Specific Workflow
|
|
114
|
+
|
|
115
|
+
Retrieve and analyze the execution trace for the identified workflow. The `output-workflow-trace` skill provides analysis techniques.
|
|
116
|
+
|
|
117
|
+
<debug_commands>
|
|
118
|
+
```bash
|
|
119
|
+
# Display execution trace (text format)
|
|
120
|
+
npx output workflow debug <workflowId>
|
|
121
|
+
|
|
122
|
+
# Display full untruncated trace (JSON format) - recommended for detailed analysis
|
|
123
|
+
npx output workflow debug <workflowId> --format json
|
|
124
|
+
```
|
|
125
|
+
</debug_commands>
|
|
126
|
+
|
|
127
|
+
**Tip**: Use `--format json` for complete trace data without truncation.
|
|
128
|
+
|
|
129
|
+
<analysis_checklist>
|
|
130
|
+
1. Identify which step failed
|
|
131
|
+
2. Examine the error message and stack trace
|
|
132
|
+
3. Check input data passed to the failing step
|
|
133
|
+
4. Check output data from preceding steps
|
|
134
|
+
5. Look for patterns matching common error types
|
|
135
|
+
</analysis_checklist>
|
|
136
|
+
|
|
137
|
+
<temporal_ui_guidance>
|
|
138
|
+
For visual workflow inspection, open the Temporal Web UI at **http://localhost:8080**:
|
|
139
|
+
- Find your workflow execution by ID
|
|
140
|
+
- View the event history timeline
|
|
141
|
+
- Inspect individual step inputs and outputs
|
|
142
|
+
</temporal_ui_guidance>
|
|
143
|
+
|
|
144
|
+
</step>
|
|
145
|
+
|
|
146
|
+
<step number="4" name="suggest_fixes" subagent="workflow-quality">
|
|
147
|
+
|
|
148
|
+
### Step 4: Suggest Fixes
|
|
149
|
+
|
|
150
|
+
Based on the trace analysis, identify the error pattern and suggest targeted fixes. Claude will invoke the relevant error skill based on symptoms.
|
|
151
|
+
|
|
152
|
+
<error_matching>
|
|
153
|
+
|
|
154
|
+
| Symptom | Skill |
|
|
155
|
+
|---------|-------|
|
|
156
|
+
| "incompatible schema" errors, type errors | `output-error-zod-import` |
|
|
157
|
+
| Replay failures, inconsistent results | `output-error-nondeterminism` |
|
|
158
|
+
| Retries not working, errors swallowed | `output-error-try-catch` |
|
|
159
|
+
| Type errors, undefined properties at step boundaries | `output-error-missing-schemas` |
|
|
160
|
+
| Workflow hangs, determinism errors | `output-error-direct-io` |
|
|
161
|
+
| Untraced requests, axios errors | `output-error-http-client` |
|
|
162
|
+
|
|
163
|
+
</error_matching>
|
|
164
|
+
|
|
165
|
+
<decision_tree>
|
|
166
|
+
IF error_matches_known_pattern:
|
|
167
|
+
INVOKE: relevant error skill for detailed fix
|
|
168
|
+
ELSE:
|
|
169
|
+
CONSULT: workflow-quality subagent for additional patterns
|
|
170
|
+
SUGGEST: Manual trace inspection in Temporal UI
|
|
171
|
+
</decision_tree>
|
|
172
|
+
|
|
173
|
+
<verification>
|
|
174
|
+
After applying fix:
|
|
175
|
+
```bash
|
|
176
|
+
# Re-run the workflow to verify
|
|
177
|
+
npx output workflow run <workflowName> <input>
|
|
178
|
+
|
|
179
|
+
# Or start asynchronously and check result
|
|
180
|
+
npx output workflow start <workflowName> <input>
|
|
181
|
+
npx output workflow status <workflowId>
|
|
182
|
+
npx output workflow result <workflowId>
|
|
183
|
+
```
|
|
184
|
+
</verification>
|
|
185
|
+
|
|
186
|
+
</step>
|
|
187
|
+
|
|
188
|
+
</process_flow>
|
|
189
|
+
|
|
190
|
+
<post_flight_check>
|
|
191
|
+
EXECUTE: @.outputai/instructions/meta/post_flight.md
|
|
192
|
+
</post_flight_check>
|
|
193
|
+
|
|
194
|
+
---- START ----
|
|
195
|
+
|
|
196
|
+
Problem Description and Optional Workflow ID:
|
|
197
|
+
|
|
198
|
+
$ARGUMENTS
|
|
@@ -25,7 +25,7 @@ Generate detailed specifications for implementation of a new workflow.
|
|
|
25
25
|
|
|
26
26
|
<process_flow>
|
|
27
27
|
|
|
28
|
-
<step number="1" name="context_gathering" subagent="context-fetcher">
|
|
28
|
+
<step number="1" name="context_gathering" subagent="workflow-context-fetcher">
|
|
29
29
|
|
|
30
30
|
### Step 1: Context Gathering
|
|
31
31
|
|
|
@@ -130,7 +130,7 @@ export const sumValues = step( {
|
|
|
130
130
|
|
|
131
131
|
</step>
|
|
132
132
|
|
|
133
|
-
<step number="5" name="prompt_engineering" subagent="prompt-writer">
|
|
133
|
+
<step number="5" name="prompt_engineering" subagent="workflow-prompt-writer">
|
|
134
134
|
|
|
135
135
|
### Step 5: Prompt Engineering
|
|
136
136
|
|
|
@@ -213,7 +213,7 @@ Design the testing strategy for the workflow.
|
|
|
213
213
|
|
|
214
214
|
Generate the complete plan in markdown format.
|
|
215
215
|
|
|
216
|
-
Note that every implementation should start with running the cli command `output workflow generate --skeleton` to create the workflow directory structure.
|
|
216
|
+
Note that every implementation should start with running the cli command `npx output workflow generate --skeleton` to create the workflow directory structure.
|
|
217
217
|
|
|
218
218
|
<file_template>
|
|
219
219
|
<header>
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: output-error-direct-io
|
|
3
|
+
description: Fix direct I/O in Output SDK workflow functions. Use when workflow hangs, returns undefined, shows "workflow must be deterministic" errors, or when HTTP/API calls are made directly in workflow code.
|
|
4
|
+
allowed-tools: [Bash, Read]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Fix Direct I/O in Workflow Functions
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
This skill helps diagnose and fix a critical error pattern where I/O operations (HTTP calls, database queries, file operations) are performed directly in workflow functions instead of in steps. This violates Temporal's determinism requirements.
|
|
12
|
+
|
|
13
|
+
## When to Use This Skill
|
|
14
|
+
|
|
15
|
+
You're seeing:
|
|
16
|
+
- Workflow hangs indefinitely
|
|
17
|
+
- Undefined or empty responses
|
|
18
|
+
- "workflow must be deterministic" errors
|
|
19
|
+
- Network operations failing silently
|
|
20
|
+
- Timeouts without clear cause
|
|
21
|
+
|
|
22
|
+
## Root Cause
|
|
23
|
+
|
|
24
|
+
Workflow functions must be **deterministic** - they should only orchestrate steps, not perform I/O directly. When you make HTTP calls, database queries, or any external operations directly in a workflow function:
|
|
25
|
+
|
|
26
|
+
1. **Hangs**: The workflow may hang because I/O isn't properly handled
|
|
27
|
+
2. **Determinism violations**: Temporal replays workflows, and I/O results differ
|
|
28
|
+
3. **No retry logic**: Direct calls bypass Output SDK's retry mechanisms
|
|
29
|
+
4. **No tracing**: Operations aren't recorded in the workflow trace
|
|
30
|
+
|
|
31
|
+
## Symptoms
|
|
32
|
+
|
|
33
|
+
### Direct fetch/axios in Workflow
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// WRONG: I/O directly in workflow
|
|
37
|
+
export default workflow({
|
|
38
|
+
fn: async (input) => {
|
|
39
|
+
const response = await fetch('https://api.example.com/data'); // BAD!
|
|
40
|
+
const data = await response.json();
|
|
41
|
+
return { data };
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Direct Database Calls
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// WRONG: Database I/O in workflow
|
|
50
|
+
export default workflow({
|
|
51
|
+
fn: async (input) => {
|
|
52
|
+
const user = await db.users.findById(input.userId); // BAD!
|
|
53
|
+
return { user };
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### File System Operations
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// WRONG: File I/O in workflow
|
|
62
|
+
import fs from 'fs/promises';
|
|
63
|
+
|
|
64
|
+
export default workflow({
|
|
65
|
+
fn: async (input) => {
|
|
66
|
+
const data = await fs.readFile(input.path, 'utf-8'); // BAD!
|
|
67
|
+
return { data };
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Solution
|
|
73
|
+
|
|
74
|
+
Move ALL I/O operations to step functions. Steps are designed to handle non-deterministic operations.
|
|
75
|
+
|
|
76
|
+
### Before (Wrong)
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
export default workflow({
|
|
80
|
+
fn: async (input) => {
|
|
81
|
+
const response = await fetch('https://api.example.com/data');
|
|
82
|
+
const data = await response.json();
|
|
83
|
+
return { data };
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### After (Correct)
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { z, step, workflow } from '@output.ai/core';
|
|
92
|
+
import { httpClient } from '@output.ai/http';
|
|
93
|
+
|
|
94
|
+
// Create a step for the I/O operation
|
|
95
|
+
export const fetchData = step({
|
|
96
|
+
name: 'fetchData',
|
|
97
|
+
inputSchema: z.object({
|
|
98
|
+
endpoint: z.string(),
|
|
99
|
+
}),
|
|
100
|
+
outputSchema: z.object({
|
|
101
|
+
data: z.unknown(),
|
|
102
|
+
}),
|
|
103
|
+
fn: async (input) => {
|
|
104
|
+
const client = httpClient({ prefixUrl: 'https://api.example.com' });
|
|
105
|
+
const data = await client.get(input.endpoint).json();
|
|
106
|
+
return { data };
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Workflow only orchestrates steps
|
|
111
|
+
export default workflow({
|
|
112
|
+
inputSchema: z.object({}),
|
|
113
|
+
outputSchema: z.object({ data: z.unknown() }),
|
|
114
|
+
fn: async (input) => {
|
|
115
|
+
const result = await fetchData({ endpoint: 'data' });
|
|
116
|
+
return result;
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Complete Example: Database Operation
|
|
122
|
+
|
|
123
|
+
### Before (Wrong)
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
export default workflow({
|
|
127
|
+
fn: async (input) => {
|
|
128
|
+
const user = await prisma.user.findUnique({
|
|
129
|
+
where: { id: input.userId }
|
|
130
|
+
});
|
|
131
|
+
const orders = await prisma.order.findMany({
|
|
132
|
+
where: { userId: input.userId }
|
|
133
|
+
});
|
|
134
|
+
return { user, orders };
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### After (Correct)
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
import { z, step, workflow } from '@output.ai/core';
|
|
143
|
+
import { prisma } from '../lib/db';
|
|
144
|
+
|
|
145
|
+
export const fetchUser = step({
|
|
146
|
+
name: 'fetchUser',
|
|
147
|
+
inputSchema: z.object({ userId: z.string() }),
|
|
148
|
+
outputSchema: z.object({
|
|
149
|
+
user: z.object({
|
|
150
|
+
id: z.string(),
|
|
151
|
+
name: z.string(),
|
|
152
|
+
email: z.string(),
|
|
153
|
+
}).nullable(),
|
|
154
|
+
}),
|
|
155
|
+
fn: async (input) => {
|
|
156
|
+
const user = await prisma.user.findUnique({
|
|
157
|
+
where: { id: input.userId }
|
|
158
|
+
});
|
|
159
|
+
return { user };
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
export const fetchOrders = step({
|
|
164
|
+
name: 'fetchOrders',
|
|
165
|
+
inputSchema: z.object({ userId: z.string() }),
|
|
166
|
+
outputSchema: z.object({
|
|
167
|
+
orders: z.array(z.object({
|
|
168
|
+
id: z.string(),
|
|
169
|
+
total: z.number(),
|
|
170
|
+
})),
|
|
171
|
+
}),
|
|
172
|
+
fn: async (input) => {
|
|
173
|
+
const orders = await prisma.order.findMany({
|
|
174
|
+
where: { userId: input.userId }
|
|
175
|
+
});
|
|
176
|
+
return { orders };
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
export default workflow({
|
|
181
|
+
inputSchema: z.object({ userId: z.string() }),
|
|
182
|
+
outputSchema: z.object({
|
|
183
|
+
user: z.unknown(),
|
|
184
|
+
orders: z.array(z.unknown()),
|
|
185
|
+
}),
|
|
186
|
+
fn: async (input) => {
|
|
187
|
+
const { user } = await fetchUser({ userId: input.userId });
|
|
188
|
+
const { orders } = await fetchOrders({ userId: input.userId });
|
|
189
|
+
return { user, orders };
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Finding Direct I/O in Workflows
|
|
195
|
+
|
|
196
|
+
Search for common I/O patterns in workflow files:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Find fetch calls
|
|
200
|
+
grep -rn "await fetch" src/workflows/
|
|
201
|
+
|
|
202
|
+
# Find axios calls
|
|
203
|
+
grep -rn "axios\." src/workflows/
|
|
204
|
+
|
|
205
|
+
# Find database operations
|
|
206
|
+
grep -rn "prisma\.\|db\.\|mongoose\." src/workflows/
|
|
207
|
+
|
|
208
|
+
# Find file system operations
|
|
209
|
+
grep -rn "fs\.\|readFile\|writeFile" src/workflows/
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Then review each match to see if it's in a workflow function vs a step function.
|
|
213
|
+
|
|
214
|
+
## What CAN Be in Workflow Functions
|
|
215
|
+
|
|
216
|
+
Workflow functions should contain:
|
|
217
|
+
- **Step calls**: `await myStep(input)`
|
|
218
|
+
- **Orchestration logic**: conditionals, loops (over step calls)
|
|
219
|
+
- **Data transformation**: Pure functions on step results
|
|
220
|
+
- **Constants**: Static values and configuration
|
|
221
|
+
|
|
222
|
+
Workflow functions should NOT contain:
|
|
223
|
+
- HTTP/API calls
|
|
224
|
+
- Database operations
|
|
225
|
+
- File system operations
|
|
226
|
+
- External service calls
|
|
227
|
+
- Anything that talks to the network or filesystem
|
|
228
|
+
|
|
229
|
+
## Verification
|
|
230
|
+
|
|
231
|
+
After moving I/O to steps:
|
|
232
|
+
|
|
233
|
+
1. **Run the workflow**: `npx output workflow run <name> '<input>'`
|
|
234
|
+
2. **Check the trace**: `npx output workflow debug <id> --format json`
|
|
235
|
+
3. **Verify steps appear**: Look for your I/O steps in the trace
|
|
236
|
+
4. **Confirm no errors**: No determinism warnings or hangs
|
|
237
|
+
|
|
238
|
+
## Benefits of Steps for I/O
|
|
239
|
+
|
|
240
|
+
1. **Retry logic**: Steps can be retried on failure
|
|
241
|
+
2. **Tracing**: I/O operations appear in workflow traces
|
|
242
|
+
3. **Timeouts**: Steps can have individual timeouts
|
|
243
|
+
4. **Determinism**: Replays use recorded results
|
|
244
|
+
5. **Debugging**: Clear visibility into what happened
|
|
245
|
+
|
|
246
|
+
## Related Issues
|
|
247
|
+
|
|
248
|
+
- For HTTP client best practices, see `output-error-http-client`
|
|
249
|
+
- For non-determinism from other causes, see `output-error-nondeterminism`
|