openfox 2.0.112 → 2.0.113
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/CHANGELOG.md +27 -0
- package/README.md +1 -0
- package/dist/CHANGELOG.md +27 -0
- package/dist/{chat-handler-BYXZIIV3.js → chat-handler-PEK5JDHO.js} +24 -24
- package/dist/{chunk-3UILDGOO.js → chunk-3R43CMLS.js} +8 -8
- package/dist/{chunk-ERYUSG5C.js → chunk-43M7QZMX.js} +2 -2
- package/dist/{chunk-SYJMUIRC.js → chunk-4NMGX5F2.js} +2 -2
- package/dist/{chunk-RAKPI4OE.js → chunk-5VYSKVZT.js} +28 -25
- package/dist/{chunk-FFPCVN5M.js → chunk-6UPBZ2ZR.js} +4 -4
- package/dist/{chunk-C5NQF2K4.js → chunk-AZFZE36I.js} +15 -6
- package/dist/chunk-B2PHPBFU.js +7 -0
- package/dist/{chunk-P45RJGOT.js → chunk-BKCW3JLL.js} +1 -1
- package/dist/{chunk-N4RTAGFY.js → chunk-BNFGDTEU.js} +2 -2
- package/dist/{chunk-JNHKKUGJ.js → chunk-BYSUSSSC.js} +2 -2
- package/dist/{chunk-NB2D6I64.js → chunk-CP44U7BT.js} +5 -5
- package/dist/{chunk-SVJFMZ2Q.js → chunk-EC5T5A6O.js} +11 -4
- package/dist/{chunk-RKMP74BB.js → chunk-EMI3YYLP.js} +3 -3
- package/dist/{chunk-BOSKQI62.js → chunk-FF2EKUQO.js} +4 -4
- package/dist/{chunk-XCK5IBO4.js → chunk-HGOTZWON.js} +41 -19
- package/dist/{chunk-XWNCKIPO.js → chunk-HKD4IMOE.js} +2 -2
- package/dist/{chunk-C372UH7N.js → chunk-KSXCOHHW.js} +18 -20
- package/dist/{chunk-Z56SEG4Z.js → chunk-O2YSYW2F.js} +6 -6
- package/dist/{chunk-UAF2FOI5.js → chunk-ONONXV3N.js} +7 -7
- package/dist/{chunk-LCQ5AN6Y.js → chunk-PWXBIUEY.js} +5 -1
- package/dist/{chunk-33Q7LCVD.js → chunk-R2MTWC7C.js} +2 -2
- package/dist/{chunk-JDT63SSP.js → chunk-SNLLOXCM.js} +3 -3
- package/dist/{chunk-FSYRANYR.js → chunk-TCGWZBTS.js} +3 -4
- package/dist/{chunk-IYTDCPEQ.js → chunk-TEQEDOWI.js} +206 -143
- package/dist/{chunk-PCC4DBPF.js → chunk-V4664YKR.js} +2 -2
- package/dist/{chunk-FR5LUTLQ.js → chunk-VGRVPYZ5.js} +10 -6
- package/dist/{chunk-RT2A2RRL.js → chunk-WWTYWLDM.js} +2 -2
- package/dist/{chunk-6FPGJR7O.js → chunk-XQR76MQ5.js} +2 -2
- package/dist/{chunk-RISQXU32.js → chunk-Y64PEWKP.js} +2 -2
- package/dist/{chunk-QGXLZZBS.js → chunk-YB6WYVNY.js} +2 -2
- package/dist/{chunk-SDGNV45R.js → chunk-YGPPFVLJ.js} +10 -10
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{client-QNQTX5EA.js → client-3LJGD6KY.js} +5 -5
- package/dist/{compactor-X2KZ3XFU.js → compactor-ZBNKANHV.js} +10 -10
- package/dist/{config-TW5FHQEM.js → config-EAB3V4QK.js} +2 -2
- package/dist/{dynamic-context-ZRQO2FJN.js → dynamic-context-F2XTQJR5.js} +9 -9
- package/dist/{events-Y6XXQYFG.js → events-224IO5NJ.js} +7 -7
- package/dist/{folding-Z4GNWRC3.js → folding-YTTTVS56.js} +5 -5
- package/dist/http-client-YC3UA5OZ.js +11 -0
- package/dist/{inspect-proxy-N42Z5TOG.js → inspect-proxy-B7LGGTM7.js} +4 -4
- package/dist/{manager-HCMDFEQH.js → manager-4QGXI6WZ.js} +5 -5
- package/dist/{model-overrides-O3ZYKFP7.js → model-overrides-OY2YKUNV.js} +4 -4
- package/dist/{orchestrator-P5EUMC7E.js → orchestrator-JKBY7B3P.js} +23 -23
- package/dist/package.json +5 -4
- package/dist/{path-security-525YLND3.js → path-security-PFMZY7IA.js} +11 -11
- package/dist/{platform-MEQUWG6U.js → platform-QNGCKX4L.js} +4 -4
- package/dist/{processor-UN4H4V7F.js → processor-NYPJ5PFA.js} +23 -23
- package/dist/{project-creator-BVA55HY6.js → project-creator-AWP2JUFS.js} +3 -3
- package/dist/{projects-PQXME5S4.js → projects-C4353IQK.js} +3 -3
- package/dist/{protocol-D6MISQyz.d.ts → protocol-CBT1d98i.d.ts} +3 -1
- package/dist/{protocol-FTHAR2YL.js → protocol-LZZ7C4VQ.js} +3 -3
- package/dist/provider/index.d.ts +4 -4
- package/dist/{provider-3R4X62LW.js → provider-PIRPN2CC.js} +8 -8
- package/dist/{provider-manager-W5N4XRE5.js → provider-manager-GNEPR6UN.js} +6 -6
- package/dist/{registry-74KPZ5NV.js → registry-VCKDSVKA.js} +4 -4
- package/dist/{serve-WHFUNQ6Z.js → serve-6DRHQLCG.js} +31 -31
- package/dist/server/index.d.ts +7 -4
- package/dist/server/index.js +30 -30
- package/dist/server-HUHFJW7U.js +48 -0
- package/dist/{session-overrides-XH6I3COP.js → session-overrides-RNKV35MU.js} +6 -6
- package/dist/{sessions-D772YTWL.js → sessions-D5CEPQGU.js} +7 -5
- package/dist/{settings-KO6DSJLD.js → settings-BNRNX6IW.js} +3 -3
- package/dist/shared/index.d.ts +3 -3
- package/dist/shared/index.js +1 -1
- package/dist/skill-defaults/workflows/SKILL.md +499 -0
- package/dist/{tools-HTUTYMKI.js → tools-2B363F7L.js} +21 -21
- package/dist/{types-BMEOlLT0.d.ts → types-BAxh20ZL.d.ts} +8 -1
- package/dist/{types-D0TgGL3t.d.ts → types-cVfqOj6M.d.ts} +1 -1
- package/dist/{update-BRUFGGTW.js → update-IQMRYN7J.js} +2 -2
- package/dist/web/assets/{index-nS1p0g8O.css → index-CjWC6EQ4.css} +1 -1
- package/dist/web/assets/index-DBUtUSHK.js +323 -0
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/dist/workflow-defaults/default.workflow.json +41 -3
- package/dist/{workspace-YDUQZ3HC.js → workspace-YUNHV4WS.js} +4 -4
- package/package.json +5 -4
- package/dist/chunk-P5AA7OYJ.js +0 -7
- package/dist/http-client-2GDKHZIG.js +0 -11
- package/dist/server-7MOOJR2N.js +0 -48
- package/dist/web/assets/index-Dukvfqm-.js +0 -323
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: workflows
|
|
3
|
+
description: 'Author and manage OpenFox workflow files (.workflow.json): step types, transition conditions, template variables, and storage locations.'
|
|
4
|
+
metadata:
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
openfox:
|
|
7
|
+
displayName: Workflows
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# OpenFox Workflows — Authoring Reference
|
|
11
|
+
|
|
12
|
+
Authoritative reference for creating and editing OpenFox workflow files (`.workflow.json`).
|
|
13
|
+
Executor implementation: `src/server/workflows/` (`types.ts`, `executor.ts`, `registry.ts`)
|
|
14
|
+
and `src/server/routes/workflows.ts`.
|
|
15
|
+
|
|
16
|
+
A workflow is a declarative **state machine**: a sequence of steps (agent turns, sub-agent
|
|
17
|
+
calls, shell commands, user pauses) wired together by **transitions** with **conditions**.
|
|
18
|
+
The executor walks the graph until it reaches a terminal state (`$done` or `$blocked`).
|
|
19
|
+
|
|
20
|
+
When a user asks you to create or edit a workflow, follow this document.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 1. Storage Locations & Precedence
|
|
25
|
+
|
|
26
|
+
Workflows are plain JSON files with extension `.workflow.json` (never markdown). Three
|
|
27
|
+
tiers, merged **by `metadata.id`** with later tiers overriding earlier ones:
|
|
28
|
+
|
|
29
|
+
| Tier | Location | Notes |
|
|
30
|
+
| ----------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
|
31
|
+
| **Default** | `src/server/workflows/defaults/{id}.workflow.json` (bundled → `dist/workflow-defaults/`) | Ships with the product. Not editable, not deletable. |
|
|
32
|
+
| **User** | `{configDir}/workflows/{id}.workflow.json` | Per-user, machine-local. |
|
|
33
|
+
| **Project** | `{projectDir}/.openfox/workflows/{id}.workflow.json` | Committed to the repo, shared with the team. **Recommended for agent-authored workflows.** |
|
|
34
|
+
|
|
35
|
+
**Precedence (highest wins):** `project > user > default`. A project workflow with the same
|
|
36
|
+
`metadata.id` as a bundled default replaces it everywhere.
|
|
37
|
+
|
|
38
|
+
**Config dirs:** production `~/.config/openfox/`, development `~/.config/openfox-dev/`
|
|
39
|
+
(other platforms: `XDG_CONFIG_HOME`/`~/.config` on Linux, `~/Library/Application Support`
|
|
40
|
+
on macOS, `%APPDATA%` on Windows).
|
|
41
|
+
|
|
42
|
+
**Filename convention:** `{id}.workflow.json` — the loader keys on the embedded
|
|
43
|
+
`metadata.id` (any `*.workflow.json` is read), but every writer uses the ID as the
|
|
44
|
+
filename, so keep them in sync: one workflow per file. `id` is a lowercase slug
|
|
45
|
+
`[a-z0-9-]` (e.g. `build-test-fix`).
|
|
46
|
+
|
|
47
|
+
**Minimum validity** (files failing this are **silently skipped** with a warning — no hard
|
|
48
|
+
error at startup): `metadata.id` is set **and** `steps` is a non-empty array. Malformed
|
|
49
|
+
JSON is also skipped.
|
|
50
|
+
|
|
51
|
+
**API surface:** CRUD routes at `/api/workflows` (`src/server/routes/workflows.ts`) — list,
|
|
52
|
+
get/create/update/delete, duplicate, template-variables. Creating via file is preferred for
|
|
53
|
+
agent-authored workflows because the file is reviewable and committable.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 2. Overall Shape
|
|
58
|
+
|
|
59
|
+
```jsonc
|
|
60
|
+
{
|
|
61
|
+
"metadata": {
|
|
62
|
+
"id": "build-test-fix",
|
|
63
|
+
"name": "Build → Test → Fix",
|
|
64
|
+
"description": "Loop: build, run tests, fix failures.",
|
|
65
|
+
"version": "1.0.0",
|
|
66
|
+
"color": "#3b82f6", // optional, UI accent
|
|
67
|
+
"parameters": [
|
|
68
|
+
// optional, prompted at launch
|
|
69
|
+
{
|
|
70
|
+
"id": "feature",
|
|
71
|
+
"label": "Feature name",
|
|
72
|
+
"description": "What to implement",
|
|
73
|
+
"position": 0, // optional, ordering
|
|
74
|
+
"required": true, // optional, default false
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
"entryStep": "build", // ID of the first step to execute
|
|
79
|
+
"settings": {
|
|
80
|
+
"maxIterations": 50, // safety cap on state-machine iterations
|
|
81
|
+
},
|
|
82
|
+
"steps": [/* see §3 */],
|
|
83
|
+
"startCondition": { "type": "always" }, // optional, gates workflow start
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Field reference
|
|
88
|
+
|
|
89
|
+
| Field | Type | Required | Description |
|
|
90
|
+
| ------------------------ | --------------------- | -------- | -------------------------------------------------------------------------------------------- |
|
|
91
|
+
| `metadata.id` | string | yes | Unique slug; filename stem. Lowercase `[a-z0-9-]`. |
|
|
92
|
+
| `metadata.name` | string | yes | Human-readable display name. |
|
|
93
|
+
| `metadata.description` | string | yes | What the workflow does. |
|
|
94
|
+
| `metadata.version` | string | yes | Semver-ish version string. |
|
|
95
|
+
| `metadata.color` | string | no | Hex color for UI badges. |
|
|
96
|
+
| `metadata.parameters` | `WorkflowParameter[]` | no | User inputs requested at launch (see §6). |
|
|
97
|
+
| `entryStep` | string | yes | ID of the step the workflow starts at. |
|
|
98
|
+
| `settings.maxIterations` | number | yes | Hard cap on executor loop iterations. Exceeding it ⇒ `BLOCKED`. Default in the editor is 50. |
|
|
99
|
+
| `steps` | `WorkflowStep[]` | yes | Non-empty. Order is display-only — execution follows transitions. |
|
|
100
|
+
| `startCondition` | `TransitionCondition` | no | Gates workflow start on session metadata (default: `always`). |
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 3. Steps
|
|
105
|
+
|
|
106
|
+
Every step shares these base fields:
|
|
107
|
+
|
|
108
|
+
| Field | Type | Required | Description |
|
|
109
|
+
| ------------- | -------------- | -------- | -------------------------------------------------------------------------------------------------- |
|
|
110
|
+
| `id` | string | yes | Unique within the workflow. Referenced by `entryStep`, `goto`, `{{stepOutput.id}}`. |
|
|
111
|
+
| `name` | string | yes | Display name. |
|
|
112
|
+
| `phase` | string | yes | Maps to the session phase for UI: `"build"`, `"verification"`, `"waiting"`, `"blocked"`, `"done"`. |
|
|
113
|
+
| `transitions` | `Transition[]` | yes | Evaluated **in order, first match wins**. See §4. |
|
|
114
|
+
| `subGroup` | string | no | Groups steps for running a subset in isolation. See §7. |
|
|
115
|
+
|
|
116
|
+
### 3.1 `agent` — full LLM turn with tools
|
|
117
|
+
|
|
118
|
+
```jsonc
|
|
119
|
+
{
|
|
120
|
+
"id": "implement",
|
|
121
|
+
"name": "Implement",
|
|
122
|
+
"type": "agent",
|
|
123
|
+
"phase": "build",
|
|
124
|
+
"agentId": "builder", // optional, default: resolved default agent (usually "planner")
|
|
125
|
+
"prompt": "Implement {{criteriaCount}} criteria…",
|
|
126
|
+
"nudgePrompt": "Keep going. {{reason}} …", // optional, injected on re-entry
|
|
127
|
+
"transitions": [/* … */],
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
- Runs a full agent turn (LLM + tool loop) with the agent's tool registry.
|
|
132
|
+
- `agentId` defaults to the resolved default agent: DB setting → global config →
|
|
133
|
+
`OPENFOX_DEFAULT_AGENT` env → `"planner"`. Common values: `"builder"`, `"planner"`.
|
|
134
|
+
- `prompt` is injected as a user message **on first entry**, with
|
|
135
|
+
`"\n\nOnce you're done, call step_done()"` appended. Supports template variables (§6).
|
|
136
|
+
- **Advance rule:** the step only advances after the agent calls **`step_done()`**
|
|
137
|
+
successfully. If it finishes without `step_done()`, the executor **loops back to the
|
|
138
|
+
same step** and injects a nudge (`nudgePrompt` if present, plus a `step_done()` reminder).
|
|
139
|
+
If no `prompt` is set and it's the first entry, a generic kickoff
|
|
140
|
+
("Proceed with the current step.") is injected.
|
|
141
|
+
- **Result:** if the agent uses `return_value` (with `result` and/or `content`), those
|
|
142
|
+
become the step's `result` and `stepOutput`; otherwise the result defaults to
|
|
143
|
+
`"completed"`. `stepOutput.stepDoneCalled` is `"true"`/`"false"`.
|
|
144
|
+
|
|
145
|
+
### 3.2 `sub_agent` — isolated sub-agent with fresh context
|
|
146
|
+
|
|
147
|
+
```jsonc
|
|
148
|
+
{
|
|
149
|
+
"id": "verify",
|
|
150
|
+
"name": "Verifier",
|
|
151
|
+
"type": "sub_agent",
|
|
152
|
+
"phase": "verification",
|
|
153
|
+
"subAgentType": "verifier", // required — any configured sub-agent type
|
|
154
|
+
"prompt": "## Criteria\n{{criteriaList}} …",
|
|
155
|
+
"nudgePrompt": "…", // declared in the schema
|
|
156
|
+
"transitions": [/* … */],
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
- Runs one isolated sub-agent turn (fresh context). The `step_done` tool is **removed**
|
|
161
|
+
from sub-agents.
|
|
162
|
+
- `prompt` defaults to `"Perform your task."` if omitted.
|
|
163
|
+
- Unknown `subAgentType` ⇒ the step resolves with `result: "error"`.
|
|
164
|
+
- **Result:** the sub-agent's `return_value` `result`, or `"success"` if none. Content
|
|
165
|
+
lands in `{{stepOutput.content}}`.
|
|
166
|
+
|
|
167
|
+
### 3.3 `shell` — run a command, branch on exit code
|
|
168
|
+
|
|
169
|
+
```jsonc
|
|
170
|
+
{
|
|
171
|
+
"id": "lint",
|
|
172
|
+
"name": "Lint",
|
|
173
|
+
"type": "shell",
|
|
174
|
+
"phase": "verification",
|
|
175
|
+
"command": "npm run lint",
|
|
176
|
+
"timeout": 90000, // optional, ms, default 60000
|
|
177
|
+
"successExitCodes": [0], // optional, default [0]
|
|
178
|
+
"transitions": [/* … */],
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
- `command` runs in the session workdir and supports template variables (§6).
|
|
183
|
+
- **Result:** `"success"` if the exit code is in `successExitCodes`, else `"failure"`.
|
|
184
|
+
- `stepOutput`: `stdout`, `stderr`, `exitCode` (string).
|
|
185
|
+
- The command and its output (truncated to 10k chars) are echoed into the chat as system
|
|
186
|
+
messages.
|
|
187
|
+
|
|
188
|
+
### 3.4 `user` — pause for a human decision
|
|
189
|
+
|
|
190
|
+
```jsonc
|
|
191
|
+
{
|
|
192
|
+
"id": "approve",
|
|
193
|
+
"name": "Approve Fix Plan",
|
|
194
|
+
"type": "user",
|
|
195
|
+
"phase": "verification",
|
|
196
|
+
"transitions": [
|
|
197
|
+
{ "when": { "type": "step_result", "result": "apply" }, "goto": "apply_fixes" },
|
|
198
|
+
{ "when": { "type": "step_result", "result": "skip" }, "goto": "start_dev_server" },
|
|
199
|
+
{ "when": { "type": "always" }, "goto": "apply_fixes" },
|
|
200
|
+
],
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
- Pauses the workflow and presents **buttons derived from the transitions**:
|
|
205
|
+
- each `step_result` transition ⇒ one choice button (its `result` string is both the id
|
|
206
|
+
and the label);
|
|
207
|
+
- an `always` transition ⇒ a `"Continue"` button (`id: "continue"`).
|
|
208
|
+
- On resume, the picked choice becomes the step's `result`; the chosen button's `goto`
|
|
209
|
+
drives the next transition. Selecting "Continue" (or resuming without an explicit choice)
|
|
210
|
+
yields the reserved result `"continue"`, which matches an `always` transition.
|
|
211
|
+
- Use this for approvals, plan sign-off, manual QA gates, etc. Only `step_result` and
|
|
212
|
+
`always` transitions matter for choices; other conditions are ignored when deriving
|
|
213
|
+
buttons.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## 4. Transitions & Conditions
|
|
218
|
+
|
|
219
|
+
Each step carries an ordered `transitions` array. The executor evaluates them **in order
|
|
220
|
+
and takes the first whose `when` matches**. If none matches, the workflow goes `$blocked`
|
|
221
|
+
("Runner blocked: No matching transition").
|
|
222
|
+
|
|
223
|
+
```jsonc
|
|
224
|
+
{ "when": { /* condition */ }, "goto": "next_step_id" | "$done" | "$blocked", "subGroup": "optional" }
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
- `goto` is a step `id` or one of the terminal states:
|
|
228
|
+
- `"$done"` — workflow completes (session phase `done`, stats recorded).
|
|
229
|
+
- `"$blocked"` — workflow stops blocked.
|
|
230
|
+
- `subGroup` on a transition is only meaningful when running that sub-group (§7).
|
|
231
|
+
|
|
232
|
+
### Conditions (all four)
|
|
233
|
+
|
|
234
|
+
| Condition | Matches when |
|
|
235
|
+
| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
236
|
+
| `{ "type": "always" }` | Always. Use as the final fallback to avoid dead ends. |
|
|
237
|
+
| `{ "type": "step_result", "result": "x" }` | The current step returned result exactly `"x"` (from `return_value`, shell exit classification, or a user choice). |
|
|
238
|
+
| `{ "type": "metadata_all_match", "key": "criteria", "field": "status", "value": "passed" }` | **Every** session-metadata entry under `key` has `entry[field] === value`. |
|
|
239
|
+
| `{ "type": "metadata_all_in", "key": "criteria", "field": "status", "values": ["completed","passed"] }` | Every entry's `field` is **one of** `values`. |
|
|
240
|
+
|
|
241
|
+
Notes on metadata conditions:
|
|
242
|
+
|
|
243
|
+
- Operate on the session's metadata entries (managed via the `session_metadata` tool),
|
|
244
|
+
keyed by name — common keys: `criteria` (fields `status`, `description`, …) and
|
|
245
|
+
`review_findings` (field `status`: `open`/`resolved`/`dismissed`).
|
|
246
|
+
- **Empty entry list ⇒ condition is `true`** (vacuous truth). If there are no criteria at
|
|
247
|
+
all, a `metadata_all_match` on `criteria` passes.
|
|
248
|
+
- Evaluated with the **latest** session state after the step executes.
|
|
249
|
+
|
|
250
|
+
Example — build → test → fix loop:
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
build ──(metadata_all_in status completed|passed)──▶ test
|
|
254
|
+
▲ │
|
|
255
|
+
└───────────────(always fallback)─────────────────────┘
|
|
256
|
+
test ──(step_result "passed")────────────────────────▶ $done
|
|
257
|
+
test ──(step_result "failed")────────────────────────▶ fix
|
|
258
|
+
fix ──(always)──────────────────────────────────────▶ test
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## 5. Runtime Semantics (authoring-critical)
|
|
264
|
+
|
|
265
|
+
- **`step_done()` is mandatory for agent steps.** Without it, the step loops back on itself
|
|
266
|
+
with nudges. Write prompts that explicitly end with "call `step_done()`".
|
|
267
|
+
- **Results come from `return_value`** (`result`, `content`). Branch on `step_result`
|
|
268
|
+
conditions. Shell steps produce `success`/`failure` from exit codes; sub-agents default
|
|
269
|
+
to `success`; agent steps default to `completed`.
|
|
270
|
+
- **`maxIterations` caps the whole workflow**, not individual steps. Tight loops +
|
|
271
|
+
`always` self-transitions can burn it fast. Escape loops with `step_result` /
|
|
272
|
+
`metadata_*` conditions.
|
|
273
|
+
- **Blocking:** no matching transition ⇒ `$blocked`. `startCondition` unmet ⇒ blocked
|
|
274
|
+
before the first step. Hitting `maxIterations` ⇒ blocked.
|
|
275
|
+
- **Abort/resume:** aborting mid-workflow keeps the execution record alive; sending a new
|
|
276
|
+
message resumes from the current step.
|
|
277
|
+
- **Phases:** `step.phase` drives the session-phase UI (`build`, `verification`, …) and is
|
|
278
|
+
set as each step runs.
|
|
279
|
+
- **Session mode:** agent steps set the session mode to their `agentId`.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## 6. Template Variables (prompts, nudges, shell commands)
|
|
284
|
+
|
|
285
|
+
The named variables below are the canonical list (the API exposes them via
|
|
286
|
+
`GET /api/workflows/template-variables`); `{{stepOutput.<key>}}` resolves generically
|
|
287
|
+
against the previous step's output map:
|
|
288
|
+
|
|
289
|
+
| Variable | Meaning |
|
|
290
|
+
| ------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
291
|
+
| `{{workdir}}` | Session working directory |
|
|
292
|
+
| `{{reason}}` | Human-readable reason (e.g. "N criteria remaining") |
|
|
293
|
+
| `{{criteriaCount}}` | Total number of criteria |
|
|
294
|
+
| `{{pendingCount}}` | Number of pending/failed criteria |
|
|
295
|
+
| `{{criteriaList}}` | Formatted list of all criteria with status (`[PASSED]`, `[NEEDS VERIFICATION]`, `[FAILED]`, `[NOT COMPLETED]`) |
|
|
296
|
+
| `{{modifiedFiles}}` | Git-diff list of files modified this session |
|
|
297
|
+
| `{{stepOutput.content}}` | Text output of the previous step (agent/sub-agent `return_value` content) |
|
|
298
|
+
| `{{stepOutput.result}}` | Result string of the previous step |
|
|
299
|
+
| `{{stepOutput.stdout}}` | Previous **shell** step stdout |
|
|
300
|
+
| `{{stepOutput.stderr}}` | Previous **shell** step stderr |
|
|
301
|
+
| `{{stepOutput.exitCode}}` | Previous **shell** step exit code |
|
|
302
|
+
| `{{stepOutput.stepDoneCalled}}` | Whether the previous agent step called `step_done()` |
|
|
303
|
+
| `{{params}}` / `{{someParam}}` | User-supplied launch parameters (see below) |
|
|
304
|
+
|
|
305
|
+
- `{{stepOutput.<anything>}}` is resolved generically from the previous step's output map;
|
|
306
|
+
unknown keys render empty.
|
|
307
|
+
- `{{stepOutput.*}}` refers to the **immediately preceding** executed step in the run (not
|
|
308
|
+
the step that transitioned to the current one via a loop).
|
|
309
|
+
- **Parameters:** any `metadata.parameters` entry is collected at launch and injected as
|
|
310
|
+
`{{paramId}}` in prompts/nudges/commands. Parameters resolve last and **cannot override**
|
|
311
|
+
the built-in variables above. Example: the `review` workflow prompts the user for
|
|
312
|
+
`pr_number` and uses `{{pr_number}}` throughout.
|
|
313
|
+
- Deprecated aliases: `{{verifierFindings}}` → `{{stepOutput.content}}`,
|
|
314
|
+
`{{previousStepOutput}}` → `{{stepOutput.stdout}}`.
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## 7. Sub-Groups
|
|
319
|
+
|
|
320
|
+
A `subGroup` string on a step groups related steps so the workflow can be **run in
|
|
321
|
+
isolation as a slice** (e.g. the UI runs just the "code review" group of a larger
|
|
322
|
+
workflow):
|
|
323
|
+
|
|
324
|
+
- Running a sub-group executes **only** steps whose `subGroup` matches, starting at the
|
|
325
|
+
group's first step.
|
|
326
|
+
- Within a group, only transitions with no `subGroup` **or** the same `subGroup` are
|
|
327
|
+
considered.
|
|
328
|
+
- A transition pointing to a step **outside** the active group is treated as `$done` (the
|
|
329
|
+
slice completes).
|
|
330
|
+
|
|
331
|
+
On a full run, `subGroup` is purely organizational (used for display/grouping).
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## 8. Authoring Checklist (do this every time)
|
|
336
|
+
|
|
337
|
+
1. **Choose scope.** Project workflows go in `.openfox/workflows/` (commit them — they're
|
|
338
|
+
part of the repo contract). User-global workflows go in `{configDir}/workflows/`.
|
|
339
|
+
2. **Slug the ID** — lowercase `[a-z0-9-]`, used as filename `{id}.workflow.json` and as
|
|
340
|
+
the override key.
|
|
341
|
+
3. **Fill `metadata`** completely: `id`, `name`, `description`, `version`; add `color` and
|
|
342
|
+
`parameters` when useful.
|
|
343
|
+
4. **Design the graph:** pick `entryStep`, size `settings.maxIterations` generously but
|
|
344
|
+
sanely, and sketch steps + transitions on paper first.
|
|
345
|
+
5. **Give every step** a unique `id`, a readable `name`, and a `phase`.
|
|
346
|
+
6. **Agent steps:** write a concrete `prompt`, end it with "call `step_done()`", and use
|
|
347
|
+
`return_value` (with distinct `result` strings) wherever downstream steps branch on
|
|
348
|
+
outcome. Add `nudgePrompt` for retries when useful.
|
|
349
|
+
7. **Transitions:** order them so specific conditions come first, and **always end with an
|
|
350
|
+
`always` fallback** to prevent `$blocked` dead ends.
|
|
351
|
+
8. **Insert `user` steps** for anything needing a human gate (approvals, test sign-off).
|
|
352
|
+
9. **Validate:** the file must be valid JSON with `metadata.id` + non-empty `steps`, or the
|
|
353
|
+
loader silently skips it. IDs must match `goto`/`entryStep` exactly.
|
|
354
|
+
10. **Test:** launch the workflow (UI "Workflows ›" dropdown or `/api/workflows`) and watch
|
|
355
|
+
for `$blocked`/`Max iterations` outcomes; iterate.
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## 9. Worked Examples
|
|
360
|
+
|
|
361
|
+
### 9.1 Minimal skeleton — linear chain
|
|
362
|
+
|
|
363
|
+
```json
|
|
364
|
+
{
|
|
365
|
+
"metadata": {
|
|
366
|
+
"id": "hello-check",
|
|
367
|
+
"name": "Hello Check",
|
|
368
|
+
"description": "Greet, run tests, report.",
|
|
369
|
+
"version": "1.0.0",
|
|
370
|
+
"color": "#22c55e"
|
|
371
|
+
},
|
|
372
|
+
"entryStep": "greet",
|
|
373
|
+
"settings": { "maxIterations": 10 },
|
|
374
|
+
"steps": [
|
|
375
|
+
{
|
|
376
|
+
"id": "greet",
|
|
377
|
+
"name": "Greet",
|
|
378
|
+
"type": "agent",
|
|
379
|
+
"phase": "build",
|
|
380
|
+
"agentId": "builder",
|
|
381
|
+
"prompt": "Say hi in one line. Then call step_done().",
|
|
382
|
+
"transitions": [{ "when": { "type": "always" }, "goto": "run_tests" }]
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
"id": "run_tests",
|
|
386
|
+
"name": "Run Tests",
|
|
387
|
+
"type": "shell",
|
|
388
|
+
"phase": "verification",
|
|
389
|
+
"command": "npm run test",
|
|
390
|
+
"transitions": [
|
|
391
|
+
{ "when": { "type": "step_result", "result": "success" }, "goto": "report" },
|
|
392
|
+
{ "when": { "type": "always" }, "goto": "$blocked" }
|
|
393
|
+
]
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
"id": "report",
|
|
397
|
+
"name": "Report",
|
|
398
|
+
"type": "agent",
|
|
399
|
+
"phase": "verification",
|
|
400
|
+
"agentId": "builder",
|
|
401
|
+
"prompt": "Tests passed. Summarize in two lines, then call step_done().",
|
|
402
|
+
"transitions": [{ "when": { "type": "always" }, "goto": "$done" }]
|
|
403
|
+
}
|
|
404
|
+
],
|
|
405
|
+
"startCondition": { "type": "always" }
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### 9.2 Rich — loop with metadata gating and a human gate
|
|
410
|
+
|
|
411
|
+
Uses `session_metadata` statuses: builder marks criteria `completed`; verifier flips them
|
|
412
|
+
to `passed`/`failed`; the workflow advances only when all are `passed`, with an `always`
|
|
413
|
+
fallback that loops back to the builder.
|
|
414
|
+
|
|
415
|
+
```json
|
|
416
|
+
{
|
|
417
|
+
"metadata": {
|
|
418
|
+
"id": "review-loop",
|
|
419
|
+
"name": "Review Loop",
|
|
420
|
+
"description": "Implement, verify, human-approve, finalize.",
|
|
421
|
+
"version": "1.0.0",
|
|
422
|
+
"color": "#a371f7"
|
|
423
|
+
},
|
|
424
|
+
"entryStep": "build",
|
|
425
|
+
"settings": { "maxIterations": 50 },
|
|
426
|
+
"steps": [
|
|
427
|
+
{
|
|
428
|
+
"id": "build",
|
|
429
|
+
"name": "Implement",
|
|
430
|
+
"type": "agent",
|
|
431
|
+
"phase": "build",
|
|
432
|
+
"agentId": "builder",
|
|
433
|
+
"prompt": "Fulfil the {{criteriaCount}} criteria. Update each with session_metadata (status completed). Then call step_done().",
|
|
434
|
+
"transitions": [
|
|
435
|
+
{
|
|
436
|
+
"when": {
|
|
437
|
+
"type": "metadata_all_in",
|
|
438
|
+
"key": "criteria",
|
|
439
|
+
"field": "status",
|
|
440
|
+
"values": ["completed", "passed"]
|
|
441
|
+
},
|
|
442
|
+
"goto": "verify"
|
|
443
|
+
},
|
|
444
|
+
{ "when": { "type": "always" }, "goto": "build" }
|
|
445
|
+
]
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
"id": "verify",
|
|
449
|
+
"name": "Verify",
|
|
450
|
+
"type": "sub_agent",
|
|
451
|
+
"phase": "verification",
|
|
452
|
+
"subAgentType": "verifier",
|
|
453
|
+
"prompt": "## Criteria\n{{criteriaList}}\n\nMark each as passed or failed via session_metadata.",
|
|
454
|
+
"transitions": [
|
|
455
|
+
{
|
|
456
|
+
"when": { "type": "metadata_all_match", "key": "criteria", "field": "status", "value": "passed" },
|
|
457
|
+
"goto": "approve"
|
|
458
|
+
},
|
|
459
|
+
{ "when": { "type": "always" }, "goto": "build" }
|
|
460
|
+
]
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
"id": "approve",
|
|
464
|
+
"name": "Approve",
|
|
465
|
+
"type": "user",
|
|
466
|
+
"phase": "verification",
|
|
467
|
+
"transitions": [
|
|
468
|
+
{ "when": { "type": "step_result", "result": "go" }, "goto": "finalize" },
|
|
469
|
+
{ "when": { "type": "step_result", "result": "rework" }, "goto": "build" },
|
|
470
|
+
{ "when": { "type": "always" }, "goto": "finalize" }
|
|
471
|
+
]
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
"id": "finalize",
|
|
475
|
+
"name": "Finalize",
|
|
476
|
+
"type": "agent",
|
|
477
|
+
"phase": "verification",
|
|
478
|
+
"agentId": "builder",
|
|
479
|
+
"prompt": "Wrap up with a summary of what changed, then call step_done().",
|
|
480
|
+
"transitions": [{ "when": { "type": "always" }, "goto": "$done" }]
|
|
481
|
+
}
|
|
482
|
+
],
|
|
483
|
+
"startCondition": { "type": "always" }
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
---
|
|
488
|
+
|
|
489
|
+
## 10. Troubleshooting (authoring mistakes)
|
|
490
|
+
|
|
491
|
+
| Symptom | Likely cause |
|
|
492
|
+
| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
493
|
+
| Workflow doesn't appear at all | File invalid (missing `metadata.id` or empty `steps`) or malformed JSON — loader skips it. Wrong filename (must be `{id}.workflow.json`). |
|
|
494
|
+
| Stuck looping on one agent step | Agent never calls `step_done()`. Add the instruction to the prompt. |
|
|
495
|
+
| "Runner blocked: No matching transition" | No condition matched. Add an `always` fallback, or fix `step_result` strings / metadata field names to match exactly. |
|
|
496
|
+
| Never leaves a step despite `step_result` | Result string mismatch (case/whitespace) or wrong step's output is being inspected (`stepOutput` is the immediately-preceding step). |
|
|
497
|
+
| Blocked immediately at start | `startCondition` (non-`always`) evaluated false against current session metadata. |
|
|
498
|
+
| "Max iterations (N) reached" | Loop lacks a terminating condition. Widen the escape conditions, not just `maxIterations`. |
|
|
499
|
+
| User step shows unexpected/missing buttons | Choices are derived only from `step_result` and `always` transitions of that step. |
|
|
@@ -9,49 +9,49 @@ import {
|
|
|
9
9
|
setMcpTools,
|
|
10
10
|
stepDoneTool,
|
|
11
11
|
validateToolAction
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-5VYSKVZT.js";
|
|
13
|
+
import "./chunk-FF2EKUQO.js";
|
|
14
14
|
import "./chunk-JR54MDZI.js";
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
15
|
+
import "./chunk-HKD4IMOE.js";
|
|
16
|
+
import "./chunk-R2MTWC7C.js";
|
|
17
|
+
import "./chunk-EC5T5A6O.js";
|
|
18
18
|
import "./chunk-I72ACQ6R.js";
|
|
19
19
|
import "./chunk-JE7LW7Y6.js";
|
|
20
20
|
import "./chunk-OAN4BXEW.js";
|
|
21
|
-
import "./chunk-
|
|
21
|
+
import "./chunk-VGRVPYZ5.js";
|
|
22
22
|
import "./chunk-J7GAZGZT.js";
|
|
23
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-SNLLOXCM.js";
|
|
24
24
|
import {
|
|
25
25
|
PathAccessDeniedError,
|
|
26
26
|
cancelPathConfirmationsForSession,
|
|
27
27
|
getConfirmationSessionId,
|
|
28
28
|
providePathConfirmation,
|
|
29
29
|
requestPathAccess
|
|
30
|
-
} from "./chunk-
|
|
31
|
-
import "./chunk-
|
|
32
|
-
import "./chunk-
|
|
33
|
-
import "./chunk-
|
|
30
|
+
} from "./chunk-6UPBZ2ZR.js";
|
|
31
|
+
import "./chunk-CP44U7BT.js";
|
|
32
|
+
import "./chunk-4NMGX5F2.js";
|
|
33
|
+
import "./chunk-BNFGDTEU.js";
|
|
34
34
|
import {
|
|
35
35
|
AskUserInterrupt,
|
|
36
36
|
cancelQuestionsForSession,
|
|
37
37
|
getPendingQuestionsForSession,
|
|
38
38
|
provideAnswer
|
|
39
39
|
} from "./chunk-JURM3RPZ.js";
|
|
40
|
-
import "./chunk-
|
|
41
|
-
import "./chunk-
|
|
42
|
-
import "./chunk-
|
|
40
|
+
import "./chunk-Y64PEWKP.js";
|
|
41
|
+
import "./chunk-XQR76MQ5.js";
|
|
42
|
+
import "./chunk-YB6WYVNY.js";
|
|
43
43
|
import "./chunk-LCLH6ZUL.js";
|
|
44
|
-
import "./chunk-
|
|
45
|
-
import "./chunk-
|
|
44
|
+
import "./chunk-AZFZE36I.js";
|
|
45
|
+
import "./chunk-BYSUSSSC.js";
|
|
46
46
|
import "./chunk-J2GP3J3X.js";
|
|
47
47
|
import "./chunk-V4IE7HJY.js";
|
|
48
48
|
import "./chunk-YHEQTVFV.js";
|
|
49
49
|
import "./chunk-L737Y63F.js";
|
|
50
|
-
import "./chunk-
|
|
51
|
-
import "./chunk-
|
|
50
|
+
import "./chunk-WWTYWLDM.js";
|
|
51
|
+
import "./chunk-PWXBIUEY.js";
|
|
52
52
|
import "./chunk-K44MW7JJ.js";
|
|
53
|
-
import "./chunk-
|
|
54
|
-
import "./chunk-
|
|
53
|
+
import "./chunk-BKCW3JLL.js";
|
|
54
|
+
import "./chunk-KSXCOHHW.js";
|
|
55
55
|
import "./chunk-CQGTEGKL.js";
|
|
56
56
|
import "./chunk-5WRI5ZAA.js";
|
|
57
57
|
export {
|
|
@@ -75,4 +75,4 @@ export {
|
|
|
75
75
|
stepDoneTool,
|
|
76
76
|
validateToolAction
|
|
77
77
|
};
|
|
78
|
-
//# sourceMappingURL=tools-
|
|
78
|
+
//# sourceMappingURL=tools-2B363F7L.js.map
|
|
@@ -23,6 +23,10 @@ interface WorkflowParameter {
|
|
|
23
23
|
position?: number;
|
|
24
24
|
required?: boolean;
|
|
25
25
|
}
|
|
26
|
+
/** Where a workflow definition lives: bundled defaults, global config, or the project's .openfox/. */
|
|
27
|
+
type WorkflowScope = 'builtin' | 'user' | 'project';
|
|
28
|
+
/** Launch scope: an explicit bucket to resolve from, or 'auto' for server precedence (project > user > builtin). */
|
|
29
|
+
type WorkflowLaunchScope = WorkflowScope | 'auto';
|
|
26
30
|
type WorkflowExecutionStatus = 'running' | 'waiting' | 'completed' | 'cancelled' | 'blocked';
|
|
27
31
|
/** A selectable branch presented to the user at a paused user step. */
|
|
28
32
|
interface UserStepChoice {
|
|
@@ -32,6 +36,8 @@ interface UserStepChoice {
|
|
|
32
36
|
label: string;
|
|
33
37
|
/** Target step the choice routes to. */
|
|
34
38
|
goto: string;
|
|
39
|
+
/** Display name of the target step, when it resolves to a step in the workflow. */
|
|
40
|
+
nextStepName?: string;
|
|
35
41
|
}
|
|
36
42
|
interface WorkflowExecution {
|
|
37
43
|
id: string;
|
|
@@ -104,6 +110,7 @@ interface SessionSummary {
|
|
|
104
110
|
mode: SessionMode;
|
|
105
111
|
phase: SessionPhase;
|
|
106
112
|
isRunning: boolean;
|
|
113
|
+
isFavorite: boolean;
|
|
107
114
|
providerId?: string | null;
|
|
108
115
|
providerModel?: string | null;
|
|
109
116
|
createdAt: string;
|
|
@@ -591,4 +598,4 @@ interface ElementData {
|
|
|
591
598
|
attributes: Record<string, string>;
|
|
592
599
|
}
|
|
593
600
|
|
|
594
|
-
export type { Attachment as A, SessionSummary as B, CallStatsDataPoint as C, DangerLevel as D, EditContextEdit as E, FileReadEntry as F, StatsDataPoint as G, StatsIdentity as H, InjectedFile as I, Todo as J, ToolMode as K, LLMCallStats as L, ModelConfig as M, ToolName as N, ToolResult as O, PreparingToolCall as P, WorkflowExecutionStatus as Q, RecentUserPrompt as R, SessionStats as S, ToolCall as T, UserStepChoice as U, ValidationResult as V, WorkflowExecution as W,
|
|
601
|
+
export type { Attachment as A, SessionSummary as B, CallStatsDataPoint as C, DangerLevel as D, EditContextEdit as E, FileReadEntry as F, StatsDataPoint as G, StatsIdentity as H, InjectedFile as I, Todo as J, ToolMode as K, LLMCallStats as L, ModelConfig as M, ToolName as N, ToolResult as O, PreparingToolCall as P, WorkflowExecutionStatus as Q, RecentUserPrompt as R, SessionStats as S, ToolCall as T, UserStepChoice as U, ValidationResult as V, WorkflowExecution as W, WorkflowLaunchScope as X, WorkflowParameter as Y, WorkflowScope as Z, Message as a, Config as b, ContextState as c, ContextWindow as d, Criterion as e, CriterionAttempt as f, CriterionStatus as g, CriterionValidation as h, Diagnostic as i, EditContextLine as j, EditContextRegion as k, ElementData as l, ExecutionState as m, LlmBackend as n, MessageRole as o, MessageSegment as p, MessageStats as q, MetadataEntry as r, ModelSessionStats as s, Project as t, Provider as u, ProviderBackend as v, Session as w, SessionMetadata as x, SessionMode as y, SessionPhase as z };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
VERSION
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-B2PHPBFU.js";
|
|
4
4
|
import "./chunk-5WRI5ZAA.js";
|
|
5
5
|
|
|
6
6
|
// src/cli/update.ts
|
|
@@ -46,4 +46,4 @@ async function runUpdate(options = {}) {
|
|
|
46
46
|
export {
|
|
47
47
|
runUpdate
|
|
48
48
|
};
|
|
49
|
-
//# sourceMappingURL=update-
|
|
49
|
+
//# sourceMappingURL=update-IQMRYN7J.js.map
|