@mlx-node/agent 0.0.7

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 (70) hide show
  1. package/dist/catalog.d.ts +26 -0
  2. package/dist/catalog.d.ts.map +1 -0
  3. package/dist/catalog.js +44 -0
  4. package/dist/extensions/approval-detail.d.ts +9 -0
  5. package/dist/extensions/approval-detail.d.ts.map +1 -0
  6. package/dist/extensions/approval-detail.js +53 -0
  7. package/dist/extensions/permission-gate.d.ts +30 -0
  8. package/dist/extensions/permission-gate.d.ts.map +1 -0
  9. package/dist/extensions/permission-gate.js +309 -0
  10. package/dist/extensions/subagent.d.ts +82 -0
  11. package/dist/extensions/subagent.d.ts.map +1 -0
  12. package/dist/extensions/subagent.js +539 -0
  13. package/dist/extensions/terminal-title.d.ts +10 -0
  14. package/dist/extensions/terminal-title.d.ts.map +1 -0
  15. package/dist/extensions/terminal-title.js +45 -0
  16. package/dist/extensions/trace-notice.d.ts +11 -0
  17. package/dist/extensions/trace-notice.d.ts.map +1 -0
  18. package/dist/extensions/trace-notice.js +34 -0
  19. package/dist/index.d.ts +14 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +12 -0
  22. package/dist/provider/chat-config.d.ts +34 -0
  23. package/dist/provider/chat-config.d.ts.map +1 -0
  24. package/dist/provider/chat-config.js +103 -0
  25. package/dist/provider/convert-messages.d.ts +59 -0
  26. package/dist/provider/convert-messages.d.ts.map +1 -0
  27. package/dist/provider/convert-messages.js +248 -0
  28. package/dist/provider/error-coercion.d.ts +19 -0
  29. package/dist/provider/error-coercion.d.ts.map +1 -0
  30. package/dist/provider/error-coercion.js +38 -0
  31. package/dist/provider/events.d.ts +67 -0
  32. package/dist/provider/events.d.ts.map +1 -0
  33. package/dist/provider/events.js +307 -0
  34. package/dist/provider/index.d.ts +28 -0
  35. package/dist/provider/index.d.ts.map +1 -0
  36. package/dist/provider/index.js +64 -0
  37. package/dist/provider/inference-trace.d.ts +58 -0
  38. package/dist/provider/inference-trace.d.ts.map +1 -0
  39. package/dist/provider/inference-trace.js +205 -0
  40. package/dist/provider/model-host.d.ts +94 -0
  41. package/dist/provider/model-host.d.ts.map +1 -0
  42. package/dist/provider/model-host.js +134 -0
  43. package/dist/provider/model-registry-filter.d.ts +36 -0
  44. package/dist/provider/model-registry-filter.d.ts.map +1 -0
  45. package/dist/provider/model-registry-filter.js +82 -0
  46. package/dist/provider/models.d.ts +35 -0
  47. package/dist/provider/models.d.ts.map +1 -0
  48. package/dist/provider/models.js +132 -0
  49. package/dist/provider/performance-status.d.ts +28 -0
  50. package/dist/provider/performance-status.d.ts.map +1 -0
  51. package/dist/provider/performance-status.js +91 -0
  52. package/dist/provider/reasoning-tag-buffer.d.ts +23 -0
  53. package/dist/provider/reasoning-tag-buffer.d.ts.map +1 -0
  54. package/dist/provider/reasoning-tag-buffer.js +60 -0
  55. package/dist/provider/stream-adapter.d.ts +61 -0
  56. package/dist/provider/stream-adapter.d.ts.map +1 -0
  57. package/dist/provider/stream-adapter.js +358 -0
  58. package/dist/provider/tool-call-buffer.d.ts +30 -0
  59. package/dist/provider/tool-call-buffer.d.ts.map +1 -0
  60. package/dist/provider/tool-call-buffer.js +75 -0
  61. package/dist/provider/warm-reuse.d.ts +73 -0
  62. package/dist/provider/warm-reuse.d.ts.map +1 -0
  63. package/dist/provider/warm-reuse.js +88 -0
  64. package/dist/run-agent.d.ts +62 -0
  65. package/dist/run-agent.d.ts.map +1 -0
  66. package/dist/run-agent.js +86 -0
  67. package/dist/types.d.ts +8 -0
  68. package/dist/types.d.ts.map +1 -0
  69. package/dist/types.js +1 -0
  70. package/package.json +42 -0
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Agent-private `ChatSession` warm-reuse helper.
3
+ *
4
+ * Port of `packages/server/src/chat-session-warm-reuse.ts` — that module
5
+ * is deliberately kept off the server's export map, so the agent package
6
+ * carries its own copy with identical runtime behavior. Keep the two in
7
+ * sync.
8
+ *
9
+ * Why this helper exists at all: `ChatSession.reset()` is the safe
10
+ * public wipe — it always calls `model.resetCaches()` because the
11
+ * underlying `SessionCapableModel` may be shared across session
12
+ * lifetimes. The agent provider bridge, however, owns exactly one
13
+ * session per model process and replays pi's full message history on
14
+ * every LLM call, so the native KV cache always belongs to the chain
15
+ * being replayed. A JS-state-only reset that preserves the native
16
+ * cache is correct there: the next `primeHistory()` +
17
+ * `startFromHistoryStream()` lets the native prefix verifier recover
18
+ * the reused prefix and skip the corresponding re-prefill.
19
+ *
20
+ * Fields accessed: `inFlight`, `history`, `lastImagesKey`, `lastAudioKey`, `turnCount`,
21
+ * `unresolvedOkToolCallCount`, `needsFullReplay`. These are TypeScript `private` fields on
22
+ * `ChatSession` (compile-time only) — at runtime they are ordinary
23
+ * properties. The cast through {@link ChatSessionWarmReuseInternals}
24
+ * gives this helper a typed view of the instance without relaxing the
25
+ * class's `private` declarations. The field names MUST stay in sync
26
+ * with `packages/lm/src/chat-session.ts`; a mismatch would silently
27
+ * skip the intended state wipe — the drift test in
28
+ * `packages/agent/__test__/warm-reuse.test.ts` checks every name in
29
+ * {@link WARM_REUSE_TOUCHED_FIELDS} against a real `ChatSession`
30
+ * instance.
31
+ */
32
+ import type { ChatSession, SessionCapableModel } from '@mlx-node/lm';
33
+ /**
34
+ * Private structural view of the `ChatSession` JS-side state that the
35
+ * warm-reuse helper needs to wipe. Mirrors the internal state
36
+ * documented on `ChatSession` itself — field names are load-bearing:
37
+ * they must byte-match the concrete class's private fields or the
38
+ * cast-based mutation below silently no-ops.
39
+ */
40
+ interface ChatSessionWarmReuseInternals {
41
+ inFlight: boolean;
42
+ history: unknown[];
43
+ lastImagesKey: string | null;
44
+ lastAudioKey: string | null;
45
+ turnCount: number;
46
+ unresolvedOkToolCallCount: number | null;
47
+ needsFullReplay: boolean;
48
+ }
49
+ /**
50
+ * Runtime list of the `ChatSession` private field names this module
51
+ * reads or writes — exported solely so the drift test can assert each
52
+ * one still exists on a real `ChatSession` instance.
53
+ */
54
+ export declare const WARM_REUSE_TOUCHED_FIELDS: ReadonlyArray<keyof ChatSessionWarmReuseInternals>;
55
+ /**
56
+ * JS-state-only reset that DELIBERATELY preserves the underlying
57
+ * model's native KV cache and `cached_token_history`.
58
+ *
59
+ * @internal agent-private — used only by the provider bridge's
60
+ * per-call warm replay (`resetPreservingNativeCacheForWarmReuse` →
61
+ * `primeHistory` → `startFromHistoryStream`). Never export from this
62
+ * package's `index.ts`.
63
+ *
64
+ * Wipes ONLY the JS-side session state (history array, image key, turn
65
+ * counter, tool-call fan-out guard). With this function, the JS session
66
+ * is fresh enough for `ChatSession.primeHistory()` (which requires
67
+ * `turnCount === 0`) while the native prefix verifier can still recover
68
+ * the reused prefix on the next `chatSessionStart` and skip the
69
+ * corresponding re-prefill.
70
+ */
71
+ export declare function resetPreservingNativeCacheForWarmReuse<M extends SessionCapableModel>(session: ChatSession<M>): Promise<void>;
72
+ export {};
73
+ //# sourceMappingURL=warm-reuse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warm-reuse.d.ts","sourceRoot":"","sources":["../../src/provider/warm-reuse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAErE;;;;;;GAMG;AACH,UAAU,6BAA6B;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,eAAe,EAAE,OAAO,CAAC;CAC1B;AAkBD;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,EAAgD,aAAa,CACjG,MAAM,6BAA6B,CACpC,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,sCAAsC,CAAC,CAAC,SAAS,mBAAmB,EACxF,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GACtB,OAAO,CAAC,IAAI,CAAC,CAqBf"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Agent-private `ChatSession` warm-reuse helper.
3
+ *
4
+ * Port of `packages/server/src/chat-session-warm-reuse.ts` — that module
5
+ * is deliberately kept off the server's export map, so the agent package
6
+ * carries its own copy with identical runtime behavior. Keep the two in
7
+ * sync.
8
+ *
9
+ * Why this helper exists at all: `ChatSession.reset()` is the safe
10
+ * public wipe — it always calls `model.resetCaches()` because the
11
+ * underlying `SessionCapableModel` may be shared across session
12
+ * lifetimes. The agent provider bridge, however, owns exactly one
13
+ * session per model process and replays pi's full message history on
14
+ * every LLM call, so the native KV cache always belongs to the chain
15
+ * being replayed. A JS-state-only reset that preserves the native
16
+ * cache is correct there: the next `primeHistory()` +
17
+ * `startFromHistoryStream()` lets the native prefix verifier recover
18
+ * the reused prefix and skip the corresponding re-prefill.
19
+ *
20
+ * Fields accessed: `inFlight`, `history`, `lastImagesKey`, `lastAudioKey`, `turnCount`,
21
+ * `unresolvedOkToolCallCount`, `needsFullReplay`. These are TypeScript `private` fields on
22
+ * `ChatSession` (compile-time only) — at runtime they are ordinary
23
+ * properties. The cast through {@link ChatSessionWarmReuseInternals}
24
+ * gives this helper a typed view of the instance without relaxing the
25
+ * class's `private` declarations. The field names MUST stay in sync
26
+ * with `packages/lm/src/chat-session.ts`; a mismatch would silently
27
+ * skip the intended state wipe — the drift test in
28
+ * `packages/agent/__test__/warm-reuse.test.ts` checks every name in
29
+ * {@link WARM_REUSE_TOUCHED_FIELDS} against a real `ChatSession`
30
+ * instance.
31
+ */
32
+ /**
33
+ * `Record<keyof ..., true>` forces this map to list EXACTLY the fields of
34
+ * {@link ChatSessionWarmReuseInternals}: adding/removing/renaming a field
35
+ * in the interface without updating the map is a compile error, so the
36
+ * runtime list below can never drift from the fields the helper touches.
37
+ */
38
+ const WARM_REUSE_TOUCHED_FIELD_SET = {
39
+ inFlight: true,
40
+ history: true,
41
+ lastImagesKey: true,
42
+ lastAudioKey: true,
43
+ turnCount: true,
44
+ unresolvedOkToolCallCount: true,
45
+ needsFullReplay: true,
46
+ };
47
+ /**
48
+ * Runtime list of the `ChatSession` private field names this module
49
+ * reads or writes — exported solely so the drift test can assert each
50
+ * one still exists on a real `ChatSession` instance.
51
+ */
52
+ export const WARM_REUSE_TOUCHED_FIELDS = Object.keys(WARM_REUSE_TOUCHED_FIELD_SET);
53
+ /**
54
+ * JS-state-only reset that DELIBERATELY preserves the underlying
55
+ * model's native KV cache and `cached_token_history`.
56
+ *
57
+ * @internal agent-private — used only by the provider bridge's
58
+ * per-call warm replay (`resetPreservingNativeCacheForWarmReuse` →
59
+ * `primeHistory` → `startFromHistoryStream`). Never export from this
60
+ * package's `index.ts`.
61
+ *
62
+ * Wipes ONLY the JS-side session state (history array, image key, turn
63
+ * counter, tool-call fan-out guard). With this function, the JS session
64
+ * is fresh enough for `ChatSession.primeHistory()` (which requires
65
+ * `turnCount === 0`) while the native prefix verifier can still recover
66
+ * the reused prefix on the next `chatSessionStart` and skip the
67
+ * corresponding re-prefill.
68
+ */
69
+ export async function resetPreservingNativeCacheForWarmReuse(session) {
70
+ // TypeScript `private` fields are only compile-time checks; at
71
+ // runtime they are ordinary properties. The cast through
72
+ // `ChatSessionWarmReuseInternals` preserves full static typing for
73
+ // this helper's mutations while bypassing the `private` gate — which
74
+ // is correct here because this helper is the designated agent-side
75
+ // friend accessor. The cast is funneled through `unknown` because TS
76
+ // correctly rejects a direct `ChatSession → Internals` cast when the
77
+ // concrete class has other non-internals fields.
78
+ const internals = session;
79
+ if (internals.inFlight) {
80
+ throw new Error('ChatSession: cannot resetPreservingNativeCacheForWarmReuse() while a send() is in flight; await the previous call first');
81
+ }
82
+ internals.history = [];
83
+ internals.lastImagesKey = null;
84
+ internals.lastAudioKey = null;
85
+ internals.turnCount = 0;
86
+ internals.unresolvedOkToolCallCount = null;
87
+ internals.needsFullReplay = false;
88
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * `runAgent` — the boot shell that hands control to pi's `main()` with
3
+ * the mlx provider, permission gate, local subagents, and terminal branding installed.
4
+ *
5
+ * Spike-proven boot contract:
6
+ * - The env vars below must be set BEFORE any runtime import of
7
+ * `@earendil-works/pi-coding-agent` (pi reads its config env at
8
+ * import/call time) — hence the dynamic import and the type-only
9
+ * top-level pi import here.
10
+ * - pi's `main()` RETURNS on the happy path but `process.exit()`s on
11
+ * help/error/package-command paths, so nothing critical may run after
12
+ * `await main()`.
13
+ * - In print/json mode pi takes over stdout (our writes are rerouted to
14
+ * stderr) and reads non-TTY stdin to EOF as prompt input — this
15
+ * wrapper must never consume or hold stdin. Paged-config temp cleanup in
16
+ * `finally` is best-effort for normal returns/rejections, never correctness-
17
+ * critical on pi's hard `process.exit()` paths.
18
+ */
19
+ import type { InlineExtension } from '@earendil-works/pi-coding-agent';
20
+ import { type FilterableModelRegistryConstructor } from './provider/model-registry-filter.js';
21
+ import type { MlxModelInfo } from './provider/models.js';
22
+ /** Shape of pi's `main(argv, { extensionFactories })` — also the test seam. */
23
+ export type RunAgentMain = (args: string[], opts: {
24
+ extensionFactories: InlineExtension[];
25
+ }) => Promise<void>;
26
+ export interface RunAgentPi {
27
+ main: RunAgentMain;
28
+ ModelRegistry: FilterableModelRegistryConstructor;
29
+ }
30
+ /** @internal Narrow lifecycle seam for the agent's paged config overlays. */
31
+ export interface AgentPagedConfigOverrides {
32
+ resolve(modelPath: string, modelType?: string): Promise<string>;
33
+ cleanup(): Promise<void>;
34
+ }
35
+ export interface RunAgentOptions {
36
+ /** Resolved models directory (context for callers/diagnostics — discovery already ran). */
37
+ modelsDir: string;
38
+ /** Discovered models to serve through the in-process `mlx` provider. */
39
+ models: MlxModelInfo[];
40
+ /** Passthrough args handed to pi's `main()` verbatim. */
41
+ argv: string[];
42
+ /** Native inference-log path to surface after Pi takes over the TUI. */
43
+ traceLogFile?: string;
44
+ /** @internal Test seam; when set, the pi dynamic import is skipped entirely. */
45
+ piImpl?: RunAgentPi;
46
+ /** @internal Test seam for paged model-path resolution and cleanup. */
47
+ pagedConfigOverrides?: AgentPagedConfigOverrides;
48
+ }
49
+ /** @internal Exact opt-in parser kept separate so non-`1` values stay disabled. */
50
+ export declare function agentGemmaDraftEnabled(env?: NodeJS.ProcessEnv): boolean;
51
+ /**
52
+ * Seed the pi/mlx environment (never clobbering user-set values) and run
53
+ * pi's `main()` with the mlx inline extensions. May not return: pi
54
+ * `process.exit()`s on help/error paths.
55
+ *
56
+ * This is a dedicated-process entrypoint: pi owns stdin/stdout, signal
57
+ * handlers, and process exit while `main()` runs. Do not run it concurrently
58
+ * with another pi SDK/runtime in the same process. The temporary registry
59
+ * policy is restored when `main()` returns or rejects.
60
+ */
61
+ export declare function runAgent(opts: RunAgentOptions): Promise<void>;
62
+ //# sourceMappingURL=run-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-agent.d.ts","sourceRoot":"","sources":["../src/run-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AASvE,OAAO,EACL,KAAK,kCAAkC,EAExC,MAAM,qCAAqC,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,+EAA+E;AAC/E,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE;IAAE,kBAAkB,EAAE,eAAe,EAAE,CAAA;CAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9G,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,aAAa,EAAE,kCAAkC,CAAC;CACnD;AAED,6EAA6E;AAC7E,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,2FAA2F;IAC3F,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,yDAAyD;IACzD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,uEAAuE;IACvE,oBAAoB,CAAC,EAAE,yBAAyB,CAAC;CAClD;AAED,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAEpF;AAED;;;;;;;;;GASG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAmDnE"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * `runAgent` — the boot shell that hands control to pi's `main()` with
3
+ * the mlx provider, permission gate, local subagents, and terminal branding installed.
4
+ *
5
+ * Spike-proven boot contract:
6
+ * - The env vars below must be set BEFORE any runtime import of
7
+ * `@earendil-works/pi-coding-agent` (pi reads its config env at
8
+ * import/call time) — hence the dynamic import and the type-only
9
+ * top-level pi import here.
10
+ * - pi's `main()` RETURNS on the happy path but `process.exit()`s on
11
+ * help/error/package-command paths, so nothing critical may run after
12
+ * `await main()`.
13
+ * - In print/json mode pi takes over stdout (our writes are rerouted to
14
+ * stderr) and reads non-TTY stdin to EOF as prompt input — this
15
+ * wrapper must never consume or hold stdin. Paged-config temp cleanup in
16
+ * `finally` is best-effort for normal returns/rejections, never correctness-
17
+ * critical on pi's hard `process.exit()` paths.
18
+ */
19
+ import { homedir } from 'node:os';
20
+ import { join } from 'node:path';
21
+ import { PagedConfigOverrideManager } from '@mlx-node/lm';
22
+ import { createPermissionGateExtension } from './extensions/permission-gate.js';
23
+ import { createSubagentExtension } from './extensions/subagent.js';
24
+ import { createTerminalTitleExtension } from './extensions/terminal-title.js';
25
+ import { createTraceNoticeExtension } from './extensions/trace-notice.js';
26
+ import { createMlxProviderExtension } from './provider/index.js';
27
+ import { MlxModelHost } from './provider/model-host.js';
28
+ import { installMlxOnlyModelRegistryFilter, } from './provider/model-registry-filter.js';
29
+ /** @internal Exact opt-in parser kept separate so non-`1` values stay disabled. */
30
+ export function agentGemmaDraftEnabled(env = process.env) {
31
+ return env.MLX_AGENT_ENABLE_GEMMA_DRAFT === '1';
32
+ }
33
+ /**
34
+ * Seed the pi/mlx environment (never clobbering user-set values) and run
35
+ * pi's `main()` with the mlx inline extensions. May not return: pi
36
+ * `process.exit()`s on help/error paths.
37
+ *
38
+ * This is a dedicated-process entrypoint: pi owns stdin/stdout, signal
39
+ * handlers, and process exit while `main()` runs. Do not run it concurrently
40
+ * with another pi SDK/runtime in the same process. The temporary registry
41
+ * policy is restored when `main()` returns or rejects.
42
+ */
43
+ export async function runAgent(opts) {
44
+ process.env.PI_CODING_AGENT_DIR ??= join(homedir(), '.mlx-node', 'agent');
45
+ process.env.PI_SKIP_VERSION_CHECK ??= '1';
46
+ // Mirrors `mlx launch claude`: chunked paged prefill keeps long-prompt
47
+ // TTFT bounded on the default paged path.
48
+ process.env.MLX_PAGED_PREFILL_CHUNK_SIZE ??= '2048';
49
+ // Force every paged-capable agent family through an isolated config clone.
50
+ // This includes quantized LFM2 (whose standalone default is deliberately
51
+ // flat) and Qwen3.5 dense/MoE (whose text-only defaults are flat). Gemma4's
52
+ // paged overlay intentionally hides an embedded draft/ directory: the
53
+ // current speculative executor is flat-cache-only and can regress quantized
54
+ // agent workloads. Users may explicitly opt back into that native behavior.
55
+ const preserveEmbeddedGemmaDraft = agentGemmaDraftEnabled();
56
+ const pagedConfigOverrides = opts.pagedConfigOverrides ?? new PagedConfigOverrideManager({ preserveEmbeddedGemmaDraft });
57
+ const modelHost = new MlxModelHost(opts.models.map((model) => model.discovered), {
58
+ resolveModelPathFn: (model) => pagedConfigOverrides.resolve(model.path, model.modelType),
59
+ requirePagedCache: true,
60
+ });
61
+ // Keep the pi import strictly behind the seam. The seam carries BOTH main
62
+ // and its registry class, so tests and production exercise the same policy
63
+ // installation/lifecycle instead of being able to bypass it accidentally.
64
+ const pi = opts.piImpl ?? (await import('@earendil-works/pi-coding-agent'));
65
+ const restoreModelRegistry = installMlxOnlyModelRegistryFilter(pi.ModelRegistry, opts.models.map((model) => model.discovered.name));
66
+ const subagentsEnabled = opts.models.length > 0 && !opts.argv.includes('--no-extensions') && !opts.argv.includes('-ne');
67
+ try {
68
+ await pi.main(opts.argv, {
69
+ extensionFactories: [
70
+ createMlxProviderExtension(opts.models, modelHost),
71
+ createPermissionGateExtension(),
72
+ ...(subagentsEnabled ? [createSubagentExtension()] : []),
73
+ ...(opts.traceLogFile !== undefined ? [createTraceNoticeExtension(opts.traceLogFile)] : []),
74
+ createTerminalTitleExtension(),
75
+ ],
76
+ });
77
+ }
78
+ finally {
79
+ try {
80
+ restoreModelRegistry();
81
+ }
82
+ finally {
83
+ await pagedConfigOverrides.cleanup();
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,8 @@
1
+ import type { ModelType } from '@mlx-node/lm';
2
+ /** Structural mirror of the CLI's DiscoveredModel — avoids a cli↔agent dependency cycle. */
3
+ export interface DiscoveredModelLike {
4
+ name: string;
5
+ path: string;
6
+ modelType: ModelType;
7
+ }
8
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,4FAA4F;AAC5F,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,SAAS,CAAC;CACtB"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@mlx-node/agent",
3
+ "version": "0.0.7",
4
+ "homepage": "https://github.com/mlx-node/mlx-node",
5
+ "bugs": {
6
+ "url": "https://github.com/mlx-node/mlx-node/issues"
7
+ },
8
+ "license": "MIT",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/mlx-node/mlx-node.git",
12
+ "directory": "packages/agent"
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "type": "module",
18
+ "main": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js"
24
+ }
25
+ },
26
+ "scripts": {
27
+ "build": "tsc -b"
28
+ },
29
+ "dependencies": {
30
+ "@earendil-works/pi-ai": "0.80.6",
31
+ "@earendil-works/pi-coding-agent": "0.80.6",
32
+ "@mlx-node/lm": "0.0.7",
33
+ "@mlx-node/server": "0.0.7",
34
+ "typebox": "1.3.6"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^26.0.0"
38
+ },
39
+ "engines": {
40
+ "node": ">=22.19.0"
41
+ }
42
+ }