@code-yeongyu/senpi 2026.9.26 → 2026.9.27
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 +21 -0
- package/dist/bun-runtime.d.ts +18 -2
- package/dist/bun-runtime.d.ts.map +1 -1
- package/dist/bun-runtime.js +60 -8
- package/dist/bun-runtime.js.map +1 -1
- package/dist/bundle/chunks/{app-server-command-ZRCKWY2X.js → app-server-command-7WEJGW7D.js} +1 -1
- package/dist/bundle/chunks/bun-extension-importer-R4HXF3GD.js +14 -0
- package/dist/bundle/chunks/{chunk-QGC46CGK.js → chunk-3QCAGZFO.js} +17 -16
- package/dist/bundle/chunks/chunk-HCXLCGMF.js +8 -0
- package/dist/bundle/chunks/{chunk-OZCB6BP3.js → chunk-HH3D5ZYA.js} +3 -3
- package/dist/bundle/chunks/chunk-W3D3ZYDS.js +2 -0
- package/dist/bundle/chunks/{cli-main-H6JAXAXV.js → cli-main-YLZ4MMLV.js} +1 -1
- package/dist/bundle/chunks/{interactive-host-runtime-YI75GFD5.js → interactive-host-runtime-6WY6424X.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-HM7UQYRC.js → interactive-mode-6AHR5TEM.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-7YX2I7UK.js → multi-session-host-5IWJEFDF.js} +1 -1
- package/dist/bundle/chunks/{package-manager-cli-3ISYTEL2.js → package-manager-cli-FZKBCLWV.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-6PY4TN5F.js → rpc-mode-JSCHAE6O.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +117 -116
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +10 -5
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/bun-extension-importer.d.ts.map +1 -1
- package/dist/core/extensions/bun-extension-importer.js +10 -4
- package/dist/core/extensions/bun-extension-importer.js.map +1 -1
- package/dist/core/extensions/bun-extension-registry.js +6 -5
- package/dist/core/extensions/bun-extension-registry.js.map +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +4 -2
- package/dist/core/messages.js.map +1 -1
- package/dist/core/provider-rejected-images.d.ts +18 -0
- package/dist/core/provider-rejected-images.d.ts.map +1 -0
- package/dist/core/provider-rejected-images.js +107 -0
- package/dist/core/provider-rejected-images.js.map +1 -0
- package/dist/core/session-title-generator.d.ts.map +1 -1
- package/dist/core/session-title-generator.js +21 -3
- package/dist/core/session-title-generator.js.map +1 -1
- package/dist/core/session-title-reasoning.d.ts +14 -0
- package/dist/core/session-title-reasoning.d.ts.map +1 -0
- package/dist/core/session-title-reasoning.js +31 -0
- package/dist/core/session-title-reasoning.js.map +1 -0
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/path-utils.js +13 -0
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +2 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/runtime-notice-presenter.d.ts +8 -0
- package/dist/modes/interactive/runtime-notice-presenter.d.ts.map +1 -0
- package/dist/modes/interactive/runtime-notice-presenter.js +69 -0
- package/dist/modes/interactive/runtime-notice-presenter.js.map +1 -0
- package/dist/modes/interactive/runtime-notice.d.ts +50 -0
- package/dist/modes/interactive/runtime-notice.d.ts.map +1 -0
- package/dist/modes/interactive/runtime-notice.js +104 -0
- package/dist/modes/interactive/runtime-notice.js.map +1 -0
- package/docs/environment-variables.md +2 -0
- package/docs/quickstart.md +7 -1
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +12 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/native/prebuilds/darwin-arm64/senpi_pty.darwin-arm64.node +0 -0
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
- package/dist/bundle/chunks/bun-extension-importer-H4IJCWWQ.js +0 -14
- package/dist/bundle/chunks/chunk-34HMVB33.js +0 -2
- package/dist/bundle/chunks/chunk-T3JBT2IK.js +0 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun-extension-importer.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/bun-extension-importer.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAYxE,iFAAiF;AACjF,wBAAgB,0BAA0B,CACzC,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"bun-extension-importer.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/bun-extension-importer.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAYxE,iFAAiF;AACjF,wBAAgB,0BAA0B,CACzC,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAiIpE,MAAM,OAAO,MAAM,YAAY;QAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBlF,aAAa,IAAI,SAAS,MAAM,EAAE;IAGlC,OAAO;EAQR"}
|
|
@@ -6,7 +6,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
6
6
|
}
|
|
7
7
|
return path;
|
|
8
8
|
};
|
|
9
|
-
import { readFileSync, realpathSync } from "node:fs";
|
|
9
|
+
import { readFileSync, realpathSync, statSync } from "node:fs";
|
|
10
10
|
import { createRequire, isBuiltin } from "node:module";
|
|
11
11
|
import { dirname, extname, resolve } from "node:path";
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
@@ -30,6 +30,10 @@ export function createBunExtensionImporter(virtualModules) {
|
|
|
30
30
|
throw new ExtensionGenerationDisposedError(registration.generation);
|
|
31
31
|
};
|
|
32
32
|
const moduleId = (filename) => `${extensionNamespace}:${registration.generation}/${encodeURIComponent(filename)}`;
|
|
33
|
+
// Only source the graph transpiles gets a graph id. Anything else (JSON, TOML, text, native
|
|
34
|
+
// addons) keeps its real path so Bun's own loader handles it: Bun 1.3.x cannot follow a
|
|
35
|
+
// plugin's hand-back to the `file` namespace from a runtime import() or require() (#2164).
|
|
36
|
+
const fileTarget = (resolved) => /\.[cm]?[jt]sx?$/.test(resolved) ? { id: moduleId(resolved), path: resolved } : { id: resolved };
|
|
33
37
|
const resolveTarget = (specifier, filename) => {
|
|
34
38
|
assertActive();
|
|
35
39
|
if (Object.hasOwn(virtualModules, specifier) || isBuiltin(specifier) || specifier.startsWith("bun:"))
|
|
@@ -37,8 +41,7 @@ export function createBunExtensionImporter(virtualModules) {
|
|
|
37
41
|
if (specifier.startsWith(`${extensionNamespace}:`))
|
|
38
42
|
return { id: specifier };
|
|
39
43
|
const path = specifier.startsWith("file:") ? fileURLToPath(specifier) : specifier;
|
|
40
|
-
|
|
41
|
-
return { id: moduleId(resolved), path: resolved };
|
|
44
|
+
return fileTarget(realpathSync(Bun.resolveSync(path, dirname(filename))));
|
|
42
45
|
};
|
|
43
46
|
const graph = {
|
|
44
47
|
assertActive,
|
|
@@ -150,7 +153,10 @@ export function createBunExtensionImporter(virtualModules) {
|
|
|
150
153
|
return {
|
|
151
154
|
async import(path, _options) {
|
|
152
155
|
assertActive();
|
|
153
|
-
const
|
|
156
|
+
const absolute = realpathSync(resolve(path));
|
|
157
|
+
// A package directory loads through its main or index file, as a native import does.
|
|
158
|
+
const entry = statSync(absolute).isDirectory() ? realpathSync(Bun.resolveSync(absolute, absolute)) : absolute;
|
|
159
|
+
const { id } = fileTarget(entry);
|
|
154
160
|
const module = await import(__rewriteRelativeImportExtension(id));
|
|
155
161
|
const factory = module.default;
|
|
156
162
|
if (typeof factory !== "function")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun-extension-importer.js","sourceRoot":"","sources":["../../../src/core/extensions/bun-extension-importer.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAGN,gCAAgC,EAChC,kBAAkB,EAElB,sBAAsB,GACtB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAYxE,iFAAiF;AACjF,MAAM,UAAU,0BAA0B,CACzC,cAA2E;IAE3E,MAAM,OAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,yFAAyF;IACzF,2FAA2F;IAC3F,oGAAoG;IACpG,MAAM,eAAe,GAAG,IAAI,GAAG,EAA0B,CAAC;IAC1D,MAAM,aAAa,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACrD,IAAI,MAAM,GAAG,IAAI,CAAC;IAClB,MAAM,YAAY,GAAG,GAAG,EAAE;QACzB,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,gCAAgC,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;IAClF,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,CAAC,QAAgB,EAAE,EAAE,CACrC,GAAG,kBAAkB,IAAI,YAAY,CAAC,UAAU,IAAI,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;IACpF,MAAM,aAAa,GAAG,CAAC,SAAiB,EAAE,QAAgB,EAAmD,EAAE;QAC9G,YAAY,EAAE,CAAC;QACf,IAAI,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,SAAS,CAAC,IAAI,SAAS,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC;YACnG,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC;QAC1B,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,kBAAkB,GAAG,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC;QAC7E,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAClF,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACxE,OAAO,EAAE,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACnD,CAAC,CAAC;IACF,MAAM,KAAK,GAAG;QACb,YAAY;QACZ,OAAO,CAAC,SAAiB,EAAE,QAAgB;YAC1C,OAAO,aAAa,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;QAC9C,CAAC;QACD,OAAO,CAAC,SAAiB,EAAE,QAAgB;YAC1C,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YAC9C,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3C,IAAI,UAAU,KAAK,SAAS;gBAAE,OAAO,UAAU,CAAC,OAAO,CAAC;YACxD,MAAM,MAAM,GAAmC,aAAa,CAAC,EAAE,CAAC,CAAC;YACjE,OAAO,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;QACnD,CAAC;QACD,gBAAgB,CAAC,QAAgB,EAAE,IAAkB;YACpD,YAAY,EAAE,CAAC;YACf,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAC9B,MAAM,MAAM,GAAmB,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YAC/C,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YAChC,IAAI,CAAC;gBACJ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACnD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBAC3B,MAAM,KAAK,CAAC;YACb,CAAC;YACD,OAAO,MAAM,CAAC,OAAO,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,QAAgB;YACpB,YAAY,EAAE,CAAC;YACf,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,QAAQ;gBAAE,OAAO,QAAQ,CAAC;YAC9B,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAC9C,IAAI,IAAI,GAAG,sBAAsB,CAAC;YAClC,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,IAAI,IAAI,GAAG,CAAC;YAC1C,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;YACpC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC;gBACrC,MAAM,EAAE,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;gBAC1E,MAAM,EAAE,KAAK;gBACb,MAAM,EAAE;oBACP,aAAa,EAAE,IAAI;oBACnB,OAAO,EAAE,GAAG,IAAI,UAAU;oBAC1B,UAAU,EAAE,GAAG,IAAI,OAAO;oBAC1B,SAAS,EAAE,GAAG,IAAI,MAAM;iBACxB;aACD,CAAC,CAAC;YACH,IAAI,QAAgB,CAAC;YACrB,IAAI,CAAC;gBACJ,QAAQ,GAAG,UAAU,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;YAC7C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,IAAI,KAAK,YAAY,cAAc;oBAAE,MAAM,IAAI,oBAAoB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBACrF,MAAM,KAAK,CAAC;YACb,CAAC;YACD,MAAM,CAAC,OAAO,EAAE,AAAD,EAAG,AAAD,EAAG,eAAe,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACjE,MAAM,KAAK,GAA8E,EAAE,CAAC;YAC5F,IAAI,eAAe,GAAG,CAAC,CAAC;YACxB,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;oBAC7B,wEAAwE;oBACxE,sEAAsE;oBACtE,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,GAAG,IAAI,SAAS,EAAE,CAAC,CAAC;gBACzF,CAAC;qBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;oBACpE,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;oBACvD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC9D,kEAAkE;wBAClE,sEAAsE;wBACtE,MAAM,MAAM,GAAG,QAAQ;6BACrB,KAAK,CAAC,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;6BACzD,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;wBAC5B,0EAA0E;wBAC1E,4EAA4E;wBAC5E,MAAM,UAAU,GACf,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;wBACnG,KAAK,CAAC,IAAI,CAAC;4BACV,KAAK,EAAE,IAAI,CAAC,WAAW;4BACvB,GAAG,EAAE,IAAI,CAAC,SAAS;4BACnB,IAAI,EAAE,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,IAAI,MAAM,eAAe,EAAE,EAAE,EAAE,UAAU,CAAC;yBAC5F,CAAC,CAAC;oBACJ,CAAC;yBAAM,CAAC;wBACP,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;oBAC3F,CAAC;gBACF,CAAC;YACF,CAAC;YACD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5D,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACjF,CAAC;YACD,iFAAiF;YACjF,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YAC/C,oEAAoE;YACpE,qEAAqE;YACrE,0EAA0E;YAC1E,gEAAgE;YAChE,IAAI,CAAC,eAAe,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;gBACtE,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACjC,QAAQ,GAAG,kBAAkB,IAAI,2CAA2C,QAAQ,OAAO,CAAC;YAC7F,CAAC;YACD,QAAQ,GAAG,wBAAwB,IAAI,mBAAmB,kBAAkB,qBAAqB,IAAI,MAAM,IAAI,WAAW,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,QAAQ,EAAE,CAAC;YAChN,MAAM,QAAQ,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAyB,CAAC;YACnE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAChC,OAAO,QAAQ,CAAC;QACjB,CAAC;KACD,CAAC;IACF,MAAM,YAAY,GAAG,sBAAsB,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;IACnE,OAAO;QACN,KAAK,CAAC,MAAM,CAAC,IAAY,EAAE,QAAoC;YAC9D,YAAY,EAAE,CAAC;YACf,MAAM,EAAE,GAAG,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,MAAM,GAAmC,MAAM,MAAM,kCAAC,EAAE,EAAC,CAAC;YAChE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;YAC/B,IAAI,OAAO,OAAO,KAAK,UAAU;gBAAE,OAAO,OAAO,CAAC;YAClD,mEAAmE;YACnE,mEAAmE;YACnE,OAAO,UAAyB,GAAG,IAAe;gBACjD,KAAK,CAAC,YAAY,EAAE,CAAC;gBACrB,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAClC,CAAC,CAAC;QACH,CAAC;QACD,iFAAiF;QACjF,aAAa;YACZ,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5B,CAAC;QACD,OAAO;YACN,MAAM,GAAG,KAAK,CAAC;YACf,YAAY,CAAC,OAAO,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,EAAE,CAAC;YAChB,QAAQ,CAAC,KAAK,EAAE,CAAC;YACjB,eAAe,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC;KACD,CAAC;AACH,CAAC","sourcesContent":["import { readFileSync, realpathSync } from \"node:fs\";\nimport { createRequire, isBuiltin } from \"node:module\";\nimport { dirname, extname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parse } from \"es-module-lexer/js\";\nimport { isCommonJsFile, rewriteCommonJsImport } from \"./bun-extension-commonjs.ts\";\nimport { ExtensionSourceError } from \"./bun-extension-error.ts\";\nimport {\n\ttype CommonJsBody,\n\ttype CommonJsModule,\n\tExtensionGenerationDisposedError,\n\textensionNamespace,\n\ttype ModuleSource,\n\tregisterExtensionGraph,\n} from \"./bun-extension-registry.ts\";\n\nexport { bunExtensionImporterStats } from \"./bun-extension-registry.ts\";\n\n// Keep the source/Node build independent of Bun's ambient type declarations.\ndeclare const Bun: {\n\tresolveSync(specifier: string, directory: string): string;\n\tTranspiler: new (options: {\n\t\treadonly loader: \"ts\" | \"tsx\" | \"jsx\";\n\t\treadonly target: \"bun\";\n\t\treadonly define: Readonly<Record<string, string>>;\n\t}) => { transformSync(source: string): string };\n};\n\n/** A generation owns only source bookkeeping; Bun owns evaluation and cycles. */\nexport function createBunExtensionImporter(\n\tvirtualModules: Readonly<Record<string, Readonly<Record<string, unknown>>>>,\n) {\n\tconst sources = new Map<string, ModuleSource>();\n\tconst commonJs = new Set<string>();\n\t// Live `module` objects by id, registered while a CommonJS body runs: a require inside a\n\t// cycle receives the partially built exports, as in Node, instead of an unset ESM default.\n\t// A body that throws is evicted so a later require re-throws instead of seeing a half-built module.\n\tconst commonJsModules = new Map<string, CommonJsModule>();\n\tconst nativeRequire = createRequire(import.meta.url);\n\tlet active = true;\n\tconst assertActive = () => {\n\t\tif (!active) throw new ExtensionGenerationDisposedError(registration.generation);\n\t};\n\tconst moduleId = (filename: string) =>\n\t\t`${extensionNamespace}:${registration.generation}/${encodeURIComponent(filename)}`;\n\tconst resolveTarget = (specifier: string, filename: string): { readonly id: string; readonly path?: string } => {\n\t\tassertActive();\n\t\tif (Object.hasOwn(virtualModules, specifier) || isBuiltin(specifier) || specifier.startsWith(\"bun:\"))\n\t\t\treturn { id: specifier };\n\t\tif (specifier.startsWith(`${extensionNamespace}:`)) return { id: specifier };\n\t\tconst path = specifier.startsWith(\"file:\") ? fileURLToPath(specifier) : specifier;\n\t\tconst resolved = realpathSync(Bun.resolveSync(path, dirname(filename)));\n\t\treturn { id: moduleId(resolved), path: resolved };\n\t};\n\tconst graph = {\n\t\tassertActive,\n\t\tresolve(specifier: string, filename: string): string {\n\t\t\treturn resolveTarget(specifier, filename).id;\n\t\t},\n\t\trequire(specifier: string, filename: string): unknown {\n\t\t\tconst id = graph.resolve(specifier, filename);\n\t\t\tconst evaluating = commonJsModules.get(id);\n\t\t\tif (evaluating !== undefined) return evaluating.exports;\n\t\t\tconst result: { readonly default?: unknown } = nativeRequire(id);\n\t\t\treturn commonJs.has(id) ? result.default : result;\n\t\t},\n\t\tevaluateCommonJs(filename: string, body: CommonJsBody): unknown {\n\t\t\tassertActive();\n\t\t\tconst id = moduleId(filename);\n\t\t\tconst module: CommonJsModule = { exports: {} };\n\t\t\tcommonJsModules.set(id, module);\n\t\t\ttry {\n\t\t\t\tbody.call(module.exports, module.exports, module);\n\t\t\t} catch (error) {\n\t\t\t\tcommonJsModules.delete(id);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn module.exports;\n\t\t},\n\t\tload(filename: string): ModuleSource {\n\t\t\tassertActive();\n\t\t\tconst existing = sources.get(filename);\n\t\t\tif (existing) return existing;\n\t\t\tconst source = readFileSync(filename, \"utf8\");\n\t\t\tlet name = \"__senpiExtensionMeta\";\n\t\t\twhile (source.includes(name)) name += \"_\";\n\t\t\tconst extension = extname(filename);\n\t\t\tconst transpiler = new Bun.Transpiler({\n\t\t\t\tloader: extension === \".tsx\" ? \"tsx\" : extension === \".jsx\" ? \"jsx\" : \"ts\",\n\t\t\t\ttarget: \"bun\",\n\t\t\t\tdefine: {\n\t\t\t\t\t\"import.meta\": name,\n\t\t\t\t\trequire: `${name}.require`,\n\t\t\t\t\t__filename: `${name}.path`,\n\t\t\t\t\t__dirname: `${name}.dir`,\n\t\t\t\t},\n\t\t\t});\n\t\t\tlet contents: string;\n\t\t\ttry {\n\t\t\t\tcontents = transpiler.transformSync(source);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof AggregateError) throw new ExtensionSourceError(filename, error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tconst [imports, , , hasModuleSyntax] = parse(contents, filename);\n\t\t\tconst edits: { readonly start: number; readonly end: number; readonly text: string }[] = [];\n\t\t\tlet commonJsImports = 0;\n\t\t\tfor (const edge of imports) {\n\t\t\t\tif (edge.type === \"dynamic\") {\n\t\t\t\t\t// Replace the keyword, not its argument: nested expressions, templates,\n\t\t\t\t\t// import attributes, and unavailable optional dependencies stay lazy.\n\t\t\t\t\tedits.push({ start: edge.importStart, end: edge.dynamicStart, text: `${name}.import` });\n\t\t\t\t} else if (edge.type === \"static\" || edge.type === \"reexport-star\") {\n\t\t\t\t\tconst target = resolveTarget(edge.specifier, filename);\n\t\t\t\t\tif (target.path !== undefined && isCommonJsFile(target.path)) {\n\t\t\t\t\t\t// \"import\" and \"export\" are both six characters, so the clause is\n\t\t\t\t\t\t// whatever sits between the keyword and the specifier in either form.\n\t\t\t\t\t\tconst clause = contents\n\t\t\t\t\t\t\t.slice(edge.importStart + \"import\".length, edge.start - 1)\n\t\t\t\t\t\t\t.replace(/\\bfrom\\s*$/, \"\");\n\t\t\t\t\t\t// This branch replaces the whole statement, so the attributes between the\n\t\t\t\t\t\t// specifier and the end of it have to travel with it: they pick the loader.\n\t\t\t\t\t\tconst attributes =\n\t\t\t\t\t\t\tedge.attributesStart < 0 ? \"\" : contents.slice(edge.end + 1, edge.importEnd).replace(/;\\s*$/, \"\");\n\t\t\t\t\t\tedits.push({\n\t\t\t\t\t\t\tstart: edge.importStart,\n\t\t\t\t\t\t\tend: edge.importEnd,\n\t\t\t\t\t\t\ttext: rewriteCommonJsImport(clause, target.id, `${name}Cjs${commonJsImports++}`, attributes),\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tedits.push({ start: edge.start - 1, end: edge.end + 1, text: JSON.stringify(target.id) });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const edit of edits.sort((a, b) => b.start - a.start)) {\n\t\t\t\tcontents = contents.slice(0, edit.start) + edit.text + contents.slice(edit.end);\n\t\t\t}\n\t\t\t// A shebang is only a shebang on the first line, so it goes before any prologue.\n\t\t\tcontents = contents.replace(/^#![^\\n]*\\n/, \"\");\n\t\t\t// Runtime plugins load ESM, even for CommonJS source. Node's module\n\t\t\t// function wrapper preserves synchronous export assignment and keeps\n\t\t\t// `exports` and `module` reassignable bindings with `this` as the exports\n\t\t\t// object, as dependencies such as whatwg-url and jsdom require.\n\t\t\tif (!hasModuleSyntax && extension !== \".mjs\" && extension !== \".mts\") {\n\t\t\t\tcommonJs.add(moduleId(filename));\n\t\t\t\tcontents = `export default ${name}.commonJs(function (exports, module) {\\n${contents}\\n});`;\n\t\t\t}\n\t\t\tcontents = `import { metadata as ${name}Factory } from \"${extensionNamespace}:runtime\";\\nconst ${name} = ${name}Factory(${JSON.stringify(registration.generation)}, ${JSON.stringify(filename)});\\n${contents}`;\n\t\t\tconst prepared = { contents, loader: \"js\" } satisfies ModuleSource;\n\t\t\tsources.set(filename, prepared);\n\t\t\treturn prepared;\n\t\t},\n\t};\n\tconst registration = registerExtensionGraph(graph, virtualModules);\n\treturn {\n\t\tasync import(path: string, _options: { readonly default: true }): Promise<unknown> {\n\t\t\tassertActive();\n\t\t\tconst id = moduleId(realpathSync(resolve(path)));\n\t\t\tconst module: { readonly default?: unknown } = await import(id);\n\t\t\tconst factory = module.default;\n\t\t\tif (typeof factory !== \"function\") return factory;\n\t\t\t// This wrapper is not stored in Bun's permanent module registry. A\n\t\t\t// reachable old factory keeps its own computed-import graph alive.\n\t\t\treturn function (this: unknown, ...args: unknown[]) {\n\t\t\t\tgraph.assertActive();\n\t\t\t\treturn factory.apply(this, args);\n\t\t\t};\n\t\t},\n\t\t// The generation's staleness check reads these: every source file it transpiled.\n\t\tcompiledFiles(): readonly string[] {\n\t\t\treturn [...sources.keys()];\n\t\t},\n\t\tdispose() {\n\t\t\tactive = false;\n\t\t\tregistration.dispose();\n\t\t\tsources.clear();\n\t\t\tcommonJs.clear();\n\t\t\tcommonJsModules.clear();\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bun-extension-importer.js","sourceRoot":"","sources":["../../../src/core/extensions/bun-extension-importer.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync, realpathSync, statSync } from \"node:fs\";\nimport { createRequire, isBuiltin } from \"node:module\";\nimport { dirname, extname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parse } from \"es-module-lexer/js\";\nimport { isCommonJsFile, rewriteCommonJsImport } from \"./bun-extension-commonjs.ts\";\nimport { ExtensionSourceError } from \"./bun-extension-error.ts\";\nimport {\n\ttype CommonJsBody,\n\ttype CommonJsModule,\n\tExtensionGenerationDisposedError,\n\textensionNamespace,\n\ttype ModuleSource,\n\tregisterExtensionGraph,\n} from \"./bun-extension-registry.ts\";\n\nexport { bunExtensionImporterStats } from \"./bun-extension-registry.ts\";\n\n// Keep the source/Node build independent of Bun's ambient type declarations.\ndeclare const Bun: {\n\tresolveSync(specifier: string, directory: string): string;\n\tTranspiler: new (options: {\n\t\treadonly loader: \"ts\" | \"tsx\" | \"jsx\";\n\t\treadonly target: \"bun\";\n\t\treadonly define: Readonly<Record<string, string>>;\n\t}) => { transformSync(source: string): string };\n};\n\n/** A generation owns only source bookkeeping; Bun owns evaluation and cycles. */\nexport function createBunExtensionImporter(\n\tvirtualModules: Readonly<Record<string, Readonly<Record<string, unknown>>>>,\n) {\n\tconst sources = new Map<string, ModuleSource>();\n\tconst commonJs = new Set<string>();\n\t// Live `module` objects by id, registered while a CommonJS body runs: a require inside a\n\t// cycle receives the partially built exports, as in Node, instead of an unset ESM default.\n\t// A body that throws is evicted so a later require re-throws instead of seeing a half-built module.\n\tconst commonJsModules = new Map<string, CommonJsModule>();\n\tconst nativeRequire = createRequire(import.meta.url);\n\tlet active = true;\n\tconst assertActive = () => {\n\t\tif (!active) throw new ExtensionGenerationDisposedError(registration.generation);\n\t};\n\tconst moduleId = (filename: string) =>\n\t\t`${extensionNamespace}:${registration.generation}/${encodeURIComponent(filename)}`;\n\t// Only source the graph transpiles gets a graph id. Anything else (JSON, TOML, text, native\n\t// addons) keeps its real path so Bun's own loader handles it: Bun 1.3.x cannot follow a\n\t// plugin's hand-back to the `file` namespace from a runtime import() or require() (#2164).\n\tconst fileTarget = (resolved: string): { readonly id: string; readonly path?: string } =>\n\t\t/\\.[cm]?[jt]sx?$/.test(resolved) ? { id: moduleId(resolved), path: resolved } : { id: resolved };\n\tconst resolveTarget = (specifier: string, filename: string): { readonly id: string; readonly path?: string } => {\n\t\tassertActive();\n\t\tif (Object.hasOwn(virtualModules, specifier) || isBuiltin(specifier) || specifier.startsWith(\"bun:\"))\n\t\t\treturn { id: specifier };\n\t\tif (specifier.startsWith(`${extensionNamespace}:`)) return { id: specifier };\n\t\tconst path = specifier.startsWith(\"file:\") ? fileURLToPath(specifier) : specifier;\n\t\treturn fileTarget(realpathSync(Bun.resolveSync(path, dirname(filename))));\n\t};\n\tconst graph = {\n\t\tassertActive,\n\t\tresolve(specifier: string, filename: string): string {\n\t\t\treturn resolveTarget(specifier, filename).id;\n\t\t},\n\t\trequire(specifier: string, filename: string): unknown {\n\t\t\tconst id = graph.resolve(specifier, filename);\n\t\t\tconst evaluating = commonJsModules.get(id);\n\t\t\tif (evaluating !== undefined) return evaluating.exports;\n\t\t\tconst result: { readonly default?: unknown } = nativeRequire(id);\n\t\t\treturn commonJs.has(id) ? result.default : result;\n\t\t},\n\t\tevaluateCommonJs(filename: string, body: CommonJsBody): unknown {\n\t\t\tassertActive();\n\t\t\tconst id = moduleId(filename);\n\t\t\tconst module: CommonJsModule = { exports: {} };\n\t\t\tcommonJsModules.set(id, module);\n\t\t\ttry {\n\t\t\t\tbody.call(module.exports, module.exports, module);\n\t\t\t} catch (error) {\n\t\t\t\tcommonJsModules.delete(id);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn module.exports;\n\t\t},\n\t\tload(filename: string): ModuleSource {\n\t\t\tassertActive();\n\t\t\tconst existing = sources.get(filename);\n\t\t\tif (existing) return existing;\n\t\t\tconst source = readFileSync(filename, \"utf8\");\n\t\t\tlet name = \"__senpiExtensionMeta\";\n\t\t\twhile (source.includes(name)) name += \"_\";\n\t\t\tconst extension = extname(filename);\n\t\t\tconst transpiler = new Bun.Transpiler({\n\t\t\t\tloader: extension === \".tsx\" ? \"tsx\" : extension === \".jsx\" ? \"jsx\" : \"ts\",\n\t\t\t\ttarget: \"bun\",\n\t\t\t\tdefine: {\n\t\t\t\t\t\"import.meta\": name,\n\t\t\t\t\trequire: `${name}.require`,\n\t\t\t\t\t__filename: `${name}.path`,\n\t\t\t\t\t__dirname: `${name}.dir`,\n\t\t\t\t},\n\t\t\t});\n\t\t\tlet contents: string;\n\t\t\ttry {\n\t\t\t\tcontents = transpiler.transformSync(source);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof AggregateError) throw new ExtensionSourceError(filename, error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tconst [imports, , , hasModuleSyntax] = parse(contents, filename);\n\t\t\tconst edits: { readonly start: number; readonly end: number; readonly text: string }[] = [];\n\t\t\tlet commonJsImports = 0;\n\t\t\tfor (const edge of imports) {\n\t\t\t\tif (edge.type === \"dynamic\") {\n\t\t\t\t\t// Replace the keyword, not its argument: nested expressions, templates,\n\t\t\t\t\t// import attributes, and unavailable optional dependencies stay lazy.\n\t\t\t\t\tedits.push({ start: edge.importStart, end: edge.dynamicStart, text: `${name}.import` });\n\t\t\t\t} else if (edge.type === \"static\" || edge.type === \"reexport-star\") {\n\t\t\t\t\tconst target = resolveTarget(edge.specifier, filename);\n\t\t\t\t\tif (target.path !== undefined && isCommonJsFile(target.path)) {\n\t\t\t\t\t\t// \"import\" and \"export\" are both six characters, so the clause is\n\t\t\t\t\t\t// whatever sits between the keyword and the specifier in either form.\n\t\t\t\t\t\tconst clause = contents\n\t\t\t\t\t\t\t.slice(edge.importStart + \"import\".length, edge.start - 1)\n\t\t\t\t\t\t\t.replace(/\\bfrom\\s*$/, \"\");\n\t\t\t\t\t\t// This branch replaces the whole statement, so the attributes between the\n\t\t\t\t\t\t// specifier and the end of it have to travel with it: they pick the loader.\n\t\t\t\t\t\tconst attributes =\n\t\t\t\t\t\t\tedge.attributesStart < 0 ? \"\" : contents.slice(edge.end + 1, edge.importEnd).replace(/;\\s*$/, \"\");\n\t\t\t\t\t\tedits.push({\n\t\t\t\t\t\t\tstart: edge.importStart,\n\t\t\t\t\t\t\tend: edge.importEnd,\n\t\t\t\t\t\t\ttext: rewriteCommonJsImport(clause, target.id, `${name}Cjs${commonJsImports++}`, attributes),\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tedits.push({ start: edge.start - 1, end: edge.end + 1, text: JSON.stringify(target.id) });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const edit of edits.sort((a, b) => b.start - a.start)) {\n\t\t\t\tcontents = contents.slice(0, edit.start) + edit.text + contents.slice(edit.end);\n\t\t\t}\n\t\t\t// A shebang is only a shebang on the first line, so it goes before any prologue.\n\t\t\tcontents = contents.replace(/^#![^\\n]*\\n/, \"\");\n\t\t\t// Runtime plugins load ESM, even for CommonJS source. Node's module\n\t\t\t// function wrapper preserves synchronous export assignment and keeps\n\t\t\t// `exports` and `module` reassignable bindings with `this` as the exports\n\t\t\t// object, as dependencies such as whatwg-url and jsdom require.\n\t\t\tif (!hasModuleSyntax && extension !== \".mjs\" && extension !== \".mts\") {\n\t\t\t\tcommonJs.add(moduleId(filename));\n\t\t\t\tcontents = `export default ${name}.commonJs(function (exports, module) {\\n${contents}\\n});`;\n\t\t\t}\n\t\t\tcontents = `import { metadata as ${name}Factory } from \"${extensionNamespace}:runtime\";\\nconst ${name} = ${name}Factory(${JSON.stringify(registration.generation)}, ${JSON.stringify(filename)});\\n${contents}`;\n\t\t\tconst prepared = { contents, loader: \"js\" } satisfies ModuleSource;\n\t\t\tsources.set(filename, prepared);\n\t\t\treturn prepared;\n\t\t},\n\t};\n\tconst registration = registerExtensionGraph(graph, virtualModules);\n\treturn {\n\t\tasync import(path: string, _options: { readonly default: true }): Promise<unknown> {\n\t\t\tassertActive();\n\t\t\tconst absolute = realpathSync(resolve(path));\n\t\t\t// A package directory loads through its main or index file, as a native import does.\n\t\t\tconst entry = statSync(absolute).isDirectory() ? realpathSync(Bun.resolveSync(absolute, absolute)) : absolute;\n\t\t\tconst { id } = fileTarget(entry);\n\t\t\tconst module: { readonly default?: unknown } = await import(id);\n\t\t\tconst factory = module.default;\n\t\t\tif (typeof factory !== \"function\") return factory;\n\t\t\t// This wrapper is not stored in Bun's permanent module registry. A\n\t\t\t// reachable old factory keeps its own computed-import graph alive.\n\t\t\treturn function (this: unknown, ...args: unknown[]) {\n\t\t\t\tgraph.assertActive();\n\t\t\t\treturn factory.apply(this, args);\n\t\t\t};\n\t\t},\n\t\t// The generation's staleness check reads these: every source file it transpiled.\n\t\tcompiledFiles(): readonly string[] {\n\t\t\treturn [...sources.keys()];\n\t\t},\n\t\tdispose() {\n\t\t\tactive = false;\n\t\t\tregistration.dispose();\n\t\t\tsources.clear();\n\t\t\tcommonJs.clear();\n\t\t\tcommonJsModules.clear();\n\t\t},\n\t};\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { dirname } from "node:path";
|
|
2
|
+
import { dirname, isAbsolute } from "node:path";
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
4
|
import { publishRuntimeMetadata } from "./extension-runtime-module.js";
|
|
5
5
|
// esbuild reads an import() only when its second argument is fully static, and these
|
|
@@ -61,7 +61,10 @@ function graphFor(generation) {
|
|
|
61
61
|
function metadata(generation, filename) {
|
|
62
62
|
const resolvePath = (specifier) => {
|
|
63
63
|
const id = graphFor(generation).resolve(specifier, filename);
|
|
64
|
-
|
|
64
|
+
if (id.startsWith(`${extensionNamespace}:`))
|
|
65
|
+
return decodeURIComponent(id.slice(id.indexOf("/") + 1));
|
|
66
|
+
// Files Bun loads natively (JSON, assets) resolve to their real path, not a graph id.
|
|
67
|
+
return isAbsolute(id) ? id : undefined;
|
|
65
68
|
};
|
|
66
69
|
// CommonJS code calls `require.resolve` for sibling files (jsdom locates its XHR sync
|
|
67
70
|
// worker that way), so `require` is a function object carrying Node's resolver shape.
|
|
@@ -117,9 +120,7 @@ function installRegistry(virtualModules) {
|
|
|
117
120
|
if (parsed === undefined)
|
|
118
121
|
throw new ExtensionModuleIdError(path);
|
|
119
122
|
graphFor(parsed.generation);
|
|
120
|
-
return
|
|
121
|
-
? { path, namespace: extensionNamespace }
|
|
122
|
-
: { path: parsed.filename, namespace: "file" };
|
|
123
|
+
return { path, namespace: extensionNamespace };
|
|
123
124
|
});
|
|
124
125
|
builder.onLoad({ filter: /.*/, namespace: extensionNamespace }, ({ path }) => {
|
|
125
126
|
const parsed = splitModuleId(path);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun-extension-registry.js","sourceRoot":"","sources":["../../../src/core/extensions/bun-extension-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { publishRuntimeMetadata } from \"./extension-runtime-module.ts\";\n\nexport type ModuleSource = { readonly contents: string; readonly loader: \"js\" };\nexport type Resolution = { readonly path: string; readonly namespace: string };\nexport type CommonJsModule = { exports: unknown };\nexport type CommonJsBody = (this: unknown, exports: unknown, module: CommonJsModule) => void;\nexport interface ExtensionGraph {\n\tresolve(specifier: string, filename: string): string;\n\tload(filename: string): ModuleSource;\n\trequire(specifier: string, filename: string): unknown;\n\tevaluateCommonJs(filename: string, body: CommonJsBody): unknown;\n}\ntype ModuleObject = { readonly exports: Readonly<Record<string, unknown>>; readonly loader: \"object\" };\ndeclare const Bun: {\n\tplugin(options: {\n\t\treadonly name: string;\n\t\treadonly setup: (builder: {\n\t\t\tmodule(name: string, load: () => ModuleObject): void;\n\t\t\tonResolve(\n\t\t\t\toptions: { readonly filter: RegExp; readonly namespace: string },\n\t\t\t\tresolve: (args: { readonly path: string }) => Resolution,\n\t\t\t): void;\n\t\t\tonLoad(\n\t\t\t\toptions: { readonly filter: RegExp; readonly namespace: string },\n\t\t\t\tload: (args: { readonly path: string }) => ModuleSource,\n\t\t\t): void;\n\t\t}) => void;\n\t}): void;\n};\n\n// esbuild reads an import() only when its second argument is fully static, and these\n// attributes are whatever the extension wrote. The call stays dynamic either way, so\n// the importer is built at runtime and the bundler never has to read it.\nconst importModule = new Function(\"specifier\", \"options\", \"return import(specifier, options)\") as (\n\tspecifier: string,\n\toptions?: ImportCallOptions,\n) => Promise<unknown>;\n\nexport const extensionNamespace = \"senpi-extension\";\nconst RUNTIME_SPECIFIER = \"runtime\";\n// Inside a `bun build --compile` binary the shim has no on-disk path (import.meta.url is a\n// $bunfs URL), so the file route is only available when the file is really there; the compiled\n// binary keeps the virtual module, which it never had a problem with.\nconst runtimeModulePath = resolveRuntimeModulePath();\n\nfunction resolveRuntimeModulePath(): string | undefined {\n\ttry {\n\t\tconst candidate = fileURLToPath(new URL(\"./extension-runtime-module.js\", import.meta.url));\n\t\treturn existsSync(candidate) ? candidate : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n// An id is `<generation>/<encodeURIComponent(filename)>`. The encoded half never contains a\n// literal \"/\" (Windows separators arrive as %5C), so the FIRST slash is always the generation\n// separator — but only when one exists. A bare id with no slash used to slice to nonsense and\n// surface as `Cannot find package '<generation>'` (omo#8427).\nfunction splitModuleId(id: string): { readonly generation: string; readonly filename: string } | undefined {\n\tconst slash = id.indexOf(\"/\");\n\tif (slash <= 0 || slash === id.length - 1) return undefined;\n\treturn { generation: id.slice(0, slash), filename: decodeURIComponent(id.slice(slash + 1)) };\n}\nconst graphs = new Map<string, WeakRef<ExtensionGraph>>();\nconst collected = new FinalizationRegistry<string>((generation) => graphs.delete(generation));\nlet nextGeneration = 0;\nlet installed = false;\nlet pluginRegistrations = 0;\nconst registeredHosts = new Set<string>();\n\nexport class ExtensionModuleIdError extends Error {\n\treadonly name = \"ExtensionModuleIdError\";\n\tconstructor(id: string) {\n\t\tsuper(`Extension module id is not \"<generation>/<encoded filename>\": ${id}`);\n\t}\n}\n\nexport class ExtensionGenerationDisposedError extends Error {\n\treadonly name = \"ExtensionGenerationDisposedError\";\n\treadonly generation: string;\n\tconstructor(generation: string) {\n\t\tsuper(`Extension generation ${generation} has been disposed`);\n\t\tthis.generation = generation;\n\t}\n}\nfunction graphFor(generation: string): ExtensionGraph {\n\tconst graph = graphs.get(generation)?.deref();\n\tif (!graph) throw new ExtensionGenerationDisposedError(generation);\n\treturn graph;\n}\n\n// Module-registry exports must never close over a graph: Bun retains modules.\n// Only the importer, returned factory wrappers, and live runtimes own graphs.\nfunction metadata(generation: string, filename: string) {\n\tconst resolvePath = (specifier: string) => {\n\t\tconst id = graphFor(generation).resolve(specifier, filename);\n\t\treturn id.startsWith(`${extensionNamespace}:`) ? decodeURIComponent(id.slice(id.indexOf(\"/\") + 1)) : undefined;\n\t};\n\t// CommonJS code calls `require.resolve` for sibling files (jsdom locates its XHR sync\n\t// worker that way), so `require` is a function object carrying Node's resolver shape.\n\tconst require = Object.assign((specifier: string) => graphFor(generation).require(specifier, filename), {\n\t\tresolve: (specifier: string) => resolvePath(specifier) ?? graphFor(generation).resolve(specifier, filename),\n\t});\n\treturn {\n\t\turl: pathToFileURL(filename).href,\n\t\tpath: filename,\n\t\tdir: dirname(filename),\n\t\trequire,\n\t\tcommonJs: (body: CommonJsBody) => graphFor(generation).evaluateCommonJs(filename, body),\n\t\timport: async (specifier: string, options?: ImportCallOptions) =>\n\t\t\timportModule(graphFor(generation).resolve(specifier, filename), options),\n\t\tresolve: (specifier: string) => {\n\t\t\tconst path = resolvePath(specifier);\n\t\t\treturn path === undefined ? graphFor(generation).resolve(specifier, filename) : pathToFileURL(path).href;\n\t\t},\n\t};\n}\n\n// A separate activation prevents permanent hooks from sharing a closure\n// environment with registerExtensionGraph's disposable graph reference.\nfunction installRegistry(virtualModules: Readonly<Record<string, Readonly<Record<string, unknown>>>>) {\n\tconst hosts = Object.entries(virtualModules).filter(([name]) => !registeredHosts.has(name));\n\tif (!installed || hosts.length > 0) {\n\t\tpluginRegistrations++;\n\t\tBun.plugin({\n\t\t\tname: extensionNamespace,\n\t\t\tsetup(builder) {\n\t\t\t\tfor (const [name, exports] of hosts) {\n\t\t\t\t\tbuilder.module(name, () => ({ exports, loader: \"object\" }));\n\t\t\t\t\tregisteredHosts.add(name);\n\t\t\t\t}\n\t\t\t\tif (installed) return;\n\t\t\t\t// \"runtime\" resolves to a real file, never a Bun.plugin virtual module. A\n\t\t\t\t// builder.module() registration is intermittently invisible to the resolver under\n\t\t\t\t// `bun test --parallel` on a loaded Windows shard: onResolve still fires and returns\n\t\t\t\t// the namespace, the registration is still listed, and Bun answers\n\t\t\t\t// `Cannot find package 'runtime'` anyway — generation 1 served 40 resolves and\n\t\t\t\t// refused the 41st in the same worker (omo#8427, run 35329245740). A file on disk\n\t\t\t\t// has no registration window to lose.\n\t\t\t\tpublishRuntimeMetadata(metadata);\n\t\t\t\tbuilder.module(`${extensionNamespace}:${RUNTIME_SPECIFIER}`, () => ({\n\t\t\t\t\texports: { metadata },\n\t\t\t\t\tloader: \"object\",\n\t\t\t\t}));\n\t\t\t\tbuilder.onResolve({ filter: /.*/, namespace: extensionNamespace }, ({ path }) => {\n\t\t\t\t\tif (path === RUNTIME_SPECIFIER)\n\t\t\t\t\t\treturn runtimeModulePath === undefined\n\t\t\t\t\t\t\t? { path, namespace: extensionNamespace }\n\t\t\t\t\t\t\t: { path: runtimeModulePath, namespace: \"file\" };\n\t\t\t\t\tconst parsed = splitModuleId(path);\n\t\t\t\t\tif (parsed === undefined) throw new ExtensionModuleIdError(path);\n\t\t\t\t\tgraphFor(parsed.generation);\n\t\t\t\t\treturn /\\.[cm]?[jt]sx?$/.test(parsed.filename)\n\t\t\t\t\t\t? { path, namespace: extensionNamespace }\n\t\t\t\t\t\t: { path: parsed.filename, namespace: \"file\" };\n\t\t\t\t});\n\t\t\t\tbuilder.onLoad({ filter: /.*/, namespace: extensionNamespace }, ({ path }) => {\n\t\t\t\t\tconst parsed = splitModuleId(path);\n\t\t\t\t\tif (parsed === undefined) throw new ExtensionModuleIdError(path);\n\t\t\t\t\treturn graphFor(parsed.generation).load(parsed.filename);\n\t\t\t\t});\n\t\t\t\tinstalled = true;\n\t\t\t},\n\t\t});\n\t}\n}\n\nexport function registerExtensionGraph(\n\tgraph: ExtensionGraph,\n\tvirtualModules: Readonly<Record<string, Readonly<Record<string, unknown>>>>,\n) {\n\tinstallRegistry(virtualModules);\n\tconst generation = String(nextGeneration++);\n\tgraphs.set(generation, new WeakRef(graph));\n\tcollected.register(graph, generation, graph);\n\treturn {\n\t\tgeneration,\n\t\tdispose() {\n\t\t\tgraphs.delete(generation);\n\t\t\tcollected.unregister(graph);\n\t\t},\n\t};\n}\n\n/** Internal lifecycle diagnostics, shared by regression and compiled probes. */\nexport function bunExtensionImporterStats() {\n\treturn { generations: [...graphs.values()].filter((entry) => entry.deref()).length, plugins: pluginRegistrations };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bun-extension-registry.js","sourceRoot":"","sources":["../../../src/core/extensions/bun-extension-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { dirname, isAbsolute } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { publishRuntimeMetadata } from \"./extension-runtime-module.ts\";\n\nexport type ModuleSource = { readonly contents: string; readonly loader: \"js\" };\nexport type Resolution = { readonly path: string; readonly namespace: string };\nexport type CommonJsModule = { exports: unknown };\nexport type CommonJsBody = (this: unknown, exports: unknown, module: CommonJsModule) => void;\nexport interface ExtensionGraph {\n\tresolve(specifier: string, filename: string): string;\n\tload(filename: string): ModuleSource;\n\trequire(specifier: string, filename: string): unknown;\n\tevaluateCommonJs(filename: string, body: CommonJsBody): unknown;\n}\ntype ModuleObject = { readonly exports: Readonly<Record<string, unknown>>; readonly loader: \"object\" };\ndeclare const Bun: {\n\tplugin(options: {\n\t\treadonly name: string;\n\t\treadonly setup: (builder: {\n\t\t\tmodule(name: string, load: () => ModuleObject): void;\n\t\t\tonResolve(\n\t\t\t\toptions: { readonly filter: RegExp; readonly namespace: string },\n\t\t\t\tresolve: (args: { readonly path: string }) => Resolution,\n\t\t\t): void;\n\t\t\tonLoad(\n\t\t\t\toptions: { readonly filter: RegExp; readonly namespace: string },\n\t\t\t\tload: (args: { readonly path: string }) => ModuleSource,\n\t\t\t): void;\n\t\t}) => void;\n\t}): void;\n};\n\n// esbuild reads an import() only when its second argument is fully static, and these\n// attributes are whatever the extension wrote. The call stays dynamic either way, so\n// the importer is built at runtime and the bundler never has to read it.\nconst importModule = new Function(\"specifier\", \"options\", \"return import(specifier, options)\") as (\n\tspecifier: string,\n\toptions?: ImportCallOptions,\n) => Promise<unknown>;\n\nexport const extensionNamespace = \"senpi-extension\";\nconst RUNTIME_SPECIFIER = \"runtime\";\n// Inside a `bun build --compile` binary the shim has no on-disk path (import.meta.url is a\n// $bunfs URL), so the file route is only available when the file is really there; the compiled\n// binary keeps the virtual module, which it never had a problem with.\nconst runtimeModulePath = resolveRuntimeModulePath();\n\nfunction resolveRuntimeModulePath(): string | undefined {\n\ttry {\n\t\tconst candidate = fileURLToPath(new URL(\"./extension-runtime-module.js\", import.meta.url));\n\t\treturn existsSync(candidate) ? candidate : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n// An id is `<generation>/<encodeURIComponent(filename)>`. The encoded half never contains a\n// literal \"/\" (Windows separators arrive as %5C), so the FIRST slash is always the generation\n// separator — but only when one exists. A bare id with no slash used to slice to nonsense and\n// surface as `Cannot find package '<generation>'` (omo#8427).\nfunction splitModuleId(id: string): { readonly generation: string; readonly filename: string } | undefined {\n\tconst slash = id.indexOf(\"/\");\n\tif (slash <= 0 || slash === id.length - 1) return undefined;\n\treturn { generation: id.slice(0, slash), filename: decodeURIComponent(id.slice(slash + 1)) };\n}\nconst graphs = new Map<string, WeakRef<ExtensionGraph>>();\nconst collected = new FinalizationRegistry<string>((generation) => graphs.delete(generation));\nlet nextGeneration = 0;\nlet installed = false;\nlet pluginRegistrations = 0;\nconst registeredHosts = new Set<string>();\n\nexport class ExtensionModuleIdError extends Error {\n\treadonly name = \"ExtensionModuleIdError\";\n\tconstructor(id: string) {\n\t\tsuper(`Extension module id is not \"<generation>/<encoded filename>\": ${id}`);\n\t}\n}\n\nexport class ExtensionGenerationDisposedError extends Error {\n\treadonly name = \"ExtensionGenerationDisposedError\";\n\treadonly generation: string;\n\tconstructor(generation: string) {\n\t\tsuper(`Extension generation ${generation} has been disposed`);\n\t\tthis.generation = generation;\n\t}\n}\nfunction graphFor(generation: string): ExtensionGraph {\n\tconst graph = graphs.get(generation)?.deref();\n\tif (!graph) throw new ExtensionGenerationDisposedError(generation);\n\treturn graph;\n}\n\n// Module-registry exports must never close over a graph: Bun retains modules.\n// Only the importer, returned factory wrappers, and live runtimes own graphs.\nfunction metadata(generation: string, filename: string) {\n\tconst resolvePath = (specifier: string) => {\n\t\tconst id = graphFor(generation).resolve(specifier, filename);\n\t\tif (id.startsWith(`${extensionNamespace}:`)) return decodeURIComponent(id.slice(id.indexOf(\"/\") + 1));\n\t\t// Files Bun loads natively (JSON, assets) resolve to their real path, not a graph id.\n\t\treturn isAbsolute(id) ? id : undefined;\n\t};\n\t// CommonJS code calls `require.resolve` for sibling files (jsdom locates its XHR sync\n\t// worker that way), so `require` is a function object carrying Node's resolver shape.\n\tconst require = Object.assign((specifier: string) => graphFor(generation).require(specifier, filename), {\n\t\tresolve: (specifier: string) => resolvePath(specifier) ?? graphFor(generation).resolve(specifier, filename),\n\t});\n\treturn {\n\t\turl: pathToFileURL(filename).href,\n\t\tpath: filename,\n\t\tdir: dirname(filename),\n\t\trequire,\n\t\tcommonJs: (body: CommonJsBody) => graphFor(generation).evaluateCommonJs(filename, body),\n\t\timport: async (specifier: string, options?: ImportCallOptions) =>\n\t\t\timportModule(graphFor(generation).resolve(specifier, filename), options),\n\t\tresolve: (specifier: string) => {\n\t\t\tconst path = resolvePath(specifier);\n\t\t\treturn path === undefined ? graphFor(generation).resolve(specifier, filename) : pathToFileURL(path).href;\n\t\t},\n\t};\n}\n\n// A separate activation prevents permanent hooks from sharing a closure\n// environment with registerExtensionGraph's disposable graph reference.\nfunction installRegistry(virtualModules: Readonly<Record<string, Readonly<Record<string, unknown>>>>) {\n\tconst hosts = Object.entries(virtualModules).filter(([name]) => !registeredHosts.has(name));\n\tif (!installed || hosts.length > 0) {\n\t\tpluginRegistrations++;\n\t\tBun.plugin({\n\t\t\tname: extensionNamespace,\n\t\t\tsetup(builder) {\n\t\t\t\tfor (const [name, exports] of hosts) {\n\t\t\t\t\tbuilder.module(name, () => ({ exports, loader: \"object\" }));\n\t\t\t\t\tregisteredHosts.add(name);\n\t\t\t\t}\n\t\t\t\tif (installed) return;\n\t\t\t\t// \"runtime\" resolves to a real file, never a Bun.plugin virtual module. A\n\t\t\t\t// builder.module() registration is intermittently invisible to the resolver under\n\t\t\t\t// `bun test --parallel` on a loaded Windows shard: onResolve still fires and returns\n\t\t\t\t// the namespace, the registration is still listed, and Bun answers\n\t\t\t\t// `Cannot find package 'runtime'` anyway — generation 1 served 40 resolves and\n\t\t\t\t// refused the 41st in the same worker (omo#8427, run 35329245740). A file on disk\n\t\t\t\t// has no registration window to lose.\n\t\t\t\tpublishRuntimeMetadata(metadata);\n\t\t\t\tbuilder.module(`${extensionNamespace}:${RUNTIME_SPECIFIER}`, () => ({\n\t\t\t\t\texports: { metadata },\n\t\t\t\t\tloader: \"object\",\n\t\t\t\t}));\n\t\t\t\tbuilder.onResolve({ filter: /.*/, namespace: extensionNamespace }, ({ path }) => {\n\t\t\t\t\tif (path === RUNTIME_SPECIFIER)\n\t\t\t\t\t\treturn runtimeModulePath === undefined\n\t\t\t\t\t\t\t? { path, namespace: extensionNamespace }\n\t\t\t\t\t\t\t: { path: runtimeModulePath, namespace: \"file\" };\n\t\t\t\t\tconst parsed = splitModuleId(path);\n\t\t\t\t\tif (parsed === undefined) throw new ExtensionModuleIdError(path);\n\t\t\t\t\tgraphFor(parsed.generation);\n\t\t\t\t\treturn { path, namespace: extensionNamespace };\n\t\t\t\t});\n\t\t\t\tbuilder.onLoad({ filter: /.*/, namespace: extensionNamespace }, ({ path }) => {\n\t\t\t\t\tconst parsed = splitModuleId(path);\n\t\t\t\t\tif (parsed === undefined) throw new ExtensionModuleIdError(path);\n\t\t\t\t\treturn graphFor(parsed.generation).load(parsed.filename);\n\t\t\t\t});\n\t\t\t\tinstalled = true;\n\t\t\t},\n\t\t});\n\t}\n}\n\nexport function registerExtensionGraph(\n\tgraph: ExtensionGraph,\n\tvirtualModules: Readonly<Record<string, Readonly<Record<string, unknown>>>>,\n) {\n\tinstallRegistry(virtualModules);\n\tconst generation = String(nextGeneration++);\n\tgraphs.set(generation, new WeakRef(graph));\n\tcollected.register(graph, generation, graph);\n\treturn {\n\t\tgeneration,\n\t\tdispose() {\n\t\t\tgraphs.delete(generation);\n\t\t\tcollected.unregister(graph);\n\t\t},\n\t};\n}\n\n/** Internal lifecycle diagnostics, shared by regression and compiled probes. */\nexport function bunExtensionImporterStats() {\n\treturn { generations: [...graphs.values()].filter((entry) => entry.deref()).length, plugins: pluginRegistrations };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/core/messages.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAGN,KAAK,YAAY,EACjB,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/core/messages.ts"],"names":[],"mappings":"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"}
|
package/dist/core/messages.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { copyContextProvenance, dropFailedAssistantTurns, } from "@earendil-works/pi-ai";
|
|
8
8
|
import { ENVIRONMENT_CONTEXT_MESSAGE_TYPE, foldEnvironmentContextIntoNextUserMessage } from "./environment-context.js";
|
|
9
|
+
import { omitProviderRejectedImages } from "./provider-rejected-images.js";
|
|
9
10
|
export const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:
|
|
10
11
|
|
|
11
12
|
<summary>
|
|
@@ -161,8 +162,9 @@ export function convertToLlm(messages) {
|
|
|
161
162
|
// deterministic per session state, so the cache-prefix guarantee above holds.
|
|
162
163
|
// senpi#2118: the environment context then becomes the leading block of the
|
|
163
164
|
// user message it precedes, so strict-alternation chat templates never see
|
|
164
|
-
// two consecutive user messages.
|
|
165
|
-
|
|
165
|
+
// two consecutive user messages. senpi#2170: images a failed turn proves the
|
|
166
|
+
// provider rejected are replaced first, while the failed turn is still visible.
|
|
167
|
+
return foldEnvironmentContextIntoNextUserMessage(dropFailedAssistantTurns(omitProviderRejectedImages(converted)), environmentMessages);
|
|
166
168
|
}
|
|
167
169
|
// ============================================================================
|
|
168
170
|
// Transport image budget
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/core/messages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Custom message types and transformers for the coding agent.\n *\n * Extends the base AgentMessage type with coding-agent specific message types,\n * and provides a transformer to convert them to LLM-compatible messages.\n */\n\nimport type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport {\n\tcopyContextProvenance,\n\tdropFailedAssistantTurns,\n\ttype ImageContent,\n\ttype Message,\n\ttype TextContent,\n} from \"@earendil-works/pi-ai\";\nimport { ENVIRONMENT_CONTEXT_MESSAGE_TYPE, foldEnvironmentContextIntoNextUserMessage } from \"./environment-context.ts\";\n\nexport const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:\n\n<summary>\n`;\n\nexport const COMPACTION_SUMMARY_SUFFIX = `\n</summary>`;\n\nexport const BRANCH_SUMMARY_PREFIX = `The following is a summary of a branch that this conversation came back from:\n\n<summary>\n`;\n\nexport const BRANCH_SUMMARY_SUFFIX = `</summary>`;\n\nexport const GOAL_CONTINUATION_MESSAGE_TYPE = \"goal-continuation\";\n\n/**\n * Per-type exclusion must remain false: compaction and branch summarization\n * inspect entries independently, where excluding this type would hide the live\n * goal-continuation message.\n */\nexport function isContextExcludedCustomMessage(_customType: string): boolean {\n\treturn false;\n}\n\n/**\n * Whole-context filtering is deliberately a no-op. Goal continuations are\n * append-only: dropping an already-sent continuation would rewrite a\n * provider-visible turn, so request N would stop being a prefix of request N+1\n * and every cached token ahead of the edit would be invalidated (full re-read,\n * cost spike, 429 storms in team mode). Continuation history is bounded by\n * normal compaction instead of by per-request deletion.\n */\nexport function filterContextExcludedMessages(messages: AgentMessage[]): AgentMessage[] {\n\treturn messages;\n}\n\n/**\n * Message type for bash executions via the ! command.\n */\nexport interface BashExecutionMessage {\n\trole: \"bashExecution\";\n\tcommand: string;\n\toutput: string;\n\texitCode: number | undefined;\n\tcancelled: boolean;\n\ttruncated: boolean;\n\tfullOutputPath?: string;\n\ttimestamp: number;\n\t/** If true, this message is excluded from LLM context (!! prefix) */\n\texcludeFromContext?: boolean;\n}\n\n/**\n * Message type for extension-injected messages via sendMessage().\n * These are custom messages that extensions can inject into the conversation.\n */\nexport interface CustomMessage<T = unknown> {\n\trole: \"custom\";\n\tcustomType: string;\n\tcontent: string | (TextContent | ImageContent)[];\n\tdisplay: boolean;\n\tdetails?: T;\n\ttimestamp: number;\n}\n\nexport interface BranchSummaryMessage {\n\trole: \"branchSummary\";\n\tsummary: string;\n\tfromId: string | null;\n\ttimestamp: number;\n}\n\nexport interface CompactionSummaryMessage {\n\trole: \"compactionSummary\";\n\tsummary: string;\n\ttokensBefore: number;\n\tdetails?: unknown;\n\ttimestamp: number;\n}\n\nexport interface ConfigurationUpdateMessage {\n\trole: \"configurationUpdate\";\n\tcontent: (TextContent | ImageContent)[];\n\teffort: string;\n\ttimestamp: number;\n}\n\n// Extend CustomAgentMessages via declaration merging\ndeclare module \"@earendil-works/pi-agent-core\" {\n\tinterface CustomAgentMessages {\n\t\tbashExecution: BashExecutionMessage;\n\t\tcustom: CustomMessage;\n\t\tbranchSummary: BranchSummaryMessage;\n\t\tconfigurationUpdate: ConfigurationUpdateMessage;\n\t}\n}\n\n/**\n * Convert a BashExecutionMessage to user message text for LLM context.\n */\nexport function bashExecutionToText(msg: BashExecutionMessage): string {\n\tlet text = `Ran \\`${msg.command}\\`\\n`;\n\tif (msg.output) {\n\t\ttext += `\\`\\`\\`\\n${msg.output}\\n\\`\\`\\``;\n\t} else {\n\t\ttext += \"(no output)\";\n\t}\n\tif (msg.cancelled) {\n\t\ttext += \"\\n\\n(command cancelled)\";\n\t} else if (msg.exitCode !== null && msg.exitCode !== undefined && msg.exitCode !== 0) {\n\t\ttext += `\\n\\nCommand exited with code ${msg.exitCode}`;\n\t}\n\tif (msg.truncated && msg.fullOutputPath) {\n\t\ttext += `\\n\\n[Output truncated. Full output: ${msg.fullOutputPath}]`;\n\t}\n\treturn text;\n}\n\nexport function createBranchSummaryMessage(summary: string, fromId: string, timestamp: string): BranchSummaryMessage {\n\treturn {\n\t\trole: \"branchSummary\",\n\t\tsummary,\n\t\tfromId,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\nexport function createCompactionSummaryMessage(\n\tsummary: string,\n\ttokensBefore: number,\n\ttimestamp: string,\n\tdetails?: unknown,\n): CompactionSummaryMessage {\n\treturn {\n\t\trole: \"compactionSummary\",\n\t\tsummary: summary,\n\t\ttokensBefore,\n\t\tdetails,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\n/** Convert CustomMessageEntry to AgentMessage format */\nexport function createCustomMessage(\n\tcustomType: string,\n\tcontent: string | (TextContent | ImageContent)[],\n\tdisplay: boolean,\n\tdetails: unknown | undefined,\n\ttimestamp: string,\n): CustomMessage {\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType,\n\t\tcontent,\n\t\tdisplay,\n\t\tdetails,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\n/**\n * Transform AgentMessages (including custom types) to LLM-compatible Messages.\n *\n * This is used by:\n * - Agent's transormToLlm option (for prompt calls and queued messages)\n * - Compaction's generateSummary (for summarization)\n * - Custom extensions and tools\n */\nexport function convertToLlm(messages: AgentMessage[]): Message[] {\n\tconst withContextProvenance = <T extends Message>(source: AgentMessage, target: T): T =>\n\t\tcopyContextProvenance(source, target);\n\t// Continuations are append-only here too: the transport array must extend the\n\t// previous request verbatim to keep the provider's cache prefix valid.\n\tconst environmentMessages = new Set<Message>();\n\tconst converted = messages\n\t\t.map((m): Message | undefined => {\n\t\t\tswitch (m.role) {\n\t\t\t\tcase \"bashExecution\":\n\t\t\t\t\t// Skip messages excluded from context (!! prefix)\n\t\t\t\t\tif (m.excludeFromContext) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\treturn withContextProvenance(m, {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: bashExecutionToText(m) }],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t});\n\t\t\t\tcase \"custom\": {\n\t\t\t\t\tif (isContextExcludedCustomMessage(m.customType)) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst content = typeof m.content === \"string\" ? [{ type: \"text\" as const, text: m.content }] : m.content;\n\t\t\t\t\tconst converted = withContextProvenance(m, {\n\t\t\t\t\t\trole: \"user\" as const,\n\t\t\t\t\t\tcontent,\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t});\n\t\t\t\t\tif (m.customType === ENVIRONMENT_CONTEXT_MESSAGE_TYPE) environmentMessages.add(converted);\n\t\t\t\t\treturn converted;\n\t\t\t\t}\n\t\t\t\tcase \"branchSummary\":\n\t\t\t\t\treturn withContextProvenance(m, {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text: BRANCH_SUMMARY_PREFIX + m.summary + BRANCH_SUMMARY_SUFFIX }],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t});\n\t\t\t\tcase \"compactionSummary\":\n\t\t\t\t\treturn withContextProvenance(m, {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t{ type: \"text\" as const, text: COMPACTION_SUMMARY_PREFIX + m.summary + COMPACTION_SUMMARY_SUFFIX },\n\t\t\t\t\t\t],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t});\n\t\t\t\tcase \"configurationUpdate\":\n\t\t\t\t\treturn m;\n\t\t\t\tcase \"user\":\n\t\t\t\tcase \"assistant\":\n\t\t\t\tcase \"toolResult\":\n\t\t\t\t\treturn m;\n\t\t\t\tdefault:\n\t\t\t\t\t// biome-ignore lint/correctness/noSwitchDeclarations: fine\n\t\t\t\t\tconst _exhaustiveCheck: never = m;\n\t\t\t\t\treturn undefined;\n\t\t\t}\n\t\t})\n\t\t.filter((m) => m !== undefined);\n\t// Failed provider turns (stopReason error/aborted) must never reach an LLM\n\t// request: lanes that build requests straight from this output (claude-sdk\n\t// prompt bridge, cursor turns) would otherwise replay their partial text and\n\t// unexecuted tool calls, and token estimation would count them. Dropping is\n\t// deterministic per session state, so the cache-prefix guarantee above holds.\n\t// senpi#2118: the environment context then becomes the leading block of the\n\t// user message it precedes, so strict-alternation chat templates never see\n\t// two consecutive user messages.\n\treturn foldEnvironmentContextIntoNextUserMessage(dropFailedAssistantTurns(converted), environmentMessages);\n}\n\n// ============================================================================\n// Transport image budget\n// ============================================================================\n\n/**\n * Cap on inline image base64 (characters approximately equal wire bytes) per\n * provider request. Anthropic documents a 32 MB request limit; reserving the\n * remainder for text and request overhead keeps the transport below that wall.\n */\nexport const TRANSPORT_IMAGE_BUDGET_BYTES = 24 * 1024 * 1024;\n\nexport const IMAGE_ELISION_PLACEHOLDER =\n\t\"[Image elided: an older image was removed to keep the request within the provider's size limit. Re-read the source file if you need to view it again.]\";\n\nexport const BLOCKED_IMAGE_PLACEHOLDER = \"Image reading is disabled.\";\n\nexport interface ElideOldImagesOptions {\n\t/** Cumulative inline image base64 budget. Defaults to TRANSPORT_IMAGE_BUDGET_BYTES. */\n\tbudgetBytes?: number;\n\t/** Newest image blocks always kept regardless of budget. They still consume it. Defaults to 1. */\n\talwaysKeepNewest?: number;\n\t/** Keep at most this many images from turns completed by a later assistant response. */\n\tmaxHistoricalImages?: number;\n}\n\nexport interface TransportConvertOptions extends ElideOldImagesOptions {\n\t/** Replace every image when the images.blockImages setting is enabled. */\n\tblockImages: boolean;\n}\n\n/** Drop consecutive duplicates of a placeholder produced by adjacent image replacements. */\nexport function dedupeConsecutivePlaceholder(\n\tcontent: (TextContent | ImageContent)[],\n\tplaceholder: string,\n): (TextContent | ImageContent)[] {\n\treturn content.filter(\n\t\t(block, index, blocks) =>\n\t\t\t!(\n\t\t\t\tblock.type === \"text\" &&\n\t\t\t\tblock.text === placeholder &&\n\t\t\t\tindex > 0 &&\n\t\t\t\tblocks[index - 1].type === \"text\" &&\n\t\t\t\t(blocks[index - 1] as TextContent).text === placeholder\n\t\t\t),\n\t);\n}\n\n/**\n * Bound inline image payload at request-build time. Images are considered from\n * newest to oldest. Once an image would exceed the budget, it and every older\n * image are replaced by a text placeholder. The newest protected blocks are\n * kept regardless of size, but still consume the budget.\n *\n * The input and persisted session remain untouched. If every image fits, the\n * original array reference is returned.\n */\nexport function elideOldImages(messages: Message[], options?: ElideOldImagesOptions): Message[] {\n\tconst budgetBytes = options?.budgetBytes ?? TRANSPORT_IMAGE_BUDGET_BYTES;\n\tconst alwaysKeepNewest = options?.alwaysKeepNewest ?? 1;\n\tconst maxHistoricalImages = options?.maxHistoricalImages;\n\tconst limitHistory = maxHistoricalImages !== undefined;\n\tconst lastAssistantIndex = messages.findLastIndex((message) => message.role === \"assistant\");\n\tconst imagesToElide = new Set<string>();\n\tlet keptImages = 0;\n\tlet keptHistoricalImages = 0;\n\tlet imageBytes = 0;\n\tlet cutoffReached = false;\n\n\tfor (let messageIndex = messages.length - 1; messageIndex >= 0; messageIndex--) {\n\t\tconst message = messages[messageIndex];\n\t\tif ((message.role !== \"user\" && message.role !== \"toolResult\") || !Array.isArray(message.content)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (let blockIndex = message.content.length - 1; blockIndex >= 0; blockIndex--) {\n\t\t\tconst block = message.content[blockIndex];\n\t\t\tif (block.type !== \"image\") continue;\n\t\t\tconst isCurrentTurn = limitHistory && messageIndex > lastAssistantIndex;\n\t\t\tconst isProtectedHistory = limitHistory && !isCurrentTurn && keptHistoricalImages < maxHistoricalImages;\n\t\t\tconst exceedsHistoryLimit = limitHistory && !isCurrentTurn && !isProtectedHistory;\n\n\t\t\tif (exceedsHistoryLimit || (cutoffReached && !isCurrentTurn && !isProtectedHistory)) {\n\t\t\t\timagesToElide.add(`${messageIndex}:${blockIndex}`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tisCurrentTurn ||\n\t\t\t\tisProtectedHistory ||\n\t\t\t\tkeptImages < alwaysKeepNewest ||\n\t\t\t\timageBytes + block.data.length <= budgetBytes\n\t\t\t) {\n\t\t\t\tkeptImages++;\n\t\t\t\tif (!isCurrentTurn) keptHistoricalImages++;\n\t\t\t\timageBytes += block.data.length;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcutoffReached = true;\n\t\t\timagesToElide.add(`${messageIndex}:${blockIndex}`);\n\t\t}\n\t}\n\n\tif (imagesToElide.size === 0) return messages;\n\n\treturn messages.map((message, messageIndex) => {\n\t\tif ((message.role !== \"user\" && message.role !== \"toolResult\") || !Array.isArray(message.content)) {\n\t\t\treturn message;\n\t\t}\n\t\tif (!message.content.some((_block, blockIndex) => imagesToElide.has(`${messageIndex}:${blockIndex}`))) {\n\t\t\treturn message;\n\t\t}\n\n\t\tconst replaced = message.content.map((block, blockIndex): TextContent | ImageContent =>\n\t\t\timagesToElide.has(`${messageIndex}:${blockIndex}`) ? { type: \"text\", text: IMAGE_ELISION_PLACEHOLDER } : block,\n\t\t);\n\t\treturn {\n\t\t\t...message,\n\t\t\tcontent: dedupeConsecutivePlaceholder(replaced, IMAGE_ELISION_PLACEHOLDER) as typeof message.content,\n\t\t};\n\t});\n}\n\n/** Convert messages for the main provider transport and apply its image policy. */\nexport function convertToLlmForTransport(messages: AgentMessage[], options: TransportConvertOptions): Message[] {\n\tconst converted = convertToLlm(messages);\n\tif (!options.blockImages) return elideOldImages(converted, options);\n\n\treturn converted.map((message) => {\n\t\tif ((message.role !== \"user\" && message.role !== \"toolResult\") || !Array.isArray(message.content)) {\n\t\t\treturn message;\n\t\t}\n\t\tif (!message.content.some((block) => block.type === \"image\")) return message;\n\n\t\tconst replaced = message.content.map((block): TextContent | ImageContent =>\n\t\t\tblock.type === \"image\" ? { type: \"text\", text: BLOCKED_IMAGE_PLACEHOLDER } : block,\n\t\t);\n\t\treturn {\n\t\t\t...message,\n\t\t\tcontent: dedupeConsecutivePlaceholder(replaced, BLOCKED_IMAGE_PLACEHOLDER) as typeof message.content,\n\t\t};\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/core/messages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Custom message types and transformers for the coding agent.\n *\n * Extends the base AgentMessage type with coding-agent specific message types,\n * and provides a transformer to convert them to LLM-compatible messages.\n */\n\nimport type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport {\n\tcopyContextProvenance,\n\tdropFailedAssistantTurns,\n\ttype ImageContent,\n\ttype Message,\n\ttype TextContent,\n} from \"@earendil-works/pi-ai\";\nimport { ENVIRONMENT_CONTEXT_MESSAGE_TYPE, foldEnvironmentContextIntoNextUserMessage } from \"./environment-context.ts\";\nimport { omitProviderRejectedImages } from \"./provider-rejected-images.ts\";\n\nexport const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:\n\n<summary>\n`;\n\nexport const COMPACTION_SUMMARY_SUFFIX = `\n</summary>`;\n\nexport const BRANCH_SUMMARY_PREFIX = `The following is a summary of a branch that this conversation came back from:\n\n<summary>\n`;\n\nexport const BRANCH_SUMMARY_SUFFIX = `</summary>`;\n\nexport const GOAL_CONTINUATION_MESSAGE_TYPE = \"goal-continuation\";\n\n/**\n * Per-type exclusion must remain false: compaction and branch summarization\n * inspect entries independently, where excluding this type would hide the live\n * goal-continuation message.\n */\nexport function isContextExcludedCustomMessage(_customType: string): boolean {\n\treturn false;\n}\n\n/**\n * Whole-context filtering is deliberately a no-op. Goal continuations are\n * append-only: dropping an already-sent continuation would rewrite a\n * provider-visible turn, so request N would stop being a prefix of request N+1\n * and every cached token ahead of the edit would be invalidated (full re-read,\n * cost spike, 429 storms in team mode). Continuation history is bounded by\n * normal compaction instead of by per-request deletion.\n */\nexport function filterContextExcludedMessages(messages: AgentMessage[]): AgentMessage[] {\n\treturn messages;\n}\n\n/**\n * Message type for bash executions via the ! command.\n */\nexport interface BashExecutionMessage {\n\trole: \"bashExecution\";\n\tcommand: string;\n\toutput: string;\n\texitCode: number | undefined;\n\tcancelled: boolean;\n\ttruncated: boolean;\n\tfullOutputPath?: string;\n\ttimestamp: number;\n\t/** If true, this message is excluded from LLM context (!! prefix) */\n\texcludeFromContext?: boolean;\n}\n\n/**\n * Message type for extension-injected messages via sendMessage().\n * These are custom messages that extensions can inject into the conversation.\n */\nexport interface CustomMessage<T = unknown> {\n\trole: \"custom\";\n\tcustomType: string;\n\tcontent: string | (TextContent | ImageContent)[];\n\tdisplay: boolean;\n\tdetails?: T;\n\ttimestamp: number;\n}\n\nexport interface BranchSummaryMessage {\n\trole: \"branchSummary\";\n\tsummary: string;\n\tfromId: string | null;\n\ttimestamp: number;\n}\n\nexport interface CompactionSummaryMessage {\n\trole: \"compactionSummary\";\n\tsummary: string;\n\ttokensBefore: number;\n\tdetails?: unknown;\n\ttimestamp: number;\n}\n\nexport interface ConfigurationUpdateMessage {\n\trole: \"configurationUpdate\";\n\tcontent: (TextContent | ImageContent)[];\n\teffort: string;\n\ttimestamp: number;\n}\n\n// Extend CustomAgentMessages via declaration merging\ndeclare module \"@earendil-works/pi-agent-core\" {\n\tinterface CustomAgentMessages {\n\t\tbashExecution: BashExecutionMessage;\n\t\tcustom: CustomMessage;\n\t\tbranchSummary: BranchSummaryMessage;\n\t\tconfigurationUpdate: ConfigurationUpdateMessage;\n\t}\n}\n\n/**\n * Convert a BashExecutionMessage to user message text for LLM context.\n */\nexport function bashExecutionToText(msg: BashExecutionMessage): string {\n\tlet text = `Ran \\`${msg.command}\\`\\n`;\n\tif (msg.output) {\n\t\ttext += `\\`\\`\\`\\n${msg.output}\\n\\`\\`\\``;\n\t} else {\n\t\ttext += \"(no output)\";\n\t}\n\tif (msg.cancelled) {\n\t\ttext += \"\\n\\n(command cancelled)\";\n\t} else if (msg.exitCode !== null && msg.exitCode !== undefined && msg.exitCode !== 0) {\n\t\ttext += `\\n\\nCommand exited with code ${msg.exitCode}`;\n\t}\n\tif (msg.truncated && msg.fullOutputPath) {\n\t\ttext += `\\n\\n[Output truncated. Full output: ${msg.fullOutputPath}]`;\n\t}\n\treturn text;\n}\n\nexport function createBranchSummaryMessage(summary: string, fromId: string, timestamp: string): BranchSummaryMessage {\n\treturn {\n\t\trole: \"branchSummary\",\n\t\tsummary,\n\t\tfromId,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\nexport function createCompactionSummaryMessage(\n\tsummary: string,\n\ttokensBefore: number,\n\ttimestamp: string,\n\tdetails?: unknown,\n): CompactionSummaryMessage {\n\treturn {\n\t\trole: \"compactionSummary\",\n\t\tsummary: summary,\n\t\ttokensBefore,\n\t\tdetails,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\n/** Convert CustomMessageEntry to AgentMessage format */\nexport function createCustomMessage(\n\tcustomType: string,\n\tcontent: string | (TextContent | ImageContent)[],\n\tdisplay: boolean,\n\tdetails: unknown | undefined,\n\ttimestamp: string,\n): CustomMessage {\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType,\n\t\tcontent,\n\t\tdisplay,\n\t\tdetails,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\n/**\n * Transform AgentMessages (including custom types) to LLM-compatible Messages.\n *\n * This is used by:\n * - Agent's transormToLlm option (for prompt calls and queued messages)\n * - Compaction's generateSummary (for summarization)\n * - Custom extensions and tools\n */\nexport function convertToLlm(messages: AgentMessage[]): Message[] {\n\tconst withContextProvenance = <T extends Message>(source: AgentMessage, target: T): T =>\n\t\tcopyContextProvenance(source, target);\n\t// Continuations are append-only here too: the transport array must extend the\n\t// previous request verbatim to keep the provider's cache prefix valid.\n\tconst environmentMessages = new Set<Message>();\n\tconst converted = messages\n\t\t.map((m): Message | undefined => {\n\t\t\tswitch (m.role) {\n\t\t\t\tcase \"bashExecution\":\n\t\t\t\t\t// Skip messages excluded from context (!! prefix)\n\t\t\t\t\tif (m.excludeFromContext) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\treturn withContextProvenance(m, {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: bashExecutionToText(m) }],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t});\n\t\t\t\tcase \"custom\": {\n\t\t\t\t\tif (isContextExcludedCustomMessage(m.customType)) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst content = typeof m.content === \"string\" ? [{ type: \"text\" as const, text: m.content }] : m.content;\n\t\t\t\t\tconst converted = withContextProvenance(m, {\n\t\t\t\t\t\trole: \"user\" as const,\n\t\t\t\t\t\tcontent,\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t});\n\t\t\t\t\tif (m.customType === ENVIRONMENT_CONTEXT_MESSAGE_TYPE) environmentMessages.add(converted);\n\t\t\t\t\treturn converted;\n\t\t\t\t}\n\t\t\t\tcase \"branchSummary\":\n\t\t\t\t\treturn withContextProvenance(m, {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text: BRANCH_SUMMARY_PREFIX + m.summary + BRANCH_SUMMARY_SUFFIX }],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t});\n\t\t\t\tcase \"compactionSummary\":\n\t\t\t\t\treturn withContextProvenance(m, {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t{ type: \"text\" as const, text: COMPACTION_SUMMARY_PREFIX + m.summary + COMPACTION_SUMMARY_SUFFIX },\n\t\t\t\t\t\t],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t});\n\t\t\t\tcase \"configurationUpdate\":\n\t\t\t\t\treturn m;\n\t\t\t\tcase \"user\":\n\t\t\t\tcase \"assistant\":\n\t\t\t\tcase \"toolResult\":\n\t\t\t\t\treturn m;\n\t\t\t\tdefault:\n\t\t\t\t\t// biome-ignore lint/correctness/noSwitchDeclarations: fine\n\t\t\t\t\tconst _exhaustiveCheck: never = m;\n\t\t\t\t\treturn undefined;\n\t\t\t}\n\t\t})\n\t\t.filter((m) => m !== undefined);\n\t// Failed provider turns (stopReason error/aborted) must never reach an LLM\n\t// request: lanes that build requests straight from this output (claude-sdk\n\t// prompt bridge, cursor turns) would otherwise replay their partial text and\n\t// unexecuted tool calls, and token estimation would count them. Dropping is\n\t// deterministic per session state, so the cache-prefix guarantee above holds.\n\t// senpi#2118: the environment context then becomes the leading block of the\n\t// user message it precedes, so strict-alternation chat templates never see\n\t// two consecutive user messages. senpi#2170: images a failed turn proves the\n\t// provider rejected are replaced first, while the failed turn is still visible.\n\treturn foldEnvironmentContextIntoNextUserMessage(\n\t\tdropFailedAssistantTurns(omitProviderRejectedImages(converted)),\n\t\tenvironmentMessages,\n\t);\n}\n\n// ============================================================================\n// Transport image budget\n// ============================================================================\n\n/**\n * Cap on inline image base64 (characters approximately equal wire bytes) per\n * provider request. Anthropic documents a 32 MB request limit; reserving the\n * remainder for text and request overhead keeps the transport below that wall.\n */\nexport const TRANSPORT_IMAGE_BUDGET_BYTES = 24 * 1024 * 1024;\n\nexport const IMAGE_ELISION_PLACEHOLDER =\n\t\"[Image elided: an older image was removed to keep the request within the provider's size limit. Re-read the source file if you need to view it again.]\";\n\nexport const BLOCKED_IMAGE_PLACEHOLDER = \"Image reading is disabled.\";\n\nexport interface ElideOldImagesOptions {\n\t/** Cumulative inline image base64 budget. Defaults to TRANSPORT_IMAGE_BUDGET_BYTES. */\n\tbudgetBytes?: number;\n\t/** Newest image blocks always kept regardless of budget. They still consume it. Defaults to 1. */\n\talwaysKeepNewest?: number;\n\t/** Keep at most this many images from turns completed by a later assistant response. */\n\tmaxHistoricalImages?: number;\n}\n\nexport interface TransportConvertOptions extends ElideOldImagesOptions {\n\t/** Replace every image when the images.blockImages setting is enabled. */\n\tblockImages: boolean;\n}\n\n/** Drop consecutive duplicates of a placeholder produced by adjacent image replacements. */\nexport function dedupeConsecutivePlaceholder(\n\tcontent: (TextContent | ImageContent)[],\n\tplaceholder: string,\n): (TextContent | ImageContent)[] {\n\treturn content.filter(\n\t\t(block, index, blocks) =>\n\t\t\t!(\n\t\t\t\tblock.type === \"text\" &&\n\t\t\t\tblock.text === placeholder &&\n\t\t\t\tindex > 0 &&\n\t\t\t\tblocks[index - 1].type === \"text\" &&\n\t\t\t\t(blocks[index - 1] as TextContent).text === placeholder\n\t\t\t),\n\t);\n}\n\n/**\n * Bound inline image payload at request-build time. Images are considered from\n * newest to oldest. Once an image would exceed the budget, it and every older\n * image are replaced by a text placeholder. The newest protected blocks are\n * kept regardless of size, but still consume the budget.\n *\n * The input and persisted session remain untouched. If every image fits, the\n * original array reference is returned.\n */\nexport function elideOldImages(messages: Message[], options?: ElideOldImagesOptions): Message[] {\n\tconst budgetBytes = options?.budgetBytes ?? TRANSPORT_IMAGE_BUDGET_BYTES;\n\tconst alwaysKeepNewest = options?.alwaysKeepNewest ?? 1;\n\tconst maxHistoricalImages = options?.maxHistoricalImages;\n\tconst limitHistory = maxHistoricalImages !== undefined;\n\tconst lastAssistantIndex = messages.findLastIndex((message) => message.role === \"assistant\");\n\tconst imagesToElide = new Set<string>();\n\tlet keptImages = 0;\n\tlet keptHistoricalImages = 0;\n\tlet imageBytes = 0;\n\tlet cutoffReached = false;\n\n\tfor (let messageIndex = messages.length - 1; messageIndex >= 0; messageIndex--) {\n\t\tconst message = messages[messageIndex];\n\t\tif ((message.role !== \"user\" && message.role !== \"toolResult\") || !Array.isArray(message.content)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (let blockIndex = message.content.length - 1; blockIndex >= 0; blockIndex--) {\n\t\t\tconst block = message.content[blockIndex];\n\t\t\tif (block.type !== \"image\") continue;\n\t\t\tconst isCurrentTurn = limitHistory && messageIndex > lastAssistantIndex;\n\t\t\tconst isProtectedHistory = limitHistory && !isCurrentTurn && keptHistoricalImages < maxHistoricalImages;\n\t\t\tconst exceedsHistoryLimit = limitHistory && !isCurrentTurn && !isProtectedHistory;\n\n\t\t\tif (exceedsHistoryLimit || (cutoffReached && !isCurrentTurn && !isProtectedHistory)) {\n\t\t\t\timagesToElide.add(`${messageIndex}:${blockIndex}`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tisCurrentTurn ||\n\t\t\t\tisProtectedHistory ||\n\t\t\t\tkeptImages < alwaysKeepNewest ||\n\t\t\t\timageBytes + block.data.length <= budgetBytes\n\t\t\t) {\n\t\t\t\tkeptImages++;\n\t\t\t\tif (!isCurrentTurn) keptHistoricalImages++;\n\t\t\t\timageBytes += block.data.length;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcutoffReached = true;\n\t\t\timagesToElide.add(`${messageIndex}:${blockIndex}`);\n\t\t}\n\t}\n\n\tif (imagesToElide.size === 0) return messages;\n\n\treturn messages.map((message, messageIndex) => {\n\t\tif ((message.role !== \"user\" && message.role !== \"toolResult\") || !Array.isArray(message.content)) {\n\t\t\treturn message;\n\t\t}\n\t\tif (!message.content.some((_block, blockIndex) => imagesToElide.has(`${messageIndex}:${blockIndex}`))) {\n\t\t\treturn message;\n\t\t}\n\n\t\tconst replaced = message.content.map((block, blockIndex): TextContent | ImageContent =>\n\t\t\timagesToElide.has(`${messageIndex}:${blockIndex}`) ? { type: \"text\", text: IMAGE_ELISION_PLACEHOLDER } : block,\n\t\t);\n\t\treturn {\n\t\t\t...message,\n\t\t\tcontent: dedupeConsecutivePlaceholder(replaced, IMAGE_ELISION_PLACEHOLDER) as typeof message.content,\n\t\t};\n\t});\n}\n\n/** Convert messages for the main provider transport and apply its image policy. */\nexport function convertToLlmForTransport(messages: AgentMessage[], options: TransportConvertOptions): Message[] {\n\tconst converted = convertToLlm(messages);\n\tif (!options.blockImages) return elideOldImages(converted, options);\n\n\treturn converted.map((message) => {\n\t\tif ((message.role !== \"user\" && message.role !== \"toolResult\") || !Array.isArray(message.content)) {\n\t\t\treturn message;\n\t\t}\n\t\tif (!message.content.some((block) => block.type === \"image\")) return message;\n\n\t\tconst replaced = message.content.map((block): TextContent | ImageContent =>\n\t\t\tblock.type === \"image\" ? { type: \"text\", text: BLOCKED_IMAGE_PLACEHOLDER } : block,\n\t\t);\n\t\treturn {\n\t\t\t...message,\n\t\t\tcontent: dedupeConsecutivePlaceholder(replaced, BLOCKED_IMAGE_PLACEHOLDER) as typeof message.content,\n\t\t};\n\t});\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider image rejections (senpi#2170). A provider that rejects an image
|
|
3
|
+
* rejects every later request that replays it, and `dropFailedAssistantTurns`
|
|
4
|
+
* removes the failed turn but not the image, so one bad image bricked the
|
|
5
|
+
* session. The failed assistant turn is persisted with its error, so the
|
|
6
|
+
* rejection is derived from history on every request (and after a restart):
|
|
7
|
+
* images no successful response had accepted before an image-rejection failure
|
|
8
|
+
* are replaced by a placeholder naming their source.
|
|
9
|
+
*/
|
|
10
|
+
interface TurnMessage {
|
|
11
|
+
role: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function isProviderImageRejection(errorMessage: string | undefined): boolean;
|
|
14
|
+
export declare function rejectedImagePlaceholder(source: string): string;
|
|
15
|
+
export declare function rejectedImageSources(messages: readonly TurnMessage[], failedTurn: TurnMessage): string[];
|
|
16
|
+
export declare function omitProviderRejectedImages<T extends TurnMessage>(messages: T[]): T[];
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=provider-rejected-images.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-rejected-images.d.ts","sourceRoot":"","sources":["../../src/core/provider-rejected-images.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH,UAAU,WAAW;IACpB,IAAI,EAAE,MAAM,CAAC;CACb;AAQD,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAElF;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/D;AAiED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,EAAE,UAAU,EAAE,WAAW,GAAG,MAAM,EAAE,CAGxG;AAED,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAmBpF"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider image rejections (senpi#2170). A provider that rejects an image
|
|
3
|
+
* rejects every later request that replays it, and `dropFailedAssistantTurns`
|
|
4
|
+
* removes the failed turn but not the image, so one bad image bricked the
|
|
5
|
+
* session. The failed assistant turn is persisted with its error, so the
|
|
6
|
+
* rejection is derived from history on every request (and after a restart):
|
|
7
|
+
* images no successful response had accepted before an image-rejection failure
|
|
8
|
+
* are replaced by a placeholder naming their source.
|
|
9
|
+
*/
|
|
10
|
+
const PROVIDER_IMAGE_REJECTION_PATTERN = /does not represent a valid image|image_parse_error|invalid_image|unsupported image|could not process image|unable to process input image|image_url'?\.?[^\n]*invalid base64|expected a base64-encoded data url|image was specified using the image\/[a-z]+ media type|unsupported media type for base64 image|invalid data url for image/i;
|
|
11
|
+
export function isProviderImageRejection(errorMessage) {
|
|
12
|
+
return errorMessage !== undefined && PROVIDER_IMAGE_REJECTION_PATTERN.test(errorMessage);
|
|
13
|
+
}
|
|
14
|
+
export function rejectedImagePlaceholder(source) {
|
|
15
|
+
return `[Image omitted: the provider rejected this image (${source}) as invalid, so it is no longer sent with the conversation.]`;
|
|
16
|
+
}
|
|
17
|
+
function field(message, key) {
|
|
18
|
+
return key in message ? message[key] : undefined;
|
|
19
|
+
}
|
|
20
|
+
function contentBlocks(message) {
|
|
21
|
+
const content = field(message, "content");
|
|
22
|
+
return Array.isArray(content) ? content : [];
|
|
23
|
+
}
|
|
24
|
+
function toolCallSource(block) {
|
|
25
|
+
const args = block.arguments;
|
|
26
|
+
if (typeof args !== "object" || args === null)
|
|
27
|
+
return undefined;
|
|
28
|
+
const record = args;
|
|
29
|
+
for (const key of ["path", "file_path", "filePath"]) {
|
|
30
|
+
const value = record[key];
|
|
31
|
+
if (typeof value === "string" && value.trim().length > 0)
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
function imageSource(message, toolCallSources) {
|
|
37
|
+
if (message.role !== "toolResult")
|
|
38
|
+
return "an attached image";
|
|
39
|
+
const toolCallId = field(message, "toolCallId");
|
|
40
|
+
const known = typeof toolCallId === "string" ? toolCallSources.get(toolCallId) : undefined;
|
|
41
|
+
if (known)
|
|
42
|
+
return known;
|
|
43
|
+
const toolName = field(message, "toolName");
|
|
44
|
+
return typeof toolName === "string" ? `${toolName} tool result` : "a tool result";
|
|
45
|
+
}
|
|
46
|
+
/** Rejected images keyed by the index of the failed assistant turn that rejected them. */
|
|
47
|
+
function scanRejectedImages(messages) {
|
|
48
|
+
const toolCallSources = new Map();
|
|
49
|
+
const rejections = new Map();
|
|
50
|
+
let unconfirmed = [];
|
|
51
|
+
messages.forEach((message, messageIndex) => {
|
|
52
|
+
if (message.role === "assistant") {
|
|
53
|
+
for (const block of contentBlocks(message)) {
|
|
54
|
+
const source = block.type === "toolCall" ? toolCallSource(block) : undefined;
|
|
55
|
+
if (source && typeof block.id === "string")
|
|
56
|
+
toolCallSources.set(block.id, source);
|
|
57
|
+
}
|
|
58
|
+
const stopReason = field(message, "stopReason");
|
|
59
|
+
const errorMessage = field(message, "errorMessage");
|
|
60
|
+
if (stopReason === "error" &&
|
|
61
|
+
isProviderImageRejection(typeof errorMessage === "string" ? errorMessage : undefined)) {
|
|
62
|
+
if (unconfirmed.length > 0)
|
|
63
|
+
rejections.set(messageIndex, unconfirmed);
|
|
64
|
+
unconfirmed = [];
|
|
65
|
+
}
|
|
66
|
+
else if (stopReason !== "error" && stopReason !== "aborted") {
|
|
67
|
+
unconfirmed = [];
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (message.role !== "user" && message.role !== "toolResult")
|
|
72
|
+
return;
|
|
73
|
+
contentBlocks(message).forEach((block, blockIndex) => {
|
|
74
|
+
if (block.type === "image") {
|
|
75
|
+
unconfirmed.push({ messageIndex, blockIndex, source: imageSource(message, toolCallSources) });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
return rejections;
|
|
80
|
+
}
|
|
81
|
+
export function rejectedImageSources(messages, failedTurn) {
|
|
82
|
+
const failedIndex = messages.lastIndexOf(failedTurn);
|
|
83
|
+
return (scanRejectedImages(messages).get(failedIndex) ?? []).map((image) => image.source);
|
|
84
|
+
}
|
|
85
|
+
export function omitProviderRejectedImages(messages) {
|
|
86
|
+
const rejected = new Map();
|
|
87
|
+
for (const images of scanRejectedImages(messages).values()) {
|
|
88
|
+
for (const image of images) {
|
|
89
|
+
const blocks = rejected.get(image.messageIndex) ?? new Map();
|
|
90
|
+
blocks.set(image.blockIndex, image.source);
|
|
91
|
+
rejected.set(image.messageIndex, blocks);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (rejected.size === 0)
|
|
95
|
+
return messages;
|
|
96
|
+
return messages.map((message, messageIndex) => {
|
|
97
|
+
const blocks = rejected.get(messageIndex);
|
|
98
|
+
if (!blocks)
|
|
99
|
+
return message;
|
|
100
|
+
const content = contentBlocks(message).map((block, blockIndex) => {
|
|
101
|
+
const source = blocks.get(blockIndex);
|
|
102
|
+
return source === undefined ? block : { type: "text", text: rejectedImagePlaceholder(source) };
|
|
103
|
+
});
|
|
104
|
+
return { ...message, content };
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=provider-rejected-images.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-rejected-images.js","sourceRoot":"","sources":["../../src/core/provider-rejected-images.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Provider image rejections (senpi#2170). A provider that rejects an image\n * rejects every later request that replays it, and `dropFailedAssistantTurns`\n * removes the failed turn but not the image, so one bad image bricked the\n * session. The failed assistant turn is persisted with its error, so the\n * rejection is derived from history on every request (and after a restart):\n * images no successful response had accepted before an image-rejection failure\n * are replaced by a placeholder naming their source.\n */\n\nconst PROVIDER_IMAGE_REJECTION_PATTERN =\n\t/does not represent a valid image|image_parse_error|invalid_image|unsupported image|could not process image|unable to process input image|image_url'?\\.?[^\\n]*invalid base64|expected a base64-encoded data url|image was specified using the image\\/[a-z]+ media type|unsupported media type for base64 image|invalid data url for image/i;\n\ninterface TurnBlock {\n\ttype: string;\n\tid?: unknown;\n\targuments?: unknown;\n}\n\ninterface TurnMessage {\n\trole: string;\n}\n\ninterface RejectedImage {\n\tmessageIndex: number;\n\tblockIndex: number;\n\tsource: string;\n}\n\nexport function isProviderImageRejection(errorMessage: string | undefined): boolean {\n\treturn errorMessage !== undefined && PROVIDER_IMAGE_REJECTION_PATTERN.test(errorMessage);\n}\n\nexport function rejectedImagePlaceholder(source: string): string {\n\treturn `[Image omitted: the provider rejected this image (${source}) as invalid, so it is no longer sent with the conversation.]`;\n}\n\nfunction field(message: TurnMessage, key: string): unknown {\n\treturn key in message ? (message as unknown as Record<string, unknown>)[key] : undefined;\n}\n\nfunction contentBlocks(message: TurnMessage): readonly TurnBlock[] {\n\tconst content = field(message, \"content\");\n\treturn Array.isArray(content) ? (content as TurnBlock[]) : [];\n}\n\nfunction toolCallSource(block: TurnBlock): string | undefined {\n\tconst args = block.arguments;\n\tif (typeof args !== \"object\" || args === null) return undefined;\n\tconst record = args as Record<string, unknown>;\n\tfor (const key of [\"path\", \"file_path\", \"filePath\"]) {\n\t\tconst value = record[key];\n\t\tif (typeof value === \"string\" && value.trim().length > 0) return value;\n\t}\n\treturn undefined;\n}\n\nfunction imageSource(message: TurnMessage, toolCallSources: ReadonlyMap<string, string>): string {\n\tif (message.role !== \"toolResult\") return \"an attached image\";\n\tconst toolCallId = field(message, \"toolCallId\");\n\tconst known = typeof toolCallId === \"string\" ? toolCallSources.get(toolCallId) : undefined;\n\tif (known) return known;\n\tconst toolName = field(message, \"toolName\");\n\treturn typeof toolName === \"string\" ? `${toolName} tool result` : \"a tool result\";\n}\n\n/** Rejected images keyed by the index of the failed assistant turn that rejected them. */\nfunction scanRejectedImages(messages: readonly TurnMessage[]): Map<number, RejectedImage[]> {\n\tconst toolCallSources = new Map<string, string>();\n\tconst rejections = new Map<number, RejectedImage[]>();\n\tlet unconfirmed: RejectedImage[] = [];\n\tmessages.forEach((message, messageIndex) => {\n\t\tif (message.role === \"assistant\") {\n\t\t\tfor (const block of contentBlocks(message)) {\n\t\t\t\tconst source = block.type === \"toolCall\" ? toolCallSource(block) : undefined;\n\t\t\t\tif (source && typeof block.id === \"string\") toolCallSources.set(block.id, source);\n\t\t\t}\n\t\t\tconst stopReason = field(message, \"stopReason\");\n\t\t\tconst errorMessage = field(message, \"errorMessage\");\n\t\t\tif (\n\t\t\t\tstopReason === \"error\" &&\n\t\t\t\tisProviderImageRejection(typeof errorMessage === \"string\" ? errorMessage : undefined)\n\t\t\t) {\n\t\t\t\tif (unconfirmed.length > 0) rejections.set(messageIndex, unconfirmed);\n\t\t\t\tunconfirmed = [];\n\t\t\t} else if (stopReason !== \"error\" && stopReason !== \"aborted\") {\n\t\t\t\tunconfirmed = [];\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (message.role !== \"user\" && message.role !== \"toolResult\") return;\n\t\tcontentBlocks(message).forEach((block, blockIndex) => {\n\t\t\tif (block.type === \"image\") {\n\t\t\t\tunconfirmed.push({ messageIndex, blockIndex, source: imageSource(message, toolCallSources) });\n\t\t\t}\n\t\t});\n\t});\n\treturn rejections;\n}\n\nexport function rejectedImageSources(messages: readonly TurnMessage[], failedTurn: TurnMessage): string[] {\n\tconst failedIndex = messages.lastIndexOf(failedTurn);\n\treturn (scanRejectedImages(messages).get(failedIndex) ?? []).map((image) => image.source);\n}\n\nexport function omitProviderRejectedImages<T extends TurnMessage>(messages: T[]): T[] {\n\tconst rejected = new Map<number, Map<number, string>>();\n\tfor (const images of scanRejectedImages(messages).values()) {\n\t\tfor (const image of images) {\n\t\t\tconst blocks = rejected.get(image.messageIndex) ?? new Map<number, string>();\n\t\t\tblocks.set(image.blockIndex, image.source);\n\t\t\trejected.set(image.messageIndex, blocks);\n\t\t}\n\t}\n\tif (rejected.size === 0) return messages;\n\treturn messages.map((message, messageIndex) => {\n\t\tconst blocks = rejected.get(messageIndex);\n\t\tif (!blocks) return message;\n\t\tconst content = contentBlocks(message).map((block, blockIndex) => {\n\t\t\tconst source = blocks.get(blockIndex);\n\t\t\treturn source === undefined ? block : { type: \"text\", text: rejectedImagePlaceholder(source) };\n\t\t});\n\t\treturn { ...message, content } as T;\n\t});\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-title-generator.d.ts","sourceRoot":"","sources":["../../src/core/session-title-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,EACX,GAAG,EAGH,KAAK,EACL,mBAAmB,
|
|
1
|
+
{"version":3,"file":"session-title-generator.d.ts","sourceRoot":"","sources":["../../src/core/session-title-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,EACX,GAAG,EAGH,KAAK,EACL,mBAAmB,EAGnB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAkB,KAAK,WAAW,EAAsB,MAAM,8BAA8B,CAAC;AAGpG,UAAU,gBAAgB;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED,UAAU,2BAA2B;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;CAC7B;AAmCD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,WAAW,GAAG,WAAW,CAM1E;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAK5D;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAqB5G;AA8FD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAsCzD"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { completeSimple, retryAssistantCall } from "@earendil-works/pi-ai/compat";
|
|
2
|
+
import { initialTitleReasoning, mandatoryReasoningRetryLevel } from "./session-title-reasoning.js";
|
|
2
3
|
const TITLE_SYSTEM_PROMPT = `Generate a concise title for this coding-agent session.
|
|
3
4
|
|
|
4
5
|
Rules:
|
|
@@ -22,6 +23,10 @@ const LOW_SIGNAL_PROMPTS = new Set([
|
|
|
22
23
|
"yep",
|
|
23
24
|
"nope",
|
|
24
25
|
]);
|
|
26
|
+
const TITLE_MAX_TOKENS = 64;
|
|
27
|
+
// Reasoning tokens count against the completion budget, so a title that must reason needs room
|
|
28
|
+
// for the thinking and the `<title>` answer.
|
|
29
|
+
const REASONING_TITLE_MAX_TOKENS = 1024;
|
|
25
30
|
const MAX_TITLE_RETRIES = 1;
|
|
26
31
|
const MAX_TITLE_RETRY_DELAY_MS = 2000;
|
|
27
32
|
/**
|
|
@@ -56,12 +61,22 @@ export async function generateSessionTitle(options) {
|
|
|
56
61
|
// Titles are cosmetic background work: honor the caller's retry policy so a
|
|
57
62
|
// single transient provider error (e.g. a 529 overloaded stream) does not
|
|
58
63
|
// surface as a scary runtime error. Mirrors completeSummarization().
|
|
59
|
-
const
|
|
64
|
+
const reasoning = initialTitleReasoning(options.model);
|
|
65
|
+
let response = await requestTitle(options, reasoning);
|
|
66
|
+
const retryReasoning = response.stopReason === "error"
|
|
67
|
+
? mandatoryReasoningRetryLevel(options.model, reasoning, response.errorMessage)
|
|
68
|
+
: undefined;
|
|
69
|
+
if (retryReasoning !== undefined) {
|
|
70
|
+
response = await requestTitle(options, retryReasoning);
|
|
71
|
+
}
|
|
60
72
|
if (response.stopReason === "error") {
|
|
61
73
|
throw new Error(humanizeProviderError(response.errorMessage ?? "Session title generation failed"));
|
|
62
74
|
}
|
|
63
75
|
return parseSessionTitle(response);
|
|
64
76
|
}
|
|
77
|
+
function requestTitle(options, reasoning) {
|
|
78
|
+
return retryAssistantCall(() => completeTitle(options.model, buildTitleContext(options.firstPrompt), buildTitleOptions(options, reasoning), options.streamFn), options.retry, options.signal);
|
|
79
|
+
}
|
|
65
80
|
function buildTitleContext(firstPrompt) {
|
|
66
81
|
return {
|
|
67
82
|
systemPrompt: TITLE_SYSTEM_PROMPT,
|
|
@@ -74,13 +89,16 @@ function buildTitleContext(firstPrompt) {
|
|
|
74
89
|
],
|
|
75
90
|
};
|
|
76
91
|
}
|
|
77
|
-
function buildTitleOptions(options) {
|
|
92
|
+
function buildTitleOptions(options, reasoning) {
|
|
78
93
|
const titleOptions = {
|
|
79
94
|
...options.baseOptions,
|
|
80
95
|
sessionId: options.sessionId,
|
|
81
96
|
cacheRetention: options.model.cacheRetention === "none" ? "none" : "short",
|
|
82
|
-
maxTokens:
|
|
97
|
+
maxTokens: reasoning === undefined ? TITLE_MAX_TOKENS : REASONING_TITLE_MAX_TOKENS,
|
|
83
98
|
};
|
|
99
|
+
if (reasoning !== undefined) {
|
|
100
|
+
titleOptions.reasoning = reasoning;
|
|
101
|
+
}
|
|
84
102
|
if (options.auth.apiKey !== undefined) {
|
|
85
103
|
titleOptions.apiKey = options.auth.apiKey;
|
|
86
104
|
}
|