indusagi-coding-agent 0.2.2 → 0.2.3
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 +21 -0
- package/dist/entry.js +10975 -9147
- package/dist/guardrails.js +876 -31
- package/dist/index.js +12738 -10903
- package/dist/types/boot/runners/delegate-runner.d.ts +6 -0
- package/dist/types/boot/runners/session.d.ts +2 -17
- package/dist/types/capability-deck/cards/index.d.ts +1 -0
- package/dist/types/capability-deck/cards/task-card.d.ts +26 -2
- package/dist/types/capability-deck/cards/workflow-card.d.ts +55 -0
- package/dist/types/capability-deck/cards/workflow-card.test.d.ts +12 -0
- package/dist/types/capability-deck/index.d.ts +1 -1
- package/dist/types/conductor/contract.d.ts +8 -0
- package/dist/types/conductor/signal-hub/translate.d.ts +4 -1
- package/dist/types/console/components/AgentsView.d.ts +41 -0
- package/dist/types/console/components/BackgroundAgents.d.ts +63 -0
- package/dist/types/console/components/BackgroundAgents.test.d.ts +8 -0
- package/dist/types/console/components/Banner.d.ts +67 -33
- package/dist/types/console/components/welcome.d.ts +115 -0
- package/dist/types/console/components/welcome.test.d.ts +9 -0
- package/dist/types/console/contract.d.ts +3 -1
- package/dist/types/console/index.d.ts +3 -0
- package/dist/types/console/input/keymap.d.ts +1 -1
- package/dist/types/console/input/paste.d.ts +5 -5
- package/dist/types/console/overlays/boards.d.ts +55 -0
- package/dist/types/console/theme/adapter.d.ts +1 -1
- package/dist/types/console/theme/index.d.ts +1 -1
- package/dist/types/console/theme/palette.d.ts +10 -0
- package/dist/types/workflow-engine/agent-runner.d.ts +105 -0
- package/dist/types/workflow-engine/agent-runner.test.d.ts +8 -0
- package/dist/types/workflow-engine/display.d.ts +148 -0
- package/dist/types/workflow-engine/display.test.d.ts +1 -0
- package/dist/types/workflow-engine/engine.d.ts +183 -0
- package/dist/types/workflow-engine/engine.test.d.ts +1 -0
- package/dist/types/workflow-engine/index.d.ts +21 -0
- package/dist/types/workflow-engine/parse.d.ts +64 -0
- package/dist/types/workflow-engine/parse.test.d.ts +1 -0
- package/dist/types/workflow-engine/structured-output.d.ts +51 -0
- package/dist/types/workflow-engine/structured-output.test.d.ts +1 -0
- package/dist/types/workspace/brand.d.ts +1 -1
- package/package.json +2 -2
- package/dist/types/console/components/Emblem.d.ts +0 -49
|
@@ -82,7 +82,7 @@ export interface KeyChord {
|
|
|
82
82
|
* - `flow:cycleModel` — rotate to the next model.
|
|
83
83
|
*
|
|
84
84
|
* Model / reasoning
|
|
85
|
-
* - `model:cycleThinking` — advance the reasoning-effort ladder one step.
|
|
85
|
+
* - `model:cycleThinking` — advance the reasoning-effort ladder one step (via /thinking command).
|
|
86
86
|
*
|
|
87
87
|
* Permission mode
|
|
88
88
|
* - `mode:cyclePermission` — cycle through ALL permission modes (Shift+Tab),
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
* the whole paste pipeline is unit-tested in isolation. The component owns only
|
|
25
25
|
* the live vault value and the burst-coalescing timer; the decisions are here.
|
|
26
26
|
*
|
|
27
|
-
* The marker format is the console's own:
|
|
28
|
-
* 1-based mint order and `K` is the hidden line count.
|
|
27
|
+
* The marker format is the console's own: `[Pasted text #N +K lines]`, where `N` is the
|
|
28
|
+
* 1-based mint order and `K` is the hidden line count. Matches induscode style:
|
|
29
29
|
* visually distinct in the composer, unambiguous to match, and trivial to strip.
|
|
30
30
|
*/
|
|
31
31
|
/**
|
|
@@ -69,14 +69,14 @@ export declare function classifyPaste(chunk: string, thresholds?: PasteThreshold
|
|
|
69
69
|
/**
|
|
70
70
|
* The immutable marker → body store.
|
|
71
71
|
*
|
|
72
|
-
* `bodies` maps each
|
|
72
|
+
* `bodies` maps each ordinal number to the exact text it hides; `minted`
|
|
73
73
|
* is the running count that drives the next ordinal. The store is replaced (not
|
|
74
74
|
* mutated) on every coalesce, so the surface holds it as a plain value and React
|
|
75
75
|
* reconciliation stays correct.
|
|
76
76
|
*/
|
|
77
77
|
export interface PasteVault {
|
|
78
|
-
/**
|
|
79
|
-
readonly bodies: ReadonlyMap<
|
|
78
|
+
/** Ordinal number → the original pasted text it stands for. */
|
|
79
|
+
readonly bodies: ReadonlyMap<number, string>;
|
|
80
80
|
/** How many markers have been minted so far (the next ordinal is this + 1). */
|
|
81
81
|
readonly minted: number;
|
|
82
82
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Saffron picker boards — the themed `/settings` and `/model` overlays styled to
|
|
3
|
+
* the "IndusCode Saffron · Settings · Config" design.
|
|
4
|
+
*
|
|
5
|
+
* The framework ships plain (un-themed) `SettingsDialog` / `ModelDialog`. These
|
|
6
|
+
* boards are the console's own theme-aware replacements for those two pickers: a
|
|
7
|
+
* saffron tab-pill header, a teal-bordered search box with a magnifier and a
|
|
8
|
+
* block caret, a two-column list whose values are tinted by kind (on/true →
|
|
9
|
+
* green, off/false → dim, everything else → teal), a windowed "↓ N more" hint,
|
|
10
|
+
* and a top-ruled footer of key hints. They reuse the framework's pure
|
|
11
|
+
* {@link matchesSearchQuery} / {@link wrapSelectionIndex} helpers (and the
|
|
12
|
+
* {@link SettingsDialogItem} shape) so only the *presentation* is re-authored,
|
|
13
|
+
* not the filter/navigation logic.
|
|
14
|
+
*
|
|
15
|
+
* All colour comes through the framework {@link InkThemeAdapter} the overlay
|
|
16
|
+
* group already holds, so the boards recolour with the active scheme; the one
|
|
17
|
+
* raw-hex touch is the chalk tab-pill (dark text on the accent fill), which has
|
|
18
|
+
* no theme role to resolve against.
|
|
19
|
+
*/
|
|
20
|
+
import { type InkThemeAdapter, type SettingsDialogItem } from "indusagi/react-ink";
|
|
21
|
+
import type { Model } from "indusagi/ai";
|
|
22
|
+
/** What the {@link SettingsBoard} renders. */
|
|
23
|
+
export interface SettingsBoardProps {
|
|
24
|
+
/** The framework adapter that turns token roles into terminal colours. */
|
|
25
|
+
readonly theme: InkThemeAdapter;
|
|
26
|
+
/** The settings rows to present and cycle. */
|
|
27
|
+
readonly items: readonly SettingsDialogItem[];
|
|
28
|
+
/** Invoked when the board is dismissed. */
|
|
29
|
+
readonly onClose: () => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The saffron `/settings` board: a filterable, value-cycling settings list in the
|
|
33
|
+
* design's look. Up/Down move (wrapping), Left/Right or Enter cycle the value,
|
|
34
|
+
* typing filters, Ctrl+U clears, Esc closes.
|
|
35
|
+
*/
|
|
36
|
+
export declare function SettingsBoard({ theme, items, onClose }: SettingsBoardProps): JSX.Element;
|
|
37
|
+
/** What the {@link ModelBoard} renders. */
|
|
38
|
+
export interface ModelBoardProps {
|
|
39
|
+
/** The framework adapter that turns token roles into terminal colours. */
|
|
40
|
+
readonly theme: InkThemeAdapter;
|
|
41
|
+
/** The selectable models. */
|
|
42
|
+
readonly models: readonly Model<any>[];
|
|
43
|
+
/** Optional initial search query. */
|
|
44
|
+
readonly search?: string;
|
|
45
|
+
/** Invoked with the chosen model. */
|
|
46
|
+
readonly onSelect: (model: Model<any>) => void | Promise<void>;
|
|
47
|
+
/** Invoked when the board is dismissed. */
|
|
48
|
+
readonly onClose: () => void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The saffron `/model` board: a filterable model list in the design's look.
|
|
52
|
+
* Up/Down move (wrapping), Enter selects, typing filters, Ctrl+U clears, Esc
|
|
53
|
+
* closes.
|
|
54
|
+
*/
|
|
55
|
+
export declare function ModelBoard({ theme, models, onClose, onSelect, search }: ModelBoardProps): JSX.Element;
|
|
@@ -34,7 +34,7 @@ import type { InkThemeAdapter, ThemeTokens } from "../contract";
|
|
|
34
34
|
* accent ← signal (primary accent the components highlight in)
|
|
35
35
|
* borderMuted ← quietFrame (de-emphasised borders/separators)
|
|
36
36
|
* bashBorder ← frame (the bash-block border tone)
|
|
37
|
-
* userMessage ←
|
|
37
|
+
* userMessage ← "" (no background, plain text)
|
|
38
38
|
* customMessage ← cardAccent (custom/plugin message background tint)
|
|
39
39
|
* success ← affirm
|
|
40
40
|
* warning ← caution
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* Consumers import from `src/console/theme` and never reach into the individual
|
|
13
13
|
* palette/tokens/adapter/resolve modules.
|
|
14
14
|
*/
|
|
15
|
-
export { MIDNIGHT_PALETTE, DAYLIGHT_PALETTE, MIDNIGHT_CB_PALETTE, DAYLIGHT_CB_PALETTE, PALETTES, } from "./palette";
|
|
15
|
+
export { SAFFRON_PALETTE, MIDNIGHT_PALETTE, DAYLIGHT_PALETTE, MIDNIGHT_CB_PALETTE, DAYLIGHT_CB_PALETTE, PALETTES, } from "./palette";
|
|
16
16
|
export { deriveTokens } from "./tokens";
|
|
17
17
|
export { themeAdapter, frameworkColors } from "./adapter";
|
|
18
18
|
export { THEMES, THEME_SCHEMES, resolveTheme } from "./resolve";
|
|
@@ -33,6 +33,16 @@ export declare const MIDNIGHT_PALETTE: ThemePalette;
|
|
|
33
33
|
* to a dark-on-light slate.
|
|
34
34
|
*/
|
|
35
35
|
export declare const DAYLIGHT_PALETTE: ThemePalette;
|
|
36
|
+
/**
|
|
37
|
+
* The "IndusCode Saffron" dark-terminal ramp — the brand scheme.
|
|
38
|
+
*
|
|
39
|
+
* The console's signature look: a warm saffron primary (borders, headings, the
|
|
40
|
+
* brand wordmark) against a cream neutral gradient, with a cool teal secondary
|
|
41
|
+
* for the interactive accents (the prompt caret, chips, bullets) — the two hues
|
|
42
|
+
* the IndusCode masthead is built from. The status hues stay warm-leaning so the
|
|
43
|
+
* whole scheme reads as one saffron identity rather than a recoloured midnight.
|
|
44
|
+
*/
|
|
45
|
+
export declare const SAFFRON_PALETTE: ThemePalette;
|
|
36
46
|
/**
|
|
37
47
|
* The dark-terminal color-blind-safe ramp.
|
|
38
48
|
*
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createWorkflowAgentRunner — the live {@link WorkflowAgentRunner} that makes the
|
|
3
|
+
* `workflow` tool's `agent()` global spawn real subagents.
|
|
4
|
+
*
|
|
5
|
+
* The pure {@link "./engine"} engine delegates every `agent(prompt, opts)` call
|
|
6
|
+
* to an injected {@link WorkflowAgentRunner}; this module supplies the production
|
|
7
|
+
* implementation. Each subagent run spins a *fresh, isolated* framework
|
|
8
|
+
* {@link Agent} — the same `facade/bot` Agent the conductor and the `task`
|
|
9
|
+
* delegate-runner drive — bound to the parent's model id and credential
|
|
10
|
+
* resolver, given the `'authoring'` capability deck.
|
|
11
|
+
*
|
|
12
|
+
* Two properties matter:
|
|
13
|
+
*
|
|
14
|
+
* 1. **Recursion guard.** The deck is built via `provisionDeck("authoring", …)`,
|
|
15
|
+
* whose profile EXCLUDES the app-novel cards — including the new `workflow`
|
|
16
|
+
* card (registered all-profile-only in {@link "../capability-deck"}). A
|
|
17
|
+
* workflow subagent therefore cannot itself call `workflow` (nor `task`).
|
|
18
|
+
*
|
|
19
|
+
* 2. **Structured output.** When the script passes `opts.schema`, the runner
|
|
20
|
+
* adds the {@link createStructuredOutputTool} `structured_output` tool to the
|
|
21
|
+
* deck and appends the pi "final action MUST be structured_output" contract
|
|
22
|
+
* to the prompt. Because the framework `AgentToolResult` has no `terminate`
|
|
23
|
+
* flag, the tool does NOT end the loop early — the runner instead runs the
|
|
24
|
+
* subagent to completion, then returns `capture.value` (throwing if the
|
|
25
|
+
* subagent never called it). With no schema it returns the final assistant
|
|
26
|
+
* text (the {@link finalAssistantText} pattern, identical to delegate-runner).
|
|
27
|
+
*
|
|
28
|
+
* Cancellation is forwarded: an already-aborted signal short-circuits and an
|
|
29
|
+
* abort raised mid-run calls `agent.abort()`.
|
|
30
|
+
*
|
|
31
|
+
* The model catalog/matcher is built ONCE at create time (the conductor pattern);
|
|
32
|
+
* each `run()` resolves the per-call `opts.model` (falling back to the runner's
|
|
33
|
+
* default `modelId`) against that single matcher. The `spawn` option is a pure
|
|
34
|
+
* test seam — a unit test drives the runner with an in-memory fake instead of a
|
|
35
|
+
* real network round-trip.
|
|
36
|
+
*/
|
|
37
|
+
import { type AgentMessage } from "../conductor";
|
|
38
|
+
import { type AgentTool } from "../capability-deck";
|
|
39
|
+
import { type AgentEvent } from "indusagi/agent";
|
|
40
|
+
import type { WorkflowAgentRunner } from "./engine";
|
|
41
|
+
/**
|
|
42
|
+
* The minimal subagent surface the runner drives.
|
|
43
|
+
*
|
|
44
|
+
* A real framework {@link Agent} satisfies this structurally; a test passes a
|
|
45
|
+
* lightweight fake via {@link WorkflowAgentRunnerOptions.spawn}. Only the pieces
|
|
46
|
+
* the runner touches are named.
|
|
47
|
+
*/
|
|
48
|
+
export interface WorkflowSubAgent {
|
|
49
|
+
prompt(input: string): Promise<void>;
|
|
50
|
+
abort(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Subscribe to the framework `Agent` event stream; returns an unsubscribe
|
|
53
|
+
* thunk. Optional on the structural fake — when absent the runner simply skips
|
|
54
|
+
* live activity reporting (the run still completes and returns its result).
|
|
55
|
+
*/
|
|
56
|
+
subscribe?(fn: (event: AgentEvent) => void): () => void;
|
|
57
|
+
readonly state: {
|
|
58
|
+
messages: readonly AgentMessage[];
|
|
59
|
+
error?: string;
|
|
60
|
+
usage?: unknown;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** The deck of tools handed to a spawned subagent. */
|
|
64
|
+
export interface WorkflowSpawnContext {
|
|
65
|
+
/** The base tools for this run (the `'authoring'` deck, recursion-guarded). */
|
|
66
|
+
readonly tools: AgentTool[];
|
|
67
|
+
/** The resolved system prompt for this subagent. */
|
|
68
|
+
readonly systemPrompt: string;
|
|
69
|
+
}
|
|
70
|
+
/** Configuration for {@link createWorkflowAgentRunner}. */
|
|
71
|
+
export interface WorkflowAgentRunnerOptions {
|
|
72
|
+
/** The default model id a subagent runs under when the script names none. */
|
|
73
|
+
readonly modelId: string;
|
|
74
|
+
/** The working directory the subagent's deck is scoped to. */
|
|
75
|
+
readonly cwd: string;
|
|
76
|
+
/**
|
|
77
|
+
* Per-call credential resolver, forwarded to the framework `Agent` unchanged.
|
|
78
|
+
* Omitted from the agent options entirely when undefined so the framework
|
|
79
|
+
* env-var lookup still wins.
|
|
80
|
+
*/
|
|
81
|
+
readonly getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* The base system prompt prepended to every subagent. A sensible default is
|
|
84
|
+
* used when omitted.
|
|
85
|
+
*/
|
|
86
|
+
readonly system?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Test seam: build the subagent instead of constructing a real framework
|
|
89
|
+
* `Agent`. When omitted the runner uses `new Agent`.
|
|
90
|
+
*/
|
|
91
|
+
readonly spawn?: (prompt: string, context: WorkflowSpawnContext) => WorkflowSubAgent;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Build a live {@link WorkflowAgentRunner} the host wires into the deck context.
|
|
95
|
+
*
|
|
96
|
+
* The model catalog/matcher is built once up front (the conductor pattern); each
|
|
97
|
+
* `run()` resolves `opts.model ?? modelId` against it. A schema request wires the
|
|
98
|
+
* `structured_output` capture tool and the structured contract; a model that does
|
|
99
|
+
* not resolve throws out of `run()` so the engine maps it to an `agent ... failed`
|
|
100
|
+
* log + a `null` branch (the engine's per-branch failure-to-null semantics).
|
|
101
|
+
*
|
|
102
|
+
* @param opts the model id, cwd, credential/system, and optional test seam
|
|
103
|
+
* @returns a runner satisfying the engine's {@link WorkflowAgentRunner} contract
|
|
104
|
+
*/
|
|
105
|
+
export declare function createWorkflowAgentRunner(opts: WorkflowAgentRunnerOptions): WorkflowAgentRunner;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createWorkflowAgentRunner — focused unit tests driven through the `spawn` seam.
|
|
3
|
+
*
|
|
4
|
+
* No model is resolved and no network is touched: each test passes an in-memory
|
|
5
|
+
* fake subagent via `opts.spawn`, so the test exercises the runner's prompt
|
|
6
|
+
* assembly, structured-output capture, final-text extraction, and abort wiring.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow progress snapshot model + text renderer.
|
|
3
|
+
*
|
|
4
|
+
* The engine emits lifecycle callbacks (phase started, agent started/ended,
|
|
5
|
+
* log) which a host folds into a {@link WorkflowSnapshot}. This module owns the
|
|
6
|
+
* snapshot's pure data shape, the two pure recompute helpers, and the
|
|
7
|
+
* `renderWorkflowText` / `renderWorkflowLines` renderers that turn a snapshot
|
|
8
|
+
* into the `◆ Workflow:` progress tree shown live in the tool result.
|
|
9
|
+
*
|
|
10
|
+
* The renderer is a verbatim behavioral port of pi-dynamic-workflows'
|
|
11
|
+
* `src/display.ts` — same `◆ Workflow: name (x/y done)` header, same per-phase
|
|
12
|
+
* `▶/✓` markers with `done/total · running · errors · skipped` counts, same
|
|
13
|
+
* ` #id <glyph> label` subagent rows, same status glyphs
|
|
14
|
+
* (`○ queued`, `● running`, `✓ done`, `✗ error`, `- skipped`), same "Unphased"
|
|
15
|
+
* group, same trailing `log:` lines.
|
|
16
|
+
*
|
|
17
|
+
* Unlike pi, this file carries NO framework-UI bindings (no `ExtensionContext`,
|
|
18
|
+
* no widget display). The card/console wiring that consumes these renderers
|
|
19
|
+
* lands in stage 2; here we expose only the pure snapshot + string surface.
|
|
20
|
+
*/
|
|
21
|
+
import type { WorkflowMeta } from "./parse";
|
|
22
|
+
/** Lifecycle status of a single workflow subagent row. */
|
|
23
|
+
export type WorkflowAgentStatus = "queued" | "running" | "done" | "error" | "skipped";
|
|
24
|
+
/** One subagent's row in the live progress tree. */
|
|
25
|
+
export interface WorkflowAgentSnapshot {
|
|
26
|
+
/** 1-based id, the order the agent started in. */
|
|
27
|
+
id: number;
|
|
28
|
+
/** Short human label for the agent (defaulted from phase + index if absent). */
|
|
29
|
+
label: string;
|
|
30
|
+
/** The phase the agent belongs to, if any. */
|
|
31
|
+
phase?: string;
|
|
32
|
+
/** The task prompt the agent was given. */
|
|
33
|
+
prompt: string;
|
|
34
|
+
/** Current lifecycle status. */
|
|
35
|
+
status: WorkflowAgentStatus;
|
|
36
|
+
/** Optional short preview of the agent's result. */
|
|
37
|
+
resultPreview?: string;
|
|
38
|
+
/** Optional error summary when the agent failed or was skipped. */
|
|
39
|
+
error?: string;
|
|
40
|
+
/** Wall-clock ms when the subagent started (for the live elapsed counter). */
|
|
41
|
+
startedAt?: number;
|
|
42
|
+
/** Wall-clock ms when the subagent settled (caps the elapsed counter). */
|
|
43
|
+
endedAt?: number;
|
|
44
|
+
/** Cumulative input tokens the subagent has spent. */
|
|
45
|
+
tokensIn?: number;
|
|
46
|
+
/** Cumulative output tokens the subagent has spent. */
|
|
47
|
+
tokensOut?: number;
|
|
48
|
+
/** How many tool calls the subagent has started. */
|
|
49
|
+
toolCount?: number;
|
|
50
|
+
/** The tool the subagent is running right now, if any. */
|
|
51
|
+
currentTool?: string;
|
|
52
|
+
/** The last tool the subagent finished (when nothing is running). */
|
|
53
|
+
lastTool?: string;
|
|
54
|
+
}
|
|
55
|
+
/** The full live progress model for one workflow run. */
|
|
56
|
+
export interface WorkflowSnapshot {
|
|
57
|
+
/** Workflow name (from `meta.name`). */
|
|
58
|
+
name: string;
|
|
59
|
+
/** Workflow description (from `meta.description`). */
|
|
60
|
+
description?: string;
|
|
61
|
+
/** Declared/observed phase titles, in order. */
|
|
62
|
+
phases: string[];
|
|
63
|
+
/** The phase currently active (last `phase()` call). */
|
|
64
|
+
currentPhase?: string;
|
|
65
|
+
/** Log lines emitted via `log()`. */
|
|
66
|
+
logs: string[];
|
|
67
|
+
/** Every subagent row, in start order. */
|
|
68
|
+
agents: WorkflowAgentSnapshot[];
|
|
69
|
+
/** Total agents seen. */
|
|
70
|
+
agentCount: number;
|
|
71
|
+
/** Agents currently running. */
|
|
72
|
+
runningCount: number;
|
|
73
|
+
/** Agents finished successfully. */
|
|
74
|
+
doneCount: number;
|
|
75
|
+
/** Agents that errored. */
|
|
76
|
+
errorCount: number;
|
|
77
|
+
/** Total run duration once complete. */
|
|
78
|
+
durationMs?: number;
|
|
79
|
+
/** The workflow's final returned value once complete. */
|
|
80
|
+
result?: unknown;
|
|
81
|
+
}
|
|
82
|
+
/** Tunables for the text renderer (how much of the tree to show). */
|
|
83
|
+
export interface WorkflowDisplayOptions {
|
|
84
|
+
/** Max subagent rows shown per phase (most recent kept). Default 8. */
|
|
85
|
+
maxAgents?: number;
|
|
86
|
+
/** Max trailing log lines shown. Default 2. */
|
|
87
|
+
maxLogs?: number;
|
|
88
|
+
/** Append a short result preview to each agent row. Default false. */
|
|
89
|
+
showResultPreviews?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Soft cap on total tree lines for the LIVE render. Default 9 — headroom under
|
|
92
|
+
* the framework `TaskPanel` 10-line clamp so a running agent is never cut off
|
|
93
|
+
* by a trailing `…`. Completed phases collapse to one line each, and if the
|
|
94
|
+
* tree is still over budget the OLDEST completed phases collapse into a single
|
|
95
|
+
* `… N earlier phases done` line (running/current phases are never collapsed).
|
|
96
|
+
* Pass a large value (e.g. the settled/final render, or Ctrl+O expand) to show
|
|
97
|
+
* everything in full.
|
|
98
|
+
*/
|
|
99
|
+
maxLines?: number;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Build an empty snapshot for a freshly parsed workflow `meta`.
|
|
103
|
+
*
|
|
104
|
+
* @param meta the workflow header
|
|
105
|
+
*/
|
|
106
|
+
export declare function createWorkflowSnapshot(meta: WorkflowMeta): WorkflowSnapshot;
|
|
107
|
+
/**
|
|
108
|
+
* Recompute the derived counts (`agentCount`/`runningCount`/`doneCount`/
|
|
109
|
+
* `errorCount`) from the `agents` array. Pure — returns a new snapshot.
|
|
110
|
+
*
|
|
111
|
+
* @param snapshot the snapshot whose counts to refresh
|
|
112
|
+
*/
|
|
113
|
+
export declare function recomputeWorkflowSnapshot(snapshot: WorkflowSnapshot): WorkflowSnapshot;
|
|
114
|
+
/**
|
|
115
|
+
* Render the snapshot as the `◆ Workflow:` progress tree (array of lines).
|
|
116
|
+
*
|
|
117
|
+
* The per-agent metrics segment (elapsed seconds, token spend, tool activity) is
|
|
118
|
+
* computed at render time from `now` so the seconds tick on every render even
|
|
119
|
+
* during a long silent tool call. Keep `now` an explicit param so the renderer
|
|
120
|
+
* stays pure and testable.
|
|
121
|
+
*
|
|
122
|
+
* @param snapshot the progress model
|
|
123
|
+
* @param options render tunables
|
|
124
|
+
* @param now the current wall-clock ms used to compute live elapsed seconds
|
|
125
|
+
*/
|
|
126
|
+
export declare function renderWorkflowLines(snapshot: WorkflowSnapshot, options?: WorkflowDisplayOptions, now?: number): string[];
|
|
127
|
+
/**
|
|
128
|
+
* Render the snapshot as a single string for the tool result.
|
|
129
|
+
*
|
|
130
|
+
* For the LIVE (not-completed) render the `◆ Workflow:` header already says the
|
|
131
|
+
* run is in progress, so no extra header line is added — this saves a line under
|
|
132
|
+
* the framework `TaskPanel` 10-line clamp. The final (completed) render keeps the
|
|
133
|
+
* explicit `Workflow completed` header.
|
|
134
|
+
*
|
|
135
|
+
* @param snapshot the progress model
|
|
136
|
+
* @param completed whether the run has finished
|
|
137
|
+
* @param options render tunables
|
|
138
|
+
* @param now the current wall-clock ms used to compute live elapsed seconds
|
|
139
|
+
*/
|
|
140
|
+
export declare function renderWorkflowText(snapshot: WorkflowSnapshot, completed?: boolean, options?: WorkflowDisplayOptions, now?: number): string;
|
|
141
|
+
/**
|
|
142
|
+
* One-line preview of an arbitrary result value (string passthrough, else
|
|
143
|
+
* JSON), truncated to `max` chars. Used to fill `resultPreview`.
|
|
144
|
+
*
|
|
145
|
+
* @param value the result to preview
|
|
146
|
+
* @param max max preview length
|
|
147
|
+
*/
|
|
148
|
+
export declare function preview(value: unknown, max?: number): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* runWorkflow — the deterministic workflow orchestration engine.
|
|
3
|
+
*
|
|
4
|
+
* A workflow script is plain JavaScript (parsed by {@link parseWorkflowScript})
|
|
5
|
+
* that orchestrates a fan-out of subagents. The engine evaluates the script's
|
|
6
|
+
* body inside a Node `vm` sandbox seeded with a small, frozen global surface:
|
|
7
|
+
*
|
|
8
|
+
* - `agent(prompt, opts?)` — spawn one subagent, awaitable, returns its
|
|
9
|
+
* result (string, or the validated `opts.schema`
|
|
10
|
+
* object). Runs under a FIFO concurrency limiter.
|
|
11
|
+
* - `parallel(thunks)` — run an array of `() => Promise` thunks and wait
|
|
12
|
+
* for ALL of them (a barrier); results in input
|
|
13
|
+
* order; a failed branch logs and yields `null`.
|
|
14
|
+
* - `pipeline(items, …st)` — run each item through the stages sequentially,
|
|
15
|
+
* while different items proceed independently
|
|
16
|
+
* (NO cross-item barrier); a failed stage logs and
|
|
17
|
+
* yields `null` for that item.
|
|
18
|
+
* - `phase(title)` — open/activate a named progress group.
|
|
19
|
+
* - `log(message)` — append a log line.
|
|
20
|
+
* - `args` — the caller-supplied JSON value.
|
|
21
|
+
* - `budget` — `{ total, spent(), remaining() }` token budget.
|
|
22
|
+
* - `cwd` — the working directory string.
|
|
23
|
+
* - frozen `console` — routed into `log`.
|
|
24
|
+
*
|
|
25
|
+
* The actual subagent spawn is NOT owned here: the engine delegates each
|
|
26
|
+
* `agent()` call to an injected {@link WorkflowAgentRunner} (stage 2 supplies a
|
|
27
|
+
* real one backed by a fresh framework `Agent`; tests pass an in-memory fake).
|
|
28
|
+
* This is the spawn seam that keeps the engine pure and network-free.
|
|
29
|
+
*
|
|
30
|
+
* Behavioral port of pi-dynamic-workflows' `runWorkflow`
|
|
31
|
+
* (pi-dynamic-workflows/src/workflow.ts): same concurrency cap formula, same
|
|
32
|
+
* FIFO limiter, same pending-run tracking + final `Promise.allSettled`, same
|
|
33
|
+
* per-branch failure-to-null semantics, same budget loop, same abort handling,
|
|
34
|
+
* same structured-clone guard on the result, same default agent labels.
|
|
35
|
+
*/
|
|
36
|
+
import { type WorkflowMeta } from "./parse";
|
|
37
|
+
/**
|
|
38
|
+
* Live activity metrics for one running subagent.
|
|
39
|
+
*
|
|
40
|
+
* Folded by the {@link WorkflowAgentRunner} from the framework `Agent`'s event
|
|
41
|
+
* stream and forwarded — via {@link WorkflowAgentRunOptions.onActivity} → the
|
|
42
|
+
* engine's {@link WorkflowRunOptions.onAgentActivity} — into that agent's row in
|
|
43
|
+
* the live `◆ Workflow:` progress tree.
|
|
44
|
+
*/
|
|
45
|
+
export interface WorkflowAgentActivity {
|
|
46
|
+
/** Cumulative input tokens spent so far. */
|
|
47
|
+
tokensIn: number;
|
|
48
|
+
/** Cumulative output tokens spent so far. */
|
|
49
|
+
tokensOut: number;
|
|
50
|
+
/** How many tool calls the subagent has started. */
|
|
51
|
+
toolCount: number;
|
|
52
|
+
/** The tool the subagent is running right now, if any. */
|
|
53
|
+
currentTool?: string;
|
|
54
|
+
/** The last tool the subagent finished (when nothing is running). */
|
|
55
|
+
lastTool?: string;
|
|
56
|
+
}
|
|
57
|
+
/** Options the engine hands a {@link WorkflowAgentRunner} for one subagent. */
|
|
58
|
+
export interface WorkflowAgentRunOptions {
|
|
59
|
+
/** The resolved, human-readable label for this subagent run. */
|
|
60
|
+
label: string;
|
|
61
|
+
/** The phase this subagent belongs to, if any. */
|
|
62
|
+
phase?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Optional JSON-Schema / TypeBox schema the subagent's result must satisfy.
|
|
65
|
+
* When present the runner returns the validated object; when absent it returns
|
|
66
|
+
* the subagent's final assistant text as a string. Left as `unknown` so the
|
|
67
|
+
* engine stays decoupled from any particular schema library.
|
|
68
|
+
*/
|
|
69
|
+
schema?: unknown;
|
|
70
|
+
/** Extra system guidance the engine derived (phase/model/type/isolation). */
|
|
71
|
+
instructions?: string;
|
|
72
|
+
/** Requested model id, if the script passed `opts.model`. */
|
|
73
|
+
model?: string;
|
|
74
|
+
/** Requested subagent profile/type, if the script passed `opts.agentType`. */
|
|
75
|
+
agentType?: string;
|
|
76
|
+
/** Requested isolation mode, if the script passed `opts.isolation`. */
|
|
77
|
+
isolation?: "worktree";
|
|
78
|
+
/** Abort signal forwarded from the workflow run. */
|
|
79
|
+
signal?: AbortSignal;
|
|
80
|
+
/**
|
|
81
|
+
* Called whenever the subagent's live activity changes (a tool starts/ends or
|
|
82
|
+
* a turn settles with token spend). The runner folds this from the framework
|
|
83
|
+
* `Agent` event stream; the engine forwards it to
|
|
84
|
+
* {@link WorkflowRunOptions.onAgentActivity}. Optional — a test fake may omit it.
|
|
85
|
+
*/
|
|
86
|
+
onActivity?: (metrics: WorkflowAgentActivity) => void;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The minimal contract the engine needs to spawn a subagent.
|
|
90
|
+
*
|
|
91
|
+
* Stage 2 implements this against a fresh, isolated framework `Agent` (the
|
|
92
|
+
* delegate-runner spawn pattern): resolve the model, build the authoring deck,
|
|
93
|
+
* prompt to completion, then read either the structured-output capture or the
|
|
94
|
+
* final assistant text. Tests implement it with an in-memory fake so the engine
|
|
95
|
+
* can be exercised with no network.
|
|
96
|
+
*/
|
|
97
|
+
export interface WorkflowAgentRunner {
|
|
98
|
+
/**
|
|
99
|
+
* Run one subagent task and resolve with its result.
|
|
100
|
+
*
|
|
101
|
+
* @param prompt the task prompt
|
|
102
|
+
* @param options the resolved run options (label, schema, signal, …)
|
|
103
|
+
* @returns the subagent's result — a string, or the validated schema object
|
|
104
|
+
*/
|
|
105
|
+
run(prompt: string, options: WorkflowAgentRunOptions): Promise<unknown>;
|
|
106
|
+
}
|
|
107
|
+
/** Per-subagent option bag accepted by the in-sandbox `agent()` global. */
|
|
108
|
+
export interface AgentOptions {
|
|
109
|
+
/** Short unique label for the run (2-5 words); defaulted when absent. */
|
|
110
|
+
label?: string;
|
|
111
|
+
/** Override the phase this agent is attributed to. */
|
|
112
|
+
phase?: string;
|
|
113
|
+
/** Result schema; when present the agent returns the validated object. */
|
|
114
|
+
schema?: unknown;
|
|
115
|
+
/** Requested model id. */
|
|
116
|
+
model?: string;
|
|
117
|
+
/** Requested isolation mode. */
|
|
118
|
+
isolation?: "worktree";
|
|
119
|
+
/** Requested subagent profile/type. */
|
|
120
|
+
agentType?: string;
|
|
121
|
+
}
|
|
122
|
+
/** Options for {@link runWorkflow}. */
|
|
123
|
+
export interface WorkflowRunOptions {
|
|
124
|
+
/** The injected subagent runner (required to actually spawn). */
|
|
125
|
+
agentRunner: WorkflowAgentRunner;
|
|
126
|
+
/** The JSON value exposed to the script as global `args`. */
|
|
127
|
+
args?: unknown;
|
|
128
|
+
/** The working directory exposed to the script as `cwd`/`process.cwd()`. */
|
|
129
|
+
cwd?: string;
|
|
130
|
+
/** Max concurrent subagents; clamped to `[1, 16]`. */
|
|
131
|
+
concurrency?: number;
|
|
132
|
+
/** Optional token budget; `null`/absent means unbounded. */
|
|
133
|
+
tokenBudget?: number | null;
|
|
134
|
+
/** Abort signal — aborts pending and future subagent spawns. */
|
|
135
|
+
signal?: AbortSignal;
|
|
136
|
+
/** Called for each `log()` / console line. */
|
|
137
|
+
onLog?: (message: string) => void;
|
|
138
|
+
/** Called when a new phase is activated. */
|
|
139
|
+
onPhase?: (title: string) => void;
|
|
140
|
+
/** Called just before a subagent starts. */
|
|
141
|
+
onAgentStart?: (event: {
|
|
142
|
+
id: number;
|
|
143
|
+
label: string;
|
|
144
|
+
phase?: string;
|
|
145
|
+
prompt: string;
|
|
146
|
+
}) => void;
|
|
147
|
+
/** Called when a subagent ends (`result === null` means it failed). */
|
|
148
|
+
onAgentEnd?: (event: {
|
|
149
|
+
id: number;
|
|
150
|
+
label: string;
|
|
151
|
+
phase?: string;
|
|
152
|
+
result: unknown;
|
|
153
|
+
}) => void;
|
|
154
|
+
/**
|
|
155
|
+
* Called whenever a running subagent's live activity changes (tool start/end,
|
|
156
|
+
* settled turn token spend). `id` is the 1-based start-order id that matches
|
|
157
|
+
* the `id` on the corresponding {@link onAgentStart} / {@link onAgentEnd} event.
|
|
158
|
+
*/
|
|
159
|
+
onAgentActivity?: (id: number, metrics: WorkflowAgentActivity) => void;
|
|
160
|
+
}
|
|
161
|
+
/** The structured result of a completed workflow run. */
|
|
162
|
+
export interface WorkflowRunResult<T = unknown> {
|
|
163
|
+
/** The validated workflow header. */
|
|
164
|
+
meta: WorkflowMeta;
|
|
165
|
+
/** The script's returned value (structured-clone checked). */
|
|
166
|
+
result: T;
|
|
167
|
+
/** All log lines emitted during the run, in order. */
|
|
168
|
+
logs: string[];
|
|
169
|
+
/** All phases observed during the run, in order. */
|
|
170
|
+
phases: string[];
|
|
171
|
+
/** Total subagents spawned. */
|
|
172
|
+
agentCount: number;
|
|
173
|
+
/** Wall-clock duration of the run. */
|
|
174
|
+
durationMs: number;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Parse and run a deterministic workflow script to completion.
|
|
178
|
+
*
|
|
179
|
+
* @param script the raw workflow JavaScript (first statement: `export const meta`)
|
|
180
|
+
* @param options the injected runner plus run configuration / callbacks
|
|
181
|
+
* @returns the meta, the script's returned value, and run telemetry
|
|
182
|
+
*/
|
|
183
|
+
export declare function runWorkflow<T = unknown>(script: string, options: WorkflowRunOptions): Promise<WorkflowRunResult<T>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* workflow-engine — the pure, network-free orchestration core for the `workflow`
|
|
3
|
+
* dynamic-workflow tool.
|
|
4
|
+
*
|
|
5
|
+
* This barrel exposes the engine subsystem only: the deterministic script
|
|
6
|
+
* parser, the `structured_output` capture tool, the progress snapshot model +
|
|
7
|
+
* text renderer, and the `runWorkflow` engine with its injectable
|
|
8
|
+
* {@link WorkflowAgentRunner} spawn seam. The card and console wiring (the real
|
|
9
|
+
* runner backed by a fresh framework `Agent`, the `tool_update` product signal,
|
|
10
|
+
* and `APP_NOVEL_CARDS` registration) live in stage 2 and consume these exports.
|
|
11
|
+
*/
|
|
12
|
+
export type { ParsedWorkflow, WorkflowMeta, WorkflowMetaPhase, } from "./parse";
|
|
13
|
+
export { NONDETERMINISM_ERROR, parseWorkflowScript } from "./parse";
|
|
14
|
+
export type { StructuredOutputCapture, StructuredOutputToolOptions, } from "./structured-output";
|
|
15
|
+
export { createStructuredOutputTool } from "./structured-output";
|
|
16
|
+
export type { WorkflowAgentSnapshot, WorkflowAgentStatus, WorkflowDisplayOptions, WorkflowSnapshot, } from "./display";
|
|
17
|
+
export { createWorkflowSnapshot, preview, recomputeWorkflowSnapshot, renderWorkflowLines, renderWorkflowText, } from "./display";
|
|
18
|
+
export type { AgentOptions, WorkflowAgentActivity, WorkflowAgentRunner, WorkflowAgentRunOptions, WorkflowRunOptions, WorkflowRunResult, } from "./engine";
|
|
19
|
+
export { runWorkflow } from "./engine";
|
|
20
|
+
export type { WorkflowAgentRunnerOptions, WorkflowSubAgent, WorkflowSpawnContext, } from "./agent-runner";
|
|
21
|
+
export { createWorkflowAgentRunner } from "./agent-runner";
|