@tt-a1i/openpi 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 +102 -40
- package/SETUP.md +22 -6
- package/assets/openpi-launch-card-v1.webp +0 -0
- package/bin/openpi.js +145 -0
- package/extensions/background-terminals/index.ts +30 -2
- package/extensions/background-terminals/src/domain.ts +2 -0
- package/extensions/background-terminals/src/manager.ts +486 -106
- package/extensions/background-terminals/src/output.ts +33 -0
- package/extensions/background-terminals/src/prompt.ts +13 -5
- package/extensions/background-terminals/src/result-delivery.ts +4 -1
- package/extensions/clear-context/index.ts +83 -0
- package/extensions/context-pivot/index.ts +16 -6
- package/extensions/cron/schedule.ts +7 -1
- package/extensions/file-mutation-display/render.ts +17 -257
- package/extensions/file-search/src/binaries.ts +57 -41
- package/extensions/git-read/index.ts +1 -3
- package/extensions/model-info/index.ts +21 -33
- package/extensions/model-info/session-metrics.ts +96 -0
- package/extensions/plan-mode/bash-policy.ts +54 -9
- package/extensions/plan-mode/index.ts +7 -2
- package/extensions/post-edit/index.ts +16 -6
- package/extensions/sessions/git-stats.ts +258 -72
- package/extensions/sessions/index.ts +153 -86
- package/extensions/sessions/preview-cache.ts +104 -0
- package/extensions/sessions/preview-loader.ts +856 -0
- package/extensions/sessions/sessions.ts +43 -4
- package/extensions/setup/index.ts +123 -127
- package/extensions/shared/activity-status.ts +30 -0
- package/extensions/shared/agent-session-page.ts +319 -0
- package/extensions/shared/agent-tool-renderer.ts +218 -0
- package/extensions/shared/agent-transcript.ts +524 -0
- package/extensions/shared/capability-intent.ts +1 -1
- package/extensions/shared/child-session.ts +437 -21
- package/extensions/shared/result-delivery.ts +34 -0
- package/extensions/shared/setup-config.ts +73 -33
- package/extensions/shared/setup-episode-state.ts +1 -1
- package/extensions/shared/terminal-text.ts +110 -23
- package/extensions/shared/text-projection.ts +72 -15
- package/extensions/shared/tool-activity.ts +382 -0
- package/extensions/shared/tool-surface.ts +29 -2
- package/extensions/shared/transcript-viewport.ts +46 -0
- package/extensions/shared/web-observer-registry.ts +390 -0
- package/extensions/shared/worktree.ts +11 -0
- package/extensions/subagents/index.ts +270 -59
- package/extensions/subagents/navigation.ts +34 -5
- package/extensions/subagents/src/backend.ts +12 -1
- package/extensions/subagents/src/backends/pi.ts +375 -66
- package/extensions/subagents/src/domain.ts +5 -0
- package/extensions/subagents/src/manager.ts +34 -2
- package/extensions/subagents/src/prompt.ts +32 -4
- package/extensions/subagents/src/result-artifact.ts +4 -0
- package/extensions/subagents/src/result-delivery.ts +7 -1
- package/extensions/subagents/src/runtime.ts +15 -1
- package/extensions/subagents/src/ui/takeover.ts +73 -257
- package/extensions/subagents/src/ui/transcript.ts +38 -535
- package/extensions/subagents/src/ui/wait-result.ts +103 -15
- package/extensions/suggestions/src/ui.ts +10 -4
- package/extensions/tasks/index.ts +0 -3
- package/extensions/ui-customization/footer.ts +0 -40
- package/extensions/ui-customization/index.ts +0 -4
- package/extensions/user-input-fold/index.ts +1 -1
- package/extensions/web/index.ts +234 -0
- package/extensions/workflows/artifacts.ts +137 -47
- package/extensions/workflows/completion-projection.ts +457 -0
- package/extensions/workflows/coordinator.ts +8 -10
- package/extensions/workflows/dashboard.ts +167 -228
- package/extensions/workflows/handoff.ts +70 -16
- package/extensions/workflows/index.ts +488 -198
- package/extensions/workflows/journal.ts +148 -13
- package/extensions/workflows/model.ts +74 -4
- package/extensions/workflows/navigation.ts +32 -8
- package/extensions/workflows/progress-projection.ts +306 -0
- package/extensions/workflows/prompt.ts +66 -6
- package/extensions/workflows/replay-safety.ts +42 -21
- package/extensions/workflows/result-delivery.ts +128 -64
- package/extensions/workflows/retention.ts +593 -0
- package/extensions/workflows/runner.ts +388 -279
- package/extensions/workflows/sandbox-child.cjs +25 -3
- package/extensions/workflows/sandbox.ts +62 -8
- package/extensions/workflows/serialization.ts +325 -17
- package/extensions/workflows/tool-renderer.ts +22 -0
- package/extensions/workflows/transcript.ts +149 -0
- package/extensions/workspace-cleanup-guard/index.ts +54 -0
- package/extensions/workspace-cleanup-guard/workspace-provenance.ts +563 -0
- package/package.json +28 -8
- package/skills/subagents/REFERENCE.md +189 -0
- package/skills/subagents/SKILL.md +1 -1
- package/skills/workflows/REFERENCE.md +4 -2
- package/web/adapter/pi-adapter.ts +661 -0
- package/web/host/browser-launcher.ts +20 -0
- package/web/host/static-assets.ts +4 -0
- package/web/host/terminal-status.ts +38 -0
- package/web/host/web-host.ts +789 -0
- package/web/http-dispatcher.ts +125 -0
- package/web/protocol/types.ts +462 -0
- package/web/runtime/pi-runtime.ts +991 -0
- package/web/runtime/types.ts +71 -0
- package/web/runtime/web-host-lease.ts +497 -0
- package/web/trace.ts +18 -0
- package/web/ui/app.js +1398 -0
- package/web/ui/index.html +139 -0
- package/web/ui/styles.css +598 -0
- package/web/vite.config.mjs +34 -0
- package/extensions/execution-convergence/active-evidence.ts +0 -129
- package/extensions/execution-convergence/index.ts +0 -442
- package/extensions/execution-convergence/workspace-provenance.ts +0 -338
- package/extensions/setup/intercom-fs-helper.cjs +0 -130
- package/extensions/setup/intercom.ts +0 -603
- package/extensions/subagents/src/backends/stub.ts +0 -303
|
@@ -1,32 +1,40 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
type TranscriptEntry,
|
|
4
|
-
type WorkflowDetails,
|
|
5
|
-
} from "./model.ts";
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
6
3
|
import {
|
|
7
4
|
boundedJournal,
|
|
8
|
-
|
|
5
|
+
JOURNAL_MAX_BYTES,
|
|
9
6
|
type JournalEntry,
|
|
7
|
+
parseJournal,
|
|
10
8
|
type WorkflowJournal,
|
|
9
|
+
type WorkflowJournalAccumulator,
|
|
11
10
|
} from "./journal.ts";
|
|
12
11
|
import {
|
|
12
|
+
refreshWorkflowGraph,
|
|
13
|
+
type TranscriptEntry,
|
|
14
|
+
type WorkflowDelivery,
|
|
15
|
+
type WorkflowDetails,
|
|
16
|
+
} from "./model.ts";
|
|
17
|
+
import {
|
|
18
|
+
encodeCompleteJson,
|
|
13
19
|
safeStringify,
|
|
14
|
-
toSerializable,
|
|
15
20
|
truncateUtf8,
|
|
16
21
|
writeFileAtomic,
|
|
17
22
|
} from "./serialization.ts";
|
|
18
|
-
import * as fs from "node:fs";
|
|
19
|
-
import * as path from "node:path";
|
|
20
23
|
|
|
21
24
|
export const JOURNAL_FILE = "journal.json";
|
|
22
25
|
|
|
23
26
|
const ARTIFACT_TRANSCRIPT_MAX_BYTES = 32 * 1024;
|
|
24
27
|
const ARTIFACT_TRANSCRIPT_ENTRY_MAX_BYTES = 8 * 1024;
|
|
28
|
+
const AGENT_RESULT_ARTIFACT_MAX_BYTES = 2 * 1024 * 1024;
|
|
25
29
|
export const WORKFLOW_CHECKPOINT_INTERVAL_MS = 500;
|
|
26
30
|
const ENTRY_TRUNCATION_MARKER = "\n[entry truncated]";
|
|
27
31
|
const TRANSCRIPT_TRUNCATION_MARKER =
|
|
28
32
|
"[artifact transcript truncated: older entries omitted]";
|
|
29
33
|
|
|
34
|
+
type WorkflowJournalSource =
|
|
35
|
+
| readonly JournalEntry[]
|
|
36
|
+
| WorkflowJournalAccumulator;
|
|
37
|
+
|
|
30
38
|
function textBytes(text: string) {
|
|
31
39
|
return Buffer.byteLength(text, "utf8");
|
|
32
40
|
}
|
|
@@ -101,44 +109,61 @@ function writeRunFile(runDir: string, name: string, content: string) {
|
|
|
101
109
|
writeFileAtomic(path.join(runDir, name), content);
|
|
102
110
|
}
|
|
103
111
|
|
|
112
|
+
export function persistWorkflowTerminalState(
|
|
113
|
+
runDir: string,
|
|
114
|
+
details: WorkflowDetails,
|
|
115
|
+
) {
|
|
116
|
+
const terminalManifest: WorkflowDetails = {
|
|
117
|
+
...details,
|
|
118
|
+
agents: details.agents.map((agent) => ({ ...agent, transcript: [] })),
|
|
119
|
+
};
|
|
120
|
+
delete terminalManifest.result;
|
|
121
|
+
delete terminalManifest.resultArtifact;
|
|
122
|
+
delete terminalManifest.transcriptArtifact;
|
|
123
|
+
writeRunFile(
|
|
124
|
+
runDir,
|
|
125
|
+
"workflow.json",
|
|
126
|
+
safeStringify(terminalManifest, { maxBytes: 1024 * 1024 }),
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
104
130
|
/** Persist one successful child result before any handoff/context projection. */
|
|
105
131
|
export function persistWorkflowAgentResult(
|
|
106
132
|
runDir: string,
|
|
107
133
|
index: number,
|
|
108
134
|
result: { output: string; structured?: unknown },
|
|
109
135
|
) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
{
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
maxNodes: 100_000,
|
|
128
|
-
maxStringBytes: 2 * 1024 * 1024,
|
|
129
|
-
},
|
|
130
|
-
),
|
|
131
|
-
null,
|
|
132
|
-
2,
|
|
133
|
-
),
|
|
136
|
+
// Artifact references are persisted as portable workflow paths. The host
|
|
137
|
+
// filesystem join happens in writeRunFile; handoff validation and replay
|
|
138
|
+
// consumers intentionally use `/` regardless of the platform.
|
|
139
|
+
const artifact = `agent-results/agent-${String(index).padStart(4, "0")}.json`;
|
|
140
|
+
const encoded = encodeCompleteJson(
|
|
141
|
+
{
|
|
142
|
+
output: result.output,
|
|
143
|
+
...(result.structured !== undefined
|
|
144
|
+
? { structured: result.structured }
|
|
145
|
+
: {}),
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
maxBytes: AGENT_RESULT_ARTIFACT_MAX_BYTES,
|
|
149
|
+
maxDepth: 32,
|
|
150
|
+
maxNodes: 100_000,
|
|
151
|
+
maxStringBytes: AGENT_RESULT_ARTIFACT_MAX_BYTES,
|
|
152
|
+
},
|
|
134
153
|
);
|
|
154
|
+
if (!encoded.ok) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
`Agent result artifact exceeded the ${AGENT_RESULT_ARTIFACT_MAX_BYTES}-byte budget (${encoded.limit} limit at ${encoded.path})`,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
writeRunFile(runDir, artifact, encoded.json);
|
|
135
160
|
return artifact;
|
|
136
161
|
}
|
|
137
162
|
|
|
138
163
|
export function persistWorkflowJson(
|
|
139
164
|
runDir: string,
|
|
140
165
|
details: WorkflowDetails,
|
|
141
|
-
journal?:
|
|
166
|
+
journal?: WorkflowJournalSource,
|
|
142
167
|
) {
|
|
143
168
|
refreshWorkflowGraph(details);
|
|
144
169
|
const transcripts = Object.fromEntries(
|
|
@@ -147,6 +172,15 @@ export function persistWorkflowJson(
|
|
|
147
172
|
boundedArtifactTranscript(agent.transcript),
|
|
148
173
|
]),
|
|
149
174
|
);
|
|
175
|
+
|
|
176
|
+
// Publish terminal execution facts before dependent side artifacts. If a
|
|
177
|
+
// later artifact write fails, readers still see an explained terminal run
|
|
178
|
+
// instead of the previous `running` manifest. The final manifest below adds
|
|
179
|
+
// the artifact references once every dependent file has committed.
|
|
180
|
+
if (details.status !== "running") {
|
|
181
|
+
persistWorkflowTerminalState(runDir, details);
|
|
182
|
+
}
|
|
183
|
+
|
|
150
184
|
writeRunFile(
|
|
151
185
|
runDir,
|
|
152
186
|
"transcripts.json",
|
|
@@ -154,15 +188,20 @@ export function persistWorkflowJson(
|
|
|
154
188
|
);
|
|
155
189
|
// Written alongside the rest so it inherits atomic write, 500ms coalescing,
|
|
156
190
|
// and the final flush. Only present once a call has actually succeeded.
|
|
157
|
-
//
|
|
158
|
-
// JSON
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
191
|
+
// Accumulators already enforce the cap incrementally and can assemble the
|
|
192
|
+
// canonical JSON from their cached entry fragments. Plain arrays retain the
|
|
193
|
+
// compatibility path through boundedJournal; plain JSON.stringify is
|
|
194
|
+
// deliberate because safeStringify would swap an over-cap value for a
|
|
195
|
+
// preview stub, silently turning the journal into something unusable.
|
|
196
|
+
if (
|
|
197
|
+
journal &&
|
|
198
|
+
(journal.length > 0 || ("toJson" in journal && journal.dropped > 0))
|
|
199
|
+
) {
|
|
200
|
+
const content =
|
|
201
|
+
"toJson" in journal
|
|
202
|
+
? journal.toJson()
|
|
203
|
+
: JSON.stringify(boundedJournal(journal).journal, null, 2);
|
|
204
|
+
writeRunFile(runDir, JOURNAL_FILE, content);
|
|
166
205
|
}
|
|
167
206
|
if (details.result !== undefined) {
|
|
168
207
|
writeRunFile(
|
|
@@ -186,6 +225,25 @@ export function persistWorkflowJson(
|
|
|
186
225
|
);
|
|
187
226
|
}
|
|
188
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Update only the durable delivery receipt. Completion delivery may retain a
|
|
230
|
+
* compact memory projection after the run has been evicted, so rewriting the
|
|
231
|
+
* whole details object here would risk replacing exact result artifacts with
|
|
232
|
+
* that projection.
|
|
233
|
+
*/
|
|
234
|
+
export function persistWorkflowDeliveryState(
|
|
235
|
+
runDir: string,
|
|
236
|
+
delivery: WorkflowDelivery,
|
|
237
|
+
) {
|
|
238
|
+
const file = path.join(runDir, "workflow.json");
|
|
239
|
+
const raw: unknown = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
240
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
241
|
+
throw new Error(`Invalid persisted workflow details: ${file}`);
|
|
242
|
+
}
|
|
243
|
+
const next = { ...(raw as Record<string, unknown>), delivery };
|
|
244
|
+
writeFileAtomic(file, JSON.stringify(next));
|
|
245
|
+
}
|
|
246
|
+
|
|
189
247
|
/** Coalesce live checkpoints while keeping final persistence synchronous. */
|
|
190
248
|
export function createWorkflowPersistence(
|
|
191
249
|
runDir: string,
|
|
@@ -195,10 +253,10 @@ export function createWorkflowPersistence(
|
|
|
195
253
|
persist?: (
|
|
196
254
|
runDir: string,
|
|
197
255
|
details: WorkflowDetails,
|
|
198
|
-
journal?:
|
|
256
|
+
journal?: WorkflowJournalSource,
|
|
199
257
|
) => void;
|
|
200
|
-
/** Read at write time so callers only have to append to their
|
|
201
|
-
journal?: () =>
|
|
258
|
+
/** Read at write time so callers only have to append to their journal. */
|
|
259
|
+
journal?: () => WorkflowJournalSource;
|
|
202
260
|
} = {},
|
|
203
261
|
) {
|
|
204
262
|
const intervalMs = Math.max(
|
|
@@ -256,10 +314,42 @@ export function createWorkflowPersistence(
|
|
|
256
314
|
* turn into a new way for a run to fail.
|
|
257
315
|
*/
|
|
258
316
|
export function loadJournal(runDir: string): WorkflowJournal | undefined {
|
|
317
|
+
let descriptor: number | undefined;
|
|
259
318
|
try {
|
|
260
|
-
|
|
319
|
+
descriptor = fs.openSync(path.join(runDir, JOURNAL_FILE), "r");
|
|
320
|
+
const initialSize = fs.fstatSync(descriptor).size;
|
|
321
|
+
if (initialSize > JOURNAL_MAX_BYTES) return undefined;
|
|
322
|
+
|
|
323
|
+
// Read at most one byte beyond the cap. The descriptor pins the inspected
|
|
324
|
+
// file, while the extra byte catches growth after fstat without ever
|
|
325
|
+
// allocating or parsing an unbounded journal.
|
|
326
|
+
const bytes = Buffer.allocUnsafe(initialSize + 1);
|
|
327
|
+
let length = 0;
|
|
328
|
+
while (length < bytes.length) {
|
|
329
|
+
const read = fs.readSync(
|
|
330
|
+
descriptor,
|
|
331
|
+
bytes,
|
|
332
|
+
length,
|
|
333
|
+
bytes.length - length,
|
|
334
|
+
null,
|
|
335
|
+
);
|
|
336
|
+
if (read === 0) break;
|
|
337
|
+
length += read;
|
|
338
|
+
}
|
|
339
|
+
// Filling the extra byte means the file changed after inspection. Reject
|
|
340
|
+
// that race even when the new size would still fit the ordinary cap.
|
|
341
|
+
if (length === bytes.length) return undefined;
|
|
342
|
+
const raw = bytes.toString("utf8", 0, length);
|
|
261
343
|
return parseJournal(JSON.parse(raw));
|
|
262
344
|
} catch {
|
|
263
345
|
return undefined;
|
|
346
|
+
} finally {
|
|
347
|
+
if (descriptor !== undefined) {
|
|
348
|
+
try {
|
|
349
|
+
fs.closeSync(descriptor);
|
|
350
|
+
} catch {
|
|
351
|
+
// Loading a replay cache is optional and always fails open to a miss.
|
|
352
|
+
}
|
|
353
|
+
}
|
|
264
354
|
}
|
|
265
355
|
}
|