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.
Files changed (53) hide show
  1. package/README.md +418 -0
  2. package/dist/args.d.ts +31 -0
  3. package/dist/args.js +109 -0
  4. package/dist/args.js.map +1 -0
  5. package/dist/cli.d.ts +9 -0
  6. package/dist/cli.js +47 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/emitter.d.ts +49 -0
  9. package/dist/emitter.js +67 -0
  10. package/dist/emitter.js.map +1 -0
  11. package/dist/extensions/github/auth.d.ts +54 -0
  12. package/dist/extensions/github/auth.js +116 -0
  13. package/dist/extensions/github/auth.js.map +1 -0
  14. package/dist/extensions/github/client.d.ts +6387 -0
  15. package/dist/extensions/github/client.js +358 -0
  16. package/dist/extensions/github/client.js.map +1 -0
  17. package/dist/extensions/github/credentials.d.ts +24 -0
  18. package/dist/extensions/github/credentials.js +44 -0
  19. package/dist/extensions/github/credentials.js.map +1 -0
  20. package/dist/extensions/github/index.d.ts +46 -0
  21. package/dist/extensions/github/index.js +67 -0
  22. package/dist/extensions/github/index.js.map +1 -0
  23. package/dist/extensions/github/profiles.d.ts +17 -0
  24. package/dist/extensions/github/profiles.js +71 -0
  25. package/dist/extensions/github/profiles.js.map +1 -0
  26. package/dist/extensions/github/tools.d.ts +18 -0
  27. package/dist/extensions/github/tools.js +289 -0
  28. package/dist/extensions/github/tools.js.map +1 -0
  29. package/dist/index.d.ts +38 -0
  30. package/dist/index.js +34 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/models.d.ts +13 -0
  33. package/dist/models.js +31 -0
  34. package/dist/models.js.map +1 -0
  35. package/dist/run.d.ts +139 -0
  36. package/dist/run.js +131 -0
  37. package/dist/run.js.map +1 -0
  38. package/dist/runner.d.ts +22 -0
  39. package/dist/runner.js +143 -0
  40. package/dist/runner.js.map +1 -0
  41. package/dist/sandbox/gondolin.d.ts +39 -0
  42. package/dist/sandbox/gondolin.js +210 -0
  43. package/dist/sandbox/gondolin.js.map +1 -0
  44. package/dist/sandbox/index.d.ts +37 -0
  45. package/dist/sandbox/index.js +55 -0
  46. package/dist/sandbox/index.js.map +1 -0
  47. package/dist/sandbox/preflight.d.ts +24 -0
  48. package/dist/sandbox/preflight.js +93 -0
  49. package/dist/sandbox/preflight.js.map +1 -0
  50. package/dist/stdin.d.ts +1 -0
  51. package/dist/stdin.js +11 -0
  52. package/dist/stdin.js.map +1 -0
  53. 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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
@@ -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":"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"}
@@ -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>;