@code-yeongyu/senpi 2026.9.23-3 → 2026.9.23-4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/bundle/chunks/{app-server-command-U5Y46LHO.js → app-server-command-QRBQLEXY.js} +1 -1
- package/dist/bundle/chunks/{chunk-UCTYTLP3.js → chunk-3RN6BFG2.js} +2 -2
- package/dist/bundle/chunks/{chunk-XTXBPXZZ.js → chunk-EN6KDFY2.js} +1 -1
- package/dist/bundle/chunks/{chunk-2NFHX2FJ.js → chunk-J3QXPP4T.js} +1 -1
- package/dist/bundle/chunks/chunk-KBG7BJIL.js +8 -0
- package/dist/bundle/chunks/{chunk-TH4PERSI.js → chunk-N46LNXHU.js} +35 -53
- package/dist/bundle/chunks/{chunk-67Z5WNA4.js → chunk-PSMTQDII.js} +1 -1
- package/dist/bundle/chunks/{chunk-Y4AJLTFT.js → chunk-WUYBEF7C.js} +1 -1
- package/dist/bundle/chunks/{chunk-IDSOMHWS.js → chunk-WXIRFRXY.js} +1 -1
- package/dist/bundle/chunks/{chunk-R6F525XB.js → chunk-XDSQYM4F.js} +1 -1
- package/dist/bundle/chunks/{chunk-TUVSARCZ.js → chunk-ZEFQYQOU.js} +1 -1
- package/dist/bundle/chunks/{cli-main-65WMMIRT.js → cli-main-ROBDBYAB.js} +1 -1
- package/dist/bundle/chunks/cursor-agent.js +1 -1
- package/dist/bundle/chunks/{help-fast-path-VXAZDQ3Z.js → help-fast-path-QXVCHTP3.js} +1 -1
- package/dist/bundle/chunks/{host-command-5PEFD4N6.js → host-command-3PUZYQOK.js} +1 -1
- package/dist/bundle/chunks/{host-lifecycle-BXW5C4JT.js → host-lifecycle-OHPSU5VU.js} +1 -1
- package/dist/bundle/chunks/{interactive-host-runtime-DUNYT24Q.js → interactive-host-runtime-57LEAJPU.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-SCG5PQZ6.js → interactive-mode-SLPAGRHH.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-QC6BZZNH.js → multi-session-host-3PACMEHC.js} +1 -1
- package/dist/bundle/chunks/{package-manager-cli-23GULCVL.js → package-manager-cli-6UIUSRQO.js} +1 -1
- package/dist/bundle/chunks/{pi-messages-B6RSUQKL.js → pi-messages-CAS467IY.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-ZIYWOB2N.js → rotation-stream-CZT4TRPD.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-ZQ4E6FFA.js → rpc-mode-47EVLL6X.js} +1 -1
- package/dist/bundle/chunks/{session-picker-CO2ZK3EC.js → session-picker-ZIBANFBQ.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +40 -58
- 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/extensions/builtin/cursor-cli-oauth/models.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/models.js +43 -26
- package/dist/core/extensions/builtin/cursor-cli-oauth/models.js.map +1 -1
- package/dist/core/extensions/builtin/nested-agents-md/index.js +1 -1
- package/dist/core/extensions/builtin/nested-agents-md/index.js.map +1 -1
- package/dist/core/extensions/builtin/rule-activation/types.d.ts +2 -0
- package/dist/core/extensions/builtin/rule-activation/types.d.ts.map +1 -1
- package/dist/core/extensions/builtin/rule-activation/types.js +7 -1
- package/dist/core/extensions/builtin/rule-activation/types.js.map +1 -1
- package/dist/core/extensions/builtin/rules/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/rules/index.js +2 -1
- package/dist/core/extensions/builtin/rules/index.js.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.d.ts +3 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.d.ts.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.js +9 -3
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +87 -14
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +12 -7
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +9 -6
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep/format.d.ts +3 -2
- package/dist/core/tools/grep/format.d.ts.map +1 -1
- package/dist/core/tools/grep/format.js +5 -3
- package/dist/core/tools/grep/format.js.map +1 -1
- package/dist/core/tools/grep/index.js +2 -2
- package/dist/core/tools/grep/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +5 -3
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/model-only-text.d.ts +4 -0
- package/dist/core/tools/model-only-text.d.ts.map +1 -0
- package/dist/core/tools/model-only-text.js +12 -0
- package/dist/core/tools/model-only-text.js.map +1 -0
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +15 -5
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +2 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/renderers/bash.d.ts.map +1 -1
- package/dist/core/tools/renderers/bash.js +1 -25
- package/dist/core/tools/renderers/bash.js.map +1 -1
- package/dist/core/tools/renderers/grep.d.ts.map +1 -1
- package/dist/core/tools/renderers/grep.js +0 -25
- package/dist/core/tools/renderers/grep.js.map +1 -1
- package/dist/core/tools/renderers/read.d.ts +8 -0
- package/dist/core/tools/renderers/read.d.ts.map +1 -1
- package/dist/core/tools/renderers/read.js +2 -14
- package/dist/core/tools/renderers/read.js.map +1 -1
- package/dist/modes/interactive/components/exploration-call.d.ts +4 -1
- package/dist/modes/interactive/components/exploration-call.d.ts.map +1 -1
- package/dist/modes/interactive/components/exploration-call.js +17 -2
- package/dist/modes/interactive/components/exploration-call.js.map +1 -1
- package/dist/modes/interactive/components/exploration-group.d.ts +3 -1
- package/dist/modes/interactive/components/exploration-group.d.ts.map +1 -1
- package/dist/modes/interactive/components/exploration-group.js +7 -1
- package/dist/modes/interactive/components/exploration-group.js.map +1 -1
- package/dist/modes/interactive/components/exploration-rules.d.ts +5 -0
- package/dist/modes/interactive/components/exploration-rules.d.ts.map +1 -0
- package/dist/modes/interactive/components/exploration-rules.js +15 -0
- package/dist/modes/interactive/components/exploration-rules.js.map +1 -0
- package/dist/modes/interactive/components/exploration-transcript-container.d.ts.map +1 -1
- package/dist/modes/interactive/components/exploration-transcript-container.js +10 -1
- package/dist/modes/interactive/components/exploration-transcript-container.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +4 -1
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +14 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +4 -19
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.js +17 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/cursor/catalog-grouping.d.ts +18 -1
- package/node_modules/@earendil-works/pi-ai/dist/cursor/catalog-grouping.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/cursor/catalog-grouping.js +103 -3
- package/node_modules/@earendil-works/pi-ai/dist/cursor/catalog-grouping.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/cursor/selection-descriptor.d.ts +3 -1
- package/node_modules/@earendil-works/pi-ai/dist/cursor/selection-descriptor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/cursor/selection-descriptor.js +15 -3
- package/node_modules/@earendil-works/pi-ai/dist/cursor/selection-descriptor.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/cursor/store-migration.d.ts +7 -2
- package/node_modules/@earendil-works/pi-ai/dist/cursor/store-migration.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/cursor/store-migration.js +92 -20
- package/node_modules/@earendil-works/pi-ai/dist/cursor/store-migration.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/model.d.ts +9 -1
- package/node_modules/@earendil-works/pi-ai/dist/model.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/model.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/cursor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/cursor.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/cursor.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.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/types.d.ts +5 -0
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- 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/chunk-XPDV6SIX.js +0 -8
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { StringEnum } from "@earendil-works/pi-ai";
|
|
2
2
|
import { Type } from "typebox";
|
|
3
|
+
import { modelOnlyText } from "../../../../tools/model-only-text.js";
|
|
3
4
|
import { defineTool } from "../../../types.js";
|
|
4
5
|
import { htmlToMarkdown, htmlToText } from "./content.lazy.js";
|
|
5
6
|
import { clampTimeout, fetchUrl } from "./fetcher.js";
|
|
@@ -107,8 +108,13 @@ export const webfetch = defineTool({
|
|
|
107
108
|
outputBytes: capped.outputBytes,
|
|
108
109
|
outputTotalBytes: capped.totalBytes,
|
|
109
110
|
};
|
|
111
|
+
const content = [
|
|
112
|
+
{ type: "text", text: capped.notice === undefined ? capped.text : `${capped.text}\n` },
|
|
113
|
+
];
|
|
114
|
+
if (capped.notice !== undefined)
|
|
115
|
+
content.push(modelOnlyText(capped.notice));
|
|
110
116
|
return {
|
|
111
|
-
content
|
|
117
|
+
content,
|
|
112
118
|
details,
|
|
113
119
|
};
|
|
114
120
|
},
|
|
@@ -138,8 +144,8 @@ export function capWebfetchOutput(text) {
|
|
|
138
144
|
}
|
|
139
145
|
const head = takeHeadBytes(text, DEFAULT_OUTPUT_MAX_BYTES);
|
|
140
146
|
const outputBytes = Buffer.byteLength(head, "utf-8");
|
|
141
|
-
const notice =
|
|
142
|
-
return { text: head
|
|
147
|
+
const notice = `[Output truncated: ${formatByteSize(outputBytes)} of ${formatByteSize(totalBytes)} shown (${formatByteSize(DEFAULT_OUTPUT_MAX_BYTES)} limit). Re-fetch a more specific URL or use web_search for targeted content.]`;
|
|
148
|
+
return { text: head, notice, truncated: true, outputBytes, totalBytes };
|
|
143
149
|
}
|
|
144
150
|
/** Keep whole leading lines within the byte ceiling; fall back to a UTF-8-safe byte prefix for one oversized line. */
|
|
145
151
|
function takeHeadBytes(text, maxBytes) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/webfetch/webfetch/tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAuB,MAAM,cAAc,CAAC;AAE3E,MAAM,gBAAgB,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAE/D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC1B,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,+BAA+B,EAAE,CAAC;IAClE,MAAM,EAAE,IAAI,CAAC,QAAQ,CACpB,UAAU,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAU,EAAE;QACjD,WAAW,EAAE,4DAA4D;KACzE,CAAC,CACF;IACD,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,2CAA2C,EAAE,CAAC,CAAC;CACjG,CAAC,CAAC;AAsCH,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAuC;IACxE,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,WAAW;IAClB,WAAW,EACV,8EAA8E;QAC9E,6DAA6D;IAC9D,aAAa,EAAE,2DAA2D;IAC1E,gBAAgB,EAAE;QACjB,qDAAqD;QACrD,4EAA4E;QAC5E,kDAAkD;KAClD;IACD,UAAU,EAAE,MAAM;IAClB,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI;QACxD,MAAM,MAAM,GAAG,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,cAAc,GAAG,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACpD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG;YAChB,QAAQ,EAAE,YAAY,MAAM,CAAC,GAAG,EAAE;YAClC,SAAS;YACT,SAAS,EAAE,cAAc,GAAG,IAAI;SAChC,CAAC;QACF,IAAI,oBAAwC,CAAC;QAC7C,MAAM,YAAY,GAAG,CAAC,OAAgC,EAAQ,EAAE;YAC/D,QAAQ,EAAE,CAAC;gBACV,OAAO,EAAE;oBACR;wBACC,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,YAAY,MAAM,CAAC,GAAG,OAAO,MAAM,aAAa,cAAc,IAAI;qBACxE;iBACD;gBACD,OAAO;aACP,CAAC,CAAC;QACJ,CAAC,CAAC;QACF,YAAY,CAAC;YACZ,KAAK,EAAE,UAAU;YACjB,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,MAAM;YACN,cAAc;YACd,QAAQ;SACR,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC;YAC9B,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,MAAM;YACN,cAAc;YACd,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;YAC3C,UAAU,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,EAAE;gBACrC,oBAAoB,GAAG,UAAU,CAAC;gBAClC,YAAY,CAAC;oBACZ,KAAK,EAAE,aAAa;oBACpB,GAAG,EAAE,MAAM,CAAC,GAAG;oBACf,MAAM;oBACN,cAAc;oBACd,SAAS;oBACT,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;oBACnD,QAAQ;iBACR,CAAC,CAAC;YACJ,CAAC;SACD,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;QACtD,YAAY,CAAC;YACZ,KAAK,EAAE,YAAY;YACnB,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,MAAM;YACN,cAAc;YACd,SAAS,EAAE,OAAO,CAAC,KAAK;YACxB,GAAG,CAAC,oBAAoB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,oBAAoB,EAAE,CAAC;YACnF,QAAQ;SACR,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC;QAClG,IAAI,IAAI,GAAG,GAAG,CAAC;QACf,IAAI,SAAS,GAAG,KAAK,CAAC;QAEtB,IAAI,MAAM,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;YACrC,IAAI,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;YAC9C,SAAS,GAAG,IAAI,CAAC;QAClB,CAAC;aAAM,IAAI,MAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACxC,IAAI,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;YAC1C,SAAS,GAAG,IAAI,CAAC;QAClB,CAAC;QAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAEvC,MAAM,OAAO,GAAoB;YAChC,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,QAAQ,EAAE,OAAO,CAAC,GAAG;YACrB,MAAM;YACN,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,cAAc;YACd,SAAS;YACT,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,eAAe,EAAE,MAAM,CAAC,SAAS;YACjC,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,gBAAgB,EAAE,MAAM,CAAC,UAAU;SACnC,CAAC;QAEF,OAAO;YACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;YAC9C,OAAO;SACP,CAAC;IACH,CAAC;CACD,CAAC,CAAC;AAEH,MAAM,UAAU,mBAAmB,CAAC,KAAc;IACjD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,UAAU,CAAC;IAC3C,KAAK,MAAM,MAAM,IAAI,gBAAgB,EAAE,CAAC;QACvC,IAAI,KAAK,KAAK,MAAM;YAAE,OAAO,MAAM,CAAC;IACrC,CAAC;IACD,OAAO,UAAU,CAAC;AACnB,CAAC;AAED,6FAA6F;AAC7F,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,GAAG,IAAI,CAAC;AAalD;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC7C,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACpD,IAAI,UAAU,IAAI,wBAAwB,EAAE,CAAC;QAC5C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;IACxE,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,wBAAwB,CAAC,CAAC;IAC3D,MAAM,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,0BAA0B,cAAc,CAAC,WAAW,CAAC,OAAO,cAAc,CACxF,UAAU,CACV,WAAW,cAAc,CAAC,wBAAwB,CAAC,gFAAgF,CAAC;IACrI,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;AAC1E,CAAC;AAED,sHAAsH;AACtH,SAAS,aAAa,CAAC,IAAY,EAAE,QAAgB;IACpD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QACvF,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChF,IAAI,SAAS,GAAG,SAAS,GAAG,QAAQ;YAAE,MAAM;QAC5C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,SAAS,IAAI,SAAS,CAAC;QACvB,IAAI,YAAY,KAAK,CAAC,CAAC;YAAE,MAAM;QAC/B,KAAK,GAAG,YAAY,GAAG,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC9E,CAAC;AAED,mGAAmG;AACnG,SAAS,aAAa,CAAC,KAAa,EAAE,QAAgB;IACrD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC9E,qFAAqF;IACrF,OAAO,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AACpE,CAAC;AAED,8CAA8C;AAC9C,SAAS,cAAc,CAAC,KAAa;IACpC,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,GAAG,CAAC;IACrC,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IACjE,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC","sourcesContent":["import { StringEnum } from \"@earendil-works/pi-ai\";\nimport { Type } from \"typebox\";\nimport { defineTool } from \"../../../types.ts\";\n\nimport { htmlToMarkdown, htmlToText } from \"./content.lazy.ts\";\nimport { clampTimeout, fetchUrl, type WebfetchFormat } from \"./fetcher.ts\";\n\nconst WEBFETCH_FORMATS = [\"markdown\", \"text\", \"html\"] as const;\n\nconst Params = Type.Object({\n\turl: Type.String({ description: \"The URL to fetch content from\" }),\n\tformat: Type.Optional(\n\t\tStringEnum([\"markdown\", \"text\", \"html\"] as const, {\n\t\t\tdescription: \"The format to return the content in. Defaults to markdown.\",\n\t\t}),\n\t),\n\ttimeout: Type.Optional(Type.Number({ description: \"Optional timeout in seconds. Maximum 120.\" })),\n});\n\nexport interface WebfetchDetails {\n\turl: string;\n\tfinalUrl: string;\n\tformat: WebfetchFormat;\n\tstatus: number;\n\tstatusText: string;\n\tcontentType: string;\n\tbytes: number;\n\ttimeoutSeconds: number;\n\tconverted: boolean;\n\t/** Whether the network response body was truncated at the {@link MAX_RESPONSE_SIZE_BYTES} fetch limit. */\n\ttruncated: boolean;\n\t/** Whether the text handed to the model was capped below the raw content size. */\n\toutputTruncated: boolean;\n\t/** Byte length of the text handed to the model (excluding the truncation notice). */\n\toutputBytes: number;\n\t/** Byte length of the full converted text before the output cap. */\n\toutputTotalBytes: number;\n}\n\nexport interface WebfetchProgressDetails {\n\tphase: \"fetching\" | \"downloading\" | \"converting\";\n\turl: string;\n\tformat: WebfetchFormat;\n\ttimeoutSeconds: number;\n\tbytesRead?: number;\n\ttotalBytes?: number;\n\tprogress: {\n\t\tactivity: string;\n\t\tstartedAt: number;\n\t\tmaxWaitMs: number;\n\t};\n}\n\nexport type WebfetchRenderDetails = WebfetchDetails | WebfetchProgressDetails;\n\nexport const webfetch = defineTool<typeof Params, WebfetchRenderDetails>({\n\tname: \"webfetch\",\n\tlabel: \"Web Fetch\",\n\tdescription:\n\t\t\"Fetches content from a URL and returns it as markdown, plain text, or HTML. \" +\n\t\t\"Network use is bounded by timeout and response size limits.\",\n\tpromptSnippet: \"webfetch: retrieve URL content as markdown, text, or html\",\n\tpromptGuidelines: [\n\t\t\"Use webfetch when a specific URL must be retrieved.\",\n\t\t\"Prefer markdown format unless raw HTML or plain text is explicitly needed.\",\n\t\t\"The tool is read-only and does not modify files.\",\n\t],\n\tparameters: Params,\n\tasync execute(_toolCallId, params, signal, onUpdate, _ctx) {\n\t\tconst format = parseWebfetchFormat(params.format);\n\t\tconst timeoutSeconds = clampTimeout(params.timeout);\n\t\tconst startedAt = Date.now();\n\t\tconst progress = {\n\t\t\tactivity: `fetching ${params.url}`,\n\t\t\tstartedAt,\n\t\t\tmaxWaitMs: timeoutSeconds * 1000,\n\t\t};\n\t\tlet downloadedTotalBytes: number | undefined;\n\t\tconst emitProgress = (details: WebfetchProgressDetails): void => {\n\t\t\tonUpdate?.({\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `Fetching ${params.url} as ${format} (timeout ${timeoutSeconds}s)`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails,\n\t\t\t});\n\t\t};\n\t\temitProgress({\n\t\t\tphase: \"fetching\",\n\t\t\turl: params.url,\n\t\t\tformat,\n\t\t\ttimeoutSeconds,\n\t\t\tprogress,\n\t\t});\n\n\t\tconst fetched = await fetchUrl({\n\t\t\turl: params.url,\n\t\t\tformat,\n\t\t\ttimeoutSeconds,\n\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\tonProgress: (bytesRead, totalBytes) => {\n\t\t\t\tdownloadedTotalBytes = totalBytes;\n\t\t\t\temitProgress({\n\t\t\t\t\tphase: \"downloading\",\n\t\t\t\t\turl: params.url,\n\t\t\t\t\tformat,\n\t\t\t\t\ttimeoutSeconds,\n\t\t\t\t\tbytesRead,\n\t\t\t\t\t...(totalBytes === undefined ? {} : { totalBytes }),\n\t\t\t\t\tprogress,\n\t\t\t\t});\n\t\t\t},\n\t\t});\n\t\tconst raw = new TextDecoder().decode(fetched.body);\n\t\tconst contentType = fetched.contentType.toLowerCase();\n\t\temitProgress({\n\t\t\tphase: \"converting\",\n\t\t\turl: params.url,\n\t\t\tformat,\n\t\t\ttimeoutSeconds,\n\t\t\tbytesRead: fetched.bytes,\n\t\t\t...(downloadedTotalBytes === undefined ? {} : { totalBytes: downloadedTotalBytes }),\n\t\t\tprogress,\n\t\t});\n\t\tconst isHtml = contentType.includes(\"text/html\") || contentType.includes(\"application/xhtml+xml\");\n\t\tlet text = raw;\n\t\tlet converted = false;\n\n\t\tif (isHtml && format === \"markdown\") {\n\t\t\ttext = await htmlToMarkdown(raw, fetched.url);\n\t\t\tconverted = true;\n\t\t} else if (isHtml && format === \"text\") {\n\t\t\ttext = await htmlToText(raw, fetched.url);\n\t\t\tconverted = true;\n\t\t}\n\n\t\tconst capped = capWebfetchOutput(text);\n\n\t\tconst details: WebfetchDetails = {\n\t\t\turl: params.url,\n\t\t\tfinalUrl: fetched.url,\n\t\t\tformat,\n\t\t\tstatus: fetched.status,\n\t\t\tstatusText: fetched.statusText,\n\t\t\tcontentType: fetched.contentType,\n\t\t\tbytes: fetched.bytes,\n\t\t\ttimeoutSeconds,\n\t\t\tconverted,\n\t\t\ttruncated: fetched.truncated,\n\t\t\toutputTruncated: capped.truncated,\n\t\t\toutputBytes: capped.outputBytes,\n\t\t\toutputTotalBytes: capped.totalBytes,\n\t\t};\n\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\", text: capped.text }],\n\t\t\tdetails,\n\t\t};\n\t},\n});\n\nexport function parseWebfetchFormat(value: unknown): WebfetchFormat {\n\tif (value === undefined) return \"markdown\";\n\tfor (const format of WEBFETCH_FORMATS) {\n\t\tif (value === format) return format;\n\t}\n\treturn \"markdown\";\n}\n\n/** Byte ceiling for the text handed to the model, mirroring senpi's read-tool output cap. */\nexport const DEFAULT_OUTPUT_MAX_BYTES = 50 * 1024;\n\nexport interface WebfetchOutputCap {\n\t/** Model-facing text after the output cap, with a notice appended when truncated. */\n\ttext: string;\n\t/** Whether the text was capped below the full converted size. */\n\ttruncated: boolean;\n\t/** Byte length of {@link WebfetchOutputCap.text} excluding the appended notice. */\n\toutputBytes: number;\n\t/** Byte length of the full converted text before capping. */\n\ttotalBytes: number;\n}\n\n/**\n * Bound the text handed to the model so a single fetch cannot flood the context\n * window and force an unwanted compaction. Keeps whole leading lines until the\n * byte ceiling is hit; when the first line alone exceeds the ceiling (minified\n * JSON, single-line payloads) it falls back to a UTF-8-safe byte prefix so the\n * head is preserved instead of dropped.\n */\nexport function capWebfetchOutput(text: string): WebfetchOutputCap {\n\tconst totalBytes = Buffer.byteLength(text, \"utf-8\");\n\tif (totalBytes <= DEFAULT_OUTPUT_MAX_BYTES) {\n\t\treturn { text, truncated: false, outputBytes: totalBytes, totalBytes };\n\t}\n\n\tconst head = takeHeadBytes(text, DEFAULT_OUTPUT_MAX_BYTES);\n\tconst outputBytes = Buffer.byteLength(head, \"utf-8\");\n\tconst notice = `\\n\\n[Output truncated: ${formatByteSize(outputBytes)} of ${formatByteSize(\n\t\ttotalBytes,\n\t)} shown (${formatByteSize(DEFAULT_OUTPUT_MAX_BYTES)} limit). Re-fetch a more specific URL or use web_search for targeted content.]`;\n\treturn { text: head + notice, truncated: true, outputBytes, totalBytes };\n}\n\n/** Keep whole leading lines within the byte ceiling; fall back to a UTF-8-safe byte prefix for one oversized line. */\nfunction takeHeadBytes(text: string, maxBytes: number): string {\n\tconst lines: string[] = [];\n\tlet usedBytes = 0;\n\tlet start = 0;\n\twhile (start <= text.length) {\n\t\tconst newlineIndex = text.indexOf(\"\\n\", start);\n\t\tconst line = newlineIndex === -1 ? text.slice(start) : text.slice(start, newlineIndex);\n\t\tconst lineBytes = Buffer.byteLength(line, \"utf-8\") + (lines.length > 0 ? 1 : 0);\n\t\tif (usedBytes + lineBytes > maxBytes) break;\n\t\tlines.push(line);\n\t\tusedBytes += lineBytes;\n\t\tif (newlineIndex === -1) break;\n\t\tstart = newlineIndex + 1;\n\t}\n\treturn lines.length === 0 ? sliceUtf8Head(text, maxBytes) : lines.join(\"\\n\");\n}\n\n/** Slice the first {@link maxBytes} bytes of a UTF-8 string without leaving a split code point. */\nfunction sliceUtf8Head(value: string, maxBytes: number): string {\n\tconst buffer = Buffer.from(value, \"utf-8\");\n\tif (buffer.length <= maxBytes) return value;\n\tconst decoded = new TextDecoder(\"utf-8\").decode(buffer.subarray(0, maxBytes));\n\t// A trailing partial code point decodes to U+FFFD; drop it so no split byte remains.\n\treturn decoded.endsWith(\"\\uFFFD\") ? decoded.slice(0, -1) : decoded;\n}\n\n/** Human-readable byte size (B / KB / MB). */\nfunction formatByteSize(bytes: number): string {\n\tif (bytes < 1024) return `${bytes}B`;\n\tif (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n\treturn `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/webfetch/webfetch/tool.ts"],"names":[],"mappings":"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","sourcesContent":["import { StringEnum, type TextContent } from \"@earendil-works/pi-ai\";\nimport { Type } from \"typebox\";\nimport { modelOnlyText } from \"../../../../tools/model-only-text.ts\";\nimport { defineTool } from \"../../../types.ts\";\n\nimport { htmlToMarkdown, htmlToText } from \"./content.lazy.ts\";\nimport { clampTimeout, fetchUrl, type WebfetchFormat } from \"./fetcher.ts\";\n\nconst WEBFETCH_FORMATS = [\"markdown\", \"text\", \"html\"] as const;\n\nconst Params = Type.Object({\n\turl: Type.String({ description: \"The URL to fetch content from\" }),\n\tformat: Type.Optional(\n\t\tStringEnum([\"markdown\", \"text\", \"html\"] as const, {\n\t\t\tdescription: \"The format to return the content in. Defaults to markdown.\",\n\t\t}),\n\t),\n\ttimeout: Type.Optional(Type.Number({ description: \"Optional timeout in seconds. Maximum 120.\" })),\n});\n\nexport interface WebfetchDetails {\n\turl: string;\n\tfinalUrl: string;\n\tformat: WebfetchFormat;\n\tstatus: number;\n\tstatusText: string;\n\tcontentType: string;\n\tbytes: number;\n\ttimeoutSeconds: number;\n\tconverted: boolean;\n\t/** Whether the network response body was truncated at the {@link MAX_RESPONSE_SIZE_BYTES} fetch limit. */\n\ttruncated: boolean;\n\t/** Whether the text handed to the model was capped below the raw content size. */\n\toutputTruncated: boolean;\n\t/** Byte length of the text handed to the model (excluding the truncation notice). */\n\toutputBytes: number;\n\t/** Byte length of the full converted text before the output cap. */\n\toutputTotalBytes: number;\n}\n\nexport interface WebfetchProgressDetails {\n\tphase: \"fetching\" | \"downloading\" | \"converting\";\n\turl: string;\n\tformat: WebfetchFormat;\n\ttimeoutSeconds: number;\n\tbytesRead?: number;\n\ttotalBytes?: number;\n\tprogress: {\n\t\tactivity: string;\n\t\tstartedAt: number;\n\t\tmaxWaitMs: number;\n\t};\n}\n\nexport type WebfetchRenderDetails = WebfetchDetails | WebfetchProgressDetails;\n\nexport const webfetch = defineTool<typeof Params, WebfetchRenderDetails>({\n\tname: \"webfetch\",\n\tlabel: \"Web Fetch\",\n\tdescription:\n\t\t\"Fetches content from a URL and returns it as markdown, plain text, or HTML. \" +\n\t\t\"Network use is bounded by timeout and response size limits.\",\n\tpromptSnippet: \"webfetch: retrieve URL content as markdown, text, or html\",\n\tpromptGuidelines: [\n\t\t\"Use webfetch when a specific URL must be retrieved.\",\n\t\t\"Prefer markdown format unless raw HTML or plain text is explicitly needed.\",\n\t\t\"The tool is read-only and does not modify files.\",\n\t],\n\tparameters: Params,\n\tasync execute(_toolCallId, params, signal, onUpdate, _ctx) {\n\t\tconst format = parseWebfetchFormat(params.format);\n\t\tconst timeoutSeconds = clampTimeout(params.timeout);\n\t\tconst startedAt = Date.now();\n\t\tconst progress = {\n\t\t\tactivity: `fetching ${params.url}`,\n\t\t\tstartedAt,\n\t\t\tmaxWaitMs: timeoutSeconds * 1000,\n\t\t};\n\t\tlet downloadedTotalBytes: number | undefined;\n\t\tconst emitProgress = (details: WebfetchProgressDetails): void => {\n\t\t\tonUpdate?.({\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `Fetching ${params.url} as ${format} (timeout ${timeoutSeconds}s)`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails,\n\t\t\t});\n\t\t};\n\t\temitProgress({\n\t\t\tphase: \"fetching\",\n\t\t\turl: params.url,\n\t\t\tformat,\n\t\t\ttimeoutSeconds,\n\t\t\tprogress,\n\t\t});\n\n\t\tconst fetched = await fetchUrl({\n\t\t\turl: params.url,\n\t\t\tformat,\n\t\t\ttimeoutSeconds,\n\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\tonProgress: (bytesRead, totalBytes) => {\n\t\t\t\tdownloadedTotalBytes = totalBytes;\n\t\t\t\temitProgress({\n\t\t\t\t\tphase: \"downloading\",\n\t\t\t\t\turl: params.url,\n\t\t\t\t\tformat,\n\t\t\t\t\ttimeoutSeconds,\n\t\t\t\t\tbytesRead,\n\t\t\t\t\t...(totalBytes === undefined ? {} : { totalBytes }),\n\t\t\t\t\tprogress,\n\t\t\t\t});\n\t\t\t},\n\t\t});\n\t\tconst raw = new TextDecoder().decode(fetched.body);\n\t\tconst contentType = fetched.contentType.toLowerCase();\n\t\temitProgress({\n\t\t\tphase: \"converting\",\n\t\t\turl: params.url,\n\t\t\tformat,\n\t\t\ttimeoutSeconds,\n\t\t\tbytesRead: fetched.bytes,\n\t\t\t...(downloadedTotalBytes === undefined ? {} : { totalBytes: downloadedTotalBytes }),\n\t\t\tprogress,\n\t\t});\n\t\tconst isHtml = contentType.includes(\"text/html\") || contentType.includes(\"application/xhtml+xml\");\n\t\tlet text = raw;\n\t\tlet converted = false;\n\n\t\tif (isHtml && format === \"markdown\") {\n\t\t\ttext = await htmlToMarkdown(raw, fetched.url);\n\t\t\tconverted = true;\n\t\t} else if (isHtml && format === \"text\") {\n\t\t\ttext = await htmlToText(raw, fetched.url);\n\t\t\tconverted = true;\n\t\t}\n\n\t\tconst capped = capWebfetchOutput(text);\n\n\t\tconst details: WebfetchDetails = {\n\t\t\turl: params.url,\n\t\t\tfinalUrl: fetched.url,\n\t\t\tformat,\n\t\t\tstatus: fetched.status,\n\t\t\tstatusText: fetched.statusText,\n\t\t\tcontentType: fetched.contentType,\n\t\t\tbytes: fetched.bytes,\n\t\t\ttimeoutSeconds,\n\t\t\tconverted,\n\t\t\ttruncated: fetched.truncated,\n\t\t\toutputTruncated: capped.truncated,\n\t\t\toutputBytes: capped.outputBytes,\n\t\t\toutputTotalBytes: capped.totalBytes,\n\t\t};\n\n\t\tconst content: TextContent[] = [\n\t\t\t{ type: \"text\", text: capped.notice === undefined ? capped.text : `${capped.text}\\n` },\n\t\t];\n\t\tif (capped.notice !== undefined) content.push(modelOnlyText(capped.notice));\n\t\treturn {\n\t\t\tcontent,\n\t\t\tdetails,\n\t\t};\n\t},\n});\n\nexport function parseWebfetchFormat(value: unknown): WebfetchFormat {\n\tif (value === undefined) return \"markdown\";\n\tfor (const format of WEBFETCH_FORMATS) {\n\t\tif (value === format) return format;\n\t}\n\treturn \"markdown\";\n}\n\n/** Byte ceiling for the text handed to the model, mirroring senpi's read-tool output cap. */\nexport const DEFAULT_OUTPUT_MAX_BYTES = 50 * 1024;\n\nexport interface WebfetchOutputCap {\n\t/** Model-facing body after the output cap. */\n\ttext: string;\n\t/** Separate model-only continuation notice when truncated. */\n\tnotice?: string;\n\t/** Whether the text was capped below the full converted size. */\n\ttruncated: boolean;\n\t/** Byte length of {@link WebfetchOutputCap.text} excluding the appended notice. */\n\toutputBytes: number;\n\t/** Byte length of the full converted text before capping. */\n\ttotalBytes: number;\n}\n\n/**\n * Bound the text handed to the model so a single fetch cannot flood the context\n * window and force an unwanted compaction. Keeps whole leading lines until the\n * byte ceiling is hit; when the first line alone exceeds the ceiling (minified\n * JSON, single-line payloads) it falls back to a UTF-8-safe byte prefix so the\n * head is preserved instead of dropped.\n */\nexport function capWebfetchOutput(text: string): WebfetchOutputCap {\n\tconst totalBytes = Buffer.byteLength(text, \"utf-8\");\n\tif (totalBytes <= DEFAULT_OUTPUT_MAX_BYTES) {\n\t\treturn { text, truncated: false, outputBytes: totalBytes, totalBytes };\n\t}\n\n\tconst head = takeHeadBytes(text, DEFAULT_OUTPUT_MAX_BYTES);\n\tconst outputBytes = Buffer.byteLength(head, \"utf-8\");\n\tconst notice = `[Output truncated: ${formatByteSize(outputBytes)} of ${formatByteSize(\n\t\ttotalBytes,\n\t)} shown (${formatByteSize(DEFAULT_OUTPUT_MAX_BYTES)} limit). Re-fetch a more specific URL or use web_search for targeted content.]`;\n\treturn { text: head, notice, truncated: true, outputBytes, totalBytes };\n}\n\n/** Keep whole leading lines within the byte ceiling; fall back to a UTF-8-safe byte prefix for one oversized line. */\nfunction takeHeadBytes(text: string, maxBytes: number): string {\n\tconst lines: string[] = [];\n\tlet usedBytes = 0;\n\tlet start = 0;\n\twhile (start <= text.length) {\n\t\tconst newlineIndex = text.indexOf(\"\\n\", start);\n\t\tconst line = newlineIndex === -1 ? text.slice(start) : text.slice(start, newlineIndex);\n\t\tconst lineBytes = Buffer.byteLength(line, \"utf-8\") + (lines.length > 0 ? 1 : 0);\n\t\tif (usedBytes + lineBytes > maxBytes) break;\n\t\tlines.push(line);\n\t\tusedBytes += lineBytes;\n\t\tif (newlineIndex === -1) break;\n\t\tstart = newlineIndex + 1;\n\t}\n\treturn lines.length === 0 ? sliceUtf8Head(text, maxBytes) : lines.join(\"\\n\");\n}\n\n/** Slice the first {@link maxBytes} bytes of a UTF-8 string without leaving a split code point. */\nfunction sliceUtf8Head(value: string, maxBytes: number): string {\n\tconst buffer = Buffer.from(value, \"utf-8\");\n\tif (buffer.length <= maxBytes) return value;\n\tconst decoded = new TextDecoder(\"utf-8\").decode(buffer.subarray(0, maxBytes));\n\t// A trailing partial code point decodes to U+FFFD; drop it so no split byte remains.\n\treturn decoded.endsWith(\"\\uFFFD\") ? decoded.slice(0, -1) : decoded;\n}\n\n/** Human-readable byte size (B / KB / MB). */\nfunction formatByteSize(bytes: number): string {\n\tif (bytes < 1024) return `${bytes}B`;\n\tif (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n\treturn `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-resolver.d.ts","sourceRoot":"","sources":["../../src/core/model-resolver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EACN,KAAK,GAAG,EACR,KAAK,oBAAoB,EAGzB,KAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"model-resolver.d.ts","sourceRoot":"","sources":["../../src/core/model-resolver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EACN,KAAK,GAAG,EACR,KAAK,oBAAoB,EAGzB,KAAK,KAAK,EAIV,KAAK,iBAAiB,EACtB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACrC,YAAY,CACX,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,oBAAoB,GAC5B,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;CAC1D;AAED,KAAK,gBAAgB,GAAG,YAAY,GAAG,aAAa,GAAG,qBAAqB,CAAC;AAE7E,gDAAgD;AAChD,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAkD1D,CAAC;AAEF,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,kGAAkG;IAClG,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,+EAA+E;IAC/E,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,uFAAuF;IACvF,WAAW,CAAC,EAAE,WAAW,CAAC;CAC1B;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE;IAClD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC,GAAG,MAAM,EAAE,CAEX;AAeD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC3C,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAC3B,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAuCxB;AASD,UAAU,sBAAsB;IAC/B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACtC;AA0HD,wBAAgB,2BAA2B,CAC1C,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAA;CAAE,GAClF,sBAAsB,GAAG,SAAS,CAkBpC;AAkCD,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC9B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAwBD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EAC7B,OAAO,CAAC,EAAE;IAAE,iCAAiC,CAAC,EAAE,OAAO,CAAA;CAAE,GACvD,iBAAiB,CAmEnB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,UAAU,GAAG,wBAAwB,CAAC;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,uBAAuB;IACvC,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,WAAW,EAAE,oBAAoB,EAAE,CAAC;IACpC,0EAA0E;IAC1E,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;CACxC;AAED,wBAAgB,2BAA2B,CAC1C,QAAQ,EAAE,MAAM,EAAE,EAClB,MAAM,EAAE,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,GAC3B,uBAAuB,CAsJzB;AAED,MAAM,WAAW,wBAAyB,SAAQ,oBAAoB;IACrE,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,wBAAsB,gCAAgC,CACrD,QAAQ,EAAE,MAAM,EAAE,EAClB,YAAY,EAAE,gBAAgB,EAC9B,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,uBAAuB,CAAC,CAElC;AAED,wBAAsB,iBAAiB,CACtC,QAAQ,EAAE,MAAM,EAAE,EAClB,YAAY,EAAE,gBAAgB,EAC9B,OAAO,CAAC,EAAE,wBAAwB,GAChC,OAAO,CAAC,WAAW,EAAE,CAAC,CAUxB;AAED,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC9B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B,YAAY,EAAE,YAAY,CAAC;CAC3B,GAAG,qBAAqB,CAuMxB;AAED,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,QAAQ,GAAG,UAAU,GAAG,kBAAkB,GAAG,iBAAiB,CAAC;AAE5G,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC9B,mFAAmF;IACnF,aAAa,EAAE,aAAa,GAAG,SAAS,CAAC;IACzC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,UAAU,EAAE,sBAAsB,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,aAAa,CAAC;IACrC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACpD,YAAY,EAAE,YAAY,CAAC;CAC3B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA8F9B;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC5C,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,EACpC,mBAAmB,EAAE,OAAO,EAC5B,YAAY,EAAE,YAAY,GACxB,OAAO,CAAC;IACV,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC9B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC,CAAC,CAoED"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model resolution, scoping, and initial selection
|
|
3
3
|
*/
|
|
4
|
-
import { getCursorVariantAlias, modelsAreEqual, } from "@earendil-works/pi-ai";
|
|
4
|
+
import { getCursorVariantAlias, modelsAreEqual, parseCursorVariantId, } from "@earendil-works/pi-ai";
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
import { minimatch } from "minimatch";
|
|
7
7
|
import { isValidThinkingLevel } from "../cli/args.js";
|
|
@@ -120,6 +120,44 @@ function legacySelection(legacyVariantId) {
|
|
|
120
120
|
return undefined;
|
|
121
121
|
return { level: alias.level, source: "legacy-variant", legacyVariantId };
|
|
122
122
|
}
|
|
123
|
+
function derivedCursorVariantIds(model) {
|
|
124
|
+
if ((model.provider !== "cursor" || model.api !== "cursor-agent") &&
|
|
125
|
+
(model.provider !== "cursor-cli-oauth" || model.api !== "cursor-cli-oauth"))
|
|
126
|
+
return undefined;
|
|
127
|
+
// The CLI provider registers its own API id but shares Cursor's catalog compat schema.
|
|
128
|
+
return model.compat?.cursorReasoning?.variantIds;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Reverse lookup through variant ids a runtime-derived Cursor group observed (senpi#2038).
|
|
132
|
+
* Case-insensitive like `findExactModelReferenceMatch`, which resolved these ids before grouping.
|
|
133
|
+
*/
|
|
134
|
+
function derivedCursorVariantMatch(model, reference) {
|
|
135
|
+
const variantIds = derivedCursorVariantIds(model);
|
|
136
|
+
if (variantIds === undefined)
|
|
137
|
+
return undefined;
|
|
138
|
+
const normalized = reference.toLowerCase();
|
|
139
|
+
for (const [level, id] of Object.entries(variantIds)) {
|
|
140
|
+
if (id?.toLowerCase() === normalized)
|
|
141
|
+
return { level: level, variantId: id };
|
|
142
|
+
}
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
function derivedResolution(model, match) {
|
|
146
|
+
return {
|
|
147
|
+
model,
|
|
148
|
+
thinkingLevel: match.level,
|
|
149
|
+
thinkingSelection: { level: match.level, source: "legacy-variant", legacyVariantId: match.variantId },
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function cursorLegacySelection(model, variantId) {
|
|
153
|
+
const alias = legacySelection(variantId);
|
|
154
|
+
if (alias)
|
|
155
|
+
return alias;
|
|
156
|
+
const match = derivedCursorVariantMatch(model, variantId);
|
|
157
|
+
return match === undefined
|
|
158
|
+
? undefined
|
|
159
|
+
: { level: match.level, source: "legacy-variant", legacyVariantId: match.variantId };
|
|
160
|
+
}
|
|
123
161
|
function resolveLegacyCursorReference(modelReference, availableModels) {
|
|
124
162
|
const trimmed = modelReference.trim();
|
|
125
163
|
if (!trimmed)
|
|
@@ -128,19 +166,31 @@ function resolveLegacyCursorReference(modelReference, availableModels) {
|
|
|
128
166
|
const explicitProvider = slashIndex === -1 ? undefined : trimmed.slice(0, slashIndex);
|
|
129
167
|
const legacyVariantId = slashIndex === -1 ? trimmed : trimmed.slice(slashIndex + 1);
|
|
130
168
|
const alias = getCursorVariantAlias(legacyVariantId);
|
|
131
|
-
|
|
169
|
+
const providerMatches = (model) => CURSOR_PROVIDER_IDS.has(model.provider) &&
|
|
170
|
+
(!explicitProvider || model.provider.toLowerCase() === explicitProvider.toLowerCase());
|
|
171
|
+
if (alias) {
|
|
172
|
+
const candidates = availableModels.filter((model) => providerMatches(model) && model.id === alias.targetId);
|
|
173
|
+
if (candidates.length !== 1)
|
|
174
|
+
return undefined;
|
|
175
|
+
const thinkingSelection = legacySelection(legacyVariantId);
|
|
176
|
+
return {
|
|
177
|
+
model: candidates[0],
|
|
178
|
+
thinkingLevel: thinkingSelection?.level,
|
|
179
|
+
thinkingSelection,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
// Unlike static aliases, derived aliases must not displace an exact raw model.
|
|
183
|
+
const exactCandidates = explicitProvider ? availableModels.filter(providerMatches) : availableModels;
|
|
184
|
+
if (findExactModelReferenceMatch(trimmed, [...exactCandidates]))
|
|
132
185
|
return undefined;
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
model
|
|
136
|
-
|
|
186
|
+
// Variant ids only the runtime derivation groups resolve through the observed ids (senpi#2038).
|
|
187
|
+
const derivedCandidates = availableModels.flatMap((model) => {
|
|
188
|
+
const match = providerMatches(model) ? derivedCursorVariantMatch(model, legacyVariantId) : undefined;
|
|
189
|
+
return match === undefined ? [] : [{ model, match }];
|
|
190
|
+
});
|
|
191
|
+
if (derivedCandidates.length !== 1)
|
|
137
192
|
return undefined;
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
model: candidates[0],
|
|
141
|
-
thinkingLevel: thinkingSelection?.level,
|
|
142
|
-
thinkingSelection,
|
|
143
|
-
};
|
|
193
|
+
return derivedResolution(derivedCandidates[0].model, derivedCandidates[0].match);
|
|
144
194
|
}
|
|
145
195
|
function cursorLegacyAliasesForModel(model) {
|
|
146
196
|
if (!CURSOR_PROVIDER_IDS.has(model.provider))
|
|
@@ -154,7 +204,22 @@ function cursorLegacyAliasesForModel(model) {
|
|
|
154
204
|
candidates.add(`${baseId}-${level}-thinking`);
|
|
155
205
|
candidates.add(`${targetId}-${level}`);
|
|
156
206
|
}
|
|
157
|
-
|
|
207
|
+
const aliases = [...candidates].filter((candidate) => getCursorVariantAlias(candidate)?.targetId === targetId);
|
|
208
|
+
for (const derivedId of Object.values(derivedCursorVariantIds(model) ?? {})) {
|
|
209
|
+
aliases.push(derivedId);
|
|
210
|
+
}
|
|
211
|
+
return aliases;
|
|
212
|
+
}
|
|
213
|
+
function resolveDerivedCursorVariant(provider, modelId, modelSource) {
|
|
214
|
+
const parsed = parseCursorVariantId(modelId);
|
|
215
|
+
if (parsed.fast || parsed.level === undefined || parsed.baseId === "")
|
|
216
|
+
return undefined;
|
|
217
|
+
const targetId = parsed.thinking === true ? `${parsed.baseId}-thinking` : parsed.baseId;
|
|
218
|
+
const model = modelSource.getModel(provider, targetId);
|
|
219
|
+
const match = model === undefined ? undefined : derivedCursorVariantMatch(model, modelId);
|
|
220
|
+
if (model === undefined || match === undefined)
|
|
221
|
+
return undefined;
|
|
222
|
+
return derivedResolution(model, match);
|
|
158
223
|
}
|
|
159
224
|
export function resolveStoredModelReference(provider, modelId, modelSource) {
|
|
160
225
|
if (CURSOR_PROVIDER_IDS.has(provider)) {
|
|
@@ -166,6 +231,14 @@ export function resolveStoredModelReference(provider, modelId, modelSource) {
|
|
|
166
231
|
return { model, thinkingLevel: thinkingSelection?.level, thinkingSelection };
|
|
167
232
|
}
|
|
168
233
|
}
|
|
234
|
+
else {
|
|
235
|
+
const direct = modelSource.getModel(provider, modelId);
|
|
236
|
+
if (direct)
|
|
237
|
+
return { model: direct };
|
|
238
|
+
const derived = resolveDerivedCursorVariant(provider, modelId, modelSource);
|
|
239
|
+
if (derived)
|
|
240
|
+
return derived;
|
|
241
|
+
}
|
|
169
242
|
}
|
|
170
243
|
const direct = modelSource.getModel(provider, modelId);
|
|
171
244
|
return direct ? { model: direct } : undefined;
|
|
@@ -361,7 +434,7 @@ export function resolveModelScopeFromModels(patterns, models) {
|
|
|
361
434
|
if (!matches(model.provider, aliasId))
|
|
362
435
|
continue;
|
|
363
436
|
const projection = projections.get(id) ?? { model, aliases: [] };
|
|
364
|
-
projection.aliases.push({ id: aliasId, selection:
|
|
437
|
+
projection.aliases.push({ id: aliasId, selection: cursorLegacySelection(model, aliasId) });
|
|
365
438
|
projections.set(id, projection);
|
|
366
439
|
}
|
|
367
440
|
}
|