agentic-pi 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 +418 -0
- package/dist/args.d.ts +31 -0
- package/dist/args.js +109 -0
- package/dist/args.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.js +47 -0
- package/dist/cli.js.map +1 -0
- package/dist/emitter.d.ts +49 -0
- package/dist/emitter.js +67 -0
- package/dist/emitter.js.map +1 -0
- package/dist/extensions/github/auth.d.ts +54 -0
- package/dist/extensions/github/auth.js +116 -0
- package/dist/extensions/github/auth.js.map +1 -0
- package/dist/extensions/github/client.d.ts +6387 -0
- package/dist/extensions/github/client.js +358 -0
- package/dist/extensions/github/client.js.map +1 -0
- package/dist/extensions/github/credentials.d.ts +24 -0
- package/dist/extensions/github/credentials.js +44 -0
- package/dist/extensions/github/credentials.js.map +1 -0
- package/dist/extensions/github/index.d.ts +46 -0
- package/dist/extensions/github/index.js +67 -0
- package/dist/extensions/github/index.js.map +1 -0
- package/dist/extensions/github/profiles.d.ts +17 -0
- package/dist/extensions/github/profiles.js +71 -0
- package/dist/extensions/github/profiles.js.map +1 -0
- package/dist/extensions/github/tools.d.ts +18 -0
- package/dist/extensions/github/tools.js +289 -0
- package/dist/extensions/github/tools.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/models.d.ts +13 -0
- package/dist/models.js +31 -0
- package/dist/models.js.map +1 -0
- package/dist/run.d.ts +139 -0
- package/dist/run.js +131 -0
- package/dist/run.js.map +1 -0
- package/dist/runner.d.ts +22 -0
- package/dist/runner.js +143 -0
- package/dist/runner.js.map +1 -0
- package/dist/sandbox/gondolin.d.ts +39 -0
- package/dist/sandbox/gondolin.js +210 -0
- package/dist/sandbox/gondolin.js.map +1 -0
- package/dist/sandbox/index.d.ts +37 -0
- package/dist/sandbox/index.js +55 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/preflight.d.ts +24 -0
- package/dist/sandbox/preflight.js +93 -0
- package/dist/sandbox/preflight.js.map +1 -0
- package/dist/stdin.d.ts +1 -0
- package/dist/stdin.js +11 -0
- package/dist/stdin.js.map +1 -0
- package/package.json +44 -0
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Programmatic entry point.
|
|
3
|
+
*
|
|
4
|
+
* Use this when calling agentic-pi in-process from a Node host (e.g.
|
|
5
|
+
* lastlight). It returns a fully-resolved `RunResult` carrying the same
|
|
6
|
+
* information lastlight's `opencode-executor` needs from the JSONL stream
|
|
7
|
+
* (sessionId, finalText, tokens, cost, sandbox + GitHub status, etc.)
|
|
8
|
+
* plus the raw event records so the caller can do anything else they want
|
|
9
|
+
* with them.
|
|
10
|
+
*
|
|
11
|
+
* Never writes to `process.stdout` or `process.stderr`. Hand it an
|
|
12
|
+
* `onEvent` and/or `onWarn` callback if you want to observe live.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Pi thinking level. Matches Pi's `thinkingLevel` enum. Kept as a local
|
|
16
|
+
* string-union rather than imported from `@earendil-works/pi-agent-core`
|
|
17
|
+
* (which is a transitive dep we don't import directly — see AGENTS.md
|
|
18
|
+
* hard rule #3).
|
|
19
|
+
*/
|
|
20
|
+
export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
21
|
+
import { type EmitterRecord, type EmitterSink } from "./emitter.js";
|
|
22
|
+
import { type RunOnceExitCode } from "./runner.js";
|
|
23
|
+
export interface RunOptions {
|
|
24
|
+
/** "provider/model_id", e.g. "anthropic/claude-haiku-4-5". */
|
|
25
|
+
model: string;
|
|
26
|
+
/** The prompt to send to the agent. */
|
|
27
|
+
prompt: string;
|
|
28
|
+
/** Pi thinking level. */
|
|
29
|
+
thinking?: ThinkingLevel;
|
|
30
|
+
/** GitHub profile: "read" | "issues-write" | "review-write" | "repo-write". */
|
|
31
|
+
profile?: string;
|
|
32
|
+
/** Sandbox backend. Default: "none". */
|
|
33
|
+
sandbox?: "none" | "gondolin";
|
|
34
|
+
/** Working directory. Default: process.cwd(). */
|
|
35
|
+
cwd?: string;
|
|
36
|
+
/** Skip session persistence. Default: false. */
|
|
37
|
+
noSession?: boolean;
|
|
38
|
+
/** Override session storage directory. */
|
|
39
|
+
sessionDir?: string;
|
|
40
|
+
/** Disable Pi's built-in tools (read/write/edit/bash/grep/find/ls). */
|
|
41
|
+
noBuiltinTools?: boolean;
|
|
42
|
+
/** Explicit tool allowlist. */
|
|
43
|
+
tools?: string[];
|
|
44
|
+
/**
|
|
45
|
+
* Called for every emitted JSONL record in order. Same shape that the
|
|
46
|
+
* CLI writes to stdout, with `sessionId` and `timestamp` already injected.
|
|
47
|
+
* Use this to mirror events into your own jsonl file, push deltas to a
|
|
48
|
+
* UI, or persist sessionId early.
|
|
49
|
+
*/
|
|
50
|
+
onEvent?: (record: EmitterRecord) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Called for human-readable warnings (e.g. partial GitHub creds). The
|
|
53
|
+
* CLI writes these to stderr; in-process callers usually want to log
|
|
54
|
+
* them somewhere structured.
|
|
55
|
+
*/
|
|
56
|
+
onWarn?: (message: string) => void;
|
|
57
|
+
/**
|
|
58
|
+
* Extra sink to fan records out to (in addition to the internal
|
|
59
|
+
* collector that powers `result.records`). Useful if you want to write
|
|
60
|
+
* the shim jsonl directly without buffering through onEvent.
|
|
61
|
+
*/
|
|
62
|
+
extraSink?: EmitterSink;
|
|
63
|
+
}
|
|
64
|
+
/** Outcome of one agentic-pi run. */
|
|
65
|
+
export interface RunResult {
|
|
66
|
+
/** Exit code the CLI would have returned (0 = ok, 1 = runtime error, 2 = config error). */
|
|
67
|
+
exitCode: RunOnceExitCode;
|
|
68
|
+
/** True iff `exitCode === 0`. */
|
|
69
|
+
ok: boolean;
|
|
70
|
+
/** True iff Pi emitted an `agent_end` (clean termination). */
|
|
71
|
+
agentEnded: boolean;
|
|
72
|
+
/** True iff at least one tool returned an error. */
|
|
73
|
+
toolErrors: boolean;
|
|
74
|
+
/** If a fatal error short-circuited the run, this is set. */
|
|
75
|
+
fatalError?: {
|
|
76
|
+
name: string;
|
|
77
|
+
message: string;
|
|
78
|
+
};
|
|
79
|
+
/** Pi session id (from the session header line). May be undefined if preflight failed. */
|
|
80
|
+
sessionId?: string;
|
|
81
|
+
/** cwd the agent ran in. */
|
|
82
|
+
cwd?: string;
|
|
83
|
+
/** ISO timestamp of session start. */
|
|
84
|
+
startedAt?: string;
|
|
85
|
+
/** Concatenated final assistant text (the agent's "answer"). */
|
|
86
|
+
finalText: string;
|
|
87
|
+
/** Full message array from `agent_end` (user + assistant + toolResult messages). */
|
|
88
|
+
messages: unknown[];
|
|
89
|
+
/** Stats from the synthesized `usage_snapshot` event. */
|
|
90
|
+
stats?: {
|
|
91
|
+
userMessages: number;
|
|
92
|
+
assistantMessages: number;
|
|
93
|
+
toolCalls: number;
|
|
94
|
+
toolResults: number;
|
|
95
|
+
tokens: {
|
|
96
|
+
input: number;
|
|
97
|
+
output: number;
|
|
98
|
+
cacheRead: number;
|
|
99
|
+
cacheWrite: number;
|
|
100
|
+
total: number;
|
|
101
|
+
};
|
|
102
|
+
cost: number;
|
|
103
|
+
};
|
|
104
|
+
/** Mirrors of the `sandbox_status` and `extension_status` lines. */
|
|
105
|
+
sandbox?: {
|
|
106
|
+
backend: string;
|
|
107
|
+
status: Record<string, unknown>;
|
|
108
|
+
};
|
|
109
|
+
github?: {
|
|
110
|
+
status: "configured" | "skipped";
|
|
111
|
+
reason?: string;
|
|
112
|
+
message?: string;
|
|
113
|
+
profile?: string;
|
|
114
|
+
toolCount: number;
|
|
115
|
+
};
|
|
116
|
+
/** Every JSONL record the run emitted, in order. */
|
|
117
|
+
records: EmitterRecord[];
|
|
118
|
+
/** Warnings that would have gone to stderr in CLI mode. */
|
|
119
|
+
warnings: string[];
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Run agentic-pi in-process and return a fully-derived result.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* import { run } from "agentic-pi";
|
|
127
|
+
*
|
|
128
|
+
* const result = await run({
|
|
129
|
+
* model: "anthropic/claude-haiku-4-5",
|
|
130
|
+
* prompt: "list the open PRs on owner/repo",
|
|
131
|
+
* profile: "read",
|
|
132
|
+
* noSession: true,
|
|
133
|
+
* });
|
|
134
|
+
*
|
|
135
|
+
* console.log(result.finalText);
|
|
136
|
+
* console.log(result.stats?.cost, "USD");
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
export declare function run(options: RunOptions): Promise<RunResult>;
|
package/dist/run.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Programmatic entry point.
|
|
3
|
+
*
|
|
4
|
+
* Use this when calling agentic-pi in-process from a Node host (e.g.
|
|
5
|
+
* lastlight). It returns a fully-resolved `RunResult` carrying the same
|
|
6
|
+
* information lastlight's `opencode-executor` needs from the JSONL stream
|
|
7
|
+
* (sessionId, finalText, tokens, cost, sandbox + GitHub status, etc.)
|
|
8
|
+
* plus the raw event records so the caller can do anything else they want
|
|
9
|
+
* with them.
|
|
10
|
+
*
|
|
11
|
+
* Never writes to `process.stdout` or `process.stderr`. Hand it an
|
|
12
|
+
* `onEvent` and/or `onWarn` callback if you want to observe live.
|
|
13
|
+
*/
|
|
14
|
+
import { CollectorSink, TeeSink, } from "./emitter.js";
|
|
15
|
+
import { runOnce } from "./runner.js";
|
|
16
|
+
/**
|
|
17
|
+
* Run agentic-pi in-process and return a fully-derived result.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { run } from "agentic-pi";
|
|
22
|
+
*
|
|
23
|
+
* const result = await run({
|
|
24
|
+
* model: "anthropic/claude-haiku-4-5",
|
|
25
|
+
* prompt: "list the open PRs on owner/repo",
|
|
26
|
+
* profile: "read",
|
|
27
|
+
* noSession: true,
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* console.log(result.finalText);
|
|
31
|
+
* console.log(result.stats?.cost, "USD");
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export async function run(options) {
|
|
35
|
+
const config = {
|
|
36
|
+
model: options.model,
|
|
37
|
+
thinking: options.thinking,
|
|
38
|
+
profile: options.profile,
|
|
39
|
+
cwd: options.cwd ?? process.cwd(),
|
|
40
|
+
noSession: options.noSession ?? false,
|
|
41
|
+
sessionDir: options.sessionDir,
|
|
42
|
+
noBuiltinTools: options.noBuiltinTools ?? false,
|
|
43
|
+
tools: options.tools,
|
|
44
|
+
dangerouslySkipPermissions: false,
|
|
45
|
+
sandbox: options.sandbox ?? "none",
|
|
46
|
+
};
|
|
47
|
+
const collector = new CollectorSink(options.onEvent);
|
|
48
|
+
const sink = options.extraSink
|
|
49
|
+
? new TeeSink([collector, options.extraSink])
|
|
50
|
+
: collector;
|
|
51
|
+
const warnings = [];
|
|
52
|
+
const onWarn = (msg) => {
|
|
53
|
+
warnings.push(msg);
|
|
54
|
+
options.onWarn?.(msg);
|
|
55
|
+
};
|
|
56
|
+
const exitCode = await runOnce(config, options.prompt, { sink, onWarn });
|
|
57
|
+
return buildResult(exitCode, collector.records, warnings);
|
|
58
|
+
}
|
|
59
|
+
function buildResult(exitCode, records, warnings) {
|
|
60
|
+
const result = {
|
|
61
|
+
exitCode,
|
|
62
|
+
ok: exitCode === 0,
|
|
63
|
+
agentEnded: false,
|
|
64
|
+
toolErrors: false,
|
|
65
|
+
finalText: "",
|
|
66
|
+
messages: [],
|
|
67
|
+
records,
|
|
68
|
+
warnings,
|
|
69
|
+
};
|
|
70
|
+
for (const r of records) {
|
|
71
|
+
switch (r.type) {
|
|
72
|
+
case "session":
|
|
73
|
+
result.sessionId = r.id;
|
|
74
|
+
result.cwd = r.cwd;
|
|
75
|
+
result.startedAt = r.timestamp;
|
|
76
|
+
break;
|
|
77
|
+
case "sandbox_status":
|
|
78
|
+
result.sandbox = {
|
|
79
|
+
backend: r.backend,
|
|
80
|
+
status: r.status ?? {},
|
|
81
|
+
};
|
|
82
|
+
break;
|
|
83
|
+
case "extension_status":
|
|
84
|
+
if (r.extension === "github") {
|
|
85
|
+
result.github = {
|
|
86
|
+
status: r.status,
|
|
87
|
+
reason: r.reason,
|
|
88
|
+
message: r.message,
|
|
89
|
+
profile: r.profile,
|
|
90
|
+
toolCount: r.toolCount ?? 0,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
case "message_end": {
|
|
95
|
+
// Accumulate assistant text. Pi's message structure:
|
|
96
|
+
// r.message = { role: "assistant", content: [{type:"text", text:"…"}, ...] }
|
|
97
|
+
const m = r.message;
|
|
98
|
+
if (m?.role === "assistant" && Array.isArray(m.content)) {
|
|
99
|
+
// Keep only the LATEST assistant text (final answer overwrites
|
|
100
|
+
// intermediate ones). Pi guarantees the last assistant message
|
|
101
|
+
// before agent_end is the final answer.
|
|
102
|
+
const text = m.content
|
|
103
|
+
.filter((c) => c.type === "text" && typeof c.text === "string")
|
|
104
|
+
.map((c) => c.text)
|
|
105
|
+
.join("");
|
|
106
|
+
if (text)
|
|
107
|
+
result.finalText = text;
|
|
108
|
+
}
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
case "tool_execution_end":
|
|
112
|
+
if (r.isError === true)
|
|
113
|
+
result.toolErrors = true;
|
|
114
|
+
break;
|
|
115
|
+
case "agent_end":
|
|
116
|
+
result.agentEnded = true;
|
|
117
|
+
if (Array.isArray(r.messages)) {
|
|
118
|
+
result.messages = r.messages;
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
case "usage_snapshot":
|
|
122
|
+
result.stats = r.stats;
|
|
123
|
+
break;
|
|
124
|
+
case "fatal_error":
|
|
125
|
+
result.fatalError = r.error;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=run.js.map
|
package/dist/run.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot Pi SDK runner.
|
|
3
|
+
*
|
|
4
|
+
* Creates an AgentSession, subscribes to events, sends one prompt, waits for
|
|
5
|
+
* `agent_end`, emits a synthetic usage snapshot, and exits.
|
|
6
|
+
*
|
|
7
|
+
* The runner is sink-agnostic: events flow through an `Emitter` whose sink
|
|
8
|
+
* is provided by the caller. The CLI passes a `StdoutSink`; the
|
|
9
|
+
* programmatic `run()` API passes a `CollectorSink`. Warnings flow through
|
|
10
|
+
* an `onWarn` callback for the same reason — so library consumers never
|
|
11
|
+
* see `process.stderr` writes they didn't ask for.
|
|
12
|
+
*/
|
|
13
|
+
import type { RunConfig } from "./args.js";
|
|
14
|
+
import { type EmitterSink } from "./emitter.js";
|
|
15
|
+
export interface RunOnceDeps {
|
|
16
|
+
/** Sink for all JSONL records. Required. */
|
|
17
|
+
sink: EmitterSink;
|
|
18
|
+
/** Called with human-readable warning text. Default: no-op. */
|
|
19
|
+
onWarn?: (message: string) => void;
|
|
20
|
+
}
|
|
21
|
+
export type RunOnceExitCode = 0 | 1 | 2;
|
|
22
|
+
export declare function runOnce(config: RunConfig, prompt: string, deps: RunOnceDeps): Promise<RunOnceExitCode>;
|
package/dist/runner.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot Pi SDK runner.
|
|
3
|
+
*
|
|
4
|
+
* Creates an AgentSession, subscribes to events, sends one prompt, waits for
|
|
5
|
+
* `agent_end`, emits a synthetic usage snapshot, and exits.
|
|
6
|
+
*
|
|
7
|
+
* The runner is sink-agnostic: events flow through an `Emitter` whose sink
|
|
8
|
+
* is provided by the caller. The CLI passes a `StdoutSink`; the
|
|
9
|
+
* programmatic `run()` API passes a `CollectorSink`. Warnings flow through
|
|
10
|
+
* an `onWarn` callback for the same reason — so library consumers never
|
|
11
|
+
* see `process.stderr` writes they didn't ask for.
|
|
12
|
+
*/
|
|
13
|
+
import { AuthStorage, ModelRegistry, SessionManager, createAgentSession, } from "@earendil-works/pi-coding-agent";
|
|
14
|
+
import { Emitter } from "./emitter.js";
|
|
15
|
+
import { loadGitHubExtension, isMisconfigurationSkip } from "./extensions/github/index.js";
|
|
16
|
+
import { resolveModel } from "./models.js";
|
|
17
|
+
import { buildSandbox } from "./sandbox/index.js";
|
|
18
|
+
export async function runOnce(config, prompt, deps) {
|
|
19
|
+
const warn = deps.onWarn ?? (() => undefined);
|
|
20
|
+
const authStorage = AuthStorage.create();
|
|
21
|
+
const modelRegistry = ModelRegistry.create(authStorage);
|
|
22
|
+
const model = resolveModel(config.model, modelRegistry);
|
|
23
|
+
const sessionManager = buildSessionManager(config);
|
|
24
|
+
// Build the sandbox backend (boots Gondolin VM if --sandbox gondolin).
|
|
25
|
+
// Done eagerly so VM-boot / preflight failures surface before any tokens
|
|
26
|
+
// are spent on a prompt.
|
|
27
|
+
const sandboxOutcome = await buildSandbox({ backend: config.sandbox, cwd: config.cwd });
|
|
28
|
+
if (!sandboxOutcome.ok) {
|
|
29
|
+
warn(`--sandbox=${sandboxOutcome.backend} failed (${sandboxOutcome.reason}): ${sandboxOutcome.hint}`);
|
|
30
|
+
return 2;
|
|
31
|
+
}
|
|
32
|
+
const sandbox = sandboxOutcome.sandbox;
|
|
33
|
+
// Build the GitHub extension up-front so we can surface auth issues before
|
|
34
|
+
// creating the session (rather than at first tool call).
|
|
35
|
+
const github = loadGitHubExtension(config.profile);
|
|
36
|
+
// Loud about misconfigurations (partial App creds, unreadable PEM) — the
|
|
37
|
+
// user almost certainly meant for GitHub to work. Silent about benign
|
|
38
|
+
// skips (no --profile, no creds at all).
|
|
39
|
+
if (isMisconfigurationSkip(github)) {
|
|
40
|
+
warn(`GitHub extension disabled (${github.reason}): ${github.message ?? ""}`);
|
|
41
|
+
}
|
|
42
|
+
else if (github.status === "skipped" &&
|
|
43
|
+
github.reason === "no-credentials" &&
|
|
44
|
+
config.profile) {
|
|
45
|
+
warn(`--profile=${config.profile} set but no GITHUB_APP_* or GITHUB_TOKEN env vars found; GitHub tools disabled`);
|
|
46
|
+
}
|
|
47
|
+
// When a sandbox is active it supplies its own read/write/edit/bash that
|
|
48
|
+
// route through the VM; Pi's host built-ins of the same names must be
|
|
49
|
+
// suppressed so they don't shadow ours.
|
|
50
|
+
const noToolsMode = config.noBuiltinTools ? "builtin" :
|
|
51
|
+
sandbox.suppressBuiltins ? "builtin" :
|
|
52
|
+
undefined;
|
|
53
|
+
const { session } = await createAgentSession({
|
|
54
|
+
cwd: config.cwd,
|
|
55
|
+
model,
|
|
56
|
+
thinkingLevel: config.thinking,
|
|
57
|
+
sessionManager,
|
|
58
|
+
authStorage,
|
|
59
|
+
modelRegistry,
|
|
60
|
+
tools: config.tools,
|
|
61
|
+
noTools: noToolsMode,
|
|
62
|
+
customTools: [...sandbox.customTools, ...github.customTools],
|
|
63
|
+
});
|
|
64
|
+
const emitter = new Emitter({
|
|
65
|
+
sessionId: session.sessionId,
|
|
66
|
+
cwd: config.cwd,
|
|
67
|
+
startedAt: new Date().toISOString(),
|
|
68
|
+
}, deps.sink);
|
|
69
|
+
emitter.sessionHeader();
|
|
70
|
+
emitter.event({
|
|
71
|
+
type: "sandbox_status",
|
|
72
|
+
backend: sandbox.backend,
|
|
73
|
+
status: sandbox.status,
|
|
74
|
+
});
|
|
75
|
+
emitter.event({
|
|
76
|
+
type: "extension_status",
|
|
77
|
+
extension: "github",
|
|
78
|
+
status: github.status,
|
|
79
|
+
reason: github.reason,
|
|
80
|
+
message: github.message,
|
|
81
|
+
profile: github.profile,
|
|
82
|
+
toolCount: github.toolNames.length,
|
|
83
|
+
});
|
|
84
|
+
let sawError = false;
|
|
85
|
+
let agentEndSeen = false;
|
|
86
|
+
const unsubscribe = session.subscribe((event) => {
|
|
87
|
+
emitter.event(event);
|
|
88
|
+
if (event.type === "tool_execution_end" && event.isError) {
|
|
89
|
+
sawError = true;
|
|
90
|
+
}
|
|
91
|
+
if (event.type === "agent_end") {
|
|
92
|
+
agentEndSeen = true;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
try {
|
|
96
|
+
await session.prompt(prompt, { expandPromptTemplates: false });
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
emitter.event({
|
|
100
|
+
type: "fatal_error",
|
|
101
|
+
error: { name: err.name, message: err.message },
|
|
102
|
+
});
|
|
103
|
+
unsubscribe();
|
|
104
|
+
session.dispose();
|
|
105
|
+
await sandbox.close();
|
|
106
|
+
return 1;
|
|
107
|
+
}
|
|
108
|
+
// Synthesize a usage snapshot from the session stats. Pi's event stream
|
|
109
|
+
// does not carry per-event token/cost; lastlight reads this terminal event.
|
|
110
|
+
try {
|
|
111
|
+
const stats = session.getSessionStats();
|
|
112
|
+
emitter.event({
|
|
113
|
+
type: "usage_snapshot",
|
|
114
|
+
stats: {
|
|
115
|
+
userMessages: stats.userMessages,
|
|
116
|
+
assistantMessages: stats.assistantMessages,
|
|
117
|
+
toolCalls: stats.toolCalls,
|
|
118
|
+
toolResults: stats.toolResults,
|
|
119
|
+
tokens: stats.tokens,
|
|
120
|
+
cost: stats.cost,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
emitter.event({
|
|
126
|
+
type: "usage_snapshot_error",
|
|
127
|
+
error: { message: err.message },
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
unsubscribe();
|
|
131
|
+
session.dispose();
|
|
132
|
+
await sandbox.close();
|
|
133
|
+
if (sawError && !agentEndSeen)
|
|
134
|
+
return 1;
|
|
135
|
+
return 0;
|
|
136
|
+
}
|
|
137
|
+
function buildSessionManager(config) {
|
|
138
|
+
if (config.noSession) {
|
|
139
|
+
return SessionManager.inMemory(config.cwd);
|
|
140
|
+
}
|
|
141
|
+
return SessionManager.create(config.cwd, config.sessionDir);
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,WAAW,EACX,aAAa,EACb,cAAc,EACd,kBAAkB,GACnB,MAAM,iCAAiC,CAAC;AAIzC,OAAO,EAAE,OAAO,EAAoB,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAsB,MAAM,oBAAoB,CAAC;AAWtE,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,MAAiB,EACjB,MAAc,EACd,IAAiB;IAEjB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAE9C,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC;IACzC,MAAM,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IAExD,MAAM,cAAc,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAEnD,uEAAuE;IACvE,yEAAyE;IACzE,yBAAyB;IACzB,MAAM,cAAc,GAAG,MAAM,YAAY,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IACxF,IAAI,CAAC,cAAc,CAAC,EAAE,EAAE,CAAC;QACvB,IAAI,CAAC,aAAa,cAAc,CAAC,OAAO,YAAY,cAAc,CAAC,MAAM,MAAM,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC;QACtG,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,OAAO,GAAkB,cAAc,CAAC,OAAO,CAAC;IAEtD,2EAA2E;IAC3E,yDAAyD;IACzD,MAAM,MAAM,GAAG,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnD,yEAAyE;IACzE,sEAAsE;IACtE,yCAAyC;IACzC,IAAI,sBAAsB,CAAC,MAAM,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,8BAA8B,MAAM,CAAC,MAAM,MAAM,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC,CAAC;IAChF,CAAC;SAAM,IACL,MAAM,CAAC,MAAM,KAAK,SAAS;QAC3B,MAAM,CAAC,MAAM,KAAK,gBAAgB;QAClC,MAAM,CAAC,OAAO,EACd,CAAC;QACD,IAAI,CAAC,aAAa,MAAM,CAAC,OAAO,gFAAgF,CAAC,CAAC;IACpH,CAAC;IAED,yEAAyE;IACzE,sEAAsE;IACtE,wCAAwC;IACxC,MAAM,WAAW,GACf,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACnC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YACtC,SAAS,CAAC;IAEZ,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,kBAAkB,CAAC;QAC3C,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,KAAK;QACL,aAAa,EAAE,MAAM,CAAC,QAAQ;QAC9B,cAAc;QACd,WAAW;QACX,aAAa;QACb,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,OAAO,EAAE,WAAW;QACpB,WAAW,EAAE,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC;KAC7D,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAI,OAAO,CACzB;QACE,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,EACD,IAAI,CAAC,IAAI,CACV,CAAC;IAEF,OAAO,CAAC,aAAa,EAAE,CAAC;IACxB,OAAO,CAAC,KAAK,CAAC;QACZ,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IACH,OAAO,CAAC,KAAK,CAAC;QACZ,IAAI,EAAE,kBAAkB;QACxB,SAAS,EAAE,QAAQ;QACnB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM;KACnC,CAAC,CAAC;IAEH,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,YAAY,GAAG,KAAK,CAAC;IAEzB,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,KAAwB,EAAE,EAAE;QACjE,OAAO,CAAC,KAAK,CAAC,KAA8D,CAAC,CAAC;QAE9E,IAAI,KAAK,CAAC,IAAI,KAAK,oBAAoB,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACzD,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC/B,YAAY,GAAG,IAAI,CAAC;QACtB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC;IACjE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC;YACZ,IAAI,EAAE,aAAa;YACnB,KAAK,EAAE,EAAE,IAAI,EAAG,GAAa,CAAC,IAAI,EAAE,OAAO,EAAG,GAAa,CAAC,OAAO,EAAE;SACtE,CAAC,CAAC;QACH,WAAW,EAAE,CAAC;QACd,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,wEAAwE;IACxE,4EAA4E;IAC5E,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;QACxC,OAAO,CAAC,KAAK,CAAC;YACZ,IAAI,EAAE,gBAAgB;YACtB,KAAK,EAAE;gBACL,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;gBAC1C,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,IAAI,EAAE,KAAK,CAAC,IAAI;aACjB;SACF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC;YACZ,IAAI,EAAE,sBAAsB;YAC5B,KAAK,EAAE,EAAE,OAAO,EAAG,GAAa,CAAC,OAAO,EAAE;SAC3C,CAAC,CAAC;IACL,CAAC;IAED,WAAW,EAAE,CAAC;IACd,OAAO,CAAC,OAAO,EAAE,CAAC;IAClB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IAEtB,IAAI,QAAQ,IAAI,CAAC,YAAY;QAAE,OAAO,CAAC,CAAC;IACxC,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,mBAAmB,CAAC,MAAiB;IAC5C,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,OAAO,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gondolin sandbox backend for agentic-pi.
|
|
3
|
+
*
|
|
4
|
+
* Routes Pi's built-in `read`/`write`/`edit`/`bash` tools through a Gondolin
|
|
5
|
+
* micro-VM. The agent's tool calls execute against `/workspace` inside the
|
|
6
|
+
* VM, where the host's current working directory has been mounted RW. Files
|
|
7
|
+
* the agent writes appear on the host because RealFSProvider is a passthrough.
|
|
8
|
+
*
|
|
9
|
+
* Pattern adapted from gondolin/host/examples/pi-gondolin.ts but adjusted
|
|
10
|
+
* for SDK mode (no Pi extension hooks; we drive `createAgentSession`
|
|
11
|
+
* directly).
|
|
12
|
+
*
|
|
13
|
+
* Note: `grep`/`find`/`ls` are NOT routed through the VM in this version —
|
|
14
|
+
* they run on the host but they read the *same* files (because the mount
|
|
15
|
+
* is a passthrough), so the agent sees consistent state. This matches the
|
|
16
|
+
* upstream example. If full FS isolation is needed later, route those too.
|
|
17
|
+
*/
|
|
18
|
+
import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
19
|
+
export interface GondolinSandbox {
|
|
20
|
+
/** Tools to pass into `createAgentSession({ customTools })`. */
|
|
21
|
+
customTools: ToolDefinition<any>[];
|
|
22
|
+
/** Tear down the VM. Idempotent. */
|
|
23
|
+
close: () => Promise<void>;
|
|
24
|
+
/** For the `sandbox_status` event. */
|
|
25
|
+
status: {
|
|
26
|
+
backend: "gondolin";
|
|
27
|
+
cwd: string;
|
|
28
|
+
guestPath: string;
|
|
29
|
+
createMs: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Boot a Gondolin VM mounting `cwd` at /workspace, and build the four
|
|
34
|
+
* Pi tool overrides (read, write, edit, bash) that route through it.
|
|
35
|
+
*
|
|
36
|
+
* Throws if VM.create rejects. The preflight check is the caller's
|
|
37
|
+
* responsibility — call `preflightGondolin()` first.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildGondolinSandbox(cwd: string): Promise<GondolinSandbox>;
|