@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.
- package/README.md +643 -0
- package/SETUP.md +74 -0
- package/THIRD_PARTY_NOTICES.md +16 -0
- package/assets/openpi-package.png +0 -0
- package/assets/readme-hero-mobile.svg +72 -0
- package/assets/readme-hero.svg +118 -0
- package/assets/readme-runtime-mobile.svg +91 -0
- package/assets/readme-runtime.svg +111 -0
- package/extensions/ask-user/handoff.ts +205 -0
- package/extensions/ask-user/index.ts +1110 -0
- package/extensions/ask-user/limits.ts +89 -0
- package/extensions/ask-user/prompt.ts +76 -0
- package/extensions/background-terminals/index.ts +653 -0
- package/extensions/background-terminals/src/domain.ts +99 -0
- package/extensions/background-terminals/src/manager.ts +989 -0
- package/extensions/background-terminals/src/output.ts +84 -0
- package/extensions/background-terminals/src/prompt.ts +195 -0
- package/extensions/background-terminals/src/result-delivery.ts +43 -0
- package/extensions/background-terminals/src/runtime.ts +36 -0
- package/extensions/background-terminals/src/ui/output-view.ts +55 -0
- package/extensions/background-terminals/src/ui/ps.ts +642 -0
- package/extensions/background-terminals/src/ui/tool-result.ts +146 -0
- package/extensions/background-terminals/src/watch.ts +192 -0
- package/extensions/context-pivot/index.ts +222 -0
- package/extensions/copy-all/index.ts +65 -0
- package/extensions/cron/index.ts +173 -0
- package/extensions/cron/schedule.ts +127 -0
- package/extensions/file-mutation-display/index.ts +105 -0
- package/extensions/file-mutation-display/render.ts +107 -0
- package/extensions/file-search/index.ts +515 -0
- package/extensions/file-search/src/args.ts +129 -0
- package/extensions/file-search/src/binaries.ts +419 -0
- package/extensions/file-search/src/output.ts +142 -0
- package/extensions/file-search/src/process.ts +309 -0
- package/extensions/file-search/src/prompt.ts +53 -0
- package/extensions/git-info/index.ts +272 -0
- package/extensions/git-info/src/changed-files-view.ts +414 -0
- package/extensions/git-info/src/process.ts +107 -0
- package/extensions/git-info/src/refresh-coordinator.ts +13 -0
- package/extensions/git-info/src/runtime.ts +28 -0
- package/extensions/goal/controller.ts +794 -0
- package/extensions/goal/index.ts +521 -0
- package/extensions/goal/prompts.ts +122 -0
- package/extensions/goal/state.ts +763 -0
- package/extensions/goal/ui.ts +158 -0
- package/extensions/model-info/index.ts +234 -0
- package/extensions/plan-mode/bash-policy.ts +313 -0
- package/extensions/plan-mode/index.ts +539 -0
- package/extensions/post-edit/index.ts +129 -0
- package/extensions/sessions/LICENSE.upstream +21 -0
- package/extensions/sessions/git-stats.ts +226 -0
- package/extensions/sessions/index.ts +1092 -0
- package/extensions/sessions/sessions.ts +385 -0
- package/extensions/setup/index.ts +408 -0
- package/extensions/shared/activity-status.ts +65 -0
- package/extensions/shared/below-editor-navigation.ts +343 -0
- package/extensions/shared/child-session.ts +352 -0
- package/extensions/shared/context-utilization.ts +47 -0
- package/extensions/shared/dashboard-state.ts +102 -0
- package/extensions/shared/plan-mode-state.ts +65 -0
- package/extensions/shared/setup-config.ts +971 -0
- package/extensions/shared/subagent-roles.ts +22 -0
- package/extensions/shared/terminal-text.ts +38 -0
- package/extensions/shared/tool-call-timeout.ts +104 -0
- package/extensions/shared/worktree.ts +526 -0
- package/extensions/subagents/index.ts +1225 -0
- package/extensions/subagents/navigation.ts +121 -0
- package/extensions/subagents/src/agent-types.ts +543 -0
- package/extensions/subagents/src/backend.ts +63 -0
- package/extensions/subagents/src/backends/pi.ts +493 -0
- package/extensions/subagents/src/backends/stub.ts +296 -0
- package/extensions/subagents/src/by-the-way.ts +21 -0
- package/extensions/subagents/src/domain.ts +271 -0
- package/extensions/subagents/src/format.ts +48 -0
- package/extensions/subagents/src/manager.ts +769 -0
- package/extensions/subagents/src/prompt.ts +190 -0
- package/extensions/subagents/src/result-delivery.ts +20 -0
- package/extensions/subagents/src/runtime.ts +51 -0
- package/extensions/subagents/src/ui/takeover.ts +615 -0
- package/extensions/subagents/src/ui/transcript.ts +293 -0
- package/extensions/subagents/src/ui/wait-result.ts +89 -0
- package/extensions/suggestions/index.ts +172 -0
- package/extensions/suggestions/src/config.ts +12 -0
- package/extensions/suggestions/src/predictor.ts +147 -0
- package/extensions/suggestions/src/prompt.ts +20 -0
- package/extensions/suggestions/src/transcript.ts +233 -0
- package/extensions/suggestions/src/ui.ts +224 -0
- package/extensions/tasks/index.ts +512 -0
- package/extensions/tasks/tasks.ts +649 -0
- package/extensions/tasks/ui.ts +421 -0
- package/extensions/turn-time/index.ts +61 -0
- package/extensions/ui-customization/footer.ts +512 -0
- package/extensions/ui-customization/index.ts +217 -0
- package/extensions/workflows/acceptance.ts +298 -0
- package/extensions/workflows/artifacts.ts +225 -0
- package/extensions/workflows/controller.ts +210 -0
- package/extensions/workflows/dashboard.ts +1226 -0
- package/extensions/workflows/index.ts +1884 -0
- package/extensions/workflows/journal.ts +188 -0
- package/extensions/workflows/meta.ts +250 -0
- package/extensions/workflows/model.ts +423 -0
- package/extensions/workflows/navigation.ts +93 -0
- package/extensions/workflows/prompt.ts +212 -0
- package/extensions/workflows/replay-safety.ts +577 -0
- package/extensions/workflows/runner.ts +786 -0
- package/extensions/workflows/sandbox-child.cjs +402 -0
- package/extensions/workflows/sandbox.ts +397 -0
- package/extensions/workflows/serialization.ts +162 -0
- package/extensions/workflows/worktree-handoff.ts +216 -0
- package/package.json +87 -0
- package/scripts/prepare-effect-tsgo.mjs +16 -0
- package/skills/background-terminals/SKILL.md +30 -0
- package/skills/subagents/SKILL.md +15 -0
- package/themes/github-dark-default.json +89 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtensionContext,
|
|
3
|
+
ToolDefinition,
|
|
4
|
+
} from "@earendil-works/pi-coding-agent";
|
|
5
|
+
import { Text } from "@earendil-works/pi-tui";
|
|
6
|
+
import { Type, type Static } from "typebox";
|
|
7
|
+
import { sanitizeTerminalText } from "../shared/terminal-text.ts";
|
|
8
|
+
import { MAX_ANSWER_DRAFT_UTF8_BYTES, answerDraftFits } from "./limits.ts";
|
|
9
|
+
|
|
10
|
+
const COMPLETE = "Done — resume and verify";
|
|
11
|
+
const UNABLE = "Unable to complete";
|
|
12
|
+
const DISMISS = "Dismiss without a status";
|
|
13
|
+
|
|
14
|
+
const HumanHandoffParams = Type.Object({
|
|
15
|
+
title: Type.String({
|
|
16
|
+
minLength: 1,
|
|
17
|
+
maxLength: 80,
|
|
18
|
+
description: "Short name for the manual action",
|
|
19
|
+
}),
|
|
20
|
+
instructions: Type.String({
|
|
21
|
+
minLength: 1,
|
|
22
|
+
maxLength: 2_000,
|
|
23
|
+
description:
|
|
24
|
+
"Concrete steps only the user can perform, such as signing in, approving access, or touching hardware",
|
|
25
|
+
}),
|
|
26
|
+
completionSignal: Type.String({
|
|
27
|
+
minLength: 1,
|
|
28
|
+
maxLength: 500,
|
|
29
|
+
description:
|
|
30
|
+
"Observable condition the agent should verify after the user marks the action done",
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export type HumanHandoffInput = Static<typeof HumanHandoffParams>;
|
|
35
|
+
export type HumanHandoffStatus =
|
|
36
|
+
"completed" | "unable" | "dismissed" | "cancelled" | "unavailable";
|
|
37
|
+
|
|
38
|
+
export interface HumanHandoffDetails {
|
|
39
|
+
status: HumanHandoffStatus;
|
|
40
|
+
note?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function safeText(value: string) {
|
|
44
|
+
return sanitizeTerminalText(value).trim();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function safeSingleLine(value: string) {
|
|
48
|
+
return safeText(value).replace(/\s+/g, " ");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function resultMessage(
|
|
52
|
+
status: HumanHandoffStatus,
|
|
53
|
+
completionSignal: string,
|
|
54
|
+
note?: string,
|
|
55
|
+
) {
|
|
56
|
+
const safeSignal = safeSingleLine(completionSignal);
|
|
57
|
+
const safeNote = note ? safeSingleLine(note) : undefined;
|
|
58
|
+
switch (status) {
|
|
59
|
+
case "completed":
|
|
60
|
+
return `User marked the manual action done. This is not proof of completion. Verify the expected signal with available tools before relying on it: ${safeSignal}.${safeNote ? ` User note: ${safeNote}` : ""}`;
|
|
61
|
+
case "unable":
|
|
62
|
+
return `User could not complete the manual action. Do not claim it succeeded or continue down a path that requires it.${safeNote ? ` User note: ${safeNote}` : ""}`;
|
|
63
|
+
case "dismissed":
|
|
64
|
+
return "User dismissed the handoff without reporting a status. Do not assume the manual action was completed.";
|
|
65
|
+
case "cancelled":
|
|
66
|
+
return "The handoff was cancelled. Do not assume the manual action was completed.";
|
|
67
|
+
case "unavailable":
|
|
68
|
+
return "No dialog-capable UI is available for the handoff. Explain the required manual action in plain text and end the turn without claiming completion.";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function optionalBoundedNote(
|
|
73
|
+
ctx: ExtensionContext,
|
|
74
|
+
signal: AbortSignal | undefined,
|
|
75
|
+
status: "completed" | "unable",
|
|
76
|
+
) {
|
|
77
|
+
const options = signal ? { signal } : undefined;
|
|
78
|
+
while (!signal?.aborted) {
|
|
79
|
+
const note = await ctx.ui.input(
|
|
80
|
+
status === "completed" ? "Optional completion note" : "What blocked you?",
|
|
81
|
+
status === "completed"
|
|
82
|
+
? "Optional detail for the agent"
|
|
83
|
+
: "Optional error or missing access",
|
|
84
|
+
options,
|
|
85
|
+
);
|
|
86
|
+
if (note === undefined) return undefined;
|
|
87
|
+
if (answerDraftFits(note)) return note.trim() || undefined;
|
|
88
|
+
ctx.ui.notify(
|
|
89
|
+
`Handoff notes are limited to ${MAX_ANSWER_DRAFT_UTF8_BYTES} UTF-8 bytes.`,
|
|
90
|
+
"error",
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function createHumanHandoffToolDefinition(): ToolDefinition<
|
|
97
|
+
typeof HumanHandoffParams,
|
|
98
|
+
HumanHandoffDetails
|
|
99
|
+
> {
|
|
100
|
+
return {
|
|
101
|
+
name: "human_handoff",
|
|
102
|
+
label: "Human Handoff",
|
|
103
|
+
description:
|
|
104
|
+
"Pause for one concrete action only the user can perform, then collect a reviewed Done or Unable status. Completion remains untrusted until the agent verifies the supplied completion signal.",
|
|
105
|
+
promptSnippet:
|
|
106
|
+
"Wait for a user-only manual action, then verify its observable completion signal",
|
|
107
|
+
promptGuidelines: [
|
|
108
|
+
"Use human_handoff only for an action the user must perform outside the available tools, such as sign-in, authorization, physical hardware, or a third-party approval. Do not use it for questions, preferences, or permission to continue.",
|
|
109
|
+
"Give short concrete instructions and an observable completion signal. After a Done result, verify that signal with available tools whenever possible; the user's status alone is not proof.",
|
|
110
|
+
"Do not call human_handoff from a child or workflow agent, and do not poll while waiting; the tool itself waits for the reviewed user status.",
|
|
111
|
+
],
|
|
112
|
+
executionMode: "sequential",
|
|
113
|
+
parameters: HumanHandoffParams,
|
|
114
|
+
|
|
115
|
+
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
116
|
+
const reply = (status: HumanHandoffStatus, note?: string) => ({
|
|
117
|
+
content: [
|
|
118
|
+
{
|
|
119
|
+
type: "text" as const,
|
|
120
|
+
text: resultMessage(status, params.completionSignal, note),
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
details: {
|
|
124
|
+
status,
|
|
125
|
+
...(note ? { note } : {}),
|
|
126
|
+
} satisfies HumanHandoffDetails,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (!ctx.hasUI) return reply("unavailable");
|
|
130
|
+
if (signal?.aborted) return reply("cancelled");
|
|
131
|
+
|
|
132
|
+
const title = safeSingleLine(params.title);
|
|
133
|
+
const instructions = safeText(params.instructions);
|
|
134
|
+
const completionSignal = safeText(params.completionSignal);
|
|
135
|
+
if (!title || !instructions || !completionSignal) {
|
|
136
|
+
throw new Error(
|
|
137
|
+
"human_handoff title, instructions, and completionSignal must contain visible text.",
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const options = signal ? { signal } : undefined;
|
|
142
|
+
const dialogTitle = `${title}\n\n${instructions}\n\nDone when: ${completionSignal}`;
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
while (!signal?.aborted) {
|
|
146
|
+
const choice = await ctx.ui.select(
|
|
147
|
+
dialogTitle,
|
|
148
|
+
[COMPLETE, UNABLE, DISMISS],
|
|
149
|
+
options,
|
|
150
|
+
);
|
|
151
|
+
if (signal?.aborted) return reply("cancelled");
|
|
152
|
+
if (!choice || choice === DISMISS) return reply("dismissed");
|
|
153
|
+
if (choice !== COMPLETE && choice !== UNABLE) continue;
|
|
154
|
+
|
|
155
|
+
const status = choice === COMPLETE ? "completed" : "unable";
|
|
156
|
+
const note = await optionalBoundedNote(ctx, signal, status);
|
|
157
|
+
if (signal?.aborted) return reply("cancelled");
|
|
158
|
+
|
|
159
|
+
const confirmed = await ctx.ui.confirm(
|
|
160
|
+
"Review handoff status",
|
|
161
|
+
`${status === "completed" ? "Done" : "Unable"}\n\nExpected completion signal: ${completionSignal}${note ? `\n\nNote: ${safeText(note)}` : ""}`,
|
|
162
|
+
options,
|
|
163
|
+
);
|
|
164
|
+
if (signal?.aborted) return reply("cancelled");
|
|
165
|
+
if (confirmed) return reply(status, note);
|
|
166
|
+
}
|
|
167
|
+
} catch (error) {
|
|
168
|
+
if (signal?.aborted) return reply("cancelled");
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return reply("cancelled");
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
renderCall(args, theme) {
|
|
176
|
+
return new Text(
|
|
177
|
+
theme.fg("toolTitle", theme.bold("human_handoff ")) +
|
|
178
|
+
theme.fg("muted", safeSingleLine(args.title)),
|
|
179
|
+
0,
|
|
180
|
+
0,
|
|
181
|
+
);
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
renderResult(result, _options, theme) {
|
|
185
|
+
const details = result.details as HumanHandoffDetails | undefined;
|
|
186
|
+
const status = details?.status;
|
|
187
|
+
const label =
|
|
188
|
+
status === "completed"
|
|
189
|
+
? "✓ marked done — verification required"
|
|
190
|
+
: status === "unable"
|
|
191
|
+
? "! unable"
|
|
192
|
+
: status === "unavailable"
|
|
193
|
+
? "! unavailable"
|
|
194
|
+
: "✗ dismissed";
|
|
195
|
+
return new Text(
|
|
196
|
+
theme.fg(status === "completed" ? "success" : "warning", label) +
|
|
197
|
+
(details?.note
|
|
198
|
+
? `\n${theme.fg("muted", safeSingleLine(details.note))}`
|
|
199
|
+
: ""),
|
|
200
|
+
0,
|
|
201
|
+
0,
|
|
202
|
+
);
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|