pi-ultracode 0.4.0 → 0.5.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/README.md +25 -9
- package/README.zh-CN.md +25 -9
- package/extensions/ultracode.ts +7 -9
- package/package.json +2 -2
- package/src/commands.ts +17 -17
- package/src/depth.ts +38 -0
- package/src/index.ts +8 -0
- package/src/mode.ts +82 -58
- package/src/prompts.ts +64 -31
- package/src/thinking.ts +1 -1
- package/src/workflow/tool.ts +5 -6
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Deterministic multi-agent workflows for [Pi](https://github.com/earendil-works/p
|
|
|
4
4
|
|
|
5
5
|
**English** · [简体中文](https://github.com/ekil1100/pi-ultracode/blob/main/README.zh-CN.md)
|
|
6
6
|
|
|
7
|
-
`pi-ultracode` adds
|
|
7
|
+
`pi-ultracode` adds opt-in semantic analysis-depth modes to Pi. It can route each task automatically or hold a fixed focused, standard, or deep policy. When delegation adds value, the main agent can run a bounded JavaScript workflow with parallel subagents, isolated worktrees, structured output, durable resume, and live progress.
|
|
8
8
|
|
|
9
9
|
The project combines the terminal-first agentic experience of [Claude Code](https://github.com/anthropics/claude-code) with the explicit workflow and structural-control ideas found in [Grok Build](https://github.com/xai-org/grok-build), while keeping Pi as the runtime.
|
|
10
10
|
|
|
@@ -14,14 +14,14 @@ The project combines the terminal-first agentic experience of [Claude Code](http
|
|
|
14
14
|
pi install npm:pi-ultracode
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Then reload Pi and
|
|
17
|
+
Then reload Pi and enable adaptive Ultracode:
|
|
18
18
|
|
|
19
19
|
```text
|
|
20
20
|
/reload
|
|
21
21
|
/ultracode
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
You can also
|
|
24
|
+
You can also start directly in `auto` mode:
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
27
|
pi --ultracode
|
|
@@ -33,7 +33,7 @@ Current releases are tested with Pi 0.84.
|
|
|
33
33
|
|
|
34
34
|
## Core features
|
|
35
35
|
|
|
36
|
-
- **
|
|
36
|
+
- **Adaptive semantic depth** — choose `auto`, `focused`, `standard`, or `deep`; `auto` selects the smallest evidence-sufficient depth and `off` restores the previous thinking level.
|
|
37
37
|
- **Explicit workflows** — compose work with `agent()`, `parallel()`, `pipeline()`, and nested `workflow()` calls.
|
|
38
38
|
- **Independent subagents** — each agent gets its own Pi session, context, tools, model selection, and optional role.
|
|
39
39
|
- **Parallel worktree isolation** — writing agents can work in temporary git worktrees before their patches are integrated.
|
|
@@ -44,7 +44,7 @@ Current releases are tested with Pi 0.84.
|
|
|
44
44
|
|
|
45
45
|
## Quick start
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
Enable adaptive Ultracode and describe a task:
|
|
48
48
|
|
|
49
49
|
```text
|
|
50
50
|
/ultracode
|
|
@@ -59,16 +59,32 @@ Useful commands:
|
|
|
59
59
|
|
|
60
60
|
| Command | Action |
|
|
61
61
|
| --- | --- |
|
|
62
|
-
| `/ultracode` |
|
|
63
|
-
| `/ultracode
|
|
62
|
+
| `/ultracode` | Enable `auto` from off; disable any active mode |
|
|
63
|
+
| `/ultracode auto` | Select adaptive semantic-depth routing |
|
|
64
|
+
| `/ultracode focused` | Fix the lightweight, narrowly scoped policy |
|
|
65
|
+
| `/ultracode standard` | Fix the balanced policy with conditional verification |
|
|
66
|
+
| `/ultracode deep` | Fix the high-assurance policy with deep verification and max effort |
|
|
64
67
|
| `/ultracode off` | Disable it and restore the previous thinking level |
|
|
65
|
-
| `/ultracode status` | Show the
|
|
68
|
+
| `/ultracode status` | Show the configured mode and effective thinking level |
|
|
66
69
|
| `/workflows` or `F6` | Open the workflow browser |
|
|
67
70
|
| `/workflows <runId>` | Open a specific run |
|
|
68
71
|
| `/workflows abort` | Abort active runs |
|
|
69
72
|
|
|
70
73
|
Press `Esc` to cancel a running workflow. In Pi's fullscreen TUI, use `Ctrl+PageUp`, `Ctrl+PageDown`, and `Ctrl+End` inside workflow details.
|
|
71
74
|
|
|
75
|
+
## Analysis depth
|
|
76
|
+
|
|
77
|
+
Depth is semantic, not time-based:
|
|
78
|
+
|
|
79
|
+
- **Focused** prefers the parent agent and one bounded line of inquiry. It does not run adversarial verification by default.
|
|
80
|
+
- **Standard** covers the few independent dimensions that can change the answer and verifies only high-risk, conflicting, or weakly evidenced claims.
|
|
81
|
+
- **Deep** uses bounded multi-perspective investigation and adversarial verification for high-risk or explicitly comprehensive work.
|
|
82
|
+
- **Auto** routes to the smallest sufficient level from user intent, consequence risk, scope, ambiguity, available evidence, and conflicts. It escalates only when evidence requires it.
|
|
83
|
+
|
|
84
|
+
Research stops when key claims have direct evidence, no material conflict or unresolved high-risk question remains, and another round would repeat known evidence. Wall-clock time, deadlines, and duration limits are never used to choose or stop analysis depth. `maxAgents` and `reserveAgents` remain structural admission limits.
|
|
85
|
+
|
|
86
|
+
Focused defaults to medium effort, auto and standard to high, and deep to max; individual workflow agents can still override effort with a model suffix. A separate skeptic or synthesis agent is not automatic.
|
|
87
|
+
|
|
72
88
|
## Workflow example
|
|
73
89
|
|
|
74
90
|
The main agent normally writes workflows for you. Reusable workflows can also be saved under `.pi/ultracode/workflows/*.workflow.js` or `~/.pi/ultracode/workflows/*.workflow.js`. Project-scoped workflows are discovered only after Pi marks the project as trusted; user-scoped workflows remain available in untrusted projects.
|
|
@@ -133,7 +149,7 @@ Workflow agent sessions retain project context and ordinary skills, but do not i
|
|
|
133
149
|
|
|
134
150
|
Resume is intentionally immutable: the normalized script, arguments, canonical repository/relative cwd, project-trust context, agent definitions, effective models, and call structure must still match. Worktree delivery writes a durable recovery intent before changing the shared repository; an interrupted or conflicted delivery blocks automatic replay and reports its recovery patch. Changed work starts a new run.
|
|
135
151
|
|
|
136
|
-
Token and cost data are reported for observability, not enforced as a budget. Worker and VM restrictions are determinism and liveness guards, not a security sandbox.
|
|
152
|
+
Token and cost data are reported for observability, not enforced as a budget. Worker and VM restrictions are determinism and liveness guards, not a security sandbox and not analysis-depth controls.
|
|
137
153
|
|
|
138
154
|
## Design inspiration
|
|
139
155
|
|
package/README.zh-CN.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[English](README.md) · **简体中文**
|
|
6
6
|
|
|
7
|
-
`pi-ultracode` 为 Pi
|
|
7
|
+
`pi-ultracode` 为 Pi 增加可选的语义化分析深度模式。它既可以自动判断任务需要的深度,也可以固定使用 focused、standard 或 deep 策略。当委派确有价值时,主代理可以运行有边界的 JavaScript 工作流,使用并行子代理、隔离 worktree、结构化输出、持久恢复和实时进度。
|
|
8
8
|
|
|
9
9
|
项目结合了 [Claude Code](https://github.com/anthropics/claude-code) 的终端 Agentic 体验,以及 [Grok Build](https://github.com/xai-org/grok-build) 的显式工作流和结构控制思路,同时继续使用 Pi 作为运行时。
|
|
10
10
|
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
pi install npm:pi-ultracode
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
然后重新加载 Pi
|
|
17
|
+
然后重新加载 Pi,并用主命令开启自适应 Ultracode:
|
|
18
18
|
|
|
19
19
|
```text
|
|
20
20
|
/reload
|
|
21
21
|
/ultracode
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
也可以在启动时直接进入 `auto` 模式:
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
27
|
pi --ultracode
|
|
@@ -33,7 +33,7 @@ pi --ultracode
|
|
|
33
33
|
|
|
34
34
|
## 核心特性
|
|
35
35
|
|
|
36
|
-
-
|
|
36
|
+
- **自适应语义深度**:可选择 `auto`、`focused`、`standard` 或 `deep`;`auto` 使用证据充分的最小深度,关闭时恢复之前的思考强度。
|
|
37
37
|
- **显式工作流**:通过 `agent()`、`parallel()`、`pipeline()` 和嵌套 `workflow()` 组合任务。
|
|
38
38
|
- **独立子代理**:每个代理拥有独立的 Pi 会话、上下文、工具、模型选择和可选角色。
|
|
39
39
|
- **并行 worktree 隔离**:写入型代理可在临时 git worktree 中工作,再集成补丁。
|
|
@@ -44,7 +44,7 @@ pi --ultracode
|
|
|
44
44
|
|
|
45
45
|
## 快速开始
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
用主命令开启自适应 Ultracode,然后描述任务:
|
|
48
48
|
|
|
49
49
|
```text
|
|
50
50
|
/ultracode
|
|
@@ -59,16 +59,32 @@ Pi 会自行判断工作流是否有帮助。小任务仍可继续使用普通
|
|
|
59
59
|
|
|
60
60
|
| 命令 | 作用 |
|
|
61
61
|
| --- | --- |
|
|
62
|
-
| `/ultracode` |
|
|
63
|
-
| `/ultracode
|
|
62
|
+
| `/ultracode` | 关闭时开启 `auto`;任一模式已开启时关闭 |
|
|
63
|
+
| `/ultracode auto` | 使用自适应语义深度路由 |
|
|
64
|
+
| `/ultracode focused` | 固定使用轻量、聚焦的分析策略 |
|
|
65
|
+
| `/ultracode standard` | 固定使用平衡策略和条件验证 |
|
|
66
|
+
| `/ultracode deep` | 固定使用高保障深度验证和 max effort |
|
|
64
67
|
| `/ultracode off` | 关闭并恢复之前的思考强度 |
|
|
65
|
-
| `/ultracode status` |
|
|
68
|
+
| `/ultracode status` | 查看配置模式和实际思考强度 |
|
|
66
69
|
| `/workflows` 或 `F6` | 打开工作流浏览器 |
|
|
67
70
|
| `/workflows <runId>` | 打开指定运行 |
|
|
68
71
|
| `/workflows abort` | 中止活动运行 |
|
|
69
72
|
|
|
70
73
|
按 `Esc` 可取消正在运行的工作流。在 Pi 的 fullscreen TUI 中,请在工作流详情内使用 `Ctrl+PageUp`、`Ctrl+PageDown` 和 `Ctrl+End`。
|
|
71
74
|
|
|
75
|
+
## 分析深度
|
|
76
|
+
|
|
77
|
+
深度是语义化质量决策,不按运行时间判断:
|
|
78
|
+
|
|
79
|
+
- **Focused** 优先使用主代理和单一、边界明确的调查路径,默认不做对抗验证。
|
|
80
|
+
- **Standard** 覆盖少量真正会改变结论的独立维度,只验证高风险、冲突或证据薄弱的结论。
|
|
81
|
+
- **Deep** 面向高风险或用户明确要求全面分析的任务,使用有界的多视角调查和对抗验证。
|
|
82
|
+
- **Auto** 根据用户意图、影响风险、范围、歧义、现有证据和结论冲突,选择足够完成任务的最小等级;仅在证据要求升级时加深。
|
|
83
|
+
|
|
84
|
+
当关键结论已有直接证据、没有实质冲突或未解决的高风险问题,且下一轮只会重复已知证据时停止。墙钟时间、deadline 和 duration limit 不得用于选择或停止分析深度。`maxAgents` 与 `reserveAgents` 继续作为结构性准入限制。
|
|
85
|
+
|
|
86
|
+
Focused 默认使用 medium effort,auto 和 standard 默认使用 high,deep 使用 max;单个 workflow agent 仍可通过模型后缀覆盖 effort。skeptic 和独立 synthesis agent 都不是默认步骤。
|
|
87
|
+
|
|
72
88
|
## 工作流示例
|
|
73
89
|
|
|
74
90
|
通常由主代理自动编写工作流。需要复用时,可以保存到 `.pi/ultracode/workflows/*.workflow.js` 或 `~/.pi/ultracode/workflows/*.workflow.js`。只有 Pi 将项目标记为可信后,才会发现项目级工作流;用户级工作流在未信任项目中仍可使用。
|
|
@@ -133,7 +149,7 @@ Workflow 子代理会保留项目上下文和普通 skills,但不会初始化
|
|
|
133
149
|
|
|
134
150
|
Resume 刻意保持不可变:规范化脚本、参数、规范仓库及仓内相对 cwd、项目信任上下文、代理定义、实际模型和调用结构都必须匹配。Worktree 交付会在修改共享仓库前先写入持久恢复意图;中断或冲突的交付会阻止自动回放,并报告恢复补丁。工作内容发生变化时,应启动新的 run。
|
|
135
151
|
|
|
136
|
-
Token 和成本只用于可观测性,不作为执行预算。Worker 与 VM
|
|
152
|
+
Token 和成本只用于可观测性,不作为执行预算。Worker 与 VM 限制用于确定性和存活性保护,不是安全沙箱,也不参与分析深度判断。
|
|
137
153
|
|
|
138
154
|
## 设计参考
|
|
139
155
|
|
package/extensions/ultracode.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* pi-ultracode extension entrypoint.
|
|
3
3
|
*
|
|
4
|
-
* Wires together
|
|
5
|
-
*
|
|
6
|
-
* 2. The full `workflow` orchestration tool.
|
|
7
|
-
* 3. The `/ultracode` and `/workflows` commands.
|
|
4
|
+
* Wires together Ultracode's semantic analysis-depth modes, deterministic
|
|
5
|
+
* workflow orchestration, and the `/ultracode` / `/workflows` commands.
|
|
8
6
|
*/
|
|
9
7
|
|
|
10
8
|
import {
|
|
@@ -53,7 +51,7 @@ export default function extension(pi: ExtensionAPI, extraDeps: UltracodeExtensio
|
|
|
53
51
|
// Opt-in via CLI flag: `pi --ultracode`.
|
|
54
52
|
pi.registerFlag("ultracode", {
|
|
55
53
|
type: "boolean",
|
|
56
|
-
description: "Start the session in
|
|
54
|
+
description: "Start the session in adaptive Ultracode mode.",
|
|
57
55
|
});
|
|
58
56
|
|
|
59
57
|
// SDK-created sessions can prompt without emitting session_start. Sync during
|
|
@@ -68,7 +66,7 @@ export default function extension(pi: ExtensionAPI, extraDeps: UltracodeExtensio
|
|
|
68
66
|
if (event.toolName === workflowTool.name && !mode.isEnforcing()) {
|
|
69
67
|
return {
|
|
70
68
|
block: true,
|
|
71
|
-
reason: "The workflow tool is disabled. Run /ultracode
|
|
69
|
+
reason: "The workflow tool is disabled. Run /ultracode or select an Ultracode depth before using it.",
|
|
72
70
|
};
|
|
73
71
|
}
|
|
74
72
|
});
|
|
@@ -92,7 +90,7 @@ export default function extension(pi: ExtensionAPI, extraDeps: UltracodeExtensio
|
|
|
92
90
|
// ignore
|
|
93
91
|
}
|
|
94
92
|
if (!mode.isEnabled() && pi.getFlag?.("ultracode") === true) {
|
|
95
|
-
mode.enable(pi);
|
|
93
|
+
mode.enable(pi, "auto");
|
|
96
94
|
}
|
|
97
95
|
// Registration makes extension tools discoverable; activation remains opt-in.
|
|
98
96
|
mode.syncWorkflowTool(pi);
|
|
@@ -128,7 +126,7 @@ export default function extension(pi: ExtensionAPI, extraDeps: UltracodeExtensio
|
|
|
128
126
|
|
|
129
127
|
pi.on("session_shutdown", async () => {
|
|
130
128
|
// Quiesce first so late model/effort events cannot undo restoration. The
|
|
131
|
-
// persisted
|
|
129
|
+
// The persisted configured mode remains active for reload/resume/fork replacements.
|
|
132
130
|
mode.suspend(pi);
|
|
133
131
|
await mode.flushThinkingPreference();
|
|
134
132
|
});
|
|
@@ -137,7 +135,7 @@ export default function extension(pi: ExtensionAPI, extraDeps: UltracodeExtensio
|
|
|
137
135
|
// Reconcile the tool schema and always append the standing block on an
|
|
138
136
|
// enforcing turn, even when another active-tool writer caused drift.
|
|
139
137
|
mode.syncWorkflowTool(pi);
|
|
140
|
-
mode.
|
|
138
|
+
mode.reapplyConfiguredThinking(pi);
|
|
141
139
|
await mode.flushThinkingPreference();
|
|
142
140
|
return mode.beforeAgentStart(event);
|
|
143
141
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-ultracode",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Adaptive semantic-depth workflow orchestration for Pi, with focused, standard, and deep modes, isolated subagents, worktree delivery, structured output, and durable resume.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"pi-package",
|
package/src/commands.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
6
|
+
import { ACTIVE_ULTRACODE_MODES, isActiveUltracodeMode } from "./depth.ts";
|
|
6
7
|
import type { UltracodeMode } from "./mode.ts";
|
|
7
8
|
import type { WorkflowRegistry } from "./workflow/registry.ts";
|
|
8
9
|
import { workflowRunsDir } from "./workflow/tool.ts";
|
|
@@ -10,10 +11,10 @@ import { openWorkflowOverlay } from "./workflow/workflow-overlay.ts";
|
|
|
10
11
|
|
|
11
12
|
export function registerCommands(pi: ExtensionAPI, mode: UltracodeMode, registry: WorkflowRegistry): void {
|
|
12
13
|
pi.registerCommand("ultracode", {
|
|
13
|
-
description: "Toggle
|
|
14
|
+
description: "Toggle adaptive Ultracode, or select a fixed semantic depth: auto|focused|standard|deep|off|status",
|
|
14
15
|
getArgumentCompletions(prefix: string) {
|
|
15
|
-
return [
|
|
16
|
-
.filter((
|
|
16
|
+
return [...ACTIVE_ULTRACODE_MODES, "off", "status"]
|
|
17
|
+
.filter((value) => value.startsWith(prefix))
|
|
17
18
|
.map((value) => ({ value, label: value }));
|
|
18
19
|
},
|
|
19
20
|
handler: async (args: string, ctx) => {
|
|
@@ -21,32 +22,31 @@ export function registerCommands(pi: ExtensionAPI, mode: UltracodeMode, registry
|
|
|
21
22
|
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
22
23
|
const sub = (parts[0] ?? "").toLowerCase();
|
|
23
24
|
|
|
24
|
-
// Bare `/ultracode`
|
|
25
|
+
// Bare `/ultracode` enables auto from off and disables any active mode.
|
|
25
26
|
if (sub === "") {
|
|
26
27
|
const nowOn = mode.toggle(pi);
|
|
27
28
|
await mode.flushThinkingPreference();
|
|
28
29
|
ctx.ui.notify(
|
|
29
|
-
nowOn
|
|
30
|
+
nowOn
|
|
31
|
+
? `Ultracode auto — ${mode.statusLine()}`
|
|
32
|
+
: "Ultracode off — thinking restored and workflow tool disabled.",
|
|
30
33
|
"info",
|
|
31
34
|
);
|
|
32
35
|
ctx.ui.setStatus("ultracode", nowOn ? mode.statusLine() : undefined);
|
|
33
36
|
return;
|
|
34
37
|
}
|
|
35
38
|
|
|
39
|
+
if (parts.length > 1) {
|
|
40
|
+
ctx.ui.notify(ultracodeUsage(), "error");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
36
44
|
if (sub === "status") {
|
|
37
|
-
if (parts.length > 1) {
|
|
38
|
-
ctx.ui.notify(ultracodeUsage(), "error");
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
45
|
ctx.ui.notify(mode.statusLine(), "info");
|
|
42
46
|
return;
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
if (sub === "off") {
|
|
46
|
-
if (parts.length > 1) {
|
|
47
|
-
ctx.ui.notify(ultracodeUsage(), "error");
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
50
|
mode.disable(pi);
|
|
51
51
|
await mode.flushThinkingPreference();
|
|
52
52
|
ctx.ui.notify("Ultracode off — thinking restored and workflow tool disabled.", "info");
|
|
@@ -54,14 +54,14 @@ export function registerCommands(pi: ExtensionAPI, mode: UltracodeMode, registry
|
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
if (sub
|
|
57
|
+
if (!isActiveUltracodeMode(sub)) {
|
|
58
58
|
ctx.ui.notify(ultracodeUsage(), "error");
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
mode.enable(pi);
|
|
62
|
+
mode.enable(pi, sub);
|
|
63
63
|
await mode.flushThinkingPreference();
|
|
64
|
-
ctx.ui.notify(`Ultracode
|
|
64
|
+
ctx.ui.notify(`Ultracode ${sub} — ${mode.statusLine()}`, "info");
|
|
65
65
|
ctx.ui.setStatus("ultracode", mode.statusLine());
|
|
66
66
|
},
|
|
67
67
|
});
|
|
@@ -100,5 +100,5 @@ export function registerCommands(pi: ExtensionAPI, mode: UltracodeMode, registry
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
function ultracodeUsage(): string {
|
|
103
|
-
return "Usage: /ultracode [
|
|
103
|
+
return "Usage: /ultracode [auto|focused|standard|deep|off|status]";
|
|
104
104
|
}
|
package/src/depth.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Ultracode's configured analysis modes and their default reasoning effort. */
|
|
2
|
+
|
|
3
|
+
import type { ThinkingLevel } from "./thinking.ts";
|
|
4
|
+
|
|
5
|
+
export const ACTIVE_ULTRACODE_MODES = ["auto", "focused", "standard", "deep"] as const;
|
|
6
|
+
|
|
7
|
+
export type ActiveUltracodeMode = (typeof ACTIVE_ULTRACODE_MODES)[number];
|
|
8
|
+
export type UltracodeModeName = "off" | ActiveUltracodeMode;
|
|
9
|
+
|
|
10
|
+
const ACTIVE_MODE_SET = new Set<string>(ACTIVE_ULTRACODE_MODES);
|
|
11
|
+
|
|
12
|
+
export function isActiveUltracodeMode(value: unknown): value is ActiveUltracodeMode {
|
|
13
|
+
return typeof value === "string" && ACTIVE_MODE_SET.has(value);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function isUltracodeModeName(value: unknown): value is UltracodeModeName {
|
|
17
|
+
return value === "off" || isActiveUltracodeMode(value);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Default effort for the parent turn and for child agents that do not override
|
|
22
|
+
* it explicitly. Auto starts from the balanced standard effort; its prompt
|
|
23
|
+
* policy can route individual workflow agents lower or higher as evidence
|
|
24
|
+
* requires. Pi still clamps each request to the selected model's capabilities.
|
|
25
|
+
*/
|
|
26
|
+
export function thinkingLevelForMode(mode: UltracodeModeName): ThinkingLevel | undefined {
|
|
27
|
+
switch (mode) {
|
|
28
|
+
case "focused":
|
|
29
|
+
return "medium";
|
|
30
|
+
case "auto":
|
|
31
|
+
case "standard":
|
|
32
|
+
return "high";
|
|
33
|
+
case "deep":
|
|
34
|
+
return "max";
|
|
35
|
+
case "off":
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
export { default } from "../extensions/ultracode.ts";
|
|
4
4
|
export { UltracodeMode, MODE_ENTRY_TYPE } from "./mode.ts";
|
|
5
|
+
export {
|
|
6
|
+
ACTIVE_ULTRACODE_MODES,
|
|
7
|
+
isActiveUltracodeMode,
|
|
8
|
+
isUltracodeModeName,
|
|
9
|
+
thinkingLevelForMode,
|
|
10
|
+
type ActiveUltracodeMode,
|
|
11
|
+
type UltracodeModeName,
|
|
12
|
+
} from "./depth.ts";
|
|
5
13
|
export { registerCommands } from "./commands.ts";
|
|
6
14
|
export {
|
|
7
15
|
ULTRACODE_TAGLINE,
|
package/src/mode.ts
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Ultracode mode controller.
|
|
3
3
|
*
|
|
4
|
-
* Ultracode is a session-scoped
|
|
5
|
-
* -
|
|
4
|
+
* Ultracode is a session-scoped semantic analysis-depth mode. While active, it:
|
|
5
|
+
* - applies the configured mode's default thinking level while preserving the
|
|
6
|
+
* user's previous level,
|
|
6
7
|
* - keeps the `workflow` tool active,
|
|
7
|
-
* - injects
|
|
8
|
-
*
|
|
9
|
-
* - persists its on/off state in session custom entries so it survives
|
|
10
|
-
* reload, resume, fork, and compaction.
|
|
8
|
+
* - injects the configured auto/focused/standard/deep policy on every turn,
|
|
9
|
+
* - persists branch-local mode state across reload, resume, fork, and compaction.
|
|
11
10
|
*/
|
|
12
11
|
|
|
13
12
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
13
|
+
import {
|
|
14
|
+
isActiveUltracodeMode,
|
|
15
|
+
thinkingLevelForMode,
|
|
16
|
+
type ActiveUltracodeMode,
|
|
17
|
+
type UltracodeModeName,
|
|
18
|
+
} from "./depth.ts";
|
|
14
19
|
import { ULTRACODE_ACTIVE_REMINDER, ULTRACODE_TAGLINE, ultracodeSystemBlock } from "./prompts.ts";
|
|
15
20
|
import {
|
|
16
21
|
LEGACY_ULTRACODE_THINKING_LEVEL,
|
|
@@ -24,7 +29,7 @@ export type { ThinkingLevel } from "./thinking.ts";
|
|
|
24
29
|
export const MODE_ENTRY_TYPE = "ultracode-mode";
|
|
25
30
|
|
|
26
31
|
interface PersistedModeState {
|
|
27
|
-
|
|
32
|
+
mode: UltracodeModeName;
|
|
28
33
|
previousThinking?: ThinkingLevel;
|
|
29
34
|
/** `null` records that the setting was originally absent (Pi defaults to medium). */
|
|
30
35
|
previousDefaultThinking?: ThinkingLevel | null;
|
|
@@ -47,13 +52,13 @@ export interface ThinkingPreferenceStore {
|
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
export class UltracodeMode {
|
|
50
|
-
private
|
|
55
|
+
private mode: UltracodeModeName = "off";
|
|
51
56
|
private suspended = false;
|
|
52
57
|
private previousThinking: ThinkingLevel | undefined;
|
|
53
58
|
private previousDefaultThinking: ThinkingLevel | null | undefined;
|
|
54
59
|
/** Restore a level later if the current non-reasoning model clamps it to off. */
|
|
55
60
|
private pendingPreviousThinking: ThinkingLevel | undefined;
|
|
56
|
-
/** The level Pi actually applied after clamping the
|
|
61
|
+
/** The level Pi actually applied after clamping the configured request. */
|
|
57
62
|
private appliedThinking: ThinkingLevel | undefined;
|
|
58
63
|
/** Prevent mode-owned thinking changes from being mistaken for manual overrides. */
|
|
59
64
|
private applyingThinking = false;
|
|
@@ -95,36 +100,45 @@ export class UltracodeMode {
|
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
|
|
98
|
-
/** Enable if off, disable
|
|
103
|
+
/** Enable auto if off, otherwise disable. Returns the new enabled state. */
|
|
99
104
|
toggle(pi: ExtensionAPI): boolean {
|
|
100
|
-
if (this.
|
|
105
|
+
if (this.isEnabled()) {
|
|
101
106
|
this.disable(pi);
|
|
102
107
|
return false;
|
|
103
108
|
}
|
|
104
|
-
this.enable(pi);
|
|
109
|
+
this.enable(pi, "auto");
|
|
105
110
|
return true;
|
|
106
111
|
}
|
|
107
112
|
|
|
108
|
-
|
|
113
|
+
getMode(): UltracodeModeName {
|
|
114
|
+
return this.mode;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** The thinking level Pi actually applied after model/runtime clamping. */
|
|
109
118
|
getAppliedThinking(): ThinkingLevel | undefined {
|
|
110
119
|
return this.appliedThinking;
|
|
111
120
|
}
|
|
112
121
|
|
|
113
122
|
/**
|
|
114
|
-
* Return the raw
|
|
115
|
-
*
|
|
123
|
+
* Return the configured raw effort request so every workflow subagent is
|
|
124
|
+
* clamped independently against its own model.
|
|
116
125
|
*/
|
|
117
126
|
getSubagentThinkingLevel(): ThinkingLevel | undefined {
|
|
118
|
-
return this.isEnforcing() ?
|
|
127
|
+
return this.isEnforcing() ? thinkingLevelForMode(this.mode) : undefined;
|
|
119
128
|
}
|
|
120
129
|
|
|
121
|
-
/** Reassert the
|
|
122
|
-
|
|
130
|
+
/** Reassert the configured mode effort before a turn or after a model change. */
|
|
131
|
+
reapplyConfiguredThinking(pi: ExtensionAPI): boolean {
|
|
123
132
|
if (!this.isEnforcing()) return false;
|
|
124
|
-
this.
|
|
133
|
+
this.applyConfiguredThinking(pi);
|
|
125
134
|
return true;
|
|
126
135
|
}
|
|
127
136
|
|
|
137
|
+
/** @deprecated Use reapplyConfiguredThinking(). */
|
|
138
|
+
reapplyMaximumThinking(pi: ExtensionAPI): boolean {
|
|
139
|
+
return this.reapplyConfiguredThinking(pi);
|
|
140
|
+
}
|
|
141
|
+
|
|
128
142
|
/**
|
|
129
143
|
* Handle model switches both while active and after a clamped restoration.
|
|
130
144
|
* Returns true when Ultracode remains active and the UI should be refreshed.
|
|
@@ -132,8 +146,8 @@ export class UltracodeMode {
|
|
|
132
146
|
handleModelSelect(pi: ExtensionAPI): boolean {
|
|
133
147
|
if (this.suspended) return false;
|
|
134
148
|
this.pendingClearGeneration++;
|
|
135
|
-
if (this.
|
|
136
|
-
this.
|
|
149
|
+
if (this.isEnabled()) {
|
|
150
|
+
this.applyConfiguredThinking(pi);
|
|
137
151
|
return true;
|
|
138
152
|
}
|
|
139
153
|
if (this.pendingPreviousThinking) {
|
|
@@ -147,7 +161,7 @@ export class UltracodeMode {
|
|
|
147
161
|
|
|
148
162
|
/** Restore the pre-mode effective effort without changing persisted mode state. */
|
|
149
163
|
restorePreviousThinking(pi: ExtensionAPI): void {
|
|
150
|
-
if (this.
|
|
164
|
+
if (this.isEnabled() && this.previousThinking) this.applyCompatibleThinking(pi, this.previousThinking);
|
|
151
165
|
}
|
|
152
166
|
|
|
153
167
|
/** Stop enforcing synchronously, then restore effort before session teardown. */
|
|
@@ -162,34 +176,32 @@ export class UltracodeMode {
|
|
|
162
176
|
}
|
|
163
177
|
|
|
164
178
|
/**
|
|
165
|
-
* Enforce the
|
|
166
|
-
* and events emitted by this mode are ignored to avoid
|
|
167
|
-
* Returns true when a manual selection was overridden.
|
|
179
|
+
* Enforce the configured effort after an external thinking-level selection.
|
|
180
|
+
* Stale events and events emitted by this mode are ignored to avoid recursion.
|
|
168
181
|
*/
|
|
169
182
|
handleThinkingLevelSelect(pi: ExtensionAPI, level: ThinkingLevel): boolean {
|
|
170
183
|
if (this.suspended || this.applyingThinking) return false;
|
|
171
184
|
const current = safeGetThinking(pi);
|
|
172
185
|
if (!current || current !== level) return false;
|
|
173
|
-
if (!this.
|
|
186
|
+
if (!this.isEnabled()) {
|
|
174
187
|
// Pi emits the same event for a user selection and an automatic model
|
|
175
188
|
// re-clamp. Defer clearing until model_select has had a chance to consume it.
|
|
176
189
|
if (this.pendingPreviousThinking) this.deferPendingClear(pi, level);
|
|
177
190
|
return false;
|
|
178
191
|
}
|
|
179
192
|
if (current === this.appliedThinking) return false;
|
|
180
|
-
this.
|
|
193
|
+
this.applyConfiguredThinking(pi);
|
|
181
194
|
return true;
|
|
182
195
|
}
|
|
183
196
|
|
|
184
197
|
isEnabled(): boolean {
|
|
185
|
-
return this.
|
|
198
|
+
return this.mode !== "off";
|
|
186
199
|
}
|
|
187
200
|
|
|
188
201
|
isSuspended(): boolean {
|
|
189
202
|
return this.suspended;
|
|
190
203
|
}
|
|
191
204
|
|
|
192
|
-
|
|
193
205
|
/** Keep tool availability aligned with the current mode state. */
|
|
194
206
|
syncWorkflowTool(pi: ExtensionAPI): void {
|
|
195
207
|
if (this.isEnforcing()) this.activateWorkflowTool(pi);
|
|
@@ -200,12 +212,16 @@ export class UltracodeMode {
|
|
|
200
212
|
return ULTRACODE_TAGLINE;
|
|
201
213
|
}
|
|
202
214
|
|
|
203
|
-
/**
|
|
204
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Enable or switch modes without replacing the saved baseline. The no-argument
|
|
217
|
+
* form retains the pre-0.5 programmatic deep behavior; user commands pass an
|
|
218
|
+
* explicit mode and bare `/ultracode` uses toggle() to enter auto.
|
|
219
|
+
*/
|
|
220
|
+
enable(pi: ExtensionAPI, mode: ActiveUltracodeMode = "deep"): void {
|
|
205
221
|
this.suspended = false;
|
|
206
222
|
this.pendingPreviousThinking = undefined;
|
|
207
223
|
this.pendingClearGeneration++;
|
|
208
|
-
if (!this.
|
|
224
|
+
if (!this.isEnabled()) {
|
|
209
225
|
const current = safeGetThinking(pi);
|
|
210
226
|
const preference = this.captureThinkingPreference();
|
|
211
227
|
const effectivePreference = this.runtimeCompatibleThinking(preference.effective) as
|
|
@@ -222,16 +238,16 @@ export class UltracodeMode {
|
|
|
222
238
|
: current;
|
|
223
239
|
this.previousDefaultThinking = this.runtimeCompatibleThinking(preference.global);
|
|
224
240
|
this.legacyDefaultMigrationPending = false;
|
|
225
|
-
this.enabled = true;
|
|
226
241
|
}
|
|
227
|
-
this.
|
|
242
|
+
this.mode = mode;
|
|
243
|
+
this.applyConfiguredThinking(pi);
|
|
228
244
|
this.syncWorkflowTool(pi);
|
|
229
245
|
this.persist(pi);
|
|
230
246
|
}
|
|
231
247
|
|
|
232
|
-
/** Turn
|
|
248
|
+
/** Turn Ultracode off, restoring the pre-mode thinking level. */
|
|
233
249
|
disable(pi: ExtensionAPI): void {
|
|
234
|
-
if (!this.
|
|
250
|
+
if (!this.isEnabled()) {
|
|
235
251
|
this.syncWorkflowTool(pi);
|
|
236
252
|
return;
|
|
237
253
|
}
|
|
@@ -241,7 +257,7 @@ export class UltracodeMode {
|
|
|
241
257
|
? previous
|
|
242
258
|
: undefined;
|
|
243
259
|
this.pendingClearGeneration++;
|
|
244
|
-
this.
|
|
260
|
+
this.mode = "off";
|
|
245
261
|
this.suspended = false;
|
|
246
262
|
this.syncWorkflowTool(pi);
|
|
247
263
|
this.persist(pi);
|
|
@@ -286,7 +302,7 @@ export class UltracodeMode {
|
|
|
286
302
|
?? (wasEnforcing ? this.previousThinking : undefined)
|
|
287
303
|
?? effectivePreference,
|
|
288
304
|
) as ThinkingLevel | undefined;
|
|
289
|
-
this.
|
|
305
|
+
this.mode = "off";
|
|
290
306
|
this.suspended = false;
|
|
291
307
|
this.pendingPreviousThinking = undefined;
|
|
292
308
|
this.previousThinking = target;
|
|
@@ -306,7 +322,7 @@ export class UltracodeMode {
|
|
|
306
322
|
}
|
|
307
323
|
|
|
308
324
|
this.suspended = false;
|
|
309
|
-
this.
|
|
325
|
+
this.mode = latest.mode;
|
|
310
326
|
this.syncWorkflowTool(pi);
|
|
311
327
|
const maxIsUnknownToRuntime = !this.runtimeSupportsMaxThinking
|
|
312
328
|
&& preference.effective === ULTRACODE_THINKING_LEVEL;
|
|
@@ -319,7 +335,7 @@ export class UltracodeMode {
|
|
|
319
335
|
// Pre-preference-store releases persisted only previousThinking while their
|
|
320
336
|
// active xhigh request polluted Pi's global default. Recover that baseline
|
|
321
337
|
// once instead of treating the known Ultracode value as a user preference.
|
|
322
|
-
const migratesLegacyDefault = latest.
|
|
338
|
+
const migratesLegacyDefault = latest.mode !== "off"
|
|
323
339
|
&& latest.previousDefaultThinking === undefined
|
|
324
340
|
&& latest.previousThinking !== undefined
|
|
325
341
|
&& (preference.global === LEGACY_ULTRACODE_THINKING_LEVEL
|
|
@@ -331,9 +347,9 @@ export class UltracodeMode {
|
|
|
331
347
|
: this.runtimeCompatibleThinking(latest.previousDefaultThinking);
|
|
332
348
|
this.legacyDefaultMigrationPending = migratesLegacyDefault;
|
|
333
349
|
|
|
334
|
-
this.pendingPreviousThinking = this.
|
|
335
|
-
if (this.
|
|
336
|
-
this.
|
|
350
|
+
this.pendingPreviousThinking = this.isEnabled() ? undefined : latest.pendingPreviousThinking;
|
|
351
|
+
if (this.isEnabled()) {
|
|
352
|
+
this.applyConfiguredThinking(pi);
|
|
337
353
|
if (migratesLegacyDefault) {
|
|
338
354
|
this.queueDefaultThinkingRestore(() => {
|
|
339
355
|
this.legacyDefaultMigrationPending = false;
|
|
@@ -374,30 +390,29 @@ export class UltracodeMode {
|
|
|
374
390
|
}
|
|
375
391
|
}
|
|
376
392
|
|
|
377
|
-
/**
|
|
378
|
-
* Build the before_agent_start result: appends the ultracode system block to the
|
|
379
|
-
* turn's system prompt when enabled.
|
|
380
|
-
*/
|
|
393
|
+
/** Append the configured semantic-depth policy to the turn's system prompt. */
|
|
381
394
|
beforeAgentStart(event: { systemPrompt: string }): { systemPrompt: string } | undefined {
|
|
382
|
-
if (!this.isEnforcing()) return undefined;
|
|
383
|
-
const block = ultracodeSystemBlock();
|
|
395
|
+
if (!this.isEnforcing() || !isActiveUltracodeMode(this.mode)) return undefined;
|
|
396
|
+
const block = ultracodeSystemBlock(this.mode);
|
|
384
397
|
return { systemPrompt: `${event.systemPrompt}\n\n${block}\n\n${ULTRACODE_ACTIVE_REMINDER}` };
|
|
385
398
|
}
|
|
386
399
|
|
|
387
400
|
statusLine(): string {
|
|
388
|
-
if (!this.
|
|
389
|
-
const parts = [
|
|
401
|
+
if (!this.isEnabled()) return "ultracode: off";
|
|
402
|
+
const parts = [`ultracode: ${this.mode}`];
|
|
390
403
|
// Show the level that actually applied, including compatibility/model fallback.
|
|
391
404
|
if (this.appliedThinking) parts.push(this.appliedThinking);
|
|
392
405
|
return parts.join(" · ");
|
|
393
406
|
}
|
|
394
407
|
|
|
395
|
-
private
|
|
408
|
+
private applyConfiguredThinking(pi: ExtensionAPI): void {
|
|
409
|
+
const target = thinkingLevelForMode(this.mode);
|
|
410
|
+
if (!target) return;
|
|
396
411
|
const writeGeneration = this.preferenceWriteGeneration;
|
|
397
|
-
this.applyCompatibleThinking(pi,
|
|
412
|
+
this.applyCompatibleThinking(pi, target);
|
|
398
413
|
// Pi normally skips persistence when the effective level is unchanged, but
|
|
399
414
|
// the extension API does not promise that. Defensively restore the raw
|
|
400
|
-
// baseline even after a stable
|
|
415
|
+
// baseline even after a stable mode-owned request.
|
|
401
416
|
if (writeGeneration === this.preferenceWriteGeneration) {
|
|
402
417
|
this.queueDefaultThinkingRestore();
|
|
403
418
|
}
|
|
@@ -433,7 +448,7 @@ export class UltracodeMode {
|
|
|
433
448
|
}
|
|
434
449
|
|
|
435
450
|
isEnforcing(): boolean {
|
|
436
|
-
return this.
|
|
451
|
+
return this.isEnabled() && !this.suspended;
|
|
437
452
|
}
|
|
438
453
|
|
|
439
454
|
private pendingRestoreSucceeded(pending: ThinkingLevel): boolean {
|
|
@@ -495,7 +510,7 @@ export class UltracodeMode {
|
|
|
495
510
|
setImmediate(() => {
|
|
496
511
|
if (
|
|
497
512
|
generation !== this.pendingClearGeneration
|
|
498
|
-
|| this.
|
|
513
|
+
|| this.isEnabled()
|
|
499
514
|
|| this.suspended
|
|
500
515
|
|| safeGetThinking(pi) !== level
|
|
501
516
|
) return;
|
|
@@ -528,7 +543,7 @@ export class UltracodeMode {
|
|
|
528
543
|
|
|
529
544
|
private persist(pi: ExtensionAPI): void {
|
|
530
545
|
const state: PersistedModeState = {
|
|
531
|
-
|
|
546
|
+
mode: this.mode,
|
|
532
547
|
previousThinking: this.previousThinking,
|
|
533
548
|
previousDefaultThinking: this.legacyDefaultMigrationPending
|
|
534
549
|
? undefined
|
|
@@ -547,8 +562,17 @@ function parsePersistedModeState(data: unknown): PersistedModeState | undefined
|
|
|
547
562
|
if (!data || typeof data !== "object") return undefined;
|
|
548
563
|
const value = data as Record<string, unknown>;
|
|
549
564
|
const previousDefault = value.previousDefaultThinking;
|
|
565
|
+
// Sessions written before semantic-depth modes stored only enabled:boolean.
|
|
566
|
+
// Preserve their behavior by migrating enabled:true to the old deep mode.
|
|
567
|
+
const mode: UltracodeModeName = isActiveUltracodeMode(value.mode)
|
|
568
|
+
? value.mode
|
|
569
|
+
: value.mode === "off"
|
|
570
|
+
? "off"
|
|
571
|
+
: value.enabled === true
|
|
572
|
+
? "deep"
|
|
573
|
+
: "off";
|
|
550
574
|
return {
|
|
551
|
-
|
|
575
|
+
mode,
|
|
552
576
|
previousThinking: isThinkingLevel(value.previousThinking) ? value.previousThinking : undefined,
|
|
553
577
|
previousDefaultThinking: previousDefault === null || isThinkingLevel(previousDefault)
|
|
554
578
|
? previousDefault
|
package/src/prompts.ts
CHANGED
|
@@ -1,59 +1,92 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* These strings reproduce the behavioural contract of Claude Code's "ultracode"
|
|
5
|
-
* effort level: a standing opt-in to deterministic multi-agent workflow
|
|
6
|
-
* orchestration, biased toward the most exhaustive, correct answer.
|
|
7
|
-
*/
|
|
1
|
+
/** Prompt text for Ultracode's adaptive analysis-depth modes. */
|
|
2
|
+
|
|
3
|
+
import type { ActiveUltracodeMode } from "./depth.ts";
|
|
8
4
|
|
|
9
5
|
/** One-line description shown by `/ultracode status` and the footer. */
|
|
10
|
-
export const ULTRACODE_TAGLINE = "
|
|
6
|
+
export const ULTRACODE_TAGLINE = "semantic-depth workflow orchestration";
|
|
11
7
|
|
|
12
8
|
/**
|
|
13
|
-
* The standing system-prompt block injected on every turn while
|
|
14
|
-
*
|
|
9
|
+
* The standing system-prompt block injected on every turn while Ultracode is
|
|
10
|
+
* active. The parent model performs the semantic routing itself; starting a
|
|
11
|
+
* separate agent merely to classify depth would defeat the focused path.
|
|
15
12
|
*/
|
|
16
|
-
export function ultracodeSystemBlock(): string {
|
|
13
|
+
export function ultracodeSystemBlock(mode: ActiveUltracodeMode = "deep"): string {
|
|
17
14
|
return [
|
|
18
15
|
"<ultracode>",
|
|
19
|
-
|
|
16
|
+
`Configured mode: ${mode}.`,
|
|
17
|
+
"Analysis depth is a semantic quality decision, never a wall-clock decision. Do not use elapsed time, deadlines, or duration limits to choose, lower, or stop analysis depth.",
|
|
18
|
+
"Use the smallest depth that can establish a correct answer. Depth is controlled by research rounds, independent perspectives, verification strength, evidence requirements, skeptic count, and per-agent reasoning effort.",
|
|
19
|
+
"Existing maxAgents/reserveAgents limits are structural admission bounds, not evidence that every available slot should be used.",
|
|
20
20
|
"",
|
|
21
|
-
|
|
22
|
-
"For multi-phase work (understand → design → implement → review), prefer one bounded workflow and inspect the result before deciding whether another workflow is justified. Do not run consecutive workflows by default; continue only when new evidence changes the plan.",
|
|
21
|
+
...modeInstructions(mode),
|
|
23
22
|
"",
|
|
24
|
-
"
|
|
23
|
+
"Evidence-driven escalation and stopping:",
|
|
24
|
+
"- Escalate only for material correctness risk, missing direct evidence, conflicting findings, or an unresolved question that can change the answer.",
|
|
25
|
+
"- Treat security, GC, ABI, deoptimization, concurrency, data-loss, irreversible operations, and critical architecture semantics as high-risk unless bounded evidence proves otherwise.",
|
|
26
|
+
"- Stop when key claims have direct evidence, no material conflict or unresolved high-risk question remains, and another round would only repeat known evidence.",
|
|
27
|
+
"- Model-reported confidence alone is not sufficient. Prefer concrete citations, reproduction, tests, and independent agreement.",
|
|
28
|
+
"- If fixed focused/standard is insufficient, report the remaining uncertainty and recommend a deeper mode; in deep, report any irreducible uncertainty. Never silently exceed a fixed mode.",
|
|
25
29
|
"",
|
|
26
|
-
"
|
|
27
|
-
"-
|
|
28
|
-
"-
|
|
29
|
-
"-
|
|
30
|
-
"-
|
|
31
|
-
"-
|
|
32
|
-
"- No silent caps: if a workflow bounds coverage (top-N, no-retry, sampling), log() what was dropped.",
|
|
33
|
-
"",
|
|
34
|
-
"Scale to the task: \"find any bugs\" → a few finders, single-vote verify; \"thoroughly audit\" / \"be comprehensive\" → a larger but explicit finder pool, 3–5 vote adversarial pass, and a synthesis stage within maxAgents.",
|
|
30
|
+
"Workflow policy:",
|
|
31
|
+
"- Use a workflow only when independent decomposition, verification, isolation, or context scale provides real value. Otherwise solve directly in the parent session.",
|
|
32
|
+
"- Make skeptics conditional: verify high-risk, conflicting, weakly evidenced, or low-confidence claims instead of automatically verifying every branch.",
|
|
33
|
+
"- Avoid a separate synthesis agent when deterministic merging or parent synthesis is enough. Use an adjudicator only when a material conflict remains.",
|
|
34
|
+
"- Match effort to the stage with per-call model suffixes when useful: focused discovery/synthesis may use :medium, standard analysis :high, and :max is reserved for deep or decisive high-risk verification.",
|
|
35
|
+
"- When a workflow runs, log `analysis-depth: <level> — <reason>` before launching agents, `analysis-escalation: ...` for each semantic escalation, and `analysis-stop: ...` for the final evidence-based stop reason. Never use time as an escalation or stop reason.",
|
|
35
36
|
"</ultracode>",
|
|
36
37
|
].join("\n");
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
function modeInstructions(mode: ActiveUltracodeMode): string[] {
|
|
41
|
+
switch (mode) {
|
|
42
|
+
case "auto":
|
|
43
|
+
return [
|
|
44
|
+
"Before acting, silently route this task to focused, standard, or deep. Do not spawn a router agent.",
|
|
45
|
+
"Choose from user intent, consequence risk, scope, ambiguity, available evidence, cross-module or cross-repository breadth, and whether independent verification is necessary.",
|
|
46
|
+
"Begin at the shallowest sufficient depth and escalate only when evidence triggers an escalation condition below.",
|
|
47
|
+
];
|
|
48
|
+
case "focused":
|
|
49
|
+
return [
|
|
50
|
+
"Focused is a fixed lightweight depth: prefer one bounded line of inquiry and the normal parent-agent loop.",
|
|
51
|
+
"Do not run adversarial verification by default. Use at most a small, narrowly scoped delegation only when it clearly reduces duplicated exploration.",
|
|
52
|
+
];
|
|
53
|
+
case "standard":
|
|
54
|
+
return [
|
|
55
|
+
"Standard is a fixed balanced depth: cover the few independent dimensions that can materially change the answer.",
|
|
56
|
+
"Prefer one discovery round and conditional verification of only disputed, high-risk, or weakly evidenced claims.",
|
|
57
|
+
];
|
|
58
|
+
case "deep":
|
|
59
|
+
return [
|
|
60
|
+
"Deep is a fixed high-assurance depth: default to a bounded workflow for substantive tasks unless the work is conversational, trivial, or already verified.",
|
|
61
|
+
"Use multi-perspective investigation and adversarial verification where the task supports it. Choose fan-out and round limits before launch.",
|
|
62
|
+
"Use at most two discovery rounds by default; add a third only when the user explicitly requests exhaustive coverage and fresh evidence is still appearing.",
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Short reminder appended after the standing block. */
|
|
40
68
|
export const ULTRACODE_ACTIVE_REMINDER =
|
|
41
|
-
"Reminder:
|
|
69
|
+
"Reminder: Ultracode is active — obey its configured semantic depth, escalate only from evidence, and never use elapsed time as an analysis budget.";
|
|
42
70
|
|
|
43
71
|
/** Tool description for the `workflow` tool. */
|
|
44
72
|
export const WORKFLOW_TOOL_DESCRIPTION = [
|
|
45
|
-
"Execute a deterministic JavaScript workflow that orchestrates
|
|
73
|
+
"Execute a deterministic JavaScript workflow that orchestrates a proportionate set of subagents for independent coverage, targeted verification, or work that exceeds one context.",
|
|
74
|
+
"Choose the smallest workflow justified by the configured Ultracode depth and current evidence; workflow use and adversarial checks are not automatic.",
|
|
46
75
|
"Each invocation must provide workflow source via `script`, `scriptPath`, or `name`. Inline `script` must be raw JavaScript (no Markdown fences) beginning with `export const meta = { name, description }` (a pure literal) and should call agent() at least once for useful orchestration.",
|
|
47
|
-
"Available globals: agent(prompt, opts), parallel(thunks, options?), pipeline(items, ...stages), phase(title), log(message), workflow(name, args), args, cwd. The tool accepts maxAgents (default 128, max 1024) as a lifetime live-agent admission cap across resumes, not a token budget; cache replay is free.",
|
|
76
|
+
"Available globals: agent(prompt, opts), parallel(thunks, options?), pipeline(items, ...stages), phase(title), log(message), workflow(name, args), args, cwd. The tool accepts maxAgents (default 128, max 1024) as a lifetime live-agent admission cap across resumes, not a token or depth budget; cache replay is free.",
|
|
48
77
|
].join(" ");
|
|
49
78
|
|
|
50
79
|
/** One-line snippet for the Available tools section. */
|
|
51
80
|
export const WORKFLOW_PROMPT_SNIPPET =
|
|
52
|
-
"Run a deterministic JS workflow
|
|
81
|
+
"Run a deterministic JS workflow with proportionate subagent fan-out. Header: export const meta = { name: 'snake_case', description: '...' }. Globals: agent/parallel/pipeline/phase/log/workflow/args/cwd.";
|
|
53
82
|
|
|
54
83
|
/** Guideline bullets appended to the Guidelines section when the tool is active. */
|
|
55
84
|
export const WORKFLOW_GUIDELINES: string[] = [
|
|
56
|
-
"
|
|
85
|
+
"Use the workflow tool only when independent decomposition, targeted verification, isolation, or context scale adds value; use the parent agent directly for a bounded task.",
|
|
86
|
+
"For an auto-depth workflow, log `analysis-depth: <level> — <reason>` before launching agents, `analysis-escalation: ...` when evidence requires more depth, and `analysis-stop: ...` when evidence is sufficient. Elapsed time must never determine depth.",
|
|
87
|
+
"For workflow verification, run skeptics only for high-risk, conflicting, low-confidence, or weakly evidenced claims. Do not automatically attach a skeptic to every branch.",
|
|
88
|
+
"For workflow synthesis, prefer structured results plus deterministic or parent-session merging. Start a synthesis/adjudication agent only for a material unresolved conflict, and normally give pure synthesis lower effort and no broad source-search mandate.",
|
|
89
|
+
"For workflow agent effort, use a model suffix such as `:medium`, `:high`, or `:max` when the stage should differ from the mode default; reserve max for deep investigation or decisive high-risk verification.",
|
|
57
90
|
"For the workflow tool, provide workflow source with `script`, `scriptPath`, or `name`. Inline `script` must be one raw JavaScript string: no Markdown fences, no prose around the script.",
|
|
58
91
|
"For the workflow tool, the script's first statement must be `export const meta = { name: 'short_snake_case', description: 'non-empty human description' }`. meta must be a pure literal: no variables, function calls, spreads, or template interpolation. meta.phases is optional and should mirror your phase() titles.",
|
|
59
92
|
"For the workflow tool, write plain JavaScript after the meta export. No TypeScript syntax, imports, require(), fs, network, Date/Intl/Temporal, Math.random(), binary memory constructors, WebAssembly, or dynamic method calls such as value[key](...) (they bypass deterministic checks or resource bounds). Stamp timestamps after the workflow returns; vary randomness by agent index.",
|
|
@@ -66,7 +99,7 @@ export const WORKFLOW_GUIDELINES: string[] = [
|
|
|
66
99
|
"For the workflow tool, agent opts also accept: model (override the subagent model by pattern), agentType (use a custom subagent role/system-prompt), isolation:'worktree' (run the agent in an isolated git worktree — use ONLY when agents mutate files in parallel and would conflict), and phase (assign the agent to a progress group explicitly inside parallel()/pipeline()).",
|
|
67
100
|
"For the workflow tool, workflow(name, args) runs a trust-aware saved workflow by name as a sub-step, sharing this run's concurrency, maxAgents, active reservations, and agent counter. Explicit nested script paths are not supported. Nesting is one level only. Child subagent sessions do not load ambient extensions or expose workflow/subagent orchestration tools, so they cannot start an independent recursive workflow chain.",
|
|
68
101
|
"For workflow resumeFromRunId, reuse the exact same script and args. Resume is immutable, successful calls replay by stable structural call path, and maxAgents may only stay the same or increase; changed work must start a new run.",
|
|
69
|
-
"For the workflow tool, failed agent()/parallel()/pipeline() branches return null and log the failure (unless the whole run is aborted or a policy limit is hit). Check for nulls before synthesizing conclusions, and prefer a final
|
|
102
|
+
"For the workflow tool, failed agent()/parallel()/pipeline() branches return null and log the failure (unless the whole run is aborted or a policy limit is hit). Check for nulls before synthesizing conclusions, and prefer a final compact JSON-serializable result.",
|
|
70
103
|
"For the workflow tool, directly await or return every orchestration promise (agent/parallel/pipeline/workflow). Native .then/.catch/.finally chains and Promise.all/allSettled/race/any are rejected; use parallel() or pipeline() so call identity stays deterministic. Unobserved, pending, or native same-scope concurrent orchestration is fatal.",
|
|
71
104
|
"Workflow helpers that call orchestration must be directly declared functions/function variables or static methods on a declared object/stored class instance. Do not alias them, assign them later, forward through this.otherMethod(), or call them from temporary/awaited factory receivers; rewrite those forms as a direct declared helper so resume identity remains stable.",
|
|
72
105
|
"For the workflow tool, do not assume subagents share the parent's repository context; include enough task context and relevant file paths in each agent prompt.",
|
package/src/thinking.ts
CHANGED
|
@@ -4,7 +4,7 @@ export const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhig
|
|
|
4
4
|
|
|
5
5
|
export type ThinkingLevel = (typeof THINKING_LEVELS)[number];
|
|
6
6
|
|
|
7
|
-
/**
|
|
7
|
+
/** Deep mode asks Pi for the strongest effort the selected model supports. */
|
|
8
8
|
export const ULTRACODE_THINKING_LEVEL: ThinkingLevel = "max";
|
|
9
9
|
|
|
10
10
|
/** Compatibility retry for Pi versions released before the `max` level existed. */
|
package/src/workflow/tool.ts
CHANGED
|
@@ -93,9 +93,8 @@ export interface WorkflowToolDeps {
|
|
|
93
93
|
registry?: WorkflowRegistry;
|
|
94
94
|
/** Canonical runtime supplied by an SDK host; shared by all child sessions. */
|
|
95
95
|
modelRuntime?: ModelRuntimeLike;
|
|
96
|
-
/** The
|
|
97
|
-
*
|
|
98
|
-
* session clamps it independently; undefined when off). A per-call
|
|
96
|
+
/** The configured Ultracode mode's raw default effort for workflow subagents.
|
|
97
|
+
* Each child session clamps it independently; undefined when off. A per-call
|
|
99
98
|
* `model: "X:level"` suffix or agentType `thinking:` override still wins. */
|
|
100
99
|
getThinkingLevel?: () => ThinkingLevel | undefined;
|
|
101
100
|
/** Optional execution gate for mode-scoped registrations. Omit for standalone use. */
|
|
@@ -132,7 +131,7 @@ export function createWorkflowTool(deps: WorkflowToolDeps = {}): ToolDefinition<
|
|
|
132
131
|
parameters: workflowToolSchema,
|
|
133
132
|
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
134
133
|
if (deps.isExecutionAllowed?.() === false) {
|
|
135
|
-
throw new Error("The workflow tool is disabled. Run /ultracode
|
|
134
|
+
throw new Error("The workflow tool is disabled. Run /ultracode or select an Ultracode depth before using it.");
|
|
136
135
|
}
|
|
137
136
|
const controller = new AbortController();
|
|
138
137
|
let abortRequested = false;
|
|
@@ -164,8 +163,8 @@ export function createWorkflowTool(deps: WorkflowToolDeps = {}): ToolDefinition<
|
|
|
164
163
|
if (resuming && !RunJournal.exists(runsDir, runId)) {
|
|
165
164
|
throw new Error(`workflow: resumeFromRunId ${runId} was not found in this session`);
|
|
166
165
|
}
|
|
167
|
-
// Forward the raw
|
|
168
|
-
// that subagent's model. Undefined when
|
|
166
|
+
// Forward the mode's raw effort request so each subagent session clamps it
|
|
167
|
+
// against that subagent's model. Undefined when Ultracode is off.
|
|
169
168
|
const thinkingLevel = deps.getThinkingLevel?.();
|
|
170
169
|
if (controller.signal.aborted) throw new Error("Workflow was aborted before it started");
|
|
171
170
|
const run = deps.runWorkflowFn ?? runWorkflow;
|