mlx-bun 0.0.4
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/LICENSE +21 -0
- package/README.md +362 -0
- package/THIRD_PARTY_LICENSES.md +41 -0
- package/bin/mlx-bun.mjs +32 -0
- package/docs/curve-designer.html +303 -0
- package/docs/design/adapters-end-to-end.md +201 -0
- package/docs/design/compat-cli-surface-design.md +227 -0
- package/docs/design/docs-reorg-plan.md +152 -0
- package/docs/design/hlg-sampling.md +340 -0
- package/docs/design/memory-system.md +339 -0
- package/docs/design/optimization_plan.md +344 -0
- package/docs/design/parallel-slots.md +515 -0
- package/docs/design/runtime-isolation.md +247 -0
- package/docs/design/segmented-backward-training.md +508 -0
- package/docs/investigations/chunk-finetune-experiment.md +84 -0
- package/docs/investigations/curve-bisector-routing.md +123 -0
- package/docs/investigations/curve-runs/bisector-route.json +98 -0
- package/docs/investigations/curve-runs/bisector-trace.json +1393 -0
- package/docs/investigations/curve-runs/curve-terrain.json +1179 -0
- package/docs/investigations/curve-runs/curve-terrain.svg +42 -0
- package/docs/investigations/curve-terrain.html +105 -0
- package/docs/investigations/expert-offload-single-user-moe.md +292 -0
- package/docs/investigations/hlg-ab.html +34 -0
- package/docs/investigations/hlg-explorer.html +238 -0
- package/docs/investigations/hlg-figs/cliff.svg +1 -0
- package/docs/investigations/hlg-figs/cross.svg +1 -0
- package/docs/investigations/hlg-figs/edges.svg +1 -0
- package/docs/investigations/hlg-figs/k20-grids.svg +1 -0
- package/docs/investigations/hlg-figs/k20-peaks.svg +1 -0
- package/docs/investigations/hlg-figs/lw-curve.svg +1 -0
- package/docs/investigations/hlg-figs/terrain.svg +1 -0
- package/docs/investigations/hlg-report.html +262 -0
- package/docs/investigations/hlg-runs/hlg-ab.json +149 -0
- package/docs/investigations/hlg-runs/hlg-blind-prompts.md +87 -0
- package/docs/investigations/hlg-runs/hlg-blind.json +107 -0
- package/docs/investigations/hlg-runs/hlg-cliff.json +197 -0
- package/docs/investigations/hlg-runs/hlg-cross.json +505 -0
- package/docs/investigations/hlg-runs/hlg-edge.json +388 -0
- package/docs/investigations/hlg-runs/hlg-eval1.json +25 -0
- package/docs/investigations/hlg-runs/hlg-frontier.json +86 -0
- package/docs/investigations/hlg-runs/hlg-grid.json +242 -0
- package/docs/investigations/hlg-runs/hlg-grid2.json +343 -0
- package/docs/investigations/hlg-runs/hlg-lw-coarse.json +110 -0
- package/docs/investigations/hlg-runs/hlg-map.json +383 -0
- package/docs/investigations/hlg-runs/run0-original.log +159 -0
- package/docs/investigations/hlg-runs/runA-recommended.log +131 -0
- package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +26 -0
- package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +18 -0
- package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +25 -0
- package/docs/investigations/hlg-runs/runAD-ab-samples.log +8 -0
- package/docs/investigations/hlg-runs/runAE-edge-e4b.log +51 -0
- package/docs/investigations/hlg-runs/runAF-logit-calibration.log +10 -0
- package/docs/investigations/hlg-runs/runAG-eval-config2.log +16 -0
- package/docs/investigations/hlg-runs/runB-gain-variants.log +192 -0
- package/docs/investigations/hlg-runs/runC-pivots.log +162 -0
- package/docs/investigations/hlg-runs/runD-oetf.log +132 -0
- package/docs/investigations/hlg-runs/runE-eotf.log +162 -0
- package/docs/investigations/hlg-runs/runF-shaper-working.log +86 -0
- package/docs/investigations/hlg-runs/runG-shaper-sweep.log +101 -0
- package/docs/investigations/hlg-runs/runH-wsweep.log +176 -0
- package/docs/investigations/hlg-runs/runI-asweep.log +176 -0
- package/docs/investigations/hlg-runs/runJ-knobmap.log +49 -0
- package/docs/investigations/hlg-runs/runK-frontier.log +19 -0
- package/docs/investigations/hlg-runs/runL-widemap.log +65 -0
- package/docs/investigations/hlg-runs/runM-frontier-emb.log +15 -0
- package/docs/investigations/hlg-runs/runN-verify.log +116 -0
- package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +15 -0
- package/docs/investigations/hlg-runs/runP-grid-AxSm.log +15 -0
- package/docs/investigations/hlg-runs/runQ-grid-tgW.log +15 -0
- package/docs/investigations/hlg-runs/runR-blind-transcript.log +79 -0
- package/docs/investigations/hlg-runs/runS-cross-coherence.log +33 -0
- package/docs/investigations/hlg-runs/runT-cross-cpm5.log +33 -0
- package/docs/investigations/hlg-runs/runU-cross-12b.log +33 -0
- package/docs/investigations/hlg-runs/runV-lw-e4b.log +22 -0
- package/docs/investigations/hlg-runs/runW-lw-12b.log +22 -0
- package/docs/investigations/hlg-runs/runX-lw-cpm5.log +22 -0
- package/docs/investigations/hlg-runs/runY-cliff-e4b.log +26 -0
- package/docs/investigations/hlg-runs/runZ-cliff-12b.log +26 -0
- package/docs/investigations/hlg-sampling-investigation.md +970 -0
- package/docs/investigations/lab-build-journal.md +157 -0
- package/docs/investigations/pi-builtin-investigation.md +308 -0
- package/docs/investigations/starter-model-port-handoff.md +323 -0
- package/docs/planning/IDEAS.md +26 -0
- package/docs/planning/PRODUCT_ROADMAP.md +426 -0
- package/docs/planning/ResearchTopics.md +119 -0
- package/docs/planning/chunk-task-roadmap.md +77 -0
- package/docs/planning/journal.md +155 -0
- package/docs/reference/distribution.md +121 -0
- package/docs/reference/embedding.md +168 -0
- package/docs/reference/library-api.md +153 -0
- package/docs/reference/server-api.md +224 -0
- package/docs/reference/server-config.md +243 -0
- package/docs/segmented-backward-handoff.md +148 -0
- package/package.json +68 -0
- package/src/anthropic.ts +491 -0
- package/src/chat-template.ts +186 -0
- package/src/cli.ts +1075 -0
- package/src/config.ts +229 -0
- package/src/curve-sampler.ts +122 -0
- package/src/dataset/generators.ts +1087 -0
- package/src/dataset/index.ts +12 -0
- package/src/dataset/job.ts +81 -0
- package/src/dataset/llm.ts +71 -0
- package/src/dataset/registry.ts +528 -0
- package/src/download.ts +283 -0
- package/src/eval/README.md +86 -0
- package/src/eval/kl-prompts.ts +29 -0
- package/src/eval/kl.ts +294 -0
- package/src/eval/quality-db.ts +92 -0
- package/src/eval/runner.ts +102 -0
- package/src/eval/score.ts +49 -0
- package/src/eval/tasks/bfcl.ts +500 -0
- package/src/eval/tasks/gsm8k.ts +85 -0
- package/src/eval/tasks/hashhop.ts +109 -0
- package/src/eval/tasks/humaneval.ts +252 -0
- package/src/eval/tasks/ifeval.ts +354 -0
- package/src/eval/tasks/mmlu.ts +145 -0
- package/src/evaldb.ts +199 -0
- package/src/expert-offload-build.ts +77 -0
- package/src/expert-offload.ts +61 -0
- package/src/expert-trace.ts +67 -0
- package/src/fit.ts +254 -0
- package/src/generate.ts +451 -0
- package/src/harness-pi.ts +177 -0
- package/src/hf-push.ts +628 -0
- package/src/index.ts +22 -0
- package/src/jobs/db.ts +139 -0
- package/src/jobs/index.ts +29 -0
- package/src/jobs/job-entry.ts +106 -0
- package/src/jobs/runner.ts +304 -0
- package/src/jobs/sse.ts +114 -0
- package/src/jobs/types.ts +58 -0
- package/src/kv-store.ts +185 -0
- package/src/lora.ts +314 -0
- package/src/md-modules.d.ts +7 -0
- package/src/mlx/array.ts +237 -0
- package/src/mlx/autograd.ts +267 -0
- package/src/mlx/checkpoint.ts +116 -0
- package/src/mlx/compile.ts +158 -0
- package/src/mlx/custom-vjp.ts +140 -0
- package/src/mlx/ffi.ts +433 -0
- package/src/mlx/metal-kernel.ts +130 -0
- package/src/mlx/ops.ts +707 -0
- package/src/mmap.ts +90 -0
- package/src/model/batched-mask.ts +204 -0
- package/src/model/batched-rotating.ts +300 -0
- package/src/model/compiled-decode.ts +681 -0
- package/src/model/factory.ts +27 -0
- package/src/model/fingerprint.ts +33 -0
- package/src/model/flash-attention.ts +674 -0
- package/src/model/fused-decode-kernel.ts +305 -0
- package/src/model/fused-geglu-kernel.ts +87 -0
- package/src/model/gemma4-base.ts +1616 -0
- package/src/model/gemma4.ts +1012 -0
- package/src/model/generated/gemma4-12b.ts +526 -0
- package/src/model/generated/gemma4-26b.ts +500 -0
- package/src/model/generated/gemma4-e4b.ts +757 -0
- package/src/model/generated/index.ts +18 -0
- package/src/model/minicpm5.ts +278 -0
- package/src/model/qwen3-delta.ts +224 -0
- package/src/model/qwen3_5.ts +429 -0
- package/src/model/support.ts +46 -0
- package/src/native-pack.ts +152 -0
- package/src/pi-provider.ts +95 -0
- package/src/pi-terminal.ts +264 -0
- package/src/pi-web.ts +924 -0
- package/src/preflight.ts +123 -0
- package/src/prompt-cache.ts +113 -0
- package/src/quantize/allocator.ts +627 -0
- package/src/quantize/calibration.ts +180 -0
- package/src/quantize/config-writer.ts +132 -0
- package/src/quantize/index.ts +57 -0
- package/src/quantize/job.ts +136 -0
- package/src/quantize/quantizer.ts +462 -0
- package/src/quantize/safetensors-writer.ts +171 -0
- package/src/quantize/sensitivity.ts +234 -0
- package/src/registry.ts +336 -0
- package/src/responses.ts +774 -0
- package/src/safetensors.ts +158 -0
- package/src/sampler.ts +517 -0
- package/src/serve/batch-scheduler.ts +362 -0
- package/src/serve/generation-gateway.ts +160 -0
- package/src/server.ts +1891 -0
- package/src/spec/drafter.ts +261 -0
- package/src/spec/generate.ts +221 -0
- package/src/status-page.html +497 -0
- package/src/tokenizer.ts +38 -0
- package/src/tool-call.ts +242 -0
- package/src/train/dataset.ts +461 -0
- package/src/train/export.ts +32 -0
- package/src/train/forward.ts +229 -0
- package/src/train/index.ts +43 -0
- package/src/train/job.ts +148 -0
- package/src/train/lora-params.ts +194 -0
- package/src/train/loss.ts +342 -0
- package/src/train/merge.ts +195 -0
- package/src/train/optimizer.ts +176 -0
- package/src/train/rank.ts +101 -0
- package/src/train/segmented.ts +520 -0
- package/src/train/trainer.ts +600 -0
- package/src/tui.ts +161 -0
- package/src/vision/embedder.ts +168 -0
- package/src/vision/preprocess.ts +247 -0
- package/src/vision/prompt.ts +158 -0
- package/src/vision/siglip.ts +599 -0
- package/src/web/app.html +2471 -0
- package/src/web/skills/web-research/SKILL.md +44 -0
- package/src/web/skills.ts +59 -0
- package/src/web-tools.ts +426 -0
- package/src/weights.ts +91 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// mlx-bun pi-provider — the in-memory pi provider/registry/auth wiring that
|
|
2
|
+
// points a pi AgentSession at the local mlx-bun server's loopback /v1.
|
|
3
|
+
//
|
|
4
|
+
// Shared by BOTH embed paths so the wiring can't drift:
|
|
5
|
+
// - src/pi-web.ts (headless web-chat session over a WebSocket)
|
|
6
|
+
// - src/pi-terminal.ts (pi's own interactive TUI, in-process)
|
|
7
|
+
//
|
|
8
|
+
// The provider advertises a single, stable model id ("local"); the server
|
|
9
|
+
// runs exactly one model at a time and which one varies run-to-run, so a
|
|
10
|
+
// fixed id resolves to "whatever is loaded" and never goes stale. The real
|
|
11
|
+
// repo id rides in the model `name` and is still reported by /v1/models.
|
|
12
|
+
// This mirrors src/harness-pi.ts (the external-provider path).
|
|
13
|
+
|
|
14
|
+
import { AuthStorage, ModelRegistry } from "@earendil-works/pi-coding-agent";
|
|
15
|
+
|
|
16
|
+
/** A resolved pi model handle. Not re-exported from the package index, so we
|
|
17
|
+
* derive it from the registry's `find()` return type. */
|
|
18
|
+
export type PiModel = NonNullable<ReturnType<ModelRegistry["find"]>>;
|
|
19
|
+
|
|
20
|
+
// Provider/model constants — kept aligned with src/harness-pi.ts so every
|
|
21
|
+
// path (web embed, terminal embed, external pi) registers the same provider.
|
|
22
|
+
export const PI_PROVIDER_ID = "mlx-bun";
|
|
23
|
+
export const PI_LOCAL_MODEL_ID = "local";
|
|
24
|
+
export const PI_API_KEY = "sk-mlx-bun-local";
|
|
25
|
+
export const PI_API = "openai-completions" as const;
|
|
26
|
+
|
|
27
|
+
export const DEFAULT_CONTEXT_WINDOW = 32_768;
|
|
28
|
+
export const DEFAULT_MAX_TOKENS = 8_192;
|
|
29
|
+
|
|
30
|
+
export interface PiProviderOptions {
|
|
31
|
+
/** Advertised context window. Default: DEFAULT_CONTEXT_WINDOW. */
|
|
32
|
+
contextWindow?: number;
|
|
33
|
+
/** Advertised max output tokens. Default: DEFAULT_MAX_TOKENS. */
|
|
34
|
+
maxTokens?: number;
|
|
35
|
+
/** Human-readable model label (e.g. the real repo id). Default: "mlx-bun (local)". */
|
|
36
|
+
name?: string;
|
|
37
|
+
/** The loaded model has a switchable reasoning channel (server's
|
|
38
|
+
* `ctx.template.supportsThinking` — true for any model whose chat template
|
|
39
|
+
* gates on enable_thinking: Qwen3.5, MiniCPM5, …). When true Pi engages
|
|
40
|
+
* reasoning and sends the on/off switch the server maps to enable_thinking.
|
|
41
|
+
* Default false. */
|
|
42
|
+
reasoning?: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface PiProviderWiring {
|
|
46
|
+
authStorage: AuthStorage;
|
|
47
|
+
modelRegistry: ModelRegistry;
|
|
48
|
+
model: PiModel;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Build the in-memory auth + registry and resolve the local model for a pi
|
|
53
|
+
* session pointed at `baseUrl` (e.g. "http://127.0.0.1:8090/v1"). The runtime
|
|
54
|
+
* key satisfies pi's auth check for our zero-cost local provider; no disk
|
|
55
|
+
* (no models.json, no ~/.pi cross-talk).
|
|
56
|
+
*/
|
|
57
|
+
export function buildPiProvider(baseUrl: string, opts: PiProviderOptions = {}): PiProviderWiring {
|
|
58
|
+
const authStorage = AuthStorage.inMemory();
|
|
59
|
+
authStorage.setRuntimeApiKey(PI_PROVIDER_ID, PI_API_KEY);
|
|
60
|
+
|
|
61
|
+
const modelRegistry = ModelRegistry.inMemory(authStorage);
|
|
62
|
+
modelRegistry.registerProvider(PI_PROVIDER_ID, {
|
|
63
|
+
baseUrl,
|
|
64
|
+
apiKey: PI_API_KEY,
|
|
65
|
+
api: PI_API,
|
|
66
|
+
models: [
|
|
67
|
+
{
|
|
68
|
+
id: PI_LOCAL_MODEL_ID,
|
|
69
|
+
name: opts.name ?? "mlx-bun (local)",
|
|
70
|
+
api: PI_API,
|
|
71
|
+
reasoning: opts.reasoning ?? false,
|
|
72
|
+
// Our local thinking models (Qwen3.5/MiniCPM5) are BINARY: the chat
|
|
73
|
+
// template's enable_thinking is a boolean. "qwen-chat-template" makes
|
|
74
|
+
// Pi send chat_template_kwargs.enable_thinking; pi-ai computes that
|
|
75
|
+
// boolean from whether the selected level is off or not, so no level
|
|
76
|
+
// map is needed here (null in thinkingLevelMap means "unsupported").
|
|
77
|
+
...(opts.reasoning
|
|
78
|
+
? { compat: { thinkingFormat: "qwen-chat-template" as const } }
|
|
79
|
+
: {}),
|
|
80
|
+
// Declare image capability so pi will carry image content to /v1.
|
|
81
|
+
// Whether the *loaded* model can actually see images is gated at the
|
|
82
|
+
// server (non-vision models 400) and surfaced to the web UI via the
|
|
83
|
+
// `ready` frame's `vision` flag.
|
|
84
|
+
input: ["text", "image"],
|
|
85
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
86
|
+
contextWindow: opts.contextWindow ?? DEFAULT_CONTEXT_WINDOW,
|
|
87
|
+
maxTokens: opts.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const model = modelRegistry.find(PI_PROVIDER_ID, PI_LOCAL_MODEL_ID);
|
|
93
|
+
if (!model) throw new Error("failed to register mlx-bun/local model");
|
|
94
|
+
return { authStorage, modelRegistry, model };
|
|
95
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// mlx-bun pi-terminal — drive pi's OWN interactive TUI in-process against the
|
|
2
|
+
// local mlx-bun server (Phase 16 P3/P4). No subprocess, no requirement that
|
|
3
|
+
// the user install pi: pi is a bundled dependency, so we build an
|
|
4
|
+
// AgentSessionRuntime with the SDK and hand it to pi's exported InteractiveMode.
|
|
5
|
+
//
|
|
6
|
+
// This is the terminal twin of src/pi-web.ts (the headless web embed). They
|
|
7
|
+
// share the provider wiring (src/pi-provider.ts) and the curated skills
|
|
8
|
+
// (src/web/skills.ts); the differences are:
|
|
9
|
+
// - we build an AgentSessionRuntime (InteractiveMode needs the runtime, not
|
|
10
|
+
// the bare session createAgentSession returns), via the same
|
|
11
|
+
// createAgentSessionServices + createAgentSessionFromServices the pi CLI
|
|
12
|
+
// uses (dist/main.js) — see examples/sdk/13-session-runtime.ts;
|
|
13
|
+
// - tool approval is pi's own built-in TUI prompt, so there's no custom
|
|
14
|
+
// approval gate here (the web path needs one only because the browser
|
|
15
|
+
// drives approvals over a WebSocket);
|
|
16
|
+
// - the system prompt is a custom mlx-bun CODING-agent persona (the web
|
|
17
|
+
// path is a general chat assistant);
|
|
18
|
+
// - sessions persist (~/.mlx-bun/pi) so /resume and history work.
|
|
19
|
+
//
|
|
20
|
+
// Modes mirror pi's CLI: interactive (InteractiveMode), one-shot print
|
|
21
|
+
// (`-p` / `--mode json` → runPrintMode), and JSONL RPC (`--mode rpc` →
|
|
22
|
+
// runRpcMode). All three are SDK exports, so the embedded CLI keeps pi's
|
|
23
|
+
// headless surface.
|
|
24
|
+
|
|
25
|
+
import { homedir } from "node:os";
|
|
26
|
+
import { join } from "node:path";
|
|
27
|
+
import {
|
|
28
|
+
InteractiveMode,
|
|
29
|
+
SessionManager,
|
|
30
|
+
createAgentSessionFromServices,
|
|
31
|
+
createAgentSessionRuntime,
|
|
32
|
+
createAgentSessionServices,
|
|
33
|
+
initTheme,
|
|
34
|
+
runPrintMode,
|
|
35
|
+
runRpcMode,
|
|
36
|
+
type CreateAgentSessionRuntimeFactory,
|
|
37
|
+
} from "@earendil-works/pi-coding-agent";
|
|
38
|
+
import { createWebTools, WEB_TOOL_NAMES } from "./web-tools";
|
|
39
|
+
import { materializeBundledSkills } from "./web/skills";
|
|
40
|
+
import { buildPiProvider, DEFAULT_CONTEXT_WINDOW } from "./pi-provider";
|
|
41
|
+
|
|
42
|
+
/** How the embedded agent runs. Mirrors pi's CLI appMode. */
|
|
43
|
+
export type PiTerminalMode = "interactive" | "print" | "rpc";
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Full toolset the terminal agent is offered: pi's built-in coding tools plus
|
|
47
|
+
* our outward-facing web tools. pi treats this list as an allowlist, so a
|
|
48
|
+
* custom tool's name MUST appear here or it's filtered out before the model
|
|
49
|
+
* sees it. Mutating tools (bash/edit/write) surface pi's own TUI approval
|
|
50
|
+
* prompt at call time — we don't add a gate.
|
|
51
|
+
*/
|
|
52
|
+
const ALL_TOOLS = ["read", "bash", "edit", "write", "grep", "find", "ls", ...WEB_TOOL_NAMES];
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* System prompt for the embedded terminal coding agent.
|
|
56
|
+
*
|
|
57
|
+
* This fully REPLACES pi's default coding-agent prompt (it flows to
|
|
58
|
+
* buildSystemPrompt's `customPrompt` via the resource loader's `systemPrompt`).
|
|
59
|
+
* We replace rather than append so the agent's identity is mlx-bun's, not
|
|
60
|
+
* "operating inside pi, a coding agent harness", and so pi's block of internal
|
|
61
|
+
* documentation paths is dropped. pi still auto-appends the current date and
|
|
62
|
+
* working directory, so we don't repeat them here.
|
|
63
|
+
*
|
|
64
|
+
* Unlike the web chat (a general assistant), this is a true terminal CODING
|
|
65
|
+
* agent: it lives in the user's project directory with real read/run/edit
|
|
66
|
+
* tools. The capability list stays honest about which tools ask for approval
|
|
67
|
+
* so the model never promises an action the user must still confirm.
|
|
68
|
+
*/
|
|
69
|
+
export function buildTerminalSystemPrompt(modelLabel?: string): string {
|
|
70
|
+
const model = modelLabel ? `the local model \`${modelLabel}\`` : "a local model";
|
|
71
|
+
return `You are mlx-bun's terminal coding agent — a capable, hands-on pair programmer working alongside the user in their terminal. You run on ${model} entirely on the user's own Apple-silicon Mac via mlx-bun, so the whole session stays local and private; nothing leaves the machine except the explicit web tools below.
|
|
72
|
+
|
|
73
|
+
You operate inside the user's current project directory and have a real toolset — use it. Prefer doing the work over describing it: open the files, search the tree, run the command, make the edit. Investigate before you answer, and follow through to a working result.
|
|
74
|
+
|
|
75
|
+
Tools used freely (no confirmation needed):
|
|
76
|
+
- read — open and read any file
|
|
77
|
+
- ls, find, grep — list directories and search the tree by name or content
|
|
78
|
+
- web_search — search the web for current, real-world information (docs, APIs, errors, anything that changes or that you don't already know)
|
|
79
|
+
- web_fetch — fetch a URL and read the page or data behind it (a natural follow-up to web_search, or when the user gives you a link)
|
|
80
|
+
- weather — current conditions and a short forecast for any place
|
|
81
|
+
|
|
82
|
+
Tools that ask the user for approval first (they stay in control — pi shows the prompt, you don't have to ask in prose):
|
|
83
|
+
- bash — run shell commands (build, test, git, scripts)
|
|
84
|
+
- edit, write — modify existing files or create new ones
|
|
85
|
+
|
|
86
|
+
When you need to change code or run something, just propose the concrete edit or command and let the approval prompt handle consent — don't narrate "I would run…" or ask permission in text. When you hit something you don't know — especially current or version-specific facts — look it up with web_search and web_fetch instead of guessing. If a request is genuinely ambiguous, ask one short clarifying question; otherwise make a sensible choice and proceed.
|
|
87
|
+
|
|
88
|
+
Be honest about what you did and what you found, including mistakes, dead ends, and anything you couldn't do. Keep responses tight and skimmable: format with Markdown, show file paths and commands plainly, and cite links when you used the web.`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface RunEmbeddedPiOptions {
|
|
92
|
+
/** mlx-bun server base URL, e.g. "http://localhost:8090/v1". */
|
|
93
|
+
baseUrl: string;
|
|
94
|
+
/** Real served model id, used to label the model in the prompt + registry. */
|
|
95
|
+
modelLabel?: string;
|
|
96
|
+
/** Context window advertised to pi. Default: DEFAULT_CONTEXT_WINDOW. */
|
|
97
|
+
contextWindow?: number;
|
|
98
|
+
/** Whether the served model has a switchable thinking channel. */
|
|
99
|
+
reasoning?: boolean;
|
|
100
|
+
/** Run mode. Default: "interactive". */
|
|
101
|
+
mode?: PiTerminalMode;
|
|
102
|
+
/** Print mode output format ("text" final-only, "json" event stream). */
|
|
103
|
+
printFormat?: "text" | "json";
|
|
104
|
+
/** First message to send (print: the prompt; interactive: pre-filled turn). */
|
|
105
|
+
initialMessage?: string;
|
|
106
|
+
/** Additional messages to send after initialMessage. */
|
|
107
|
+
messages?: string[];
|
|
108
|
+
/** Force pi's verbose startup banner (interactive only). */
|
|
109
|
+
verbose?: boolean;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Build an AgentSessionRuntime against the local server and run pi in the
|
|
114
|
+
* requested mode. Returns the process exit code. Disposes the runtime on the
|
|
115
|
+
* way out. Runs in the SAME process as the server when the CLI started one —
|
|
116
|
+
* pi's TUI event loop and the generation queue share the JS thread (mlx
|
|
117
|
+
* compute is native); pi's rendering is differential and cheap.
|
|
118
|
+
*/
|
|
119
|
+
export async function runEmbeddedPi(opts: RunEmbeddedPiOptions): Promise<number> {
|
|
120
|
+
const mode = opts.mode ?? "interactive";
|
|
121
|
+
const cwd = process.cwd();
|
|
122
|
+
// Own session/settings dir, isolated from any standalone pi install.
|
|
123
|
+
const agentDir = join(homedir(), ".mlx-bun", "pi");
|
|
124
|
+
|
|
125
|
+
const { authStorage, modelRegistry, model } = buildPiProvider(opts.baseUrl, {
|
|
126
|
+
contextWindow: opts.contextWindow ?? DEFAULT_CONTEXT_WINDOW,
|
|
127
|
+
name: opts.modelLabel ? `${opts.modelLabel} (mlx-bun local)` : undefined,
|
|
128
|
+
reasoning: opts.reasoning ?? false,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Curated skills (web-research, …) written to ~/.mlx-bun/skills and loaded
|
|
132
|
+
// on top of an otherwise-isolated session. See src/web/skills.ts.
|
|
133
|
+
const skillsRoot = materializeBundledSkills();
|
|
134
|
+
const systemPrompt = buildTerminalSystemPrompt(opts.modelLabel);
|
|
135
|
+
|
|
136
|
+
// The runtime factory: same shape as pi's own CLI (dist/main.js) and the
|
|
137
|
+
// shipped examples/sdk/13-session-runtime.ts. The same factory is reused by
|
|
138
|
+
// pi for /new, /resume, /fork — so the provider/prompt/tools are stable
|
|
139
|
+
// across session switches within the TUI.
|
|
140
|
+
const createRuntime: CreateAgentSessionRuntimeFactory = async ({ cwd: rcwd, sessionManager, sessionStartEvent }) => {
|
|
141
|
+
const services = await createAgentSessionServices({
|
|
142
|
+
cwd: rcwd,
|
|
143
|
+
agentDir,
|
|
144
|
+
authStorage,
|
|
145
|
+
modelRegistry,
|
|
146
|
+
resourceLoaderOptions: {
|
|
147
|
+
// Isolated from the user's own ~/.pi: don't inherit their extensions,
|
|
148
|
+
// prompt templates, themes, or auto-discovered skills.
|
|
149
|
+
noExtensions: true,
|
|
150
|
+
noSkills: true,
|
|
151
|
+
noPromptTemplates: true,
|
|
152
|
+
noThemes: true,
|
|
153
|
+
// A coding agent in a project dir SHOULD read the project's own
|
|
154
|
+
// AGENTS.md / CLAUDE.md context files (unlike the web chat).
|
|
155
|
+
noContextFiles: false,
|
|
156
|
+
// Our curated skills on top (noSkills above only disables discovery).
|
|
157
|
+
additionalSkillPaths: [skillsRoot],
|
|
158
|
+
// Replace pi's default coding-agent prompt with our mlx-bun persona.
|
|
159
|
+
systemPrompt,
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
return {
|
|
163
|
+
...(await createAgentSessionFromServices({
|
|
164
|
+
services,
|
|
165
|
+
sessionManager,
|
|
166
|
+
sessionStartEvent,
|
|
167
|
+
model,
|
|
168
|
+
tools: ALL_TOOLS,
|
|
169
|
+
customTools: createWebTools(),
|
|
170
|
+
})),
|
|
171
|
+
services,
|
|
172
|
+
diagnostics: services.diagnostics,
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const sessionManager = SessionManager.create(cwd);
|
|
177
|
+
const runtime = await createAgentSessionRuntime(createRuntime, { cwd, agentDir, sessionManager });
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
if (mode === "rpc") {
|
|
181
|
+
// runRpcMode never returns (Promise<never>); it owns stdin/stdout.
|
|
182
|
+
await runRpcMode(runtime);
|
|
183
|
+
return 0;
|
|
184
|
+
}
|
|
185
|
+
if (mode === "print") {
|
|
186
|
+
return await runPrintMode(runtime, {
|
|
187
|
+
mode: opts.printFormat ?? "text",
|
|
188
|
+
messages: opts.messages,
|
|
189
|
+
initialMessage: opts.initialMessage,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
// interactive — initialize the theme (pi's CLI does this before the TUI)
|
|
193
|
+
// then run pi's own full interactive mode.
|
|
194
|
+
initTheme(runtime.services.settingsManager.getTheme(), true);
|
|
195
|
+
await new InteractiveMode(runtime, {
|
|
196
|
+
initialMessage: opts.initialMessage,
|
|
197
|
+
initialMessages: opts.messages,
|
|
198
|
+
verbose: opts.verbose,
|
|
199
|
+
}).run();
|
|
200
|
+
return 0;
|
|
201
|
+
} finally {
|
|
202
|
+
try {
|
|
203
|
+
await runtime.dispose();
|
|
204
|
+
} catch {
|
|
205
|
+
// Best-effort teardown; never mask the real exit path.
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Result of parsing the pi passthrough argv into an embedded run config. */
|
|
211
|
+
export interface ParsedPiArgs {
|
|
212
|
+
mode: PiTerminalMode;
|
|
213
|
+
printFormat: "text" | "json";
|
|
214
|
+
/** Joined free-text message (the trailing words / `-p <text>`). */
|
|
215
|
+
message?: string;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Parse the argv left over after mlx-bun's own flags are stripped into a
|
|
220
|
+
* mode + message for runEmbeddedPi. Pure (takes `isStdinPiped`) so it's
|
|
221
|
+
* unit-testable. Covers the headline pi modes:
|
|
222
|
+
* - `-p` / `--print` → print (text), prompt from -p value / words / stdin
|
|
223
|
+
* - `--mode json` / `-p --json` → print (json)
|
|
224
|
+
* - `--mode rpc` → rpc
|
|
225
|
+
* - piped stdin (non-TTY) → print (text), like pi's own CLI
|
|
226
|
+
* - anything else → interactive (trailing words pre-fill turn 1)
|
|
227
|
+
* The built-in agent is deliberately scoped to these modes. The full pi
|
|
228
|
+
* flag surface (--continue, --resume, @file expansion, extensions, themes)
|
|
229
|
+
* belongs to the user's OWN pi — point it at this server with
|
|
230
|
+
* `mlx-bun harness pi`.
|
|
231
|
+
*/
|
|
232
|
+
export function parsePiArgs(passthrough: string[], isStdinPiped: boolean): ParsedPiArgs {
|
|
233
|
+
let print = false;
|
|
234
|
+
let rpc = false;
|
|
235
|
+
let json = false;
|
|
236
|
+
const words: string[] = [];
|
|
237
|
+
for (let i = 0; i < passthrough.length; i++) {
|
|
238
|
+
const a = passthrough[i]!;
|
|
239
|
+
if (a === "-p" || a === "--print") {
|
|
240
|
+
print = true;
|
|
241
|
+
} else if (a === "--json") {
|
|
242
|
+
json = true;
|
|
243
|
+
} else if (a === "--mode") {
|
|
244
|
+
const m = passthrough[++i];
|
|
245
|
+
if (m === "rpc") rpc = true;
|
|
246
|
+
else if (m === "json") { print = true; json = true; }
|
|
247
|
+
else if (m === "text") print = true;
|
|
248
|
+
} else if (a.startsWith("-")) {
|
|
249
|
+
// Unknown flag for the built-in agent: ignore it (the full pi flag
|
|
250
|
+
// surface lives in the user's own pi via `mlx-bun harness pi`). Don't
|
|
251
|
+
// treat it as message text.
|
|
252
|
+
continue;
|
|
253
|
+
} else {
|
|
254
|
+
words.push(a);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const message = words.length > 0 ? words.join(" ") : undefined;
|
|
258
|
+
const printFormat = json ? "json" : "text";
|
|
259
|
+
if (rpc) return { mode: "rpc", printFormat: "text", message };
|
|
260
|
+
// `-p`/`--mode` request print; piped stdin makes a bare invocation one-shot
|
|
261
|
+
// too, matching pi's own CLI (it reads stdin → switches to print mode).
|
|
262
|
+
if (print || isStdinPiped) return { mode: "print", printFormat, message };
|
|
263
|
+
return { mode: "interactive", printFormat, message };
|
|
264
|
+
}
|