@oh-my-pi/pi-coding-agent 15.7.2 → 15.7.5
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/CHANGELOG.md +114 -6
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/cli/extension-flags.d.ts +36 -0
- package/dist/types/config/config-file.d.ts +4 -0
- package/dist/types/config/file-lock.d.ts +23 -0
- package/dist/types/config/keybindings.d.ts +2 -1
- package/dist/types/config/model-registry.d.ts +6 -0
- package/dist/types/config/settings-schema.d.ts +69 -65
- package/dist/types/edit/hashline/diff.d.ts +3 -3
- package/dist/types/eval/__tests__/agent-bridge.test.d.ts +1 -0
- package/dist/types/eval/__tests__/budget-bridge.test.d.ts +1 -0
- package/dist/types/eval/__tests__/idle-timeout.test.d.ts +1 -0
- package/dist/types/eval/agent-bridge.d.ts +25 -0
- package/dist/types/eval/backend.d.ts +17 -2
- package/dist/types/eval/budget-bridge.d.ts +29 -0
- package/dist/types/eval/idle-timeout.d.ts +28 -0
- package/dist/types/eval/js/executor.d.ts +8 -0
- package/dist/types/eval/js/tool-bridge.d.ts +2 -1
- package/dist/types/eval/py/executor.d.ts +13 -0
- package/dist/types/exec/bash-executor.d.ts +1 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
- package/dist/types/extensibility/extensions/runner.d.ts +7 -0
- package/dist/types/extensibility/plugins/git-url.d.ts +11 -1
- package/dist/types/extensibility/plugins/manager.d.ts +12 -1
- package/dist/types/extensibility/shared-events.d.ts +2 -2
- package/dist/types/internal-urls/local-protocol.d.ts +19 -9
- package/dist/types/internal-urls/types.d.ts +14 -0
- package/dist/types/lsp/client.d.ts +3 -0
- package/dist/types/mcp/manager.d.ts +14 -5
- package/dist/types/memory-backend/index.d.ts +1 -1
- package/dist/types/memory-backend/resolve.d.ts +1 -1
- package/dist/types/memory-backend/types.d.ts +3 -3
- package/dist/types/mnemopi/backend.d.ts +4 -0
- package/dist/types/mnemopi/config.d.ts +29 -0
- package/dist/types/mnemopi/state.d.ts +72 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -2
- package/dist/types/modes/components/omfg-panel.d.ts +19 -0
- package/dist/types/modes/controllers/command-controller.d.ts +6 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -3
- package/dist/types/modes/controllers/omfg-controller.d.ts +10 -0
- package/dist/types/modes/controllers/omfg-rule.d.ts +26 -0
- package/dist/types/modes/gradient-highlight.d.ts +5 -1
- package/dist/types/modes/interactive-mode.d.ts +7 -3
- package/dist/types/modes/magic-keywords.d.ts +14 -0
- package/dist/types/modes/markdown-prose.d.ts +27 -0
- package/dist/types/modes/orchestrate.d.ts +7 -2
- package/dist/types/modes/shared.d.ts +1 -1
- package/dist/types/modes/turn-budget.d.ts +18 -0
- package/dist/types/modes/types.d.ts +7 -3
- package/dist/types/modes/ultrathink.d.ts +7 -2
- package/dist/types/modes/workflow.d.ts +15 -0
- package/dist/types/sdk.d.ts +13 -3
- package/dist/types/session/agent-session.d.ts +36 -17
- package/dist/types/session/session-manager.d.ts +18 -0
- package/dist/types/session/session-storage.d.ts +6 -0
- package/dist/types/session/shake-types.d.ts +24 -0
- package/dist/types/task/executor.d.ts +2 -2
- package/dist/types/task/repair-args.d.ts +52 -0
- package/dist/types/tiny/models.d.ts +1 -1
- package/dist/types/tiny/title-client.d.ts +28 -2
- package/dist/types/tiny/title-protocol.d.ts +8 -5
- package/dist/types/tools/find.d.ts +1 -1
- package/dist/types/tools/index.d.ts +19 -3
- package/dist/types/tools/memory-edit.d.ts +1 -1
- package/dist/types/tools/path-utils.d.ts +7 -0
- package/dist/types/tui/output-block.d.ts +7 -7
- package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
- package/package.json +10 -10
- package/scripts/build-binary.ts +0 -1
- package/src/autoresearch/tools/run-experiment.ts +45 -113
- package/src/cli/args.ts +39 -16
- package/src/cli/extension-flags.ts +48 -0
- package/src/cli/plugin-cli.ts +11 -2
- package/src/cli.ts +59 -0
- package/src/config/config-file.ts +98 -13
- package/src/config/file-lock.ts +60 -17
- package/src/config/keybindings.ts +78 -27
- package/src/config/model-registry.ts +7 -1
- package/src/config/settings-schema.ts +73 -67
- package/src/config/settings.ts +22 -0
- package/src/edit/hashline/diff.ts +81 -24
- package/src/edit/renderer.ts +16 -12
- package/src/eval/__tests__/agent-bridge.test.ts +433 -0
- package/src/eval/__tests__/budget-bridge.test.ts +69 -0
- package/src/eval/__tests__/idle-timeout.test.ts +66 -0
- package/src/eval/__tests__/shared-executors.test.ts +21 -0
- package/src/eval/agent-bridge.ts +295 -0
- package/src/eval/backend.ts +17 -2
- package/src/eval/budget-bridge.ts +48 -0
- package/src/eval/idle-timeout.ts +80 -0
- package/src/eval/js/executor.ts +35 -7
- package/src/eval/js/index.ts +2 -1
- package/src/eval/js/shared/prelude.txt +85 -1
- package/src/eval/js/tool-bridge.ts +9 -0
- package/src/eval/py/executor.ts +41 -14
- package/src/eval/py/index.ts +2 -1
- package/src/eval/py/prelude.py +132 -1
- package/src/exec/bash-executor.ts +2 -3
- package/src/extensibility/custom-tools/types.ts +2 -2
- package/src/extensibility/extensions/runner.ts +12 -2
- package/src/extensibility/plugins/git-url.ts +90 -4
- package/src/extensibility/plugins/manager.ts +103 -7
- package/src/extensibility/shared-events.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +88 -88
- package/src/internal-urls/local-protocol.ts +23 -11
- package/src/internal-urls/types.ts +15 -0
- package/src/lsp/client.ts +28 -5
- package/src/main.ts +44 -55
- package/src/mcp/manager.ts +87 -4
- package/src/memory-backend/index.ts +1 -1
- package/src/memory-backend/resolve.ts +3 -3
- package/src/memory-backend/types.ts +3 -3
- package/src/{mnemosyne → mnemopi}/backend.ts +70 -70
- package/src/{mnemosyne → mnemopi}/config.ts +36 -36
- package/src/{mnemosyne → mnemopi}/state.ts +67 -67
- package/src/modes/components/agent-dashboard.ts +6 -6
- package/src/modes/components/custom-editor.ts +4 -11
- package/src/modes/components/extensions/state-manager.ts +3 -4
- package/src/modes/components/footer.ts +8 -9
- package/src/modes/components/hook-selector.ts +86 -20
- package/src/modes/components/oauth-selector.ts +93 -21
- package/src/modes/components/omfg-panel.ts +141 -0
- package/src/modes/components/settings-defs.ts +2 -2
- package/src/modes/components/tips.txt +2 -1
- package/src/modes/components/tool-execution.ts +38 -19
- package/src/modes/components/tree-selector.ts +4 -3
- package/src/modes/components/user-message-selector.ts +94 -19
- package/src/modes/components/user-message.ts +8 -1
- package/src/modes/controllers/command-controller.ts +25 -0
- package/src/modes/controllers/event-controller.ts +68 -3
- package/src/modes/controllers/input-controller.ts +14 -11
- package/src/modes/controllers/mcp-command-controller.ts +1 -1
- package/src/modes/controllers/omfg-controller.ts +283 -0
- package/src/modes/controllers/omfg-rule.ts +647 -0
- package/src/modes/controllers/selector-controller.ts +1 -0
- package/src/modes/gradient-highlight.ts +23 -6
- package/src/modes/interactive-mode.ts +41 -7
- package/src/modes/magic-keywords.ts +20 -0
- package/src/modes/markdown-prose.ts +247 -0
- package/src/modes/orchestrate.ts +17 -11
- package/src/modes/shared.ts +3 -11
- package/src/modes/turn-budget.ts +31 -0
- package/src/modes/types.ts +7 -1
- package/src/modes/ultrathink.ts +16 -10
- package/src/modes/utils/hotkeys-markdown.ts +1 -1
- package/src/modes/workflow.ts +42 -0
- package/src/prompts/system/omfg-user.md +51 -0
- package/src/prompts/system/project-prompt.md +3 -2
- package/src/prompts/system/subagent-system-prompt.md +12 -8
- package/src/prompts/system/system-prompt.md +9 -6
- package/src/prompts/system/workflow-notice.md +70 -0
- package/src/prompts/tools/eval.md +13 -1
- package/src/prompts/tools/memory-edit.md +1 -1
- package/src/sdk.ts +63 -33
- package/src/session/agent-session.ts +290 -55
- package/src/session/session-manager.ts +32 -0
- package/src/session/session-storage.ts +68 -8
- package/src/session/shake-types.ts +43 -0
- package/src/slash-commands/builtin-registry.ts +39 -16
- package/src/task/executor.ts +17 -7
- package/src/task/index.ts +9 -8
- package/src/task/repair-args.ts +117 -0
- package/src/tiny/models.ts +2 -2
- package/src/tiny/title-client.ts +133 -43
- package/src/tiny/title-protocol.ts +10 -5
- package/src/tiny/worker.ts +3 -46
- package/src/tools/ast-edit.ts +3 -0
- package/src/tools/ast-grep.ts +3 -0
- package/src/tools/eval.ts +202 -26
- package/src/tools/find.ts +20 -6
- package/src/tools/gh.ts +1 -0
- package/src/tools/grouped-file-output.ts +9 -2
- package/src/tools/index.ts +17 -5
- package/src/tools/memory-edit.ts +4 -4
- package/src/tools/memory-recall.ts +5 -5
- package/src/tools/memory-reflect.ts +5 -5
- package/src/tools/memory-retain.ts +4 -4
- package/src/tools/path-utils.ts +13 -2
- package/src/tools/read.ts +1 -0
- package/src/tools/render-utils.ts +2 -1
- package/src/tools/search.ts +491 -76
- package/src/tui/output-block.ts +37 -75
- package/src/utils/git.ts +9 -3
- package/dist/types/mnemosyne/backend.d.ts +0 -4
- package/dist/types/mnemosyne/config.d.ts +0 -29
- package/dist/types/mnemosyne/state.d.ts +0 -72
- /package/dist/types/{mnemosyne → mnemopi}/index.d.ts +0 -0
- /package/src/{mnemosyne → mnemopi}/index.ts +0 -0
package/src/tiny/title-client.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
1
2
|
import { $env, isCompiledBinary, logger } from "@oh-my-pi/pi-utils";
|
|
3
|
+
import type { Subprocess } from "bun";
|
|
2
4
|
import { settings } from "../config/settings";
|
|
3
5
|
import { tinyModelDeviceSettingToEnv } from "./device";
|
|
4
6
|
import { tinyModelDtypeSettingToEnv } from "./dtype";
|
|
@@ -12,6 +14,14 @@ import {
|
|
|
12
14
|
} from "./models";
|
|
13
15
|
import type { TinyTitleProgressEvent, TinyTitleWorkerInbound, TinyTitleWorkerOutbound } from "./title-protocol";
|
|
14
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Abstraction over the tiny-model subprocess. Modelled as a worker interface
|
|
19
|
+
* so existing callers (titles, memory completions, downloads) compose the
|
|
20
|
+
* same way; the runtime implementation is a Bun child process so
|
|
21
|
+
* `onnxruntime-node`'s NAPI finalizer never runs inside the main agent
|
|
22
|
+
* address space — that destructor segfaults Bun on Windows during shutdown
|
|
23
|
+
* (issue #1606).
|
|
24
|
+
*/
|
|
15
25
|
interface WorkerHandle {
|
|
16
26
|
send(message: TinyTitleWorkerInbound): void;
|
|
17
27
|
onMessage(handler: (message: TinyTitleWorkerOutbound) => void): () => void;
|
|
@@ -31,6 +41,12 @@ export interface TinyTitleDownloadOptions {
|
|
|
31
41
|
|
|
32
42
|
const SMOKE_TEST_TIMEOUT_MS = 5_000;
|
|
33
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Hidden subcommand on the main CLI that boots the tiny-model worker in the
|
|
46
|
+
* spawned subprocess. Kept in sync with the dispatch in `cli.ts`.
|
|
47
|
+
*/
|
|
48
|
+
export const TINY_WORKER_ARG = "--tiny-worker";
|
|
49
|
+
|
|
34
50
|
function readTinyModelSetting(path: "providers.tinyModelDevice" | "providers.tinyModelDtype"): string | undefined {
|
|
35
51
|
try {
|
|
36
52
|
const value = settings.get(path);
|
|
@@ -66,49 +82,128 @@ export function tinyWorkerEnvOverlay(
|
|
|
66
82
|
}
|
|
67
83
|
|
|
68
84
|
/**
|
|
69
|
-
* Env handed to the tiny-model
|
|
70
|
-
* vars win; otherwise the persisted `providers.tinyModelDevice` /
|
|
71
|
-
* `providers.tinyModelDtype` settings are mapped onto those vars so the
|
|
72
|
-
* env-based resolution picks them up. Resolved once at spawn
|
|
85
|
+
* Env handed to the tiny-model subprocess. The `PI_TINY_DEVICE` / `PI_TINY_DTYPE`
|
|
86
|
+
* env vars win; otherwise the persisted `providers.tinyModelDevice` /
|
|
87
|
+
* `providers.tinyModelDtype` settings are mapped onto those vars so the
|
|
88
|
+
* subprocess's env-based resolution picks them up. Resolved once at spawn
|
|
89
|
+
* (pipelines are cached for the lifetime of the subprocess).
|
|
73
90
|
*/
|
|
74
|
-
function tinyWorkerEnv(): Record<string, string>
|
|
91
|
+
function tinyWorkerEnv(): Record<string, string> {
|
|
75
92
|
const overlay = tinyWorkerEnvOverlay(
|
|
76
93
|
$env,
|
|
77
94
|
readTinyModelSetting("providers.tinyModelDevice"),
|
|
78
95
|
readTinyModelSetting("providers.tinyModelDtype"),
|
|
79
96
|
);
|
|
80
|
-
|
|
81
|
-
|
|
97
|
+
const base = $env as Record<string, string | undefined>;
|
|
98
|
+
const merged: Record<string, string> = {};
|
|
99
|
+
for (const key in base) {
|
|
100
|
+
const value = base[key];
|
|
101
|
+
if (typeof value === "string") merged[key] = value;
|
|
102
|
+
}
|
|
103
|
+
for (const key in overlay) merged[key] = overlay[key];
|
|
104
|
+
return merged;
|
|
82
105
|
}
|
|
83
106
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Resolve the argv used to relaunch the agent CLI into tiny-worker mode. In a
|
|
109
|
+
* compiled binary the entry point is the binary itself; in dev/source the
|
|
110
|
+
* spawned `bun` needs the absolute path to `cli.ts` so it can resolve module
|
|
111
|
+
* imports against the on-disk source tree.
|
|
112
|
+
*/
|
|
113
|
+
function tinyWorkerSpawnCmd(): string[] {
|
|
114
|
+
if (isCompiledBinary()) return [process.execPath, TINY_WORKER_ARG];
|
|
115
|
+
const cliPath = path.resolve(import.meta.dir, "..", "cli.ts");
|
|
116
|
+
return [process.execPath, cliPath, TINY_WORKER_ARG];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
interface SpawnedSubprocess {
|
|
120
|
+
proc: Subprocess<"ignore", "inherit", "inherit">;
|
|
121
|
+
inbound: Set<(message: TinyTitleWorkerOutbound) => void>;
|
|
122
|
+
errors: Set<(error: Error) => void>;
|
|
123
|
+
/**
|
|
124
|
+
* Flipped to `true` by {@link wrapSubprocess}'s `terminate()` right
|
|
125
|
+
* before it SIGKILLs the child so `onExit` can distinguish the
|
|
126
|
+
* expected hard-kill from a crash/OOM/external signal. Only the
|
|
127
|
+
* latter is surfaced as a worker error.
|
|
128
|
+
*/
|
|
129
|
+
intentionalExit: { value: boolean };
|
|
90
130
|
}
|
|
91
131
|
|
|
92
|
-
|
|
93
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Spawn the tiny-model worker as a subprocess. Exported for tests and the
|
|
134
|
+
* smoke probe; production callers go through {@link spawnTinyTitleWorker}
|
|
135
|
+
* which wraps the result in a {@link WorkerHandle}.
|
|
136
|
+
*/
|
|
137
|
+
export function createTinyTitleSubprocess(): SpawnedSubprocess {
|
|
138
|
+
const inbound = new Set<(message: TinyTitleWorkerOutbound) => void>();
|
|
139
|
+
const errors = new Set<(error: Error) => void>();
|
|
140
|
+
const intentionalExit = { value: false };
|
|
141
|
+
const proc = Bun.spawn({
|
|
142
|
+
cmd: tinyWorkerSpawnCmd(),
|
|
143
|
+
env: tinyWorkerEnv(),
|
|
144
|
+
stdin: "ignore",
|
|
145
|
+
stdout: "inherit",
|
|
146
|
+
stderr: "inherit",
|
|
147
|
+
serialization: "advanced",
|
|
148
|
+
windowsHide: true,
|
|
149
|
+
ipc(message) {
|
|
150
|
+
for (const handler of inbound) handler(message as TinyTitleWorkerOutbound);
|
|
151
|
+
},
|
|
152
|
+
onExit(_proc, exitCode, signalCode) {
|
|
153
|
+
// Clean exit. The child only exits via SIGKILL in practice, but
|
|
154
|
+
// treat code 0 as a no-op for symmetry.
|
|
155
|
+
if (exitCode === 0) return;
|
|
156
|
+
// `exitCode === null` + non-null `signalCode` covers both the
|
|
157
|
+
// expected SIGKILL from `terminate()` AND external kills
|
|
158
|
+
// (SIGSEGV from a native crash, SIGKILL from the OOM killer, an
|
|
159
|
+
// operator `kill -9`, etc.). Swallow only the expected one;
|
|
160
|
+
// every other signal exit is a real worker death that must
|
|
161
|
+
// fault every in-flight request so callers don't await forever.
|
|
162
|
+
if (exitCode === null && intentionalExit.value) return;
|
|
163
|
+
const reason = exitCode !== null ? `code ${exitCode}` : `signal ${signalCode ?? "unknown"}`;
|
|
164
|
+
const err = new Error(`tiny model subprocess exited with ${reason}`);
|
|
165
|
+
for (const handler of errors) handler(err);
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
// Don't keep the parent event loop alive on account of an idle worker; the
|
|
169
|
+
// agent dispose path calls `terminate()` explicitly when shutting down.
|
|
170
|
+
proc.unref();
|
|
171
|
+
return { proc, inbound, errors, intentionalExit };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function wrapSubprocess({ proc, inbound, errors, intentionalExit }: SpawnedSubprocess): WorkerHandle {
|
|
94
175
|
return {
|
|
95
176
|
send(message) {
|
|
96
|
-
|
|
177
|
+
try {
|
|
178
|
+
proc.send(message);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
logger.debug("tiny-title: send to subprocess failed", {
|
|
181
|
+
error: error instanceof Error ? error.message : String(error),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
97
184
|
},
|
|
98
185
|
onMessage(handler) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return () => worker.removeEventListener("message", wrap);
|
|
186
|
+
inbound.add(handler);
|
|
187
|
+
return () => inbound.delete(handler);
|
|
102
188
|
},
|
|
103
189
|
onError(handler) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
};
|
|
107
|
-
worker.addEventListener("error", wrap);
|
|
108
|
-
return () => worker.removeEventListener("error", wrap);
|
|
190
|
+
errors.add(handler);
|
|
191
|
+
return () => errors.delete(handler);
|
|
109
192
|
},
|
|
110
193
|
async terminate() {
|
|
111
|
-
|
|
194
|
+
// SIGKILL: the whole point of the subprocess isolation is that the
|
|
195
|
+
// parent never runs `onnxruntime-node`'s NAPI finalizer. A polite
|
|
196
|
+
// SIGTERM lets the subprocess try to clean up, which is exactly the
|
|
197
|
+
// codepath that crashes Bun on Windows. Hard-kill instead — the
|
|
198
|
+
// model lives in process memory and the OS reclaims everything.
|
|
199
|
+
// Flip the intentional-exit flag *before* killing so `onExit` can
|
|
200
|
+
// tell this apart from a crash or external SIGKILL.
|
|
201
|
+
intentionalExit.value = true;
|
|
202
|
+
try {
|
|
203
|
+
proc.kill("SIGKILL");
|
|
204
|
+
} catch {
|
|
205
|
+
// Already gone.
|
|
206
|
+
}
|
|
112
207
|
},
|
|
113
208
|
};
|
|
114
209
|
}
|
|
@@ -126,10 +221,6 @@ function spawnInlineUnavailableWorker(error: unknown): WorkerHandle {
|
|
|
126
221
|
emit({ type: "pong", id: message.id });
|
|
127
222
|
return;
|
|
128
223
|
}
|
|
129
|
-
if (message.type === "close") {
|
|
130
|
-
emit({ type: "closed" });
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
224
|
emit({ type: "error", id: message.id, error: errorMessage });
|
|
134
225
|
});
|
|
135
226
|
},
|
|
@@ -148,9 +239,9 @@ function spawnInlineUnavailableWorker(error: unknown): WorkerHandle {
|
|
|
148
239
|
|
|
149
240
|
function spawnTinyTitleWorker(): WorkerHandle {
|
|
150
241
|
try {
|
|
151
|
-
return
|
|
242
|
+
return wrapSubprocess(createTinyTitleSubprocess());
|
|
152
243
|
} catch (error) {
|
|
153
|
-
logger.warn("Tiny title
|
|
244
|
+
logger.warn("Tiny title worker spawn failed; local titles disabled", {
|
|
154
245
|
error: error instanceof Error ? error.message : String(error),
|
|
155
246
|
});
|
|
156
247
|
return spawnInlineUnavailableWorker(error);
|
|
@@ -293,9 +384,9 @@ export class TinyTitleClient {
|
|
|
293
384
|
}
|
|
294
385
|
this.#pending.clear();
|
|
295
386
|
try {
|
|
296
|
-
worker?.
|
|
387
|
+
await worker?.terminate();
|
|
297
388
|
} catch {
|
|
298
|
-
//
|
|
389
|
+
// Already gone.
|
|
299
390
|
}
|
|
300
391
|
}
|
|
301
392
|
|
|
@@ -317,7 +408,6 @@ export class TinyTitleClient {
|
|
|
317
408
|
this.#emitProgress(message.event);
|
|
318
409
|
return;
|
|
319
410
|
}
|
|
320
|
-
if (message.type === "closed") return;
|
|
321
411
|
if (message.type === "pong") return;
|
|
322
412
|
|
|
323
413
|
const pending = this.#pending.get(message.id);
|
|
@@ -371,25 +461,25 @@ export async function smokeTestTinyTitleWorker({
|
|
|
371
461
|
}: {
|
|
372
462
|
timeoutMs?: number;
|
|
373
463
|
} = {}): Promise<void> {
|
|
374
|
-
const
|
|
464
|
+
const handle = wrapSubprocess(createTinyTitleSubprocess());
|
|
375
465
|
const { promise, resolve, reject } = Promise.withResolvers<void>();
|
|
376
466
|
const timer = setTimeout(() => reject(new Error(`tiny title worker did not pong within ${timeoutMs}ms`)), timeoutMs);
|
|
377
|
-
|
|
378
|
-
const message = event.data;
|
|
467
|
+
const unsubscribeMessage = handle.onMessage(message => {
|
|
379
468
|
if (message.type === "pong") {
|
|
380
469
|
resolve();
|
|
381
470
|
return;
|
|
382
471
|
}
|
|
472
|
+
if (message.type === "log") return;
|
|
383
473
|
reject(new Error(`tiny title worker: expected pong, got ${JSON.stringify(message)}`));
|
|
384
|
-
};
|
|
385
|
-
|
|
386
|
-
reject(event.error instanceof Error ? event.error : new Error(event.message || "tiny title worker error"));
|
|
387
|
-
};
|
|
474
|
+
});
|
|
475
|
+
const unsubscribeError = handle.onError(reject);
|
|
388
476
|
try {
|
|
389
|
-
|
|
477
|
+
handle.send({ type: "ping", id: "smoke" } satisfies TinyTitleWorkerInbound);
|
|
390
478
|
await promise;
|
|
391
479
|
} finally {
|
|
392
480
|
clearTimeout(timer);
|
|
393
|
-
|
|
481
|
+
unsubscribeMessage();
|
|
482
|
+
unsubscribeError();
|
|
483
|
+
await handle.terminate();
|
|
394
484
|
}
|
|
395
485
|
}
|
|
@@ -31,8 +31,7 @@ export type TinyTitleWorkerInbound =
|
|
|
31
31
|
| { type: "ping"; id: string }
|
|
32
32
|
| { type: "generate"; id: string; modelKey: TinyTitleLocalModelKey; message: string }
|
|
33
33
|
| { type: "complete"; id: string; modelKey: TinyLocalModelKey; prompt: string; maxTokens?: number }
|
|
34
|
-
| { type: "download"; id: string; modelKey: TinyLocalModelKey }
|
|
35
|
-
| { type: "close" };
|
|
34
|
+
| { type: "download"; id: string; modelKey: TinyLocalModelKey };
|
|
36
35
|
|
|
37
36
|
export type TinyTitleWorkerOutbound =
|
|
38
37
|
| { type: "pong"; id: string }
|
|
@@ -41,11 +40,17 @@ export type TinyTitleWorkerOutbound =
|
|
|
41
40
|
| { type: "downloaded"; id: string }
|
|
42
41
|
| { type: "error"; id: string; error: string }
|
|
43
42
|
| { type: "progress"; id: string; event: TinyTitleProgressEvent }
|
|
44
|
-
| { type: "log"; level: "debug" | "warn" | "error"; msg: string; meta?: Record<string, unknown> }
|
|
45
|
-
| { type: "closed" };
|
|
43
|
+
| { type: "log"; level: "debug" | "warn" | "error"; msg: string; meta?: Record<string, unknown> };
|
|
46
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Wire transport between the parent (`TinyTitleClient`) and the tiny-model
|
|
47
|
+
* subprocess. The parent owns the subprocess lifecycle (graceful work, hard
|
|
48
|
+
* kill on shutdown); the protocol therefore carries no explicit close
|
|
49
|
+
* handshake — once the parent decides to terminate, it signals the OS to
|
|
50
|
+
* reap the child so `onnxruntime-node`'s NAPI finalizer never runs in any
|
|
51
|
+
* shared address space. See `title-client.ts` for the spawn/kill glue.
|
|
52
|
+
*/
|
|
47
53
|
export interface TinyTitleTransport {
|
|
48
54
|
send(message: TinyTitleWorkerOutbound): void;
|
|
49
55
|
onMessage(handler: (message: TinyTitleWorkerInbound) => void): () => void;
|
|
50
|
-
close(): void;
|
|
51
56
|
}
|
package/src/tiny/worker.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import { parentPort } from "node:worker_threads";
|
|
5
4
|
import type {
|
|
6
5
|
ProgressInfo,
|
|
7
6
|
TextGenerationPipeline,
|
|
@@ -20,12 +19,7 @@ import {
|
|
|
20
19
|
type TinyTitleLocalModelSpec,
|
|
21
20
|
} from "./models";
|
|
22
21
|
import { formatTitleUserMessage, normalizeGeneratedTitle } from "./text";
|
|
23
|
-
import type {
|
|
24
|
-
TinyTitleProgressEvent,
|
|
25
|
-
TinyTitleTransport,
|
|
26
|
-
TinyTitleWorkerInbound,
|
|
27
|
-
TinyTitleWorkerOutbound,
|
|
28
|
-
} from "./title-protocol";
|
|
22
|
+
import type { TinyTitleProgressEvent, TinyTitleTransport, TinyTitleWorkerInbound } from "./title-protocol";
|
|
29
23
|
|
|
30
24
|
const TITLE_PREFILL = "<title>";
|
|
31
25
|
const TITLE_CLOSE = "</title>";
|
|
@@ -472,8 +466,8 @@ function buildCompletionPrompt(generator: TextGenerationPipeline, promptText: st
|
|
|
472
466
|
}
|
|
473
467
|
|
|
474
468
|
/**
|
|
475
|
-
* Generic single-turn completion used by
|
|
476
|
-
* and consolidation). The caller (
|
|
469
|
+
* Generic single-turn completion used by Mnemopi memory tasks (fact extraction
|
|
470
|
+
* and consolidation). The caller (Mnemopi) supplies the full task prompt; we
|
|
477
471
|
* wrap it as the user turn, decode greedily, and return the raw text for the
|
|
478
472
|
* caller's own parser. Output is capped to keep local inference latency bounded.
|
|
479
473
|
*/
|
|
@@ -497,16 +491,6 @@ async function generateCompletion(
|
|
|
497
491
|
return generated === "" ? null : generated;
|
|
498
492
|
}
|
|
499
493
|
|
|
500
|
-
function releasePipelines(): void {
|
|
501
|
-
// Intentionally NOT calling `pipeline.dispose()`. transformers.js disposes the
|
|
502
|
-
// underlying onnxruntime InferenceSession, freeing native memory that Bun's
|
|
503
|
-
// worker/NAPI teardown then frees a second time — a double-free that aborts the
|
|
504
|
-
// process on quit ("malloc: pointer being freed was not allocated" /
|
|
505
|
-
// "NAPI FATAL ERROR"). The worker is torn down immediately after `close`, so the
|
|
506
|
-
// OS reclaims the model memory regardless; skipping dispose avoids the crash.
|
|
507
|
-
pipelines.clear();
|
|
508
|
-
}
|
|
509
|
-
|
|
510
494
|
function enqueueRequest(
|
|
511
495
|
transport: TinyTitleTransport,
|
|
512
496
|
request: Extract<TinyTitleWorkerInbound, { type: "generate" | "complete" | "download" }>,
|
|
@@ -555,33 +539,6 @@ export function startTinyTitleWorker(transport: TinyTitleTransport): void {
|
|
|
555
539
|
transport.send({ type: "pong", id: message.id });
|
|
556
540
|
return;
|
|
557
541
|
}
|
|
558
|
-
if (message.type === "close") {
|
|
559
|
-
releasePipelines();
|
|
560
|
-
transport.send({ type: "closed" });
|
|
561
|
-
transport.close();
|
|
562
|
-
return;
|
|
563
|
-
}
|
|
564
542
|
enqueueRequest(transport, message);
|
|
565
543
|
});
|
|
566
544
|
}
|
|
567
|
-
|
|
568
|
-
if (!parentPort) throw new Error("tiny-title-worker: missing parentPort");
|
|
569
|
-
|
|
570
|
-
const port = parentPort;
|
|
571
|
-
const transport: TinyTitleTransport = {
|
|
572
|
-
send: (message: TinyTitleWorkerOutbound) => port.postMessage(message),
|
|
573
|
-
onMessage: handler => {
|
|
574
|
-
const wrap = (data: unknown): void => handler(data as TinyTitleWorkerInbound);
|
|
575
|
-
port.on("message", wrap);
|
|
576
|
-
return () => port.off("message", wrap);
|
|
577
|
-
},
|
|
578
|
-
close: () => {
|
|
579
|
-
try {
|
|
580
|
-
port.close();
|
|
581
|
-
} catch {
|
|
582
|
-
// Already closed.
|
|
583
|
-
}
|
|
584
|
-
},
|
|
585
|
-
};
|
|
586
|
-
|
|
587
|
-
startTinyTitleWorker(transport);
|
package/src/tools/ast-edit.ts
CHANGED
|
@@ -230,6 +230,9 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
230
230
|
rawPaths: params.paths,
|
|
231
231
|
cwd: this.session.cwd,
|
|
232
232
|
internalUrlAction: "rewrite",
|
|
233
|
+
settings: this.session.settings,
|
|
234
|
+
signal,
|
|
235
|
+
localProtocolOptions: this.session.localProtocolOptions,
|
|
233
236
|
});
|
|
234
237
|
const { searchPath: resolvedSearchPath, scopePath, isDirectory, multiTargets, globFilter } = scope;
|
|
235
238
|
|
package/src/tools/ast-grep.ts
CHANGED
|
@@ -155,6 +155,9 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
155
155
|
rawPaths: params.paths,
|
|
156
156
|
cwd: this.session.cwd,
|
|
157
157
|
internalUrlAction: "search",
|
|
158
|
+
settings: this.session.settings,
|
|
159
|
+
signal,
|
|
160
|
+
localProtocolOptions: this.session.localProtocolOptions,
|
|
158
161
|
});
|
|
159
162
|
const { searchPath: resolvedSearchPath, scopePath, isDirectory, multiTargets, globFilter } = scope;
|
|
160
163
|
|