@bastani/atomic 0.8.28-alpha.4 → 0.8.29-alpha.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/CHANGELOG.md +75 -0
- package/dist/builtin/cursor/CHANGELOG.md +27 -0
- package/dist/builtin/cursor/LICENSE +26 -0
- package/dist/builtin/cursor/README.md +22 -0
- package/dist/builtin/cursor/index.ts +9 -0
- package/dist/builtin/cursor/package.json +46 -0
- package/dist/builtin/cursor/src/auth.ts +352 -0
- package/dist/builtin/cursor/src/catalog-cache.ts +155 -0
- package/dist/builtin/cursor/src/config.ts +123 -0
- package/dist/builtin/cursor/src/conversation-state.ts +135 -0
- package/dist/builtin/cursor/src/cursor-models-raw.json +583 -0
- package/dist/builtin/cursor/src/model-mapper.ts +270 -0
- package/dist/builtin/cursor/src/models.ts +54 -0
- package/dist/builtin/cursor/src/native-loader.ts +71 -0
- package/dist/builtin/cursor/src/proto/README.md +34 -0
- package/dist/builtin/cursor/src/proto/agent_pb.ts +15294 -0
- package/dist/builtin/cursor/src/proto/protobuf-codec.ts +717 -0
- package/dist/builtin/cursor/src/provider.ts +301 -0
- package/dist/builtin/cursor/src/stream.ts +564 -0
- package/dist/builtin/cursor/src/transport.ts +791 -0
- package/dist/builtin/intercom/CHANGELOG.md +10 -0
- package/dist/builtin/intercom/package.json +2 -2
- package/dist/builtin/intercom/skills/intercom/SKILL.md +5 -5
- package/dist/builtin/mcp/CHANGELOG.md +10 -0
- package/dist/builtin/mcp/package.json +3 -3
- package/dist/builtin/subagents/CHANGELOG.md +18 -0
- package/dist/builtin/subagents/README.md +7 -3
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +9 -24
- package/dist/builtin/subagents/agents/debugger.md +3 -5
- package/dist/builtin/subagents/package.json +4 -4
- package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +2 -1
- package/dist/builtin/subagents/src/runs/foreground/execution.ts +2 -1
- package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +1 -0
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +19 -2
- package/dist/builtin/subagents/src/runs/shared/structured-output.ts +271 -10
- package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +12 -39
- package/dist/builtin/subagents/src/shared/types.ts +1 -0
- package/dist/builtin/subagents/src/shared/utils.ts +50 -10
- package/dist/builtin/subagents/src/slash/saved-chain-mapping.ts +77 -0
- package/dist/builtin/subagents/src/slash/slash-commands.ts +1 -55
- package/dist/builtin/web-access/CHANGELOG.md +11 -1
- package/dist/builtin/web-access/README.md +1 -1
- package/dist/builtin/web-access/github-extract.ts +1 -1
- package/dist/builtin/web-access/package.json +3 -3
- package/dist/builtin/workflows/CHANGELOG.md +44 -0
- package/dist/builtin/workflows/README.md +19 -1
- package/dist/builtin/workflows/package.json +2 -2
- package/dist/builtin/workflows/skills/research-codebase/SKILL.md +17 -3
- package/dist/builtin/workflows/src/extension/wiring.ts +17 -1
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +34 -0
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +13 -2
- package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +86 -14
- package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +11 -3
- package/dist/builtin/workflows/src/shared/types.ts +8 -4
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +64 -2
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +8 -8
- package/dist/builtin/workflows/src/tui/workflow-status.ts +2 -0
- package/dist/core/builtin-packages.d.ts.map +1 -1
- package/dist/core/builtin-packages.js +6 -0
- package/dist/core/builtin-packages.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/types.d.ts +20 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-resolver.d.ts +1 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +17 -8
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-manager.d.ts +11 -9
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +55 -10
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/project-trust.d.ts +1 -0
- package/dist/core/project-trust.d.ts.map +1 -1
- package/dist/core/project-trust.js +3 -3
- package/dist/core/project-trust.js.map +1 -1
- package/dist/core/resource-loader.d.ts +9 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +72 -9
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +3 -3
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -5
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/structured-output.d.ts +39 -0
- package/dist/core/tools/structured-output.d.ts.map +1 -0
- package/dist/core/tools/structured-output.js +141 -0
- package/dist/core/tools/structured-output.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +36 -14
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +3 -0
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +16 -0
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +11 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +158 -11
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +39 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/docs/custom-provider.md +1 -0
- package/docs/extensions.md +2 -2
- package/docs/models.md +2 -0
- package/docs/packages.md +3 -1
- package/docs/providers.md +15 -0
- package/docs/sdk.md +61 -0
- package/docs/security.md +1 -1
- package/docs/subagents.md +21 -0
- package/docs/usage.md +2 -0
- package/docs/workflows.md +10 -7
- package/examples/extensions/README.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/structured-output.ts +22 -53
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +12 -9
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/web-access",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.29-alpha.2",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
|
|
6
6
|
"contributors": [
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"@bastani/atomic": "*",
|
|
33
|
-
"@earendil-works/pi-tui": "^0.
|
|
33
|
+
"@earendil-works/pi-tui": "^0.79.3"
|
|
34
34
|
},
|
|
35
35
|
"peerDependenciesMeta": {
|
|
36
36
|
"@bastani/atomic": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@mozilla/readability": "^0.6.0",
|
|
45
45
|
"linkedom": "^0.18.12",
|
|
46
|
-
"p-limit": "^
|
|
46
|
+
"p-limit": "^7.3.0",
|
|
47
47
|
"turndown": "^7.2.0",
|
|
48
48
|
"unpdf": "^1.6.2"
|
|
49
49
|
}
|
|
@@ -6,6 +6,50 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Added opt-in schema-backed workflow item results: `ctx.stage(..., { schema })`, `ctx.task(..., { schema })`, `ctx.chain` items, and `ctx.parallel` items now receive a schema-specific `structured_output` tool only for that item, require the final tool call, return the parsed value from `ctx.stage().prompt(...)`, and expose parsed task values as `result.structured` while preserving formatted JSON handoff text ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Aligned the workflows extension with upstream pi TUI `^0.79.3` so workflow graph, custom UI, and prompt-broker integrations inherit the latest shared TUI compatibility fixes.
|
|
16
|
+
- Documented the opt-in `structured_output` workflow path and clarified that ordinary workflow stages do not receive `structured_output` from the default tool registry; schema-enabled items auto-add the runtime tool to explicit `tools` allowlists ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
|
|
17
|
+
- Clarified that workflow `structured_output` gate schemas must be top-level object tool-argument schemas, with arrays and primitives wrapped in object fields before being returned through the terminating tool, and documented the one-`prompt()` limit for schema-backed `StageContext` result contracts ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
|
|
18
|
+
- Documented that terminating workflow-stage `structured_output` JSON stays inline even when large, while artifact-sized handoffs should still be saved to files when downstream stages do not need the full payload in context ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Fixed direct workflow tool validation so schema-enabled `task`, `tasks`, `chain`, and `parallel` items reject array or primitive structured-output schemas at argument-validation time while accepting the same object-root contracts as runtime validation, including object-only `allOf` schemas ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
|
|
23
|
+
- Fixed schema-backed workflow stages to fail with a clear stage-level error when `prompt()` is called more than once on the same `StageContext`, rather than surfacing the lower-level structured-output single-use guard ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
|
|
24
|
+
- Fixed schema-backed workflow model fallback so an attempt that already captured a valid terminating `structured_output` result is treated as successful instead of retrying against fallback models and tripping the single-use result guard ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
|
|
25
|
+
- Fixed the workflow graph overlay remaining interactive when the parent/main-chat agent opens `ask_user_question`: the graph keeps focus, the parent question stays pending behind it with a clear “Main chat needs input — exit graph to answer.” status hint, hiding/exiting the graph focuses the pending question, and host custom-UI state changes no longer hide, restore, remount, or repaint the overlay ([#1353](https://github.com/bastani-inc/atomic/issues/1353)).
|
|
26
|
+
|
|
27
|
+
## [0.8.28] - 2026-06-11
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- Added workflow `ctx.ui.custom<T>(factory, options?)` for graph-visible custom TUI human-in-the-loop prompts. Custom prompts create `awaiting_input` prompt nodes, reuse the stage UI broker/attached stage chat component path, expose the same real TUI/theme/keybinding/component types as Atomic extension custom UI, participate in live-memory prompt replay through hashed custom identities, honor prompt/run abort signals, and reject clearly in headless/unavailable UI modes ([#1309](https://github.com/bastani-inc/atomic/issues/1309)).
|
|
32
|
+
- Added workflow authoring `ctx.exit(options?)` for intentional early terminal runs from any call depth, supporting `completed`, `skipped`, `cancelled`, and `blocked` terminal statuses, optional persisted/displayed reasons, and partial declared outputs with strict validation for provided output keys. Public run/detail/child status unions widen with `skipped`, `cancelled`, and `blocked`, and child workflow results are discriminated by `exited`.
|
|
33
|
+
- Added workflow stage/task `bashPolicy` wiring so individual workflow stages can constrain the built-in `bash` tool with command-level allow/deny rules, command-string glob matching, fail-closed invalid-policy validation, and default-allow no-rule compatibility.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- Changed the builtin `deep-research-codebase`, `goal`, `ralph`, and `open-claude-design` workflows to use `anthropic/claude-fable-5:xhigh` as the primary planner/reviewer/design model, demoting each previous primary to the head of the fallback chain ([#1345](https://github.com/bastani-inc/atomic/pull/1345)).
|
|
38
|
+
- Changed workflow transcript introspection to return `sessionFile`/`transcriptPath` metadata with a lazy-read prompt by default when a transcript path exists, keeping bounded inline previews behind explicit `tail`/`limit` requests ([#1314](https://github.com/bastani-inc/atomic/issues/1314)).
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- Fixed a workflow kill/abort race that could crash the entire CLI with a process-level uncaught exception when a workflow was killed mid-prompt; `raceAbort` now always observes the in-flight promise in the already-aborted branch so a killed run can no longer orphan a rejecting prompt.
|
|
43
|
+
- Fixed `ctx.exit(...)` cleanup races across the executor: the selected exit is a level-triggered gate so delayed `ctx.stage`/`ctx.task`/`ctx.chain`/`ctx.parallel`/`ctx.workflow`/graph-backed `ctx.ui.*` calls and retained `StageContext` session-control methods no longer create artifacts after exit, queued `ctx.parallel` work stops after exit, parent exits cancel linked hidden child workflows with typed parent-exit abort reasons and exactly-once stage-end ordering, and prompt-node abort handling preserves `workflow-exit` skipped reasons.
|
|
44
|
+
- Fixed terminal run-end reconciliation after `ctx.exit(...)` so when an external kill or another terminal writer wins `Store.recordRunEnd(...)`, the returned `RunResult` and `onRunEnd` callback report the canonical store status and only the winning run-end write is persisted.
|
|
45
|
+
- Fixed workflow-boundary child-edge metadata cleanup for `ctx.exit(...)` and continuation replay: skipped/failed boundaries clear `workflowChild`/`workflowChildRun`, stage-end persistence only emits child replay metadata for completed boundary stages, and expanded graph views no longer flatten stale child stages.
|
|
46
|
+
- Fixed `ctx.exit({ outputs })` payload capture to snapshot outputs by value at the first selected exit call, and deep-froze the thrown exit signal so author code cannot rewrite the terminal status, reason, or outputs after the fact.
|
|
47
|
+
- Fixed continuation replay races where replayed stage `prompt`/`complete` or prompt-node finalizers could complete after a concurrent `ctx.exit(...)`; pending replay finalizers now re-check the exit gate so resumed runs skip those stages instead of writing misleading completed stage-end entries.
|
|
48
|
+
- Fixed control-signal probing for arbitrary workflow-thrown values and abort reasons to use non-throwing reads, so throwing or inaccessible author accessors no longer leak from the executor catch path.
|
|
49
|
+
- Fixed interactive `ctx.ui.*` handling so workflow runs degrade gracefully: every primitive is guarded against method-less UI adapters with a clear per-method error, and headless (non-interactive) runs without a UI adapter reject with an explicit actionable message ([#1339](https://github.com/bastani-inc/atomic/issues/1339)).
|
|
50
|
+
- Fixed the builtin `open-claude-design` workflow not installing the browser skill's `browse` CLI before it is needed: a deterministic best-effort setup step probes `PATH` and installs the CLI when missing, per-run bootstrap guidance is injected into every browser-using stage, the install outcome is exposed via a new `browse_cli_status` output, and read-only `read`/`grep`/`ls` tools are granted to the refinement and pre-export decision gates ([#1327](https://github.com/bastani-inc/atomic/issues/1327)).
|
|
51
|
+
- Fixed paused workflow runs being counted as running in `/workflow status` (now shown separately as `❚❚ paused`) and run detail cards to surface the natural `workflow resume` action hint ([#1283](https://github.com/bastani-inc/atomic/issues/1283)).
|
|
52
|
+
|
|
9
53
|
## [0.8.28-alpha.4] - 2026-06-11
|
|
10
54
|
|
|
11
55
|
### Changed
|
|
@@ -264,6 +264,24 @@ Worktree semantics:
|
|
|
264
264
|
|
|
265
265
|
For advanced integrations, the SDK also exports `setupGitWorktree(options)`, which returns `{ worktreeRoot, cwd, repositoryRoot, created }` and uses the same validation/path behavior as the executor.
|
|
266
266
|
|
|
267
|
+
### Structured stage results
|
|
268
|
+
|
|
269
|
+
`structured_output` is opt-in for workflow items. Add `schema` to `ctx.stage`, `ctx.task`, `ctx.chain` items, or `ctx.parallel` items when the stage must finish with machine-readable JSON:
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
const Decision = Type.Object({
|
|
273
|
+
approved: Type.Boolean(),
|
|
274
|
+
findings: Type.Array(Type.String()),
|
|
275
|
+
}, { additionalProperties: false });
|
|
276
|
+
|
|
277
|
+
const decision = await ctx.stage("review-gate", { schema: Decision }).prompt(
|
|
278
|
+
"Review the artifact and return the decision.",
|
|
279
|
+
);
|
|
280
|
+
// decision.approved is typed from the schema.
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Atomic registers the canonical `structured_output` tool only for schema-enabled items, automatically adds it to explicit `tools` allowlists, and fails the item if the model completes without the final tool call. The schema is used directly as the tool argument contract, so wrap arrays or primitives in an object field such as `{ items: [...] }` or `{ value: ... }`. A schema-backed `StageContext` supports one `prompt()` call because the final-answer tool is an exact-once result contract; create another `ctx.stage(..., { schema })` for another structured prompt. `ctx.task`/`ctx.chain`/`ctx.parallel` results expose the parsed value as `result.structured` and keep `result.text` as formatted JSON for handoffs.
|
|
284
|
+
|
|
267
285
|
### Model fallbacks
|
|
268
286
|
|
|
269
287
|
Stages and high-level task helpers can retry transient provider/model failures with an ordered `fallbackModels` list. The primary `model` is tried first, then each fallback, and finally the current Atomic-selected model when available. Fallbacks are only used for retryable model/provider failures such as rate limits, quota/auth/provider outages, unavailable models, network timeouts, and 5xx errors — ordinary tool, shell, validation, cancellation, and workflow-code failures are not retried.
|
|
@@ -501,7 +519,7 @@ Prompt answer replay is live-memory only. `StageSnapshot.promptAnswerState` repo
|
|
|
501
519
|
"async": "optional boolean to dispatch a run in the background",
|
|
502
520
|
"intercom": "optional intercom coordination options",
|
|
503
521
|
"chainDir": "optional directory for direct chain artifacts",
|
|
504
|
-
"session/task options": "per-stage overrides also accepted at the top level and on direct task items — model, thinkingLevel, fallbackModels, tools, noTools, customTools, mcp, context, cwd, output, outputMode, reads, worktree, gitWorktreeDir, baseBranch, maxOutput, artifacts, and more"
|
|
522
|
+
"session/task options": "per-stage overrides also accepted at the top level and on direct task items — schema, model, thinkingLevel, fallbackModels, tools, noTools, customTools, mcp, context, cwd, output, outputMode, reads, worktree, gitWorktreeDir, baseBranch, maxOutput, artifacts, and more"
|
|
505
523
|
}
|
|
506
524
|
}
|
|
507
525
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/workflows",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.29-alpha.2",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension for multi-stage workflow authoring and execution.",
|
|
6
6
|
"contributors": [
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
},
|
|
84
84
|
"peerDependencies": {
|
|
85
85
|
"@bastani/atomic": "*",
|
|
86
|
-
"@earendil-works/pi-tui": "^0.
|
|
86
|
+
"@earendil-works/pi-tui": "^0.79.3"
|
|
87
87
|
},
|
|
88
88
|
"peerDependenciesMeta": {
|
|
89
89
|
"@bastani/atomic": {
|
|
@@ -65,10 +65,24 @@ The user's research question/request is: **$ARGUMENTS**
|
|
|
65
65
|
- The agent fetches live web content using the **browser** skill's `browse` CLI (or `npx browse` / `curl`). Instruct it to apply the token-efficient fetch order: (1) try `curl https://<site>/llms.txt` for an AI-friendly index (see [llmstxt.org](https://llmstxt.org/llms.txt)), (2) try `curl <url> -H "Accept: text/markdown"` to get pre-converted Markdown (supported on Cloudflare-hosted docs via [Markdown for Agents](https://developers.cloudflare.com/fundamentals/reference/markdown-for-agents/)), (3) fall back to HTML parsing via `browse`
|
|
66
66
|
- Instruct the agent to return LINKS with their findings and INCLUDE those links in the research document
|
|
67
67
|
- The agent should persist reusable source documents under `research/web/<YYYY-MM-DD>-<kebab-case-topic>.md` (with frontmatter noting `source_url`, `fetched_at`, and `fetch_method`) so future research can reuse them without re-fetching
|
|
68
|
-
- Output directory for the synthesized research
|
|
68
|
+
- Output directory for the synthesized web research artifacts: `research/web/`:
|
|
69
|
+
|
|
70
|
+
When you fetch a document that is worth keeping for future sessions (reference docs, API schemas, SDK guides, release notes, troubleshooting writeups, architecture articles), `write` it to `research/web/<YYYY-MM-DD>-<kebab-case-topic>.md` with frontmatter capturing:
|
|
71
|
+
|
|
72
|
+
```markdown
|
|
73
|
+
---
|
|
74
|
+
source_url: <original URL>
|
|
75
|
+
fetched_at: <YYYY-MM-DD>
|
|
76
|
+
fetch_method: read | llms.txt | markdown-accept-header | browser | browse
|
|
77
|
+
topic: <short description>
|
|
78
|
+
---
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- Followed by the extracted content (trimmed of nav chrome, ads, and irrelevant boilerplate). This lets future work reuse the lookup without re-fetching. Before fetching anything, quickly `find research/web/` for an existing, recent copy.
|
|
82
|
+
|
|
69
83
|
- Examples:
|
|
70
|
-
- If researching `Redis` locks usage, the agent might find relevant usage and create a document `research/
|
|
71
|
-
- If researching `OAuth` flows, the agent might find relevant external articles and create a document `research/
|
|
84
|
+
- If researching `Redis` locks usage, the agent might find relevant usage and create a document `research/web/2024-01-15-redis-locks-usage.md` with internal links to Redis docs and code references (and cache the fetched Redis docs under `research/web/`)
|
|
85
|
+
- If researching `OAuth` flows, the agent might find relevant external articles and create a document `research/web/2024-01-16-oauth-flows.md` with links to those articles
|
|
72
86
|
|
|
73
87
|
The key is to use these agents intelligently:
|
|
74
88
|
- Start with locator agents to find what exists
|
|
@@ -253,7 +253,7 @@ async function createTestAgentSession(_options?: CreateAgentSessionOptions): Pro
|
|
|
253
253
|
function stripWorkflowOnlyOptions(options: (StageOptions | CreateAgentSessionOptions) | undefined): CreateAgentSessionOptions | undefined {
|
|
254
254
|
if (!options) return options;
|
|
255
255
|
const maybeWorkflowOptions = options as StageOptions;
|
|
256
|
-
const { mcp: _mcp, fallbackModels: _fallbackModels, ...sessionOptions } = maybeWorkflowOptions;
|
|
256
|
+
const { schema: _schema, mcp: _mcp, fallbackModels: _fallbackModels, ...sessionOptions } = maybeWorkflowOptions;
|
|
257
257
|
return sessionOptions as CreateAgentSessionOptions;
|
|
258
258
|
}
|
|
259
259
|
|
|
@@ -499,6 +499,14 @@ export interface PiOverlayHandle {
|
|
|
499
499
|
* (`overlay-adapter.ts`); inline pickers leave it unset and dismiss
|
|
500
500
|
* via the factory `done()` callback.
|
|
501
501
|
*/
|
|
502
|
+
export interface PiHostCustomUiState {
|
|
503
|
+
blockingInlineCustomUiDepth: number;
|
|
504
|
+
blockingInlineCustomUiActive: boolean;
|
|
505
|
+
blockingInlineCustomUiFocusDeferred?: boolean;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
export type PiHostCustomUiStateListener = (state: PiHostCustomUiState) => void;
|
|
509
|
+
|
|
502
510
|
export interface PiCustomOverlayOptions {
|
|
503
511
|
/**
|
|
504
512
|
* `true` mounts a floating popup; `false` mounts a focused
|
|
@@ -506,6 +514,8 @@ export interface PiCustomOverlayOptions {
|
|
|
506
514
|
* place of the editor until the factory's `done()` callback fires.
|
|
507
515
|
*/
|
|
508
516
|
overlay: boolean;
|
|
517
|
+
/** Keep host inline custom UI pending in the background while this overlay is visible. */
|
|
518
|
+
deferInlineCustomUiFocus?: boolean;
|
|
509
519
|
/**
|
|
510
520
|
* Geometry / anchoring intended for pi-tui's `resolveOverlayLayout`.
|
|
511
521
|
* NOT forwarded by current pi interactive `custom()` — see
|
|
@@ -636,6 +646,12 @@ export interface PiUISurface {
|
|
|
636
646
|
setTitle?: (title: string) => void;
|
|
637
647
|
/** Show a custom component or overlay. */
|
|
638
648
|
custom?: PiCustomOverlayFunction;
|
|
649
|
+
/** Get host-owned inline custom UI focus state, if exposed by the host. */
|
|
650
|
+
getHostCustomUiState?: () => PiHostCustomUiState;
|
|
651
|
+
/** Observe host-owned inline custom UI focus state changes, if exposed by the host. */
|
|
652
|
+
onHostCustomUiStateChange?: (listener: PiHostCustomUiStateListener) => () => void;
|
|
653
|
+
/** Move focus to a mounted host-owned inline custom UI, if one is pending. */
|
|
654
|
+
focusHostInlineCustomUi?: () => boolean;
|
|
639
655
|
pasteToEditor?: (text: string) => void;
|
|
640
656
|
setEditorText?: (text: string) => void;
|
|
641
657
|
getEditorText?: () => string;
|
|
@@ -37,6 +37,39 @@ const McpOptionsSchema = Type.Object({
|
|
|
37
37
|
deny: Type.Optional(Type.Array(Type.String())),
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
+
const JsonSchemaObjectTypeValue = {
|
|
41
|
+
anyOf: [
|
|
42
|
+
{ const: "object" },
|
|
43
|
+
{ type: "array", minItems: 1, maxItems: 1, items: { const: "object" } },
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const JsonSchemaExplicitObjectDescriptor = {
|
|
48
|
+
type: "object",
|
|
49
|
+
required: ["type"],
|
|
50
|
+
properties: { type: JsonSchemaObjectTypeValue },
|
|
51
|
+
additionalProperties: true,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const JsonSchemaObject = Type.Unsafe<Record<string, unknown>>({
|
|
55
|
+
description: "Top-level object JSON Schema used as structured_output tool arguments for this workflow item.",
|
|
56
|
+
anyOf: [
|
|
57
|
+
JsonSchemaExplicitObjectDescriptor,
|
|
58
|
+
{
|
|
59
|
+
type: "object",
|
|
60
|
+
required: ["allOf"],
|
|
61
|
+
properties: {
|
|
62
|
+
allOf: {
|
|
63
|
+
type: "array",
|
|
64
|
+
minItems: 1,
|
|
65
|
+
items: JsonSchemaExplicitObjectDescriptor,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
additionalProperties: true,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
});
|
|
72
|
+
|
|
40
73
|
const BashCommandRuleSchema = Type.Union([
|
|
41
74
|
Type.String(),
|
|
42
75
|
Type.Object({ prefix: Type.String() }, { additionalProperties: false }),
|
|
@@ -55,6 +88,7 @@ const BashCommandPolicySchema = Type.Object({
|
|
|
55
88
|
}, { additionalProperties: false });
|
|
56
89
|
|
|
57
90
|
const StageSessionOptionProperties = {
|
|
91
|
+
schema: Type.Optional(JsonSchemaObject),
|
|
58
92
|
cwd: Type.Optional(Type.String()),
|
|
59
93
|
agentDir: Type.Optional(Type.String()),
|
|
60
94
|
authStorage: Type.Optional(SdkSessionOptionSchema("authStorage")),
|
|
@@ -1267,6 +1267,15 @@ function truncateByBytes(text: string, maxBytes: number): { text: string; trunca
|
|
|
1267
1267
|
return { text: text.slice(0, low), truncated: true };
|
|
1268
1268
|
}
|
|
1269
1269
|
|
|
1270
|
+
function structuredTaskOutputText(value: unknown): string {
|
|
1271
|
+
if (typeof value === "string") return value;
|
|
1272
|
+
try {
|
|
1273
|
+
return JSON.stringify(value, null, 2);
|
|
1274
|
+
} catch (error) {
|
|
1275
|
+
throw new Error(`atomic-workflows: structured task output is not JSON-serializable: ${error instanceof Error ? error.message : String(error)}`);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1270
1279
|
function truncateTaskOutput(text: string, maxOutput: WorkflowMaxOutput | undefined): string {
|
|
1271
1280
|
const limits = normalizeMaxOutput(maxOutput);
|
|
1272
1281
|
const byLines = truncateByLines(text, limits.lines);
|
|
@@ -4827,11 +4836,12 @@ export async function run<TInputs extends WorkflowInputValues>(
|
|
|
4827
4836
|
taskStageOptions(resolvedTaskOptions),
|
|
4828
4837
|
stageFailFastScope,
|
|
4829
4838
|
);
|
|
4830
|
-
const
|
|
4839
|
+
const rawOutput = await stage.prompt(
|
|
4831
4840
|
applyTaskContext(`${taskReadInstruction(resolvedTaskOptions)}${taskPrompt(resolvedTaskOptions)}`, taskPrevious(resolvedTaskOptions)),
|
|
4832
4841
|
taskPromptOptions(resolvedTaskOptions),
|
|
4833
4842
|
);
|
|
4834
|
-
const
|
|
4843
|
+
const structured = typeof rawOutput === "string" ? undefined : rawOutput;
|
|
4844
|
+
const text = truncateTaskOutput(structuredTaskOutputText(rawOutput), resolvedTaskOptions.maxOutput);
|
|
4835
4845
|
const sessionId = (() => {
|
|
4836
4846
|
try {
|
|
4837
4847
|
return stage.sessionId;
|
|
@@ -4844,6 +4854,7 @@ export async function run<TInputs extends WorkflowInputValues>(
|
|
|
4844
4854
|
name,
|
|
4845
4855
|
stageName: name,
|
|
4846
4856
|
text,
|
|
4857
|
+
...(structured !== undefined ? { structured: structured as WorkflowSerializableValue } : {}),
|
|
4847
4858
|
...(sessionId !== undefined ? { sessionId } : {}),
|
|
4848
4859
|
...(stage.sessionFile !== undefined ? { sessionFile: stage.sessionFile } : {}),
|
|
4849
4860
|
...(stageMeta.model !== undefined ? { model: stageMeta.model } : {}),
|
|
@@ -10,11 +10,14 @@
|
|
|
10
10
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
11
11
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
12
12
|
import {
|
|
13
|
+
createStructuredOutputCapture,
|
|
14
|
+
createStructuredOutputTool,
|
|
13
15
|
shouldApplyCodexFastModeForScope,
|
|
14
16
|
SessionManager,
|
|
15
17
|
type AgentSession,
|
|
16
18
|
type CreateAgentSessionOptions,
|
|
17
19
|
type PromptOptions,
|
|
20
|
+
type StructuredOutputCapture,
|
|
18
21
|
} from "@bastani/atomic";
|
|
19
22
|
import type {
|
|
20
23
|
CompleteStageOpts,
|
|
@@ -28,6 +31,7 @@ import type {
|
|
|
28
31
|
WorkflowExecutionMode,
|
|
29
32
|
WorkflowModelCatalogPort,
|
|
30
33
|
} from "../../shared/types.js";
|
|
34
|
+
import type { Static, TSchema } from "typebox";
|
|
31
35
|
import {
|
|
32
36
|
buildModelCandidatesFromCatalog,
|
|
33
37
|
errorMessage,
|
|
@@ -167,6 +171,7 @@ export interface InternalStageContext extends StageContext {
|
|
|
167
171
|
function stripWorkflowOnlyOptions(options: StageOptions | undefined): CreateAgentSessionOptions {
|
|
168
172
|
if (!options) return {};
|
|
169
173
|
const {
|
|
174
|
+
schema: _schema,
|
|
170
175
|
mcp: _mcp,
|
|
171
176
|
fallbackModels: _fallbackModels,
|
|
172
177
|
fallbackThinkingLevels: _fallbackThinkingLevels,
|
|
@@ -530,6 +535,43 @@ function splitPromptOptions(options: StagePromptOptions | undefined): {
|
|
|
530
535
|
};
|
|
531
536
|
}
|
|
532
537
|
|
|
538
|
+
const STRUCTURED_OUTPUT_TOOL_NAME = "structured_output";
|
|
539
|
+
|
|
540
|
+
function structuredOutputPrompt(text: string): string {
|
|
541
|
+
return `${text}\n\nFinal output contract:\n- Your final action MUST be a structured_output tool call.\n- Pass the schema fields directly as tool arguments; do not wrap them in { value: ... } unless the schema explicitly defines a top-level value field.\n- Do not emit a prose final answer instead of structured_output.\n- If you need to inspect files or run commands first, do so, then call structured_output exactly once.`;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
function stringifyStructuredOutputValue(value: unknown): string {
|
|
545
|
+
try {
|
|
546
|
+
return JSON.stringify(value, null, 2);
|
|
547
|
+
} catch (error) {
|
|
548
|
+
throw new Error(`atomic-workflows: structured_output returned a non-serializable value: ${error instanceof Error ? error.message : String(error)}`);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function stageOptionsWithStructuredOutput(
|
|
553
|
+
options: StageOptions | undefined,
|
|
554
|
+
capture: StructuredOutputCapture<unknown> | undefined,
|
|
555
|
+
): StageOptions | undefined {
|
|
556
|
+
if (!options?.schema || !capture) return options;
|
|
557
|
+
const tools = options.tools === undefined
|
|
558
|
+
? undefined
|
|
559
|
+
: Array.from(new Set([...options.tools, STRUCTURED_OUTPUT_TOOL_NAME]));
|
|
560
|
+
const excludedTools = options.excludedTools?.filter((toolName) => toolName !== STRUCTURED_OUTPUT_TOOL_NAME);
|
|
561
|
+
return {
|
|
562
|
+
...options,
|
|
563
|
+
...(tools !== undefined ? { tools } : {}),
|
|
564
|
+
...(excludedTools !== undefined ? { excludedTools } : {}),
|
|
565
|
+
customTools: [
|
|
566
|
+
...(options.customTools ?? []),
|
|
567
|
+
createStructuredOutputTool({
|
|
568
|
+
schema: options.schema as TSchema,
|
|
569
|
+
capture: capture as StructuredOutputCapture<Static<TSchema>>,
|
|
570
|
+
}),
|
|
571
|
+
],
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
533
575
|
function validatePromptOutputOptions(outputOptions: StageOutputOptions): void {
|
|
534
576
|
if (outputOptions.outputMode === "file-only" && (typeof outputOptions.output !== "string" || outputOptions.output.length === 0)) {
|
|
535
577
|
throw new Error(
|
|
@@ -564,7 +606,9 @@ async function finalizePromptOutput(
|
|
|
564
606
|
|
|
565
607
|
export function createStageContext(opts: StageRunnerOpts): InternalStageContext {
|
|
566
608
|
const { stageId, stageName, adapters, runId, signal, stageOptions, executionMode } = opts;
|
|
567
|
-
const
|
|
609
|
+
const structuredOutputCapture = stageOptions?.schema ? createStructuredOutputCapture<unknown>() : undefined;
|
|
610
|
+
const effectiveStageOptions = stageOptionsWithStructuredOutput(stageOptions, structuredOutputCapture);
|
|
611
|
+
const meta: StageExecutionMeta = { runId, stageId, stageName, signal, stageOptions: effectiveStageOptions, executionMode };
|
|
568
612
|
let session: StageSessionRuntime | undefined;
|
|
569
613
|
let sessionPromise: Promise<StageSessionRuntime> | undefined;
|
|
570
614
|
let lastAssistantText: string | undefined;
|
|
@@ -633,7 +677,7 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
|
|
|
633
677
|
}
|
|
634
678
|
|
|
635
679
|
const hasExplicitModelFallbackConfig =
|
|
636
|
-
|
|
680
|
+
effectiveStageOptions?.model !== undefined || (effectiveStageOptions?.fallbackModels?.length ?? 0) > 0;
|
|
637
681
|
let candidatesPromise: Promise<WorkflowResolvedModelCandidate[]> | undefined;
|
|
638
682
|
let activeCandidateIndex: number | undefined;
|
|
639
683
|
let selectedModel: string | undefined;
|
|
@@ -653,9 +697,9 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
|
|
|
653
697
|
function modelCandidates(): Promise<WorkflowResolvedModelCandidate[]> {
|
|
654
698
|
if (!candidatesPromise) {
|
|
655
699
|
candidatesPromise = buildModelCandidatesFromCatalog({
|
|
656
|
-
primaryModel:
|
|
657
|
-
fallbackModels:
|
|
658
|
-
fallbackThinkingLevels:
|
|
700
|
+
primaryModel: effectiveStageOptions?.model,
|
|
701
|
+
fallbackModels: effectiveStageOptions?.fallbackModels,
|
|
702
|
+
fallbackThinkingLevels: effectiveStageOptions?.fallbackThinkingLevels,
|
|
659
703
|
catalog: modelCatalog,
|
|
660
704
|
});
|
|
661
705
|
}
|
|
@@ -663,9 +707,9 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
|
|
|
663
707
|
}
|
|
664
708
|
|
|
665
709
|
function stageOptionsForCandidate(candidate: WorkflowResolvedModelCandidate | undefined): StageOptions | undefined {
|
|
666
|
-
if (candidate === undefined) return
|
|
710
|
+
if (candidate === undefined) return effectiveStageOptions;
|
|
667
711
|
return {
|
|
668
|
-
...(
|
|
712
|
+
...(effectiveStageOptions ?? {}),
|
|
669
713
|
model: candidate.value,
|
|
670
714
|
...(candidate.reasoningLevel !== undefined ? { thinkingLevel: candidate.reasoningLevel } : {}),
|
|
671
715
|
fallbackModels: undefined,
|
|
@@ -677,7 +721,7 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
|
|
|
677
721
|
|
|
678
722
|
function isWorkflowFastModeEnabled(): boolean | undefined {
|
|
679
723
|
const model = session?.model;
|
|
680
|
-
const settingsManager = sessionSettingsManager ??
|
|
724
|
+
const settingsManager = sessionSettingsManager ?? effectiveStageOptions?.settingsManager;
|
|
681
725
|
if (model === undefined || settingsManager === undefined) return undefined;
|
|
682
726
|
return shouldApplyCodexFastModeForScope(model, settingsManager.getCodexFastModeSettings(), "workflow");
|
|
683
727
|
}
|
|
@@ -705,7 +749,7 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
|
|
|
705
749
|
}
|
|
706
750
|
|
|
707
751
|
function effectiveCandidateReasoning(candidate: WorkflowResolvedModelCandidate): StageOptions["thinkingLevel"] | undefined {
|
|
708
|
-
return candidate.reasoningLevel ??
|
|
752
|
+
return candidate.reasoningLevel ?? effectiveStageOptions?.thinkingLevel;
|
|
709
753
|
}
|
|
710
754
|
|
|
711
755
|
function modelAttemptReasoning(candidate: WorkflowResolvedModelCandidate): Pick<WorkflowModelAttempt, "reasoningLevel"> {
|
|
@@ -715,7 +759,7 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
|
|
|
715
759
|
|
|
716
760
|
function applyCandidateThinking(candidate: WorkflowResolvedModelCandidate | undefined): void {
|
|
717
761
|
pendingThinkingLevel = candidate === undefined
|
|
718
|
-
?
|
|
762
|
+
? effectiveStageOptions?.thinkingLevel
|
|
719
763
|
: effectiveCandidateReasoning(candidate);
|
|
720
764
|
}
|
|
721
765
|
|
|
@@ -843,6 +887,13 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
|
|
|
843
887
|
}
|
|
844
888
|
|
|
845
889
|
let index = activeCandidateIndex ?? 0;
|
|
890
|
+
const capturedStructuredOutputForAttempt = (): boolean =>
|
|
891
|
+
structuredOutputCapture?.called === true && signal?.aborted !== true;
|
|
892
|
+
const recordSuccessfulAttempt = (candidate: WorkflowResolvedModelCandidate): void => {
|
|
893
|
+
modelAttempts.push({ model: candidate.id, success: true, ...modelAttemptReasoning(candidate) });
|
|
894
|
+
pendingFallbackWarnings.length = 0;
|
|
895
|
+
};
|
|
896
|
+
|
|
846
897
|
while (index < candidates.length) {
|
|
847
898
|
const candidate = candidates[index]!;
|
|
848
899
|
const activeSession = session && activeCandidateIndex === index
|
|
@@ -855,13 +906,20 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
|
|
|
855
906
|
const { terminalScanStartIndex } = await promptWithPauseResume(activeSession, text, sdkOptions);
|
|
856
907
|
const terminalFailure = latestTerminalAssistantFailureSince(activeSession.messages, terminalScanStartIndex);
|
|
857
908
|
if (terminalFailure !== undefined) {
|
|
909
|
+
if (capturedStructuredOutputForAttempt()) {
|
|
910
|
+
recordSuccessfulAttempt(candidate);
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
858
913
|
throw new WorkflowPromptModelFailure(terminalFailure);
|
|
859
914
|
}
|
|
860
|
-
|
|
861
|
-
pendingFallbackWarnings.length = 0;
|
|
915
|
+
recordSuccessfulAttempt(candidate);
|
|
862
916
|
return;
|
|
863
917
|
} catch (err) {
|
|
864
918
|
const message = errorMessage(err);
|
|
919
|
+
if (capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
|
|
920
|
+
recordSuccessfulAttempt(candidate);
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
865
923
|
modelAttempts.push({ model: candidate.id, success: false, ...modelAttemptReasoning(candidate), error: message });
|
|
866
924
|
if (signal?.aborted || !isRetryableModelFailure(err) || index === candidates.length - 1) {
|
|
867
925
|
modelWarnings.push(...pendingFallbackWarnings);
|
|
@@ -887,15 +945,29 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
|
|
|
887
945
|
|
|
888
946
|
async prompt(text, options) {
|
|
889
947
|
const { sdkOptions, outputOptions } = splitPromptOptions(options);
|
|
890
|
-
const runtimeCwd = typeof
|
|
948
|
+
const runtimeCwd = typeof effectiveStageOptions?.cwd === "string" ? effectiveStageOptions.cwd : process.cwd();
|
|
891
949
|
validatePromptOutputOptions(outputOptions);
|
|
950
|
+
if (structuredOutputCapture?.called) {
|
|
951
|
+
throw new Error("atomic-workflows: stage schema supports one prompt() call per stage context because structured_output may be called exactly once. Create a new ctx.stage(...) for each additional schema-backed prompt.");
|
|
952
|
+
}
|
|
892
953
|
if (adapters.prompt) {
|
|
954
|
+
if (structuredOutputCapture) {
|
|
955
|
+
throw new Error("atomic-workflows: stage schema requires an AgentSessionAdapter so the structured_output tool can be registered.");
|
|
956
|
+
}
|
|
893
957
|
const rawText = await adapters.prompt.prompt(text, meta);
|
|
894
958
|
lastAssistantText = await finalizePromptOutput(rawText, outputOptions, runtimeCwd);
|
|
895
959
|
adapterMessages = assistantMessage(lastAssistantText);
|
|
896
960
|
return lastAssistantText;
|
|
897
961
|
}
|
|
898
|
-
await promptWithFallback(text, sdkOptions);
|
|
962
|
+
await promptWithFallback(structuredOutputCapture ? structuredOutputPrompt(text) : text, sdkOptions);
|
|
963
|
+
if (structuredOutputCapture) {
|
|
964
|
+
if (!structuredOutputCapture.called) {
|
|
965
|
+
throw new Error("atomic-workflows: stage configured with schema must finish by calling structured_output.");
|
|
966
|
+
}
|
|
967
|
+
const rawStructuredText = stringifyStructuredOutputValue(structuredOutputCapture.value);
|
|
968
|
+
lastAssistantText = await finalizePromptOutput(rawStructuredText, outputOptions, runtimeCwd);
|
|
969
|
+
return structuredOutputCapture.value as never;
|
|
970
|
+
}
|
|
899
971
|
const rawText = lastAssistantTextFromSession(session, lastAssistantText, terminatingToolCallIds) ?? "";
|
|
900
972
|
lastAssistantText = await finalizePromptOutput(rawText, outputOptions, runtimeCwd);
|
|
901
973
|
return lastAssistantText;
|
|
@@ -48,6 +48,7 @@ export interface WorkflowModelFallbackFields {
|
|
|
48
48
|
readonly fallbackThinkingLevels?: readonly string[];
|
|
49
49
|
}
|
|
50
50
|
export type WorkflowModelValue = string | object;
|
|
51
|
+
export type WorkflowStageResult<TSchemaDef extends TSchema | undefined = undefined> = [TSchemaDef] extends [TSchema] ? Static<TSchemaDef> : string;
|
|
51
52
|
export interface WorkflowModelUsage extends WorkflowSerializableObject {
|
|
52
53
|
readonly input?: number;
|
|
53
54
|
readonly output?: number;
|
|
@@ -111,7 +112,9 @@ export interface WorkflowFastModeSettings extends WorkflowSerializableObject {
|
|
|
111
112
|
export interface WorkflowFastModeSettingsManager {
|
|
112
113
|
getCodexFastModeSettings(): WorkflowFastModeSettings;
|
|
113
114
|
}
|
|
114
|
-
export interface StageOptions extends WorkflowModelFallbackFields {
|
|
115
|
+
export interface StageOptions<TSchemaDef extends TSchema | undefined = TSchema | undefined> extends WorkflowModelFallbackFields {
|
|
116
|
+
/** Optional structured final-answer schema. When set, the stage receives a schema-specific `structured_output` tool and must finish by calling it. */
|
|
117
|
+
readonly schema?: TSchemaDef;
|
|
115
118
|
readonly model?: WorkflowModelValue;
|
|
116
119
|
readonly mcp?: StageMcpOptions;
|
|
117
120
|
readonly tools?: readonly string[];
|
|
@@ -231,9 +234,9 @@ export interface StageAdapters {
|
|
|
231
234
|
readonly prompt?: PromptAdapter;
|
|
232
235
|
readonly complete?: CompleteAdapter;
|
|
233
236
|
}
|
|
234
|
-
export interface StageContext {
|
|
237
|
+
export interface StageContext<TSchemaDef extends TSchema | undefined = undefined> {
|
|
235
238
|
readonly name: string;
|
|
236
|
-
prompt(text: string, options?: StagePromptOptions): Promise<
|
|
239
|
+
prompt(text: string, options?: StagePromptOptions): Promise<WorkflowStageResult<TSchemaDef>>;
|
|
237
240
|
complete(text: string, options?: CompleteStageOpts): Promise<string>;
|
|
238
241
|
steer(text: string): Promise<void>;
|
|
239
242
|
followUp(text: string): Promise<void>;
|
|
@@ -279,6 +282,8 @@ export interface WorkflowTaskContext extends WorkflowSerializableObject {
|
|
|
279
282
|
export type WorkflowTaskContextInput = string | WorkflowTaskContext | WorkflowTaskResult;
|
|
280
283
|
export interface WorkflowTaskResult extends WorkflowTaskContext {
|
|
281
284
|
readonly stageName: string;
|
|
285
|
+
/** Parsed structured value when the task/stage was configured with `schema`. */
|
|
286
|
+
readonly structured?: WorkflowSerializableValue;
|
|
282
287
|
readonly sessionId?: string;
|
|
283
288
|
readonly sessionFile?: string;
|
|
284
289
|
readonly artifacts?: readonly WorkflowArtifact[];
|
|
@@ -400,6 +405,9 @@ export interface WorkflowRunContext<TInputs extends WorkflowInputValues = Workfl
|
|
|
400
405
|
readonly inputs: Readonly<TInputs>;
|
|
401
406
|
readonly cwd?: string;
|
|
402
407
|
exit(options?: WorkflowExitOptions<TOutputs>): never;
|
|
408
|
+
stage<TSchemaDef extends TSchema>(name: string, options: StageOptions<TSchemaDef> & {
|
|
409
|
+
readonly schema: TSchemaDef;
|
|
410
|
+
}): StageContext<TSchemaDef>;
|
|
403
411
|
stage(name: string, options?: StageOptions): StageContext;
|
|
404
412
|
task(name: string, options: WorkflowTaskOptions): Promise<WorkflowTaskResult>;
|
|
405
413
|
chain(steps: readonly WorkflowTaskStep[], options?: WorkflowChainOptions): Promise<WorkflowTaskResult[]>;
|
|
@@ -153,9 +153,11 @@ export interface StageMcpOptions extends AuthoringContract.StageMcpOptions {
|
|
|
153
153
|
* All pi SDK createAgentSession options are forwarded to the stage session;
|
|
154
154
|
* workflow-owned options such as `mcp` and `gitWorktreeDir` are stripped before SDK session creation.
|
|
155
155
|
*/
|
|
156
|
-
export interface StageOptions
|
|
156
|
+
export interface StageOptions<TSchemaDef extends TSchema | undefined = TSchema | undefined>
|
|
157
157
|
extends Omit<CreateAgentSessionOptions, "model" | keyof AuthoringContract.StageOptions>,
|
|
158
|
-
Omit<Mutable<AuthoringContract.StageOptions
|
|
158
|
+
Omit<Mutable<AuthoringContract.StageOptions<TSchemaDef>>, "sessionManager" | "settingsManager"> {
|
|
159
|
+
/** Optional structured final-answer schema. When set, the stage receives a schema-specific `structured_output` tool and must finish by calling it. */
|
|
160
|
+
schema?: TSchemaDef;
|
|
159
161
|
/** Model id or pi SDK model object used as the primary stage model. */
|
|
160
162
|
model?: WorkflowModelValue;
|
|
161
163
|
/** Per-stage MCP server gating. No-op when no WorkflowMcpPort is configured. */
|
|
@@ -231,6 +233,7 @@ export interface WorkflowPersistencePort {
|
|
|
231
233
|
export type WorkflowTaskContext = AuthoringContract.WorkflowTaskContext;
|
|
232
234
|
export type WorkflowTaskContextInput = AuthoringContract.WorkflowTaskContextInput;
|
|
233
235
|
export type WorkflowTaskResult = AuthoringContract.WorkflowTaskResult;
|
|
236
|
+
export type WorkflowStageResult<TSchemaDef extends TSchema | undefined = undefined> = AuthoringContract.WorkflowStageResult<TSchemaDef>;
|
|
234
237
|
|
|
235
238
|
/**
|
|
236
239
|
* Higher-level task API: create a tracked stage, optionally inject prior task
|
|
@@ -276,12 +279,12 @@ export interface WorkflowDirectOptions extends StageOptions, Omit<Mutable<Author
|
|
|
276
279
|
* This exposes the supported subset of pi's SDK AgentSession. The workflow
|
|
277
280
|
* executor owns disposal and wraps prompt() with stage lifecycle tracking.
|
|
278
281
|
*/
|
|
279
|
-
export interface StageContext {
|
|
282
|
+
export interface StageContext<TSchemaDef extends TSchema | undefined = undefined> {
|
|
280
283
|
/** Human-readable name for this stage (used in TUI + persistence). */
|
|
281
284
|
readonly name: string;
|
|
282
285
|
|
|
283
286
|
/** Send a prompt and wait for completion. */
|
|
284
|
-
prompt(text: string, options?: StagePromptOptions): Promise<
|
|
287
|
+
prompt(text: string, options?: StagePromptOptions): Promise<WorkflowStageResult<TSchemaDef>>;
|
|
285
288
|
complete(text: string, options?: CompleteStageOpts): Promise<string>;
|
|
286
289
|
|
|
287
290
|
/** Queue messages during streaming. */
|
|
@@ -344,6 +347,7 @@ export interface WorkflowRunContext<
|
|
|
344
347
|
* @param name Human-readable stage name (used in TUI + persistence).
|
|
345
348
|
* @param options Optional per-stage configuration (mcp allow/deny, etc.).
|
|
346
349
|
*/
|
|
350
|
+
stage<TSchemaDef extends TSchema>(name: string, options: StageOptions<TSchemaDef> & { schema: TSchemaDef }): StageContext<TSchemaDef>;
|
|
347
351
|
stage(name: string, options?: StageOptions): StageContext;
|
|
348
352
|
/**
|
|
349
353
|
* Safe high-level task primitive. Equivalent to creating a named stage and
|