@tt-a1i/openpi 0.1.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 (114) hide show
  1. package/README.md +643 -0
  2. package/SETUP.md +74 -0
  3. package/THIRD_PARTY_NOTICES.md +16 -0
  4. package/assets/openpi-package.png +0 -0
  5. package/assets/readme-hero-mobile.svg +72 -0
  6. package/assets/readme-hero.svg +118 -0
  7. package/assets/readme-runtime-mobile.svg +91 -0
  8. package/assets/readme-runtime.svg +111 -0
  9. package/extensions/ask-user/handoff.ts +205 -0
  10. package/extensions/ask-user/index.ts +1110 -0
  11. package/extensions/ask-user/limits.ts +89 -0
  12. package/extensions/ask-user/prompt.ts +76 -0
  13. package/extensions/background-terminals/index.ts +653 -0
  14. package/extensions/background-terminals/src/domain.ts +99 -0
  15. package/extensions/background-terminals/src/manager.ts +989 -0
  16. package/extensions/background-terminals/src/output.ts +84 -0
  17. package/extensions/background-terminals/src/prompt.ts +195 -0
  18. package/extensions/background-terminals/src/result-delivery.ts +43 -0
  19. package/extensions/background-terminals/src/runtime.ts +36 -0
  20. package/extensions/background-terminals/src/ui/output-view.ts +55 -0
  21. package/extensions/background-terminals/src/ui/ps.ts +642 -0
  22. package/extensions/background-terminals/src/ui/tool-result.ts +146 -0
  23. package/extensions/background-terminals/src/watch.ts +192 -0
  24. package/extensions/context-pivot/index.ts +222 -0
  25. package/extensions/copy-all/index.ts +65 -0
  26. package/extensions/cron/index.ts +173 -0
  27. package/extensions/cron/schedule.ts +127 -0
  28. package/extensions/file-mutation-display/index.ts +105 -0
  29. package/extensions/file-mutation-display/render.ts +107 -0
  30. package/extensions/file-search/index.ts +515 -0
  31. package/extensions/file-search/src/args.ts +129 -0
  32. package/extensions/file-search/src/binaries.ts +419 -0
  33. package/extensions/file-search/src/output.ts +142 -0
  34. package/extensions/file-search/src/process.ts +309 -0
  35. package/extensions/file-search/src/prompt.ts +53 -0
  36. package/extensions/git-info/index.ts +272 -0
  37. package/extensions/git-info/src/changed-files-view.ts +414 -0
  38. package/extensions/git-info/src/process.ts +107 -0
  39. package/extensions/git-info/src/refresh-coordinator.ts +13 -0
  40. package/extensions/git-info/src/runtime.ts +28 -0
  41. package/extensions/goal/controller.ts +794 -0
  42. package/extensions/goal/index.ts +521 -0
  43. package/extensions/goal/prompts.ts +122 -0
  44. package/extensions/goal/state.ts +763 -0
  45. package/extensions/goal/ui.ts +158 -0
  46. package/extensions/model-info/index.ts +234 -0
  47. package/extensions/plan-mode/bash-policy.ts +313 -0
  48. package/extensions/plan-mode/index.ts +539 -0
  49. package/extensions/post-edit/index.ts +129 -0
  50. package/extensions/sessions/LICENSE.upstream +21 -0
  51. package/extensions/sessions/git-stats.ts +226 -0
  52. package/extensions/sessions/index.ts +1092 -0
  53. package/extensions/sessions/sessions.ts +385 -0
  54. package/extensions/setup/index.ts +408 -0
  55. package/extensions/shared/activity-status.ts +65 -0
  56. package/extensions/shared/below-editor-navigation.ts +343 -0
  57. package/extensions/shared/child-session.ts +352 -0
  58. package/extensions/shared/context-utilization.ts +47 -0
  59. package/extensions/shared/dashboard-state.ts +102 -0
  60. package/extensions/shared/plan-mode-state.ts +65 -0
  61. package/extensions/shared/setup-config.ts +971 -0
  62. package/extensions/shared/subagent-roles.ts +22 -0
  63. package/extensions/shared/terminal-text.ts +38 -0
  64. package/extensions/shared/tool-call-timeout.ts +104 -0
  65. package/extensions/shared/worktree.ts +526 -0
  66. package/extensions/subagents/index.ts +1225 -0
  67. package/extensions/subagents/navigation.ts +121 -0
  68. package/extensions/subagents/src/agent-types.ts +543 -0
  69. package/extensions/subagents/src/backend.ts +63 -0
  70. package/extensions/subagents/src/backends/pi.ts +493 -0
  71. package/extensions/subagents/src/backends/stub.ts +296 -0
  72. package/extensions/subagents/src/by-the-way.ts +21 -0
  73. package/extensions/subagents/src/domain.ts +271 -0
  74. package/extensions/subagents/src/format.ts +48 -0
  75. package/extensions/subagents/src/manager.ts +769 -0
  76. package/extensions/subagents/src/prompt.ts +190 -0
  77. package/extensions/subagents/src/result-delivery.ts +20 -0
  78. package/extensions/subagents/src/runtime.ts +51 -0
  79. package/extensions/subagents/src/ui/takeover.ts +615 -0
  80. package/extensions/subagents/src/ui/transcript.ts +293 -0
  81. package/extensions/subagents/src/ui/wait-result.ts +89 -0
  82. package/extensions/suggestions/index.ts +172 -0
  83. package/extensions/suggestions/src/config.ts +12 -0
  84. package/extensions/suggestions/src/predictor.ts +147 -0
  85. package/extensions/suggestions/src/prompt.ts +20 -0
  86. package/extensions/suggestions/src/transcript.ts +233 -0
  87. package/extensions/suggestions/src/ui.ts +224 -0
  88. package/extensions/tasks/index.ts +512 -0
  89. package/extensions/tasks/tasks.ts +649 -0
  90. package/extensions/tasks/ui.ts +421 -0
  91. package/extensions/turn-time/index.ts +61 -0
  92. package/extensions/ui-customization/footer.ts +512 -0
  93. package/extensions/ui-customization/index.ts +217 -0
  94. package/extensions/workflows/acceptance.ts +298 -0
  95. package/extensions/workflows/artifacts.ts +225 -0
  96. package/extensions/workflows/controller.ts +210 -0
  97. package/extensions/workflows/dashboard.ts +1226 -0
  98. package/extensions/workflows/index.ts +1884 -0
  99. package/extensions/workflows/journal.ts +188 -0
  100. package/extensions/workflows/meta.ts +250 -0
  101. package/extensions/workflows/model.ts +423 -0
  102. package/extensions/workflows/navigation.ts +93 -0
  103. package/extensions/workflows/prompt.ts +212 -0
  104. package/extensions/workflows/replay-safety.ts +577 -0
  105. package/extensions/workflows/runner.ts +786 -0
  106. package/extensions/workflows/sandbox-child.cjs +402 -0
  107. package/extensions/workflows/sandbox.ts +397 -0
  108. package/extensions/workflows/serialization.ts +162 -0
  109. package/extensions/workflows/worktree-handoff.ts +216 -0
  110. package/package.json +87 -0
  111. package/scripts/prepare-effect-tsgo.mjs +16 -0
  112. package/skills/background-terminals/SKILL.md +30 -0
  113. package/skills/subagents/SKILL.md +15 -0
  114. package/themes/github-dark-default.json +89 -0
@@ -0,0 +1,190 @@
1
+ /** All model-facing strings for the subagents tools. */
2
+
3
+ import { StringEnum } from "@earendil-works/pi-ai";
4
+ import { Type } from "typebox";
5
+ import { effectiveChildToolAllowlist } from "../../shared/child-session.ts";
6
+ import type { AgentType } from "./agent-types.ts";
7
+ import { MAX_RUNNING } from "./manager.ts";
8
+
9
+ /** Describes subagent_spawn, including the fixed concurrency cap. */
10
+ export const SUBAGENT_SPAWN_TOOL_DESCRIPTION =
11
+ "Spawn a background subagent: a fully autonomous, headless pi session with its own context window, this environment's tools and config, and normal host permissions. Fire-and-forget: this returns immediately with an id. The subagent's final output is queued back to you as a message when it settles, or collect it explicitly with subagent_wait. Children cannot orchestrate more agents/workflows or ask the user, and cannot see this conversation, so the prompt must be self-contained. Only use trusted working directories. " +
12
+ `Max ${MAX_RUNNING} subagents can be running at once.`;
13
+
14
+ /**
15
+ * Appends the configured agent types, if any. They are a runtime resource, so
16
+ * the roster has to be baked into the description at registration time.
17
+ */
18
+ export function buildSubagentSpawnToolDescription(
19
+ agentTypes: readonly AgentType[],
20
+ ) {
21
+ if (agentTypes.length === 0) return SUBAGENT_SPAWN_TOOL_DESCRIPTION;
22
+ return `${SUBAGENT_SPAWN_TOOL_DESCRIPTION} This environment also defines agent types (see agent_type): named presets that fix a child's system prompt, and often restrict it to a subset of tools. Prefer one when it matches the task — a type's tool restriction is enforced, not advisory.`;
23
+ }
24
+
25
+ /** Lists each agent type's enforced capabilities and reasoning default. */
26
+ export function buildAgentTypeParameterDescription(
27
+ agentTypes: readonly AgentType[],
28
+ ) {
29
+ const entries = agentTypes.map((agentType) => {
30
+ const tools = agentType.tools
31
+ ? (() => {
32
+ const effectiveTools = effectiveChildToolAllowlist(agentType.tools);
33
+ return effectiveTools?.length
34
+ ? ` [only: ${effectiveTools.join(", ")}]`
35
+ : " [only: no child-safe tools]";
36
+ })()
37
+ : "";
38
+ const effort = agentType.reasoningEffort
39
+ ? ` [default reasoning_effort: ${agentType.reasoningEffort}]`
40
+ : " [reasoning_effort: inherits parent]";
41
+ return `"${agentType.name}" — ${agentType.description}${tools}${effort}`;
42
+ });
43
+ return `Optional agent type: a preset that gives the child a specialized system prompt and, when listed, restricts it to exactly those child-safe tools. Omit for a general-purpose subagent with the normal tool set. Available: ${entries.join("; ")}. Model precedence: explicit spawn model > selected type file model > configured built-in role model > parent model. Reasoning precedence: explicit spawn reasoning_effort > selected type default > parent reasoning effort.`;
44
+ }
45
+
46
+ /** Generated schema for the dynamic agent-type roster. */
47
+ export function createAgentTypeParameterSchema(
48
+ agentTypes: readonly AgentType[],
49
+ ) {
50
+ return Type.Optional(
51
+ StringEnum(
52
+ agentTypes.map((agentType) => agentType.name) as [string, ...string[]],
53
+ { description: buildAgentTypeParameterDescription(agentTypes) },
54
+ ),
55
+ );
56
+ }
57
+
58
+ /** Adds background subagent delegation to the parent model's available-tools prompt. */
59
+ export const SUBAGENT_SPAWN_PROMPT_SNIPPET =
60
+ "Spawn a background subagent (own context, normal tools) for a self-contained task";
61
+
62
+ /** Guides the parent model to delegate standalone tasks and avoid unnecessary blocking waits. */
63
+ export const SUBAGENT_SPAWN_PROMPT_GUIDELINES = [
64
+ "Reserve subagent_spawn for substantial, self-contained work; give it a complete, standalone prompt. For a single lookup or edit you can do inline, just do it — each subagent spends a fresh context window and cannot see this conversation.",
65
+ "After subagent_spawn, keep working on other things; results arrive automatically and you are re-invoked when a subagent settles. Do not poll with subagent_check and do not subagent_wait just to sit idle — wait only when your next step genuinely cannot proceed without the result, and never answer from a guessed result before it arrives.",
66
+ ];
67
+
68
+ /** Model-facing schema descriptions for subagent_spawn task and execution options. */
69
+ export const SUBAGENT_SPAWN_PARAMETER_DESCRIPTIONS = {
70
+ prompt:
71
+ "Task prompt for the subagent. Must be self-contained: include all needed context, file paths, and what to report back.",
72
+ name: "Short human-readable name for this subagent, shown in listings and the UI",
73
+ harness:
74
+ 'Optional. The only harness is "pi" (an in-process Pi session that inherits this environment), which is the default; you can omit this.',
75
+ workingDir:
76
+ "Trusted working directory for the autonomous child (default: current working directory)",
77
+ isolation:
78
+ 'Set to "worktree" to run this child in its own git worktree on its own branch, branched from HEAD. Use it whenever children may edit the same files or stage changes concurrently — without it, parallel children share one checkout and one git index, so their edits and `git add`s overwrite each other. The child should COMMIT its work. A direct child can receive later subagent_send turns, so its checkout lives with that child Session. On retirement it is reclaimed only when a bounded inspection proves it empty; commits, dirty/untracked/ignored files, detached HEAD, timeout, or Git failure preserve it. Requires a git repository, and the checkout starts clean, so anything gitignored (build output, .env) will not be there.',
79
+ model:
80
+ 'Optional model override, as "provider/model-id" or a bare id resolved against the current provider. Precedence: explicit spawn model > selected type file model > configured built-in role model > parent model. Never guess a model name.',
81
+ reasoningEffort:
82
+ "Optional thinking level for the child. Precedence: explicit spawn reasoning_effort > selected type default > parent reasoning effort.",
83
+ };
84
+
85
+ /** Builds the subagent_spawn result that tells the parent model how to continue or inspect the child. */
86
+ export function buildSubagentSpawnResult(options: {
87
+ id: string;
88
+ title: string;
89
+ harness: string;
90
+ modelLabel: string;
91
+ cwd: string;
92
+ agentTypeName?: string;
93
+ tools?: readonly string[];
94
+ worktreeBranch?: string;
95
+ }) {
96
+ const typeNote = options.agentTypeName
97
+ ? ` Agent type "${options.agentTypeName}" applied.`
98
+ : "";
99
+ // Report the effective allowlist independently of agent type: plan mode can
100
+ // narrow a general child too, and the parent must not expect work the child
101
+ // structurally cannot do. Defend this presentation boundary as well as the
102
+ // child-session boundary, so a future caller cannot advertise parent tools.
103
+ const effectiveTools = effectiveChildToolAllowlist(options.tools);
104
+ const toolNote = effectiveTools
105
+ ? effectiveTools.length > 0
106
+ ? ` It can only use: ${effectiveTools.join(", ")}.`
107
+ : " It has no tools available."
108
+ : "";
109
+ // Direct child sessions can be steered after settling, so their checkout is
110
+ // retained until the session retires; fail-closed cleanup preserves work.
111
+ const worktreeNote = options.worktreeBranch
112
+ ? ` Isolated in its own worktree on branch "${options.worktreeBranch}" — its edits are invisible here until you merge that branch. The checkout stays available for later send/review and is reclaimed on Session retirement only when bounded inspection proves it empty.`
113
+ : "";
114
+ return (
115
+ `Spawned subagent ${options.id} "${options.title}" (${options.harness}: ${options.modelLabel}, ${options.cwd}).${typeNote}${toolNote}${worktreeNote}\n` +
116
+ `It runs in the background — keep working on other things; its result is delivered to you automatically when it finishes, so do not poll or wait for it. ` +
117
+ `Only if your next step truly cannot proceed without it, subagent_wait(ids: ["${options.id}"]) blocks for it; subagent_cancel stops it, subagent_check peeks at a running one, subagent_list shows all.`
118
+ );
119
+ }
120
+
121
+ /** Describes explicit blocking collection of one or more subagent results. */
122
+ export const SUBAGENT_WAIT_TOOL_DESCRIPTION =
123
+ "Block until all listed subagents have settled, then return their final outputs. This is the EXCEPTION, not the default: after spawning, keep doing other useful work — each subagent's result is delivered to you automatically when it settles, and you'll be re-invoked then. Call subagent_wait only when your very next step cannot proceed without the result (e.g. you must synthesize several children's outputs and have nothing else to do first). Never poll for completion and never answer from a guessed result before it arrives.";
124
+
125
+ /** Model-facing schema description for the subagent ids to await. */
126
+ export const SUBAGENT_WAIT_PARAMETER_DESCRIPTIONS = {
127
+ ids: 'Subagent ids to wait for, e.g. ["sa-1", "sa-2"]',
128
+ };
129
+
130
+ /** Describes aborting running subagents while retaining their partial transcripts. */
131
+ export const SUBAGENT_CANCEL_TOOL_DESCRIPTION =
132
+ "Cancel one or more running subagents. This aborts their active work but preserves their partial session transcripts on disk.";
133
+
134
+ /** Model-facing schema description for the subagent ids to cancel. */
135
+ export const SUBAGENT_CANCEL_PARAMETER_DESCRIPTIONS = {
136
+ ids: 'Subagent ids to cancel, e.g. ["sa-1", "sa-2"]',
137
+ };
138
+
139
+ /** Describes sending a follow-up to one subagent: steer a running one or restart a settled one. */
140
+ export const SUBAGENT_SEND_TOOL_DESCRIPTION =
141
+ "Send a message to one subagent: steer a running one mid-run, or restart a finished/failed one for another turn with its transcript and context intact. Use this to correct course, add missing context, or ask a follow-up on the SAME subagent instead of cancelling and respawning it. Spawn a fresh subagent for unrelated work. Restarting a settled subagent re-occupies a running slot, so it fails when the concurrency cap is full — wait for one to finish first. The subagent still cannot see this conversation, so make the message self-contained. Its result is delivered back to you when it next settles, exactly like subagent_spawn.";
142
+
143
+ /** Model-facing schema descriptions for the subagent id and follow-up message. */
144
+ export const SUBAGENT_SEND_PARAMETER_DESCRIPTIONS = {
145
+ id: 'Subagent id to send to, e.g. "sa-1"',
146
+ text: "Message for the subagent: steering guidance for a running one, or the next instruction for a finished one. Must be self-contained — it cannot see this conversation.",
147
+ };
148
+
149
+ /** Builds the subagent_send result, distinguishing a live steer from a restart. */
150
+ export function buildSubagentSendResult(options: {
151
+ id: string;
152
+ title: string;
153
+ wasRunning: boolean;
154
+ }) {
155
+ return options.wasRunning
156
+ ? `Steered ${options.id} "${options.title}". It is queued into the active run; the result is delivered when it settles.`
157
+ : `Restarted ${options.id} "${options.title}" for another turn on its existing transcript. The result is delivered when it settles, or use subagent_wait(ids: ["${options.id}"]) to block for it.`;
158
+ }
159
+
160
+ /** Describes nonblocking inspection of a subagent without consuming its result. */
161
+ export const SUBAGENT_CHECK_TOOL_DESCRIPTION =
162
+ "Peek at a subagent's status and recent activity without blocking. Does not consume its result. Do NOT poll with it to wait for completion — a settled subagent's result is delivered to you automatically. Use it only when you need a running subagent's current partial state right now (e.g. to decide whether to steer it).";
163
+
164
+ /** Model-facing schema description for the subagent id to inspect. */
165
+ export const SUBAGENT_CHECK_PARAMETER_DESCRIPTIONS = {
166
+ id: "Subagent id",
167
+ };
168
+
169
+ /** Describes listing all tracked running and settled subagents. */
170
+ export const SUBAGENT_LIST_TOOL_DESCRIPTION =
171
+ "List all subagents (running and finished) with their status.";
172
+
173
+ /** Builds the child completion/failure wrapper injected into the parent model's context. */
174
+ export function buildSubagentResultMessage(options: {
175
+ id: string;
176
+ title: string;
177
+ status: "running" | "done" | "error";
178
+ errorText?: string;
179
+ output: string;
180
+ }) {
181
+ const verb = options.status === "error" ? "failed" : "finished";
182
+ let text = `Subagent ${options.id} "${options.title}" ${verb}.`;
183
+ if (options.errorText) text += `\nError: ${options.errorText}`;
184
+ text += `\n\n${options.output}`;
185
+ // This message is already displayed to the user, so tell the parent to act on
186
+ // it rather than reprint it verbatim.
187
+ text +=
188
+ "\n\n(This result is already shown to the user. Act on it and relay only the decisions or next steps — do not repeat it verbatim.)";
189
+ return text;
190
+ }
@@ -0,0 +1,20 @@
1
+ export function createDeferredResultDelivery<T extends { id: string }>() {
2
+ const pending = new Map<string, T>();
3
+
4
+ return {
5
+ defer(result: T) {
6
+ pending.set(result.id, result);
7
+ },
8
+ consume(ids: Iterable<string>) {
9
+ for (const id of ids) pending.delete(id);
10
+ },
11
+ drain() {
12
+ const results = [...pending.values()];
13
+ pending.clear();
14
+ return results;
15
+ },
16
+ clear() {
17
+ pending.clear();
18
+ },
19
+ };
20
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Layer composition and the async entry-point boundary.
3
+ *
4
+ * Everything inside the extension is Effect generators; this module is where
5
+ * tool handlers (plain async functions) run those effects against one shared
6
+ * ManagedRuntime.
7
+ */
8
+
9
+ import { Cause, Exit, Layer, ManagedRuntime, type Effect } from "effect";
10
+ import { BackendRegistry, type SubagentBackend } from "./backend.ts";
11
+ import { piBackend } from "./backends/pi.ts";
12
+ import type { BackendName } from "./domain.ts";
13
+
14
+ const BackendRegistryLive = Layer.sync(BackendRegistry, () => {
15
+ const backends: SubagentBackend[] = [piBackend];
16
+ return new Map<BackendName, SubagentBackend>(
17
+ backends.map((backend) => [backend.name, backend]),
18
+ );
19
+ });
20
+
21
+ import { SubagentManagerLive } from "./manager.ts";
22
+
23
+ const AppLayer = SubagentManagerLive.pipe(Layer.provide(BackendRegistryLive));
24
+
25
+ export function createSubagentRuntime() {
26
+ return ManagedRuntime.make(AppLayer);
27
+ }
28
+
29
+ export type SubagentRuntime = ReturnType<typeof createSubagentRuntime>;
30
+
31
+ /**
32
+ * Run an effect from an async tool handler. Typed failures and defects are
33
+ * converted to thrown Errors (what pi's tool contract expects); interruption
34
+ * (tool AbortSignal) throws `interruptMessage`.
35
+ */
36
+ export async function runTool<A, E>(
37
+ runtime: SubagentRuntime,
38
+ effect: Effect.Effect<A, E>,
39
+ options: { signal?: AbortSignal; interruptMessage?: string } = {},
40
+ ) {
41
+ const exit = await runtime.runPromiseExit(
42
+ effect,
43
+ options.signal ? { signal: options.signal } : undefined,
44
+ );
45
+ if (Exit.isSuccess(exit)) return exit.value;
46
+ if (Cause.hasInterruptsOnly(exit.cause)) {
47
+ throw new Error(options.interruptMessage ?? "Operation was aborted.");
48
+ }
49
+ const [first] = Cause.prettyErrors(exit.cause);
50
+ throw new Error(first?.message ?? Cause.pretty(exit.cause));
51
+ }