@tt-a1i/openpi 0.3.1 → 0.4.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.
Files changed (60) hide show
  1. package/README.md +87 -24
  2. package/SETUP.md +3 -3
  3. package/extensions/ask-user/index.ts +30 -14
  4. package/extensions/background-terminals/src/prompt.ts +1 -1
  5. package/extensions/background-terminals/src/ui/ps.ts +132 -129
  6. package/extensions/capabilities/index.ts +30 -42
  7. package/extensions/capabilities/src/ui.ts +93 -0
  8. package/extensions/file-mutation-display/index.ts +34 -76
  9. package/extensions/file-mutation-display/render.ts +387 -88
  10. package/extensions/file-search/index.ts +8 -7
  11. package/extensions/file-search/src/binaries.ts +18 -18
  12. package/extensions/git-info/src/changed-files-view.ts +47 -14
  13. package/extensions/git-read/index.ts +330 -0
  14. package/extensions/git-read/src/args.ts +171 -0
  15. package/extensions/git-read/src/process.ts +81 -0
  16. package/extensions/git-read/src/prompt.ts +56 -0
  17. package/extensions/sessions/index.ts +70 -55
  18. package/extensions/setup/index.ts +6 -6
  19. package/extensions/shared/activity-status.ts +6 -5
  20. package/extensions/shared/below-editor-navigation.ts +26 -0
  21. package/extensions/shared/capability-intent.ts +53 -0
  22. package/extensions/shared/child-session.ts +7 -1
  23. package/extensions/shared/result-budget.ts +134 -0
  24. package/extensions/shared/screen-chrome.ts +133 -0
  25. package/extensions/shared/setup-config.ts +24 -5
  26. package/extensions/shared/spinner.ts +28 -0
  27. package/extensions/shared/text-projection.ts +56 -0
  28. package/extensions/shared/tool-surface.ts +13 -6
  29. package/extensions/subagents/index.ts +204 -140
  30. package/extensions/subagents/navigation.ts +52 -23
  31. package/extensions/subagents/src/agent-types.ts +37 -15
  32. package/extensions/subagents/src/backends/stub.ts +7 -0
  33. package/extensions/subagents/src/id-sequence.ts +84 -0
  34. package/extensions/subagents/src/manager.ts +620 -537
  35. package/extensions/subagents/src/prompt.ts +153 -38
  36. package/extensions/subagents/src/result-artifact.ts +142 -0
  37. package/extensions/subagents/src/runtime.ts +8 -5
  38. package/extensions/subagents/src/ui/takeover.ts +84 -109
  39. package/extensions/subagents/src/ui/transcript.ts +76 -42
  40. package/extensions/subagents/src/ui/wait-result.ts +1 -1
  41. package/extensions/tasks/ui.ts +79 -62
  42. package/extensions/ui-customization/footer.ts +7 -4
  43. package/extensions/user-input-fold/index.ts +185 -0
  44. package/extensions/workflows/artifacts.ts +35 -0
  45. package/extensions/workflows/controller.ts +14 -2
  46. package/extensions/workflows/coordinator.ts +64 -0
  47. package/extensions/workflows/dashboard.ts +353 -173
  48. package/extensions/workflows/handoff.ts +62 -20
  49. package/extensions/workflows/index.ts +647 -387
  50. package/extensions/workflows/model.ts +57 -15
  51. package/extensions/workflows/navigation.ts +33 -14
  52. package/extensions/workflows/prompt.ts +104 -8
  53. package/extensions/workflows/replay-safety.ts +16 -6
  54. package/extensions/workflows/result-delivery.ts +189 -0
  55. package/extensions/workflows/sandbox-child.cjs +11 -0
  56. package/package.json +1 -1
  57. package/skills/subagents/SKILL.md +2 -2
  58. package/skills/workflows/REFERENCE.md +7 -4
  59. package/skills/workflows/SKILL.md +53 -10
  60. package/extensions/subagents/src/format.ts +0 -48
@@ -24,18 +24,18 @@ import * as fs from "node:fs";
24
24
  import * as path from "node:path";
25
25
  import type { Model } from "@earendil-works/pi-ai";
26
26
  import {
27
- parseFrontmatter,
28
27
  type ModelRegistry,
28
+ parseFrontmatter,
29
29
  } from "@earendil-works/pi-coding-agent";
30
30
  import {
31
31
  CHILD_EXCLUDED_TOOL_NAMES,
32
32
  CHILD_SAFE_PACKAGE_TOOL_NAMES,
33
33
  } from "../../shared/child-session.ts";
34
- import { sanitizeTerminalText } from "../../shared/terminal-text.ts";
35
34
  import {
36
35
  isSubagentRoleName,
37
36
  type SubagentRoleModel,
38
37
  } from "../../shared/subagent-roles.ts";
38
+ import { sanitizeTerminalText } from "../../shared/terminal-text.ts";
39
39
  import { REASONING_EFFORTS, type ReasoningEffort } from "./domain.ts";
40
40
 
41
41
  /** Directory name scanned under both the agent dir and a project's `.pi`. */
@@ -101,7 +101,17 @@ export interface AgentType {
101
101
  readonly source: string;
102
102
  }
103
103
 
104
- const READ_ONLY_TOOLS = ["read", "grep", "find", "ls", "fd", "rg"];
104
+ export const READ_ONLY_AGENT_TOOLS = [
105
+ "read",
106
+ "grep",
107
+ "find",
108
+ "ls",
109
+ "fd",
110
+ "rg",
111
+ "git_show",
112
+ "git_diff",
113
+ "git_log",
114
+ ];
105
115
 
106
116
  /**
107
117
  * Built-in role definitions are deliberately provider-free: model selection is
@@ -112,33 +122,45 @@ export const BUILT_IN_AGENT_TYPES: readonly AgentType[] = [
112
122
  {
113
123
  name: "explorer",
114
124
  description:
115
- "Read-only codebase exploration. Use high for routine, local, direct tracing; xhigh for interacting state transitions, concurrency or trust boundaries, or subtle multi-path lifecycle/control-flow; max only for exceptionally difficult broad unfamiliar architecture with unresolved competing flows.",
116
- tools: READ_ONLY_TOOLS,
117
- reasoningEffort: "high",
125
+ "Read-only codebase exploration. Usually use moderate reasoning, increasing it for harder tasks.",
126
+ tools: READ_ONLY_AGENT_TOOLS,
118
127
  body: "Explore the codebase read-only. Trace the real flow, inspect related callers, and report concise evidence with file paths and line references.",
119
128
  source: "built-in:explorer",
120
129
  },
121
130
  {
122
131
  name: "implementer",
123
- description: "Focused implementation with repository checks.",
124
- tools: ["read", "bash", "edit", "write", "grep", "find", "ls", "fd", "rg"],
125
- reasoningEffort: "high",
132
+ description:
133
+ "Focused implementation with repository checks. Usually use medium-high reasoning, adjusted for scope, risk, and task difficulty.",
134
+ tools: [
135
+ "read",
136
+ "bash",
137
+ "edit",
138
+ "write",
139
+ "grep",
140
+ "find",
141
+ "ls",
142
+ "fd",
143
+ "rg",
144
+ "git_show",
145
+ "git_diff",
146
+ "git_log",
147
+ ],
126
148
  body: "Implement the requested change carefully. Trace the affected flow first, make the smallest correct edit, and run relevant checks before reporting results.",
127
149
  source: "built-in:implementer",
128
150
  },
129
151
  {
130
152
  name: "reviewer",
131
- description: "Read-only review for correctness, safety, and regressions.",
132
- tools: READ_ONLY_TOOLS,
133
- reasoningEffort: "medium",
153
+ description:
154
+ "Read-only review for correctness, safety, and regressions. Usually use high reasoning, adjusted for task difficulty.",
155
+ tools: READ_ONLY_AGENT_TOOLS,
134
156
  body: "Review the requested code or change read-only. Identify concrete correctness, security, and regression risks with evidence; do not modify files.",
135
157
  source: "built-in:reviewer",
136
158
  },
137
159
  {
138
160
  name: "advisor",
139
- description: "Deep read-only analysis and technical advice.",
140
- tools: READ_ONLY_TOOLS,
141
- reasoningEffort: "xhigh",
161
+ description:
162
+ "Deep read-only analysis and technical advice. Usually use high reasoning, adjusted for task difficulty.",
163
+ tools: READ_ONLY_AGENT_TOOLS,
142
164
  body: "Analyze the problem deeply without modifying files. Explain the relevant tradeoffs, risks, and recommended next step using repository evidence.",
143
165
  source: "built-in:advisor",
144
166
  },
@@ -10,6 +10,8 @@
10
10
  * - supports interrupt (RunSettled Interrupted -> status "error", matching v1);
11
11
  * - fails the run when the prompt starts with "FAIL:", and refuses to spawn
12
12
  * at all when it starts with "SPAWNFAIL:" (error-path testing);
13
+ * - hangs the run after RunStarted without any assistant event when the
14
+ * prompt starts with "HANG:" (first-response watchdog testing);
13
15
  * - appends every event to a JSONL "session file" in tmpdir so the
14
16
  * "full transcript in session file" pointers resolve.
15
17
  */
@@ -114,6 +116,11 @@ const makeStubSession = (
114
116
  Effect.gen(function* () {
115
117
  yield* emit({ _tag: "RunStarted" });
116
118
  const failing = userText.trimStart().startsWith("FAIL:");
119
+ // Stand in for a provider that accepts the request but never emits
120
+ // its first assistant event.
121
+ if (userText.trimStart().startsWith("HANG:")) {
122
+ return yield* Effect.never;
123
+ }
117
124
 
118
125
  const thinking = "Looking at the task and planning an approach...";
119
126
  for (const delta of chunked(thinking, 16)) {
@@ -0,0 +1,84 @@
1
+ import type { SessionEntry } from "@earendil-works/pi-coding-agent";
2
+
3
+ export const SUBAGENT_ID_WATERMARK_ENTRY_TYPE = "subagent-id-watermark";
4
+
5
+ export interface SubagentIdCounters {
6
+ readonly modelCounter: number;
7
+ readonly btwCounter: number;
8
+ }
9
+
10
+ interface IdWatermarkData {
11
+ readonly version: 1;
12
+ readonly id: string;
13
+ }
14
+
15
+ function record(value: unknown): Record<string, unknown> | undefined {
16
+ return typeof value === "object" && value !== null
17
+ ? (value as Record<string, unknown>)
18
+ : undefined;
19
+ }
20
+
21
+ function idFrom(value: unknown) {
22
+ const candidate = record(value)?.id;
23
+ return typeof candidate === "string" ? candidate : undefined;
24
+ }
25
+
26
+ function idFromEntry(entry: SessionEntry) {
27
+ if (entry.type === "custom") {
28
+ const data = record(entry.data);
29
+ if (
30
+ entry.customType === SUBAGENT_ID_WATERMARK_ENTRY_TYPE &&
31
+ data?.version === 1
32
+ ) {
33
+ return idFrom(data);
34
+ }
35
+ if (
36
+ entry.customType === "subagent-finished" ||
37
+ entry.customType === "btw-result"
38
+ ) {
39
+ return idFrom(data);
40
+ }
41
+ if (entry.customType === "subagent-result") {
42
+ return idFrom(data?.details) ?? idFrom(data);
43
+ }
44
+ return undefined;
45
+ }
46
+
47
+ if (entry.type === "custom_message") {
48
+ return entry.customType === "subagent-result"
49
+ ? idFrom(entry.details)
50
+ : undefined;
51
+ }
52
+
53
+ if (entry.type !== "message") return undefined;
54
+ const message = record(entry.message);
55
+ return message?.role === "toolResult" && message.toolName === "subagent_spawn"
56
+ ? idFrom(message.details)
57
+ : undefined;
58
+ }
59
+
60
+ function sequence(id: string | undefined, prefix: "sa" | "btw") {
61
+ if (!id) return undefined;
62
+ const match = new RegExp(`^${prefix}-(\\d+)$`, "u").exec(id);
63
+ if (!match) return undefined;
64
+ const value = Number(match[1]);
65
+ return Number.isSafeInteger(value) && value > 0 ? value : undefined;
66
+ }
67
+
68
+ /** Restore branch-local id high-water marks, including sessions from before watermarks existed. */
69
+ export function restoreSubagentIdCounters(
70
+ entries: readonly SessionEntry[],
71
+ ): SubagentIdCounters {
72
+ let modelCounter = 0;
73
+ let btwCounter = 0;
74
+ for (const entry of entries) {
75
+ const id = idFromEntry(entry);
76
+ modelCounter = Math.max(modelCounter, sequence(id, "sa") ?? 0);
77
+ btwCounter = Math.max(btwCounter, sequence(id, "btw") ?? 0);
78
+ }
79
+ return { modelCounter, btwCounter };
80
+ }
81
+
82
+ export function subagentIdWatermark(id: string): IdWatermarkData {
83
+ return { version: 1, id };
84
+ }