one-code-extension 0.1.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +200 -172
- package/agents/explore.md +9 -6
- package/agents/general-purpose.md +1 -1
- package/agents/plan.md +6 -4
- package/docs/guide/README.md +52 -0
- package/docs/guide/bring-your-claude-code-setup.md +126 -0
- package/docs/guide/configuration.md +171 -0
- package/docs/guide/differences-from-claude-code.md +150 -0
- package/docs/guide/doctor.md +86 -0
- package/docs/guide/hooks.md +109 -0
- package/docs/guide/installation.md +124 -0
- package/docs/guide/permissions-modes-and-auto-mode.md +450 -0
- package/docs/guide/providers-and-models.md +194 -0
- package/docs/guide/reference.md +224 -0
- package/docs/guide/sessions-and-context.md +190 -0
- package/docs/guide/skills-plugins-and-mcp.md +176 -0
- package/docs/guide/subagents-and-workflows.md +193 -0
- package/docs/guide/tasks-and-background-work.md +111 -0
- package/docs/guide/terminal-interface.md +155 -0
- package/docs/guide/tools.md +175 -0
- package/docs/guide/troubleshooting.md +175 -0
- package/extensions/ask-user/index.ts +65 -71
- package/extensions/ask-user/questions.ts +15 -28
- package/extensions/ask-user/widget.ts +533 -0
- package/extensions/auto-mode/actions.ts +9 -26
- package/extensions/auto-mode/classifier-prompt.ts +127 -0
- package/extensions/auto-mode/classifier.ts +305 -227
- package/extensions/auto-mode/config.ts +279 -77
- package/extensions/auto-mode/defaults.ts +17 -60
- package/extensions/auto-mode/instructions.ts +2 -1
- package/extensions/auto-mode/model-picker.ts +53 -31
- package/extensions/auto-mode/model-select.ts +153 -82
- package/extensions/auto-mode/paths.ts +13 -1
- package/extensions/auto-mode/pause.ts +8 -0
- package/extensions/auto-mode/prompt.ts +205 -238
- package/extensions/auto-mode/recoverability.ts +229 -0
- package/extensions/auto-mode/rules.ts +92 -75
- package/extensions/auto-mode/safety-floor.ts +43 -12
- package/extensions/auto-mode/sensitive.ts +11 -0
- package/extensions/auto-mode/setup-run.ts +245 -0
- package/extensions/auto-mode/setup.ts +235 -0
- package/extensions/auto-mode/shell-analysis.ts +332 -26
- package/extensions/auto-mode/transcript.ts +102 -0
- package/extensions/background/index.ts +256 -43
- package/extensions/background/monitor-batch.ts +58 -0
- package/extensions/background/registry.ts +9 -0
- package/extensions/background/wakeup.ts +45 -0
- package/extensions/bash/background.ts +47 -22
- package/extensions/bash/guards.ts +229 -0
- package/extensions/bash/index.ts +81 -19
- package/extensions/branding/index.ts +44 -18
- package/extensions/branding/startup.ts +23 -8
- package/extensions/claude-compat/index.ts +17 -2
- package/extensions/claude-context/index.ts +41 -12
- package/extensions/clear/index.ts +27 -0
- package/extensions/compaction/fit.ts +121 -0
- package/extensions/compaction/index.ts +176 -71
- package/extensions/compaction/prompt.ts +21 -1
- package/extensions/context-budget/budget.ts +61 -0
- package/extensions/context-budget/index.ts +66 -0
- package/extensions/context-management/index.ts +40 -16
- package/extensions/doctor/build.ts +226 -0
- package/extensions/doctor/cli.ts +99 -0
- package/extensions/doctor/compat.ts +532 -0
- package/extensions/doctor/dependencies.ts +186 -0
- package/extensions/doctor/fix-prompt.ts +125 -0
- package/extensions/doctor/index.ts +308 -0
- package/extensions/doctor/models.ts +231 -0
- package/extensions/doctor/presets.ts +208 -0
- package/extensions/doctor/report.ts +189 -0
- package/extensions/doctor/update-lookup.ts +46 -0
- package/extensions/doctor/viewer.ts +124 -0
- package/extensions/effort/index.ts +41 -4
- package/extensions/effort/slider.ts +33 -2
- package/extensions/file-tracker/index.ts +143 -20
- package/extensions/file-tracker/replay.ts +46 -0
- package/extensions/file-tracker/tracker.ts +51 -4
- package/extensions/footer/footer-line.ts +207 -0
- package/extensions/footer/index.ts +152 -0
- package/extensions/footer/pr.ts +53 -0
- package/extensions/hooks/executor.ts +57 -20
- package/extensions/hooks/formatter-notice.ts +76 -0
- package/extensions/hooks/index.ts +314 -73
- package/extensions/hooks/matcher.ts +35 -1
- package/extensions/hooks/plugin-hooks.ts +3 -3
- package/extensions/hooks/protocol.ts +58 -0
- package/extensions/hooks/subagent-bridge.ts +77 -0
- package/extensions/hooks/trust.ts +15 -4
- package/extensions/init/index.ts +26 -0
- package/extensions/init/prompt.ts +40 -0
- package/extensions/interrupted/index.ts +35 -0
- package/extensions/interrupted/line.ts +9 -0
- package/extensions/lib/abort.ts +15 -0
- package/extensions/lib/agent-loader.ts +183 -0
- package/extensions/lib/anthropic-payload.ts +15 -0
- package/extensions/lib/atomic-write.ts +56 -0
- package/extensions/lib/bridge-watch.ts +20 -0
- package/extensions/lib/cache-retention.ts +60 -0
- package/extensions/lib/capability-index.ts +466 -0
- package/extensions/lib/claude-context.ts +318 -27
- package/extensions/lib/claude-settings.ts +64 -0
- package/extensions/lib/consent-preview.ts +30 -0
- package/extensions/lib/deferred.ts +144 -13
- package/extensions/lib/favorites.ts +43 -0
- package/extensions/lib/fetch-timeout.ts +15 -0
- package/extensions/lib/frontmatter.ts +31 -0
- package/extensions/lib/git.ts +44 -2
- package/extensions/lib/hook-gate.ts +90 -0
- package/extensions/lib/interrupt.ts +94 -0
- package/extensions/lib/mcp-overrides.ts +61 -0
- package/extensions/lib/mcp-share.ts +25 -0
- package/extensions/lib/mcp-status.ts +34 -0
- package/extensions/lib/memory.ts +41 -6
- package/extensions/lib/model-facts.generated.json +2480 -0
- package/extensions/lib/model-facts.ts +162 -0
- package/extensions/lib/model-policy.ts +145 -189
- package/extensions/lib/model-tier.ts +480 -64
- package/extensions/lib/model-unusable.ts +37 -0
- package/extensions/lib/notifications.ts +320 -1
- package/extensions/lib/one-code-settings.ts +63 -0
- package/extensions/lib/original-command.ts +71 -0
- package/extensions/lib/package-version.ts +31 -0
- package/extensions/lib/paths.ts +39 -4
- package/extensions/lib/permission-gate.ts +192 -0
- package/extensions/lib/persisted-output.ts +18 -0
- package/extensions/lib/pi-ai-estimate.ts +160 -0
- package/extensions/lib/pi-version.ts +1 -1
- package/extensions/lib/plan-mode-channels.ts +11 -0
- package/extensions/lib/plugin-overrides.ts +24 -0
- package/extensions/lib/plugin-root.ts +44 -0
- package/extensions/lib/plugins.ts +233 -54
- package/extensions/lib/prefix-warm-gate.ts +157 -0
- package/extensions/lib/process-tree.ts +56 -0
- package/extensions/lib/reminders.ts +321 -68
- package/extensions/lib/scratchpad.ts +11 -8
- package/extensions/lib/session-lifecycle.ts +28 -0
- package/extensions/lib/settings-channels.ts +14 -0
- package/extensions/lib/shell-tasks.ts +54 -0
- package/extensions/lib/skill-overrides.ts +86 -0
- package/extensions/lib/skill-scan.ts +110 -0
- package/extensions/lib/text-width.ts +267 -0
- package/extensions/lib/tui-render.ts +281 -54
- package/extensions/lib/usage-bus.ts +75 -0
- package/extensions/lib/usage-tracker.ts +67 -0
- package/extensions/lib/worktree-isolation.ts +170 -0
- package/extensions/lsp/client.ts +69 -12
- package/extensions/lsp/format.ts +12 -2
- package/extensions/lsp/index.ts +273 -84
- package/extensions/lsp/install-hints.ts +43 -0
- package/extensions/lsp/keep-alive.ts +19 -0
- package/extensions/lsp/plugin-servers.ts +331 -0
- package/extensions/lsp/watcher.ts +157 -0
- package/extensions/mcp/announce.ts +99 -0
- package/extensions/mcp/client.ts +181 -22
- package/extensions/mcp/config.ts +55 -24
- package/extensions/mcp/index.ts +586 -86
- package/extensions/mcp/oauth/browser.ts +26 -0
- package/extensions/mcp/oauth/callback.ts +104 -0
- package/extensions/mcp/oauth/flow.ts +68 -0
- package/extensions/mcp/oauth/provider.ts +147 -0
- package/extensions/mcp/oauth/store.ts +86 -0
- package/extensions/mcp/panel/keys.ts +34 -0
- package/extensions/mcp/panel/model.ts +62 -0
- package/extensions/mcp/panel/render.ts +141 -0
- package/extensions/mcp/panel/state.ts +108 -0
- package/extensions/mcp/schema.ts +83 -6
- package/extensions/mcp/trust.ts +340 -0
- package/extensions/memory/entries.ts +163 -0
- package/extensions/memory/index.ts +119 -2
- package/extensions/memory/open-external.ts +97 -0
- package/extensions/memory/panel.ts +124 -0
- package/extensions/model-default/index.ts +74 -0
- package/extensions/notebook/index.ts +36 -18
- package/extensions/notebook/notebook.ts +110 -17
- package/extensions/permissions/index.ts +1012 -247
- package/extensions/permissions/matcher.ts +488 -57
- package/extensions/permissions/modes.ts +55 -7
- package/extensions/permissions/project-trust.ts +81 -0
- package/extensions/permissions/protected-paths.ts +16 -3
- package/extensions/permissions/rule-prose.ts +79 -0
- package/extensions/permissions/session-grant.ts +91 -0
- package/extensions/permissions/settings.ts +112 -33
- package/extensions/permissions/subagent-gate.ts +57 -0
- package/extensions/plan-mode/index.ts +143 -33
- package/extensions/plan-mode/reminder.ts +16 -19
- package/extensions/plan-mode/viewer.ts +40 -31
- package/extensions/plugins/counts.ts +68 -0
- package/extensions/plugins/index.ts +496 -32
- package/extensions/plugins/install/install.ts +167 -0
- package/extensions/plugins/install/paths.ts +23 -0
- package/extensions/plugins/install/registry.ts +72 -0
- package/extensions/plugins/marketplace/git.ts +103 -0
- package/extensions/plugins/marketplace/official.ts +36 -0
- package/extensions/plugins/marketplace/parse.ts +94 -0
- package/extensions/plugins/marketplace/registry.ts +60 -0
- package/extensions/plugins/marketplace/sync.ts +146 -0
- package/extensions/plugins/marketplace/types.ts +128 -0
- package/extensions/plugins/panel/keys.ts +52 -0
- package/extensions/plugins/panel/render.ts +315 -0
- package/extensions/plugins/panel/rows.ts +230 -0
- package/extensions/plugins/panel/state.ts +333 -0
- package/extensions/recap/index.ts +215 -0
- package/extensions/recap/prompt.ts +44 -0
- package/extensions/recap/scheduler.ts +87 -0
- package/extensions/search-tools/index.ts +0 -0
- package/extensions/search-tools/tools.ts +7 -5
- package/extensions/skill/index.ts +360 -34
- package/extensions/skill/invoke.ts +185 -0
- package/extensions/skill/listing.ts +21 -0
- package/extensions/skill/panel/keys.ts +41 -0
- package/extensions/skill/panel/render.ts +91 -0
- package/extensions/skill/panel/state.ts +115 -0
- package/extensions/spinner/index.ts +110 -0
- package/extensions/spinner/line.ts +51 -0
- package/extensions/spinner/verbs.ts +201 -0
- package/extensions/subagents/agents.ts +88 -44
- package/extensions/subagents/default-model.ts +62 -32
- package/extensions/subagents/delegation-steer.ts +23 -0
- package/extensions/subagents/hand-back-review.ts +67 -0
- package/extensions/subagents/index.ts +1545 -346
- package/extensions/subagents/live-runs.ts +293 -0
- package/extensions/subagents/model-select.ts +252 -82
- package/extensions/subagents/outcome.ts +90 -0
- package/extensions/subagents/panel-keys.ts +41 -0
- package/extensions/subagents/panel-render.ts +357 -0
- package/extensions/subagents/panel-widget.ts +330 -0
- package/extensions/subagents/pending-claim.ts +45 -0
- package/extensions/subagents/prose.ts +105 -0
- package/extensions/subagents/runner.ts +674 -0
- package/extensions/subagents/runs.ts +68 -1
- package/extensions/subagents/send-to-main-tool.ts +55 -0
- package/extensions/subagents/session-turns.ts +138 -0
- package/extensions/subagents/shell-panel.ts +198 -0
- package/extensions/subagents/usage.ts +16 -4
- package/extensions/subagents/worktree.ts +13 -0
- package/extensions/system-prompt/environment.ts +5 -3
- package/extensions/system-prompt/git-status.ts +93 -0
- package/extensions/system-prompt/index.ts +23 -1
- package/extensions/system-prompt/template.ts +34 -4
- package/extensions/system-prompt/tiers/common.ts +31 -6
- package/extensions/system-prompt/tiers/low.ts +13 -3
- package/extensions/system-prompt/tiers/mid.ts +21 -8
- package/extensions/system-reminder/index.ts +53 -9
- package/extensions/tasks/index.ts +65 -16
- package/extensions/tasks/store.ts +76 -3
- package/extensions/tool-search/announce.ts +42 -0
- package/extensions/tool-search/index.ts +136 -13
- package/extensions/turn-duration/index.ts +60 -0
- package/extensions/turn-duration/line.ts +22 -0
- package/extensions/turn-duration/span.ts +41 -0
- package/extensions/turn-duration/verbs.ts +24 -0
- package/extensions/web/backends.ts +421 -0
- package/extensions/web/index.ts +178 -21
- package/extensions/web-fetch/index.ts +74 -18
- package/extensions/web-fetch/summarize.ts +1 -1
- package/extensions/workflow/agent-session.ts +182 -112
- package/extensions/workflow/globals.ts +129 -106
- package/extensions/workflow/index.ts +343 -28
- package/extensions/workflow/records.ts +118 -0
- package/extensions/workflow/run-manager.ts +80 -31
- package/extensions/workflow/saved-workflows.ts +2 -1
- package/extensions/workflow/script-worker.mjs +110 -0
- package/extensions/workflow/types.ts +74 -8
- package/extensions/workflow/viewer.ts +562 -0
- package/extensions/workflow/vm-runtime.ts +118 -22
- package/extensions/workflow/widget.ts +126 -18
- package/extensions/worktree/guards.ts +240 -0
- package/extensions/worktree/index.ts +30 -5
- package/extensions/worktree/rewrite.ts +32 -16
- package/package.json +20 -10
- package/skills/code-review/SKILL.md +165 -0
- package/skills/fewer-permission-prompts/SKILL.md +61 -0
- package/skills/security-review/SKILL.md +178 -0
- package/skills/simplify/SKILL.md +70 -0
- package/themes/{one-code-light.json → onecode-light.json} +6 -1
- package/themes/{one-code.json → onecode.json} +6 -1
- package/types/app.d.ts +8 -1
- package/types/community-packages.d.ts +45 -2
- package/docs/decisions/auto-mode.md +0 -526
- package/docs/decisions/branding.md +0 -127
- package/docs/decisions/code-review-remediation.md +0 -106
- package/docs/decisions/compaction.md +0 -140
- package/docs/decisions/distribution.md +0 -168
- package/docs/decisions/hooks.md +0 -64
- package/docs/decisions/lsp.md +0 -58
- package/docs/decisions/mcp.md +0 -104
- package/docs/decisions/memory-state.md +0 -170
- package/docs/decisions/model-policy.md +0 -126
- package/docs/decisions/modes.md +0 -178
- package/docs/decisions/skills-plugins.md +0 -56
- package/docs/decisions/subagents-workflows.md +0 -225
- package/docs/decisions/system-prompt.md +0 -98
- package/docs/decisions/tools.md +0 -407
- package/docs/decisions/tui.md +0 -217
- package/docs/decisions.md +0 -148
- package/extensions/subagents/child.ts +0 -414
- package/extensions/subagents/rpc-turns.ts +0 -123
- package/extensions/todo/index.ts +0 -133
- package/extensions/workflow/permission-gate.ts +0 -71
|
@@ -1,28 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* script
|
|
4
|
-
* is built here around one injected AgentCallFn
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* Host-side script globals (pure, dependency-injected). The script itself runs
|
|
3
|
+
* in a worker thread (`script-worker.mjs`, launched by `vm-runtime.ts`); what
|
|
4
|
+
* reaches the host over RPC is built here around one injected AgentCallFn —
|
|
5
|
+
* agent()/workflow() calls, phase/log notices, args and the budget snapshot —
|
|
6
|
+
* so the orchestration semantics that matter for replay and safety
|
|
7
|
+
* (concurrency, caps, budget admission, null-on-failure, journal replay) are
|
|
8
|
+
* unit-testable with a fake agent runner. parallel()/pipeline()/console live
|
|
9
|
+
* in the worker: they take callbacks, which cannot cross the RPC boundary.
|
|
7
10
|
*
|
|
8
11
|
* Claude Code semantics implemented here:
|
|
9
12
|
* - agent() resolves null when the underlying agent fails; caps/budget/abort
|
|
10
13
|
* violations throw (they must unwind the script).
|
|
11
|
-
* - parallel() takes thunks, is a barrier, and maps a throwing thunk to null.
|
|
12
|
-
* - pipeline() has no barrier between stages; stage callbacks receive
|
|
13
|
-
* (prev, originalItem, index); a throwing stage drops that item to null.
|
|
14
14
|
* - callIndex is assigned synchronously at invocation time, which is what
|
|
15
15
|
* makes journal replay deterministic under parallel().
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { hashAgentCall } from "./journal.ts";
|
|
19
|
-
import
|
|
19
|
+
import { previewValue } from "./records.ts";
|
|
20
|
+
import type {
|
|
21
|
+
AgentCallFn,
|
|
22
|
+
AgentCallOptions,
|
|
23
|
+
AgentRunUpdate,
|
|
24
|
+
BudgetSnapshot,
|
|
25
|
+
JournalEntry,
|
|
26
|
+
RunProgressEvent,
|
|
27
|
+
} from "./types.ts";
|
|
20
28
|
import { WorkflowScriptError } from "./types.ts";
|
|
21
29
|
import type { ReplayCursor } from "./journal.ts";
|
|
22
30
|
|
|
23
31
|
export const MAX_AGENTS_PER_RUN = 1000;
|
|
24
32
|
export const MAX_ITEMS_PER_CALL = 4096;
|
|
25
33
|
export const MAX_CONCURRENCY = 16;
|
|
34
|
+
/** log()/phase() notices a script may emit between two worker heartbeats (25 ms) before it is judged a flood. */
|
|
35
|
+
export const MAX_NOTICES_PER_TICK = 10_000;
|
|
26
36
|
|
|
27
37
|
/** Promise-queue limiter: at most `limit` callbacks in flight, FIFO overflow. */
|
|
28
38
|
export function createLimiter(limit: number): <T>(fn: () => Promise<T>) => Promise<T> {
|
|
@@ -43,13 +53,61 @@ export function createLimiter(limit: number): <T>(fn: () => Promise<T>) => Promi
|
|
|
43
53
|
};
|
|
44
54
|
}
|
|
45
55
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
/**
|
|
57
|
+
* One run tree's admission controls and totals: the budget snapshot, the
|
|
58
|
+
* concurrency limiter, the agent cap and the counters they read. Created ONCE
|
|
59
|
+
* per run (`createRunAdmission`) and shared by every nested workflow(), so a
|
|
60
|
+
* child's agents queue behind the same limiter, spend the same budget and
|
|
61
|
+
* count against the same cap as the root's — a per-child copy taken at spawn
|
|
62
|
+
* could not see the parent's later spend and let a tree exceed the run's
|
|
63
|
+
* concurrency (review S9).
|
|
64
|
+
*/
|
|
65
|
+
export interface RunAdmission {
|
|
66
|
+
budget: BudgetSnapshot;
|
|
67
|
+
limit: ReturnType<typeof createLimiter>;
|
|
68
|
+
maxAgents: number;
|
|
69
|
+
agentCount: () => number;
|
|
70
|
+
outputTokens: () => number;
|
|
71
|
+
cost: () => number;
|
|
72
|
+
account: (delta: { agents?: number; outputTokens?: number; cost?: number }) => void;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface RunAdmissionOptions {
|
|
76
|
+
/** null = no budget target. */
|
|
50
77
|
budgetTotal: number | null;
|
|
51
78
|
concurrency: number;
|
|
52
79
|
maxAgents?: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function createRunAdmission(options: RunAdmissionOptions): RunAdmission {
|
|
83
|
+
const total = options.budgetTotal;
|
|
84
|
+
let agents = 0;
|
|
85
|
+
let outputTokens = 0;
|
|
86
|
+
let cost = 0;
|
|
87
|
+
return {
|
|
88
|
+
budget: Object.freeze({
|
|
89
|
+
total,
|
|
90
|
+
spent: () => outputTokens,
|
|
91
|
+
remaining: () => (total === null ? Number.POSITIVE_INFINITY : Math.max(0, total - outputTokens)),
|
|
92
|
+
}),
|
|
93
|
+
limit: createLimiter(Math.max(1, Math.min(options.concurrency, MAX_CONCURRENCY))),
|
|
94
|
+
maxAgents: options.maxAgents ?? MAX_AGENTS_PER_RUN,
|
|
95
|
+
agentCount: () => agents,
|
|
96
|
+
outputTokens: () => outputTokens,
|
|
97
|
+
cost: () => cost,
|
|
98
|
+
account: (delta) => {
|
|
99
|
+
agents += delta.agents ?? 0;
|
|
100
|
+
outputTokens += delta.outputTokens ?? 0;
|
|
101
|
+
cost += delta.cost ?? 0;
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface ScriptGlobalsOptions {
|
|
107
|
+
agentCall: AgentCallFn;
|
|
108
|
+
args: unknown;
|
|
109
|
+
/** The run tree's shared controls — the root's own, or inherited by a nested workflow(). */
|
|
110
|
+
admission: RunAdmission;
|
|
53
111
|
signal: AbortSignal;
|
|
54
112
|
onEvent: (event: RunProgressEvent) => void;
|
|
55
113
|
onJournal?: (entry: JournalEntry) => void;
|
|
@@ -62,17 +120,16 @@ export interface ScriptGlobalsOptions {
|
|
|
62
120
|
|
|
63
121
|
export interface ScriptGlobals {
|
|
64
122
|
agent: (prompt: string, opts?: AgentCallOptions) => Promise<unknown>;
|
|
65
|
-
parallel: (thunks: Array<() => Promise<unknown>>) => Promise<unknown[]>;
|
|
66
|
-
pipeline: (items: unknown[], ...stages: Array<(prev: unknown, item: unknown, index: number) => unknown>) => Promise<unknown[]>;
|
|
67
123
|
workflow: (nameOrRef: unknown, childArgs?: unknown) => Promise<unknown>;
|
|
68
124
|
phase: (title: string) => void;
|
|
69
125
|
log: (message: unknown) => void;
|
|
70
|
-
console: { log: (m: unknown) => void; info: (m: unknown) => void; warn: (m: unknown) => void; error: (m: unknown) => void };
|
|
71
126
|
args: unknown;
|
|
72
127
|
budget: BudgetSnapshot;
|
|
73
128
|
}
|
|
74
129
|
|
|
130
|
+
/** What the run manager reads back: tree-wide totals plus this script's phase. */
|
|
75
131
|
export interface ScriptRunState {
|
|
132
|
+
admission: RunAdmission;
|
|
76
133
|
agentCount: () => number;
|
|
77
134
|
outputTokens: () => number;
|
|
78
135
|
cost: () => number;
|
|
@@ -80,25 +137,21 @@ export interface ScriptRunState {
|
|
|
80
137
|
}
|
|
81
138
|
|
|
82
139
|
export function createScriptGlobals(options: ScriptGlobalsOptions): { globals: ScriptGlobals; state: ScriptRunState } {
|
|
83
|
-
const
|
|
84
|
-
const limiter =
|
|
140
|
+
const { admission } = options;
|
|
141
|
+
const { budget, limit: limiter } = admission;
|
|
85
142
|
const now = options.now ?? (() => Date.now());
|
|
86
143
|
|
|
87
144
|
let callSeq = 0;
|
|
88
|
-
let agentCount = 0;
|
|
89
|
-
let outputTokens = 0;
|
|
90
|
-
let cost = 0;
|
|
91
145
|
let currentPhase: string | undefined;
|
|
92
146
|
|
|
93
|
-
const budget: BudgetSnapshot = Object.freeze({
|
|
94
|
-
total: options.budgetTotal,
|
|
95
|
-
spent: () => outputTokens,
|
|
96
|
-
remaining: () => (options.budgetTotal === null ? Number.POSITIVE_INFINITY : Math.max(0, options.budgetTotal - outputTokens)),
|
|
97
|
-
});
|
|
98
|
-
|
|
99
147
|
const throwIfAborted = () => {
|
|
100
148
|
if (options.signal.aborted) throw new WorkflowScriptError("Workflow run was aborted");
|
|
101
149
|
};
|
|
150
|
+
const checkBudget = () => {
|
|
151
|
+
if (budget.total !== null && budget.remaining() <= 0) {
|
|
152
|
+
throw new WorkflowScriptError(`Workflow token budget exhausted (${budget.total} output tokens)`);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
102
155
|
|
|
103
156
|
const agent = async (prompt: string, opts: AgentCallOptions = {}): Promise<unknown> => {
|
|
104
157
|
if (typeof prompt !== "string" || !prompt.trim()) {
|
|
@@ -108,41 +161,70 @@ export function createScriptGlobals(options: ScriptGlobalsOptions): { globals: S
|
|
|
108
161
|
throw new WorkflowScriptError("agent() schema must be a JSON Schema object");
|
|
109
162
|
}
|
|
110
163
|
throwIfAborted();
|
|
111
|
-
if (agentCount >= maxAgents) {
|
|
112
|
-
throw new WorkflowScriptError(`Workflow agent limit reached (${maxAgents} agents per run)`);
|
|
113
|
-
}
|
|
114
|
-
if (budget.total !== null && budget.remaining() <= 0) {
|
|
115
|
-
throw new WorkflowScriptError(`Workflow token budget exhausted (${budget.total} output tokens)`);
|
|
164
|
+
if (admission.agentCount() >= admission.maxAgents) {
|
|
165
|
+
throw new WorkflowScriptError(`Workflow agent limit reached (${admission.maxAgents} agents per run)`);
|
|
116
166
|
}
|
|
167
|
+
checkBudget();
|
|
117
168
|
|
|
118
169
|
// Everything up to here — and the index/hash/phase capture — is
|
|
119
170
|
// synchronous, so invocation order fully determines replay identity.
|
|
120
171
|
const callIndex = callSeq++;
|
|
121
|
-
|
|
172
|
+
admission.account({ agents: 1 });
|
|
122
173
|
const hash = hashAgentCall(prompt, opts);
|
|
123
174
|
const phase = opts.phase ?? currentPhase;
|
|
124
175
|
const label = opts.label ?? `agent ${callIndex + 1}`;
|
|
125
176
|
|
|
126
177
|
const replayed = options.replay?.match(callIndex, hash);
|
|
127
178
|
if (replayed !== undefined) {
|
|
128
|
-
outputTokens
|
|
129
|
-
|
|
130
|
-
|
|
179
|
+
admission.account({ outputTokens: replayed.tokens?.output ?? 0, cost: replayed.cost ?? 0 });
|
|
180
|
+
options.onEvent({
|
|
181
|
+
type: "agentEnd",
|
|
182
|
+
callIndex,
|
|
183
|
+
label,
|
|
184
|
+
phase,
|
|
185
|
+
tokens: replayed.tokens,
|
|
186
|
+
replayed: true,
|
|
187
|
+
prompt,
|
|
188
|
+
preview: previewValue(replayed.value),
|
|
189
|
+
});
|
|
131
190
|
return replayed.value;
|
|
132
191
|
}
|
|
133
192
|
|
|
134
193
|
return limiter(async () => {
|
|
135
|
-
|
|
136
|
-
|
|
194
|
+
// Queued calls were admitted before earlier agents reported usage.
|
|
195
|
+
// Recheck here, before any provider work or agentStart event — and
|
|
196
|
+
// give the admission slot back, since this agent never runs.
|
|
197
|
+
try {
|
|
198
|
+
throwIfAborted();
|
|
199
|
+
checkBudget();
|
|
200
|
+
} catch (error) {
|
|
201
|
+
admission.account({ agents: -1 });
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
options.onEvent({ type: "agentStart", callIndex, label, phase, prompt });
|
|
137
205
|
try {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
206
|
+
const onUpdate = (update: AgentRunUpdate) =>
|
|
207
|
+
options.onEvent({ type: "agentUpdate", callIndex, label, phase, ...update });
|
|
208
|
+
const result = await options.agentCall(prompt, opts, onUpdate);
|
|
209
|
+
admission.account({ outputTokens: result.tokens.output, cost: result.cost });
|
|
141
210
|
options.onJournal?.({ callIndex, hash, result, timestamp: now() });
|
|
142
|
-
options.onEvent({
|
|
211
|
+
options.onEvent({
|
|
212
|
+
type: "agentEnd",
|
|
213
|
+
callIndex,
|
|
214
|
+
label,
|
|
215
|
+
phase,
|
|
216
|
+
tokens: result.tokens,
|
|
217
|
+
cost: result.cost,
|
|
218
|
+
preview: previewValue(result.value),
|
|
219
|
+
});
|
|
143
220
|
return result.value;
|
|
144
221
|
} catch (error) {
|
|
145
|
-
|
|
222
|
+
if (options.signal.aborted) {
|
|
223
|
+
// Close the record: the viewer would otherwise show a completed or
|
|
224
|
+
// stopped run with this agent still "running".
|
|
225
|
+
options.onEvent({ type: "agentEnd", callIndex, label, phase, text: "aborted" });
|
|
226
|
+
throw new WorkflowScriptError("Workflow run was aborted");
|
|
227
|
+
}
|
|
146
228
|
// A script-authoring mistake (bad agentType/model, worktree without a
|
|
147
229
|
// git repo, malformed schema) must unwind the script, not vanish into
|
|
148
230
|
// a null the way a genuine agent failure does — same rule parallel()
|
|
@@ -157,58 +239,6 @@ export function createScriptGlobals(options: ScriptGlobalsOptions): { globals: S
|
|
|
157
239
|
});
|
|
158
240
|
};
|
|
159
241
|
|
|
160
|
-
const parallel = async (thunks: Array<() => Promise<unknown>>): Promise<unknown[]> => {
|
|
161
|
-
if (!Array.isArray(thunks)) throw new WorkflowScriptError("parallel() takes an array of functions");
|
|
162
|
-
if (thunks.length > MAX_ITEMS_PER_CALL) {
|
|
163
|
-
throw new WorkflowScriptError(`parallel() accepts at most ${MAX_ITEMS_PER_CALL} items (got ${thunks.length})`);
|
|
164
|
-
}
|
|
165
|
-
// Invoke every thunk synchronously first so agent() callIndexes are
|
|
166
|
-
// assigned in array order regardless of completion timing.
|
|
167
|
-
const promises = thunks.map((thunk) => {
|
|
168
|
-
if (typeof thunk !== "function") {
|
|
169
|
-
return Promise.reject(new WorkflowScriptError("parallel() items must be functions returning promises"));
|
|
170
|
-
}
|
|
171
|
-
try {
|
|
172
|
-
return Promise.resolve(thunk());
|
|
173
|
-
} catch (error) {
|
|
174
|
-
return Promise.reject(error);
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
const settled = await Promise.allSettled(promises);
|
|
178
|
-
return settled.map((s) => {
|
|
179
|
-
if (s.status === "fulfilled") return s.value;
|
|
180
|
-
if (s.reason instanceof WorkflowScriptError) throw s.reason;
|
|
181
|
-
return null;
|
|
182
|
-
});
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
const pipeline = async (
|
|
186
|
-
items: unknown[],
|
|
187
|
-
...stages: Array<(prev: unknown, item: unknown, index: number) => unknown>
|
|
188
|
-
): Promise<unknown[]> => {
|
|
189
|
-
if (!Array.isArray(items)) throw new WorkflowScriptError("pipeline() takes an array of items");
|
|
190
|
-
if (items.length > MAX_ITEMS_PER_CALL) {
|
|
191
|
-
throw new WorkflowScriptError(`pipeline() accepts at most ${MAX_ITEMS_PER_CALL} items (got ${items.length})`);
|
|
192
|
-
}
|
|
193
|
-
if (stages.some((s) => typeof s !== "function")) {
|
|
194
|
-
throw new WorkflowScriptError("pipeline() stages must be functions");
|
|
195
|
-
}
|
|
196
|
-
return Promise.all(
|
|
197
|
-
items.map(async (item, index) => {
|
|
198
|
-
let prev: unknown = item;
|
|
199
|
-
for (const stage of stages) {
|
|
200
|
-
try {
|
|
201
|
-
prev = await stage(prev, item, index);
|
|
202
|
-
} catch (error) {
|
|
203
|
-
if (error instanceof WorkflowScriptError) throw error;
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
return prev;
|
|
208
|
-
}),
|
|
209
|
-
);
|
|
210
|
-
};
|
|
211
|
-
|
|
212
242
|
const workflowFn = async (nameOrRef: unknown, childArgs?: unknown): Promise<unknown> => {
|
|
213
243
|
if (!options.runWorkflow) {
|
|
214
244
|
throw new WorkflowScriptError("workflow() nesting is one level only — this run cannot start another child workflow");
|
|
@@ -222,28 +252,21 @@ export function createScriptGlobals(options: ScriptGlobalsOptions): { globals: S
|
|
|
222
252
|
|
|
223
253
|
const globals: ScriptGlobals = {
|
|
224
254
|
agent,
|
|
225
|
-
parallel,
|
|
226
|
-
pipeline,
|
|
227
255
|
workflow: workflowFn,
|
|
228
256
|
phase: (title: string) => {
|
|
229
257
|
currentPhase = String(title);
|
|
230
258
|
options.onEvent({ type: "phase", phase: currentPhase });
|
|
231
259
|
},
|
|
232
260
|
log,
|
|
233
|
-
console: {
|
|
234
|
-
log,
|
|
235
|
-
info: log,
|
|
236
|
-
warn: (m) => log(`[warn] ${String(m)}`),
|
|
237
|
-
error: (m) => log(`[error] ${String(m)}`),
|
|
238
|
-
},
|
|
239
261
|
args: options.args,
|
|
240
262
|
budget,
|
|
241
263
|
};
|
|
242
264
|
|
|
243
265
|
const state: ScriptRunState = {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
266
|
+
admission,
|
|
267
|
+
agentCount: admission.agentCount,
|
|
268
|
+
outputTokens: admission.outputTokens,
|
|
269
|
+
cost: admission.cost,
|
|
247
270
|
currentPhase: () => currentPhase,
|
|
248
271
|
};
|
|
249
272
|
|