@astralyn/pi 0.84.14 → 0.84.16
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 +23 -0
- package/dist/cli.js +2435 -18
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +12 -6
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/types.d.ts +4 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/tools/bash.d.ts +1 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +4 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/find.d.ts +2 -0
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +18 -15
- package/dist/core/tools/find.js.map +1 -1
- package/dist/extensions/background/actions.d.ts.map +1 -1
- package/dist/extensions/background/actions.js +3 -2
- package/dist/extensions/background/actions.js.map +1 -1
- package/dist/extensions/background/index.d.ts +5 -4
- package/dist/extensions/background/index.d.ts.map +1 -1
- package/dist/extensions/background/index.js +9 -5
- package/dist/extensions/background/index.js.map +1 -1
- package/dist/extensions/background/manager.d.ts.map +1 -1
- package/dist/extensions/background/manager.js +8 -9
- package/dist/extensions/background/manager.js.map +1 -1
- package/dist/extensions/background/registry.d.ts +4 -1
- package/dist/extensions/background/registry.d.ts.map +1 -1
- package/dist/extensions/background/registry.js +30 -17
- package/dist/extensions/background/registry.js.map +1 -1
- package/dist/extensions/background/task-view.d.ts +6 -0
- package/dist/extensions/background/task-view.d.ts.map +1 -1
- package/dist/extensions/background/task-view.js +11 -6
- package/dist/extensions/background/task-view.js.map +1 -1
- package/dist/extensions/deepwiki/client.d.ts.map +1 -1
- package/dist/extensions/deepwiki/client.js +3 -0
- package/dist/extensions/deepwiki/client.js.map +1 -1
- package/dist/extensions/deepwiki/execute.d.ts +2 -1
- package/dist/extensions/deepwiki/execute.d.ts.map +1 -1
- package/dist/extensions/deepwiki/execute.js +17 -2
- package/dist/extensions/deepwiki/execute.js.map +1 -1
- package/dist/extensions/deepwiki/http.d.ts +1 -0
- package/dist/extensions/deepwiki/http.d.ts.map +1 -1
- package/dist/extensions/deepwiki/http.js +16 -2
- package/dist/extensions/deepwiki/http.js.map +1 -1
- package/dist/extensions/deepwiki/schema.d.ts +1 -1
- package/dist/extensions/deepwiki/schema.d.ts.map +1 -1
- package/dist/extensions/deepwiki/schema.js +8 -2
- package/dist/extensions/deepwiki/schema.js.map +1 -1
- package/dist/extensions/question/dialog.d.ts.map +1 -1
- package/dist/extensions/question/dialog.js +80 -9
- package/dist/extensions/question/dialog.js.map +1 -1
- package/dist/extensions/question/index.d.ts.map +1 -1
- package/dist/extensions/question/index.js +8 -0
- package/dist/extensions/question/index.js.map +1 -1
- package/dist/extensions/question/schema.d.ts +2 -2
- package/dist/extensions/question/schema.d.ts.map +1 -1
- package/dist/extensions/question/schema.js +41 -11
- package/dist/extensions/question/schema.js.map +1 -1
- package/dist/extensions/question/types.d.ts +1 -1
- package/dist/extensions/question/types.d.ts.map +1 -1
- package/dist/extensions/question/types.js.map +1 -1
- package/dist/extensions/router/probe.d.ts.map +1 -1
- package/dist/extensions/router/probe.js +10 -29
- package/dist/extensions/router/probe.js.map +1 -1
- package/dist/extensions/router/register.d.ts.map +1 -1
- package/dist/extensions/router/register.js +16 -6
- package/dist/extensions/router/register.js.map +1 -1
- package/dist/extensions/router/store.d.ts.map +1 -1
- package/dist/extensions/router/store.js +108 -51
- package/dist/extensions/router/store.js.map +1 -1
- package/dist/extensions/router/ui.d.ts +6 -0
- package/dist/extensions/router/ui.d.ts.map +1 -1
- package/dist/extensions/router/ui.js +14 -6
- package/dist/extensions/router/ui.js.map +1 -1
- package/dist/extensions/statusline/index.d.ts.map +1 -1
- package/dist/extensions/statusline/index.js +40 -43
- package/dist/extensions/statusline/index.js.map +1 -1
- package/dist/extensions/subagent/activity.d.ts +7 -1
- package/dist/extensions/subagent/activity.d.ts.map +1 -1
- package/dist/extensions/subagent/activity.js +69 -6
- package/dist/extensions/subagent/activity.js.map +1 -1
- package/dist/extensions/subagent/agents-command.js +1 -1
- package/dist/extensions/subagent/agents-command.js.map +1 -1
- package/dist/extensions/subagent/agents.d.ts.map +1 -1
- package/dist/extensions/subagent/agents.js +0 -3
- package/dist/extensions/subagent/agents.js.map +1 -1
- package/dist/extensions/subagent/budget.d.ts.map +1 -1
- package/dist/extensions/subagent/budget.js +29 -2
- package/dist/extensions/subagent/budget.js.map +1 -1
- package/dist/extensions/subagent/cancellation.d.ts +4 -4
- package/dist/extensions/subagent/cancellation.d.ts.map +1 -1
- package/dist/extensions/subagent/cancellation.js +31 -13
- package/dist/extensions/subagent/cancellation.js.map +1 -1
- package/dist/extensions/subagent/constants.d.ts +1 -0
- package/dist/extensions/subagent/constants.d.ts.map +1 -1
- package/dist/extensions/subagent/constants.js +1 -0
- package/dist/extensions/subagent/constants.js.map +1 -1
- package/dist/extensions/subagent/index.d.ts.map +1 -1
- package/dist/extensions/subagent/index.js +1 -0
- package/dist/extensions/subagent/index.js.map +1 -1
- package/dist/extensions/subagent/render.d.ts +8 -1
- package/dist/extensions/subagent/render.d.ts.map +1 -1
- package/dist/extensions/subagent/render.js +155 -178
- package/dist/extensions/subagent/render.js.map +1 -1
- package/dist/extensions/subagent/runner.d.ts +1 -0
- package/dist/extensions/subagent/runner.d.ts.map +1 -1
- package/dist/extensions/subagent/runner.js +53 -44
- package/dist/extensions/subagent/runner.js.map +1 -1
- package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
- package/dist/extensions/subagent/sdk-runner.js +0 -3
- package/dist/extensions/subagent/sdk-runner.js.map +1 -1
- package/dist/extensions/subagent/settings.d.ts +1 -1
- package/dist/extensions/subagent/settings.d.ts.map +1 -1
- package/dist/extensions/subagent/settings.js +74 -25
- package/dist/extensions/subagent/settings.js.map +1 -1
- package/dist/extensions/subagent/state.d.ts +1 -0
- package/dist/extensions/subagent/state.d.ts.map +1 -1
- package/dist/extensions/subagent/state.js +46 -16
- package/dist/extensions/subagent/state.js.map +1 -1
- package/dist/extensions/subagent/types.d.ts +0 -7
- package/dist/extensions/subagent/types.d.ts.map +1 -1
- package/dist/extensions/subagent/types.js.map +1 -1
- package/dist/extensions/subagent/ui/agents-dialog.js +1 -1
- package/dist/extensions/subagent/ui/agents-dialog.js.map +1 -1
- package/dist/extensions/subagent/ui/model-list.d.ts.map +1 -1
- package/dist/extensions/subagent/ui/model-list.js +3 -4
- package/dist/extensions/subagent/ui/model-list.js.map +1 -1
- package/dist/extensions/subagent/ui/model-picker.d.ts.map +1 -1
- package/dist/extensions/subagent/ui/model-picker.js +2 -1
- package/dist/extensions/subagent/ui/model-picker.js.map +1 -1
- package/dist/extensions/web-search/format.d.ts.map +1 -1
- package/dist/extensions/web-search/format.js +36 -15
- package/dist/extensions/web-search/format.js.map +1 -1
- package/dist/extensions/web-search/index.d.ts.map +1 -1
- package/dist/extensions/web-search/index.js +11 -8
- package/dist/extensions/web-search/index.js.map +1 -1
- package/dist/extensions/web-search/providers/deepseek.d.ts.map +1 -1
- package/dist/extensions/web-search/providers/deepseek.js +36 -5
- package/dist/extensions/web-search/providers/deepseek.js.map +1 -1
- package/dist/extensions/web-search/providers/http.d.ts +2 -7
- package/dist/extensions/web-search/providers/http.d.ts.map +1 -1
- package/dist/extensions/web-search/providers/http.js +12 -57
- package/dist/extensions/web-search/providers/http.js.map +1 -1
- package/dist/extensions/web-search/providers/minimax.d.ts.map +1 -1
- package/dist/extensions/web-search/providers/minimax.js +18 -6
- package/dist/extensions/web-search/providers/minimax.js.map +1 -1
- package/dist/extensions/web-search/render.d.ts.map +1 -1
- package/dist/extensions/web-search/render.js +16 -5
- package/dist/extensions/web-search/render.js.map +1 -1
- package/dist/extensions/web-search/results.d.ts +10 -3
- package/dist/extensions/web-search/results.d.ts.map +1 -1
- package/dist/extensions/web-search/results.js +25 -7
- package/dist/extensions/web-search/results.js.map +1 -1
- package/dist/image-resize-worker.js +2 -0
- package/dist/modes/interactive/components/tool-execution.d.ts +1 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +7 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-group.js +10 -0
- package/dist/modes/interactive/components/tool-group.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +3 -40
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +0 -4
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +16 -23
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/rpc-entry.js +2435 -10
- package/dist/utils/http-response.d.ts +10 -0
- package/dist/utils/http-response.d.ts.map +1 -0
- package/dist/utils/http-response.js +68 -0
- package/dist/utils/http-response.js.map +1 -0
- package/docs/bundled/extensions/background.md +4 -3
- package/docs/bundled/extensions/deepwiki.md +7 -5
- package/docs/bundled/extensions/question.md +6 -4
- package/docs/bundled/extensions/router.md +1 -1
- package/docs/bundled/extensions/statusline.md +1 -0
- package/docs/bundled/extensions/subagent.md +29 -39
- package/docs/bundled/extensions/web-search.md +3 -3
- package/docs/development.md +8 -3
- package/docs/extensions.md +2 -2
- package/npm-shrinkwrap.json +110 -109
- package/package.json +4 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"probe.js","sourceRoot":"","sources":["../../../src/extensions/router/probe.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAElE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AASvD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAKtC;IACA,IAAI,OAAY,CAAC;IACjB,IAAI,CAAC;QACJ,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC;IAC7D,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACnE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;IAC1E,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,EAAE,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IACpE,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,QAAQ,CAAC,cAAc,CAAC;IAC5D,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAC9D,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC9C,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAErE,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC1C,MAAM,OAAO,GAA2B,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;QACvE,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,aAAa,GAAG,UAAU,IAAI,CAAC,MAAM,EAAE,CAAC;QAEjE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QAC1E,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,IAAI,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"probe.js","sourceRoot":"","sources":["../../../src/extensions/router/probe.ts"],"names":[],"mappings":"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","sourcesContent":["/** Fetch OpenAI-compatible model catalog from a relay baseUrl. */\n\nimport { readResponseTextBounded } from \"../../utils/http-response.ts\";\nimport { DEFAULTS, formatError } from \"./constants.ts\";\n\nexport interface ProbeModel {\n\tid: string;\n\tname?: string;\n}\n\nexport type ProbeResult = { ok: true; models: ProbeModel[]; truncated: boolean } | { ok: false; error: string };\n\nexport async function probeRelayModels(opts: {\n\tbaseUrl: string;\n\tapiKey?: string;\n\tsignal?: AbortSignal;\n\ttimeoutMs?: number;\n}): Promise<ProbeResult> {\n\tlet baseUrl: URL;\n\ttry {\n\t\tbaseUrl = new URL(opts.baseUrl);\n\t} catch {\n\t\treturn { ok: false, error: \"Base URL is not a valid URL.\" };\n\t}\n\tif (baseUrl.protocol !== \"http:\" && baseUrl.protocol !== \"https:\") {\n\t\treturn { ok: false, error: `Unsupported protocol: ${baseUrl.protocol}` };\n\t}\n\n\tif (opts.signal?.aborted) return { ok: false, error: \"Cancelled.\" };\n\tconst controller = new AbortController();\n\tconst timeoutMs = opts.timeoutMs ?? DEFAULTS.probeTimeoutMs;\n\tconst timer = setTimeout(() => controller.abort(), timeoutMs);\n\tconst onOuterAbort = () => controller.abort();\n\topts.signal?.addEventListener(\"abort\", onOuterAbort, { once: true });\n\n\ttry {\n\t\tconst url = appendPath(baseUrl, \"models\");\n\t\tconst headers: Record<string, string> = { Accept: \"application/json\" };\n\t\tif (opts.apiKey) headers.Authorization = `Bearer ${opts.apiKey}`;\n\n\t\tconst response = await fetch(url, { headers, signal: controller.signal });\n\t\tif (!response.ok) {\n\t\t\tconst body = await readResponseTextBounded(response, {\n\t\t\t\tmaxBytes: 4_096,\n\t\t\t\tsignal: controller.signal,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: `HTTP ${response.status}${body ? `: ${body.slice(0, 400)}` : \"\"}`,\n\t\t\t};\n\t\t}\n\t\tconst text = await readResponseTextBounded(response, {\n\t\t\tmaxBytes: DEFAULTS.probeBodyBytes,\n\t\t\toverflowMessage: `Response exceeds ${DEFAULTS.probeBodyBytes} bytes.`,\n\t\t\tsignal: controller.signal,\n\t\t});\n\t\tlet json: unknown;\n\t\ttry {\n\t\t\tjson = JSON.parse(text);\n\t\t} catch {\n\t\t\treturn { ok: false, error: \"Model catalog response is not JSON.\" };\n\t\t}\n\t\tconst models = parseOpenAIModels(json);\n\t\tif (models === null) {\n\t\t\treturn { ok: false, error: \"JSON has no OpenAI-style `data` array of model ids.\" };\n\t\t}\n\t\tconst sorted = dedupeSort(models);\n\t\tconst truncated = sorted.length > DEFAULTS.probeMaxModels;\n\t\treturn {\n\t\t\tok: true,\n\t\t\tmodels: sorted.slice(0, DEFAULTS.probeMaxModels),\n\t\t\ttruncated,\n\t\t};\n\t} catch (error) {\n\t\tif (controller.signal.aborted) {\n\t\t\treturn { ok: false, error: opts.signal?.aborted ? \"Cancelled.\" : `Timed out after ${timeoutMs}ms.` };\n\t\t}\n\t\treturn { ok: false, error: formatError(error) };\n\t} finally {\n\t\tclearTimeout(timer);\n\t\topts.signal?.removeEventListener(\"abort\", onOuterAbort);\n\t}\n}\n\nfunction appendPath(base: URL, segment: string): URL {\n\tconst url = new URL(base.href);\n\tconst path = url.pathname.replace(/\\/+$/, \"\");\n\turl.pathname = `${path}/${segment}`;\n\treturn url;\n}\n\nfunction parseOpenAIModels(json: unknown): ProbeModel[] | null {\n\tif (!json || typeof json !== \"object\") return null;\n\tconst data = (json as { data?: unknown }).data;\n\tif (!Array.isArray(data)) return null;\n\tconst models: ProbeModel[] = [];\n\tfor (const item of data) {\n\t\tif (!item || typeof item !== \"object\") continue;\n\t\tconst record = item as Record<string, unknown>;\n\t\tconst id = typeof record.id === \"string\" ? record.id.trim() : \"\";\n\t\tif (!id) continue;\n\t\tconst name =\n\t\t\ttypeof record.name === \"string\" && record.name.trim() && record.name.trim() !== id\n\t\t\t\t? record.name.trim()\n\t\t\t\t: undefined;\n\t\tmodels.push(name ? { id, name } : { id });\n\t}\n\treturn models;\n}\n\nfunction dedupeSort(models: ProbeModel[]): ProbeModel[] {\n\tconst map = new Map<string, ProbeModel>();\n\tfor (const model of models) {\n\t\tif (!map.has(model.id)) map.set(model.id, model);\n\t}\n\treturn [...map.values()].sort((a, b) => a.id.localeCompare(b.id));\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/register.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/register.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAc1D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;EAYlD;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CA+BxE;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAe3E;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAOrE"}
|
|
@@ -4,8 +4,16 @@
|
|
|
4
4
|
import { ROUTER_API } from "./constants.js";
|
|
5
5
|
import { toRegisterModel } from "./presets.js";
|
|
6
6
|
import { streamRouterCodex } from "./stream.js";
|
|
7
|
-
/** Provider ids
|
|
8
|
-
const
|
|
7
|
+
/** Provider ids registered by this extension, isolated to each SDK host. */
|
|
8
|
+
const registeredIdsByApi = new WeakMap();
|
|
9
|
+
function registeredIdsFor(pi) {
|
|
10
|
+
let ids = registeredIdsByApi.get(pi);
|
|
11
|
+
if (!ids) {
|
|
12
|
+
ids = new Set();
|
|
13
|
+
registeredIdsByApi.set(pi, ids);
|
|
14
|
+
}
|
|
15
|
+
return ids;
|
|
16
|
+
}
|
|
9
17
|
export function toProviderConfig(relay) {
|
|
10
18
|
return {
|
|
11
19
|
name: relay.id,
|
|
@@ -20,6 +28,7 @@ export function toProviderConfig(relay) {
|
|
|
20
28
|
};
|
|
21
29
|
}
|
|
22
30
|
export function applyRouterFile(pi, file) {
|
|
31
|
+
const registeredIds = registeredIdsFor(pi);
|
|
23
32
|
const nextIds = new Set(file.relays.map((relay) => relay.id));
|
|
24
33
|
for (const id of [...registeredIds]) {
|
|
25
34
|
if (!nextIds.has(id)) {
|
|
@@ -40,7 +49,7 @@ export function applyRouterFile(pi, file) {
|
|
|
40
49
|
pi.unregisterProvider(relay.id);
|
|
41
50
|
}
|
|
42
51
|
catch {
|
|
43
|
-
//
|
|
52
|
+
// Ignore stale registrations after /reload.
|
|
44
53
|
}
|
|
45
54
|
registeredIds.delete(relay.id);
|
|
46
55
|
}
|
|
@@ -51,13 +60,14 @@ export function applyRouterFile(pi, file) {
|
|
|
51
60
|
}
|
|
52
61
|
}
|
|
53
62
|
export function registerOneRelay(pi, relay) {
|
|
63
|
+
const registeredIds = registeredIdsFor(pi);
|
|
54
64
|
if (relay.models.length === 0) {
|
|
55
65
|
if (registeredIds.has(relay.id)) {
|
|
56
66
|
try {
|
|
57
67
|
pi.unregisterProvider(relay.id);
|
|
58
68
|
}
|
|
59
69
|
catch {
|
|
60
|
-
//
|
|
70
|
+
// Ignore stale registrations after /reload.
|
|
61
71
|
}
|
|
62
72
|
registeredIds.delete(relay.id);
|
|
63
73
|
}
|
|
@@ -71,8 +81,8 @@ export function unregisterOneRelay(pi, id) {
|
|
|
71
81
|
pi.unregisterProvider(id);
|
|
72
82
|
}
|
|
73
83
|
catch {
|
|
74
|
-
//
|
|
84
|
+
// Ignore stale registrations after /reload.
|
|
75
85
|
}
|
|
76
|
-
|
|
86
|
+
registeredIdsFor(pi).delete(id);
|
|
77
87
|
}
|
|
78
88
|
//# sourceMappingURL=register.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/extensions/router/register.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/extensions/router/register.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Apply router.json relays to Pi via registerProvider (config form + streamSimple).\n */\n\nimport type { ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { ROUTER_API } from \"./constants.ts\";\nimport { toRegisterModel } from \"./presets.ts\";\nimport { streamRouterCodex } from \"./stream.ts\";\nimport type { RelayConfig, RouterFile } from \"./types.ts\";\n\n/** Provider ids registered by this extension, isolated to each SDK host. */\nconst registeredIdsByApi = new WeakMap<ExtensionAPI, Set<string>>();\n\nfunction registeredIdsFor(pi: ExtensionAPI): Set<string> {\n\tlet ids = registeredIdsByApi.get(pi);\n\tif (!ids) {\n\t\tids = new Set<string>();\n\t\tregisteredIdsByApi.set(pi, ids);\n\t}\n\treturn ids;\n}\n\nexport function toProviderConfig(relay: RelayConfig) {\n\treturn {\n\t\tname: relay.id,\n\t\tbaseUrl: relay.baseUrl.replace(/\\/+$/, \"\"),\n\t\tapiKey: relay.apiKey,\n\t\tapi: ROUTER_API,\n\t\tmodels: relay.models.map((model) => ({\n\t\t\t...toRegisterModel(model),\n\t\t\tapi: ROUTER_API,\n\t\t})),\n\t\tstreamSimple: streamRouterCodex,\n\t};\n}\n\nexport function applyRouterFile(pi: ExtensionAPI, file: RouterFile): void {\n\tconst registeredIds = registeredIdsFor(pi);\n\tconst nextIds = new Set(file.relays.map((relay) => relay.id));\n\n\tfor (const id of [...registeredIds]) {\n\t\tif (!nextIds.has(id)) {\n\t\t\ttry {\n\t\t\t\tpi.unregisterProvider(id);\n\t\t\t} catch {\n\t\t\t\t// Provider may already be gone after /reload.\n\t\t\t}\n\t\t\tregisteredIds.delete(id);\n\t\t}\n\t}\n\n\tfor (const relay of file.relays) {\n\t\t// Only register relays that have at least one model; empty catalog is not selectable.\n\t\tif (relay.models.length === 0) {\n\t\t\tif (registeredIds.has(relay.id)) {\n\t\t\t\ttry {\n\t\t\t\t\tpi.unregisterProvider(relay.id);\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore stale registrations after /reload.\n\t\t\t\t}\n\t\t\t\tregisteredIds.delete(relay.id);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tpi.registerProvider(relay.id, toProviderConfig(relay));\n\t\tregisteredIds.add(relay.id);\n\t}\n}\n\nexport function registerOneRelay(pi: ExtensionAPI, relay: RelayConfig): void {\n\tconst registeredIds = registeredIdsFor(pi);\n\tif (relay.models.length === 0) {\n\t\tif (registeredIds.has(relay.id)) {\n\t\t\ttry {\n\t\t\t\tpi.unregisterProvider(relay.id);\n\t\t\t} catch {\n\t\t\t\t// Ignore stale registrations after /reload.\n\t\t\t}\n\t\t\tregisteredIds.delete(relay.id);\n\t\t}\n\t\treturn;\n\t}\n\tpi.registerProvider(relay.id, toProviderConfig(relay));\n\tregisteredIds.add(relay.id);\n}\n\nexport function unregisterOneRelay(pi: ExtensionAPI, id: string): void {\n\ttry {\n\t\tpi.unregisterProvider(id);\n\t} catch {\n\t\t// Ignore stale registrations after /reload.\n\t}\n\tregisteredIdsFor(pi).delete(id);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAoB,UAAU,EAAoB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAoB,UAAU,EAAoB,MAAM,YAAY,CAAC;AAM9F,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC,CAU1D;AA4BD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CA0BvD;AA4ED,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BpE;AAeD,wBAAsB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAOzE;AAED,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAKjE"}
|
|
@@ -5,7 +5,10 @@ import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
6
|
import { getAgentDir } from "../../config.js";
|
|
7
7
|
import { withFileMutationQueue } from "../../core/tools/file-mutation-queue.js";
|
|
8
|
-
import { CONFIG_VERSION, isValidRelayId } from "./constants.js";
|
|
8
|
+
import { CONFIG_VERSION, isValidRelayId, THINKING_LEVELS } from "./constants.js";
|
|
9
|
+
const ROOT_FIELDS = ["version", "relays"];
|
|
10
|
+
const RELAY_FIELDS = ["id", "baseUrl", "apiKey", "models"];
|
|
11
|
+
const MODEL_FIELDS = ["id", "name", "reasoning", "input", "contextWindow", "maxTokens", "thinkingLevelMap"];
|
|
9
12
|
export function getRouterConfigPath() {
|
|
10
13
|
return join(getAgentDir(), "router.json");
|
|
11
14
|
}
|
|
@@ -25,6 +28,31 @@ export async function loadRouterFile() {
|
|
|
25
28
|
}
|
|
26
29
|
return parseRouterFile(raw);
|
|
27
30
|
}
|
|
31
|
+
function expectObject(value, path) {
|
|
32
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
33
|
+
throw new Error(`${path} must be an object.`);
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
function rejectUnknownFields(record, allowed, path) {
|
|
38
|
+
const unknown = Object.keys(record).filter((key) => !allowed.includes(key));
|
|
39
|
+
if (unknown.length > 0)
|
|
40
|
+
throw new Error(`${path} has unsupported field(s): ${unknown.join(", ")}.`);
|
|
41
|
+
}
|
|
42
|
+
function expectString(value, path, allowEmpty = false) {
|
|
43
|
+
if (typeof value !== "string")
|
|
44
|
+
throw new Error(`${path} must be a string.`);
|
|
45
|
+
const trimmed = value.trim();
|
|
46
|
+
if (!allowEmpty && !trimmed)
|
|
47
|
+
throw new Error(`${path} must not be empty.`);
|
|
48
|
+
return allowEmpty ? value : trimmed;
|
|
49
|
+
}
|
|
50
|
+
function expectPositiveInteger(value, path) {
|
|
51
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
52
|
+
throw new Error(`${path} must be a positive integer.`);
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
28
56
|
export function parseRouterFile(raw) {
|
|
29
57
|
let parsed;
|
|
30
58
|
try {
|
|
@@ -33,71 +61,100 @@ export function parseRouterFile(raw) {
|
|
|
33
61
|
catch {
|
|
34
62
|
throw new Error("router.json is not valid JSON.");
|
|
35
63
|
}
|
|
36
|
-
|
|
37
|
-
|
|
64
|
+
const root = expectObject(parsed, "router.json");
|
|
65
|
+
rejectUnknownFields(root, ROOT_FIELDS, "router.json");
|
|
66
|
+
const version = root.version ?? CONFIG_VERSION;
|
|
67
|
+
if (version !== CONFIG_VERSION) {
|
|
68
|
+
throw new Error(`router.json has unsupported version ${String(version)}.`);
|
|
38
69
|
}
|
|
39
|
-
|
|
40
|
-
const relaysRaw = root.relays;
|
|
41
|
-
if (relaysRaw !== undefined && !Array.isArray(relaysRaw)) {
|
|
70
|
+
if (root.relays !== undefined && !Array.isArray(root.relays)) {
|
|
42
71
|
throw new Error("router.json relays must be an array.");
|
|
43
72
|
}
|
|
44
|
-
const relays = [];
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (relay)
|
|
48
|
-
|
|
73
|
+
const relays = (root.relays ?? []).map((value, index) => parseRelay(value, `router.json relays[${index}]`));
|
|
74
|
+
const relayIds = new Set();
|
|
75
|
+
for (const relay of relays) {
|
|
76
|
+
if (relayIds.has(relay.id))
|
|
77
|
+
throw new Error(`router.json contains duplicate relay id "${relay.id}".`);
|
|
78
|
+
relayIds.add(relay.id);
|
|
49
79
|
}
|
|
50
80
|
return { version: CONFIG_VERSION, relays };
|
|
51
81
|
}
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
82
|
+
function parseRelay(value, path) {
|
|
83
|
+
const record = expectObject(value, path);
|
|
84
|
+
rejectUnknownFields(record, RELAY_FIELDS, path);
|
|
85
|
+
const id = expectString(record.id, `${path}.id`);
|
|
86
|
+
if (!isValidRelayId(id))
|
|
87
|
+
throw new Error(`${path}.id must be a valid provider id without '/'.`);
|
|
88
|
+
const baseUrl = expectString(record.baseUrl, `${path}.baseUrl`);
|
|
89
|
+
try {
|
|
90
|
+
const url = new URL(baseUrl);
|
|
91
|
+
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
92
|
+
throw new Error("unsupported protocol");
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
throw new Error(`${path}.baseUrl must be an http or https URL.`);
|
|
96
|
+
}
|
|
97
|
+
const apiKey = expectString(record.apiKey, `${path}.apiKey`, true);
|
|
98
|
+
if (record.models !== undefined && !Array.isArray(record.models)) {
|
|
99
|
+
throw new Error(`${path}.models must be an array.`);
|
|
100
|
+
}
|
|
101
|
+
const models = (record.models ?? []).map((model, index) => parseModel(model, `${path}.models[${index}]`));
|
|
102
|
+
const modelIds = new Set();
|
|
103
|
+
for (const model of models) {
|
|
104
|
+
if (modelIds.has(model.id))
|
|
105
|
+
throw new Error(`${path}.models contains duplicate id "${model.id}".`);
|
|
106
|
+
modelIds.add(model.id);
|
|
68
107
|
}
|
|
69
108
|
return { id, baseUrl, apiKey, models };
|
|
70
109
|
}
|
|
71
|
-
function
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
110
|
+
function parseModel(value, path) {
|
|
111
|
+
const record = expectObject(value, path);
|
|
112
|
+
rejectUnknownFields(record, MODEL_FIELDS, path);
|
|
113
|
+
const model = { id: expectString(record.id, `${path}.id`) };
|
|
114
|
+
if (record.name !== undefined) {
|
|
115
|
+
const name = expectString(record.name, `${path}.name`, true).trim();
|
|
116
|
+
if (name)
|
|
117
|
+
model.name = name;
|
|
118
|
+
}
|
|
119
|
+
if (record.reasoning !== undefined) {
|
|
120
|
+
if (typeof record.reasoning !== "boolean")
|
|
121
|
+
throw new Error(`${path}.reasoning must be a boolean.`);
|
|
82
122
|
model.reasoning = record.reasoning;
|
|
83
|
-
if (Array.isArray(record.input)) {
|
|
84
|
-
const input = record.input.filter((item) => item === "text" || item === "image");
|
|
85
|
-
if (input.includes("text"))
|
|
86
|
-
model.input = input.includes("image") ? ["text", "image"] : ["text"];
|
|
87
123
|
}
|
|
88
|
-
if (
|
|
89
|
-
|
|
124
|
+
if (record.input !== undefined) {
|
|
125
|
+
if (!Array.isArray(record.input) || record.input.some((item) => item !== "text" && item !== "image")) {
|
|
126
|
+
throw new Error(`${path}.input must contain only "text" and "image".`);
|
|
127
|
+
}
|
|
128
|
+
const input = new Set(record.input);
|
|
129
|
+
if (!input.has("text"))
|
|
130
|
+
throw new Error(`${path}.input must include "text".`);
|
|
131
|
+
model.input = input.has("image") ? ["text", "image"] : ["text"];
|
|
132
|
+
}
|
|
133
|
+
if (record.contextWindow !== undefined) {
|
|
134
|
+
model.contextWindow = expectPositiveInteger(record.contextWindow, `${path}.contextWindow`);
|
|
90
135
|
}
|
|
91
|
-
if (
|
|
92
|
-
model.maxTokens =
|
|
136
|
+
if (record.maxTokens !== undefined) {
|
|
137
|
+
model.maxTokens = expectPositiveInteger(record.maxTokens, `${path}.maxTokens`);
|
|
93
138
|
}
|
|
94
|
-
if (record.thinkingLevelMap
|
|
95
|
-
|
|
96
|
-
!Array.isArray(record.thinkingLevelMap)) {
|
|
97
|
-
model.thinkingLevelMap = record.thinkingLevelMap;
|
|
139
|
+
if (record.thinkingLevelMap !== undefined) {
|
|
140
|
+
model.thinkingLevelMap = parseThinkingLevelMap(record.thinkingLevelMap, `${path}.thinkingLevelMap`);
|
|
98
141
|
}
|
|
99
142
|
return model;
|
|
100
143
|
}
|
|
144
|
+
function parseThinkingLevelMap(value, path) {
|
|
145
|
+
const record = expectObject(value, path);
|
|
146
|
+
const map = {};
|
|
147
|
+
for (const [level, target] of Object.entries(record)) {
|
|
148
|
+
if (!THINKING_LEVELS.includes(level)) {
|
|
149
|
+
throw new Error(`${path} has unsupported thinking level "${level}".`);
|
|
150
|
+
}
|
|
151
|
+
if (target !== null && (typeof target !== "string" || target.trim().length === 0)) {
|
|
152
|
+
throw new Error(`${path}.${level} must be a non-empty string or null.`);
|
|
153
|
+
}
|
|
154
|
+
map[level] = target === null ? null : target.trim();
|
|
155
|
+
}
|
|
156
|
+
return map;
|
|
157
|
+
}
|
|
101
158
|
export async function saveRouterFile(file) {
|
|
102
159
|
const filePath = getRouterConfigPath();
|
|
103
160
|
const payload = {
|
|
@@ -122,7 +179,7 @@ export async function saveRouterFile(file) {
|
|
|
122
179
|
await unlink(tempPath);
|
|
123
180
|
}
|
|
124
181
|
catch {
|
|
125
|
-
//
|
|
182
|
+
// Ignore cleanup errors and preserve the original failure.
|
|
126
183
|
}
|
|
127
184
|
throw error;
|
|
128
185
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/extensions/router/store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AAChF,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhE,MAAM,UAAU,mBAAmB;IAClC,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,aAAa,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,eAAe;IAC9B,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IACnC,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;IACvC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACJ,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,eAAe,EAAE,CAAC;QACjF,MAAM,KAAK,CAAC;IACb,CAAC;IACD,OAAO,eAAe,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IAC1C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACpE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,IAAI,GAAG,MAAiC,CAAC;IAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC;IAC9B,IAAI,SAAS,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,KAAK,MAAM,IAAI,IAAI,SAAS,IAAI,EAAE,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,KAAK;YAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC;AAC5C,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACrC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAClF,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,MAAM,EAAE,GAAG,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,MAAM,OAAO,GAAG,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAChF,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,IAAI,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC7D,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YACnC,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;YACzC,IAAI,UAAU;gBAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACzC,CAAC;IACF,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACxC,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACrC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAClF,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,MAAM,EAAE,GAAG,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,IAAI,CAAC,EAAE;QAAE,OAAO,SAAS,CAAC;IAC1B,MAAM,KAAK,GAAqB,EAAE,EAAE,EAAE,CAAC;IACvC,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE;QAAE,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAC3F,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,SAAS;QAAE,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IAC9E,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAA4B,EAAE,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,OAAO,CAAC,CAAC;QAC3G,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAClG,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,aAAa,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;QACnH,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;QACvG,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC;IACD,IACC,MAAM,CAAC,gBAAgB;QACvB,OAAO,MAAM,CAAC,gBAAgB,KAAK,QAAQ;QAC3C,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,EACtC,CAAC;QACF,KAAK,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAoC,CAAC;IACtE,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAgB;IACpD,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;IACvC,MAAM,OAAO,GAAe;QAC3B,OAAO,EAAE,cAAc;QACvB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACnC,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;SAC1D,CAAC,CAAC;KACH,CAAC;IACF,MAAM,UAAU,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IAC3D,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,qBAAqB,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,QAAQ,GAAG,GAAG,QAAQ,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC;QAChE,IAAI,CAAC;YACJ,MAAM,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACzE,MAAM,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC;gBACJ,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACR,SAAS;YACV,CAAC;YACD,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,KAAuB;IAC9C,MAAM,GAAG,GAAqB,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;IAC/C,IAAI,KAAK,CAAC,IAAI;QAAE,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IACtC,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS;QAAE,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IACnE,IAAI,KAAK,CAAC,KAAK;QAAE,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IACzC,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS;QAAE,GAAG,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;IAC/E,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS;QAAE,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IACnE,IAAI,KAAK,CAAC,gBAAgB,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9E,GAAG,CAAC,gBAAgB,GAAG,KAAK,CAAC,gBAAgB,CAAC;IAC/C,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAkB;IACnD,MAAM,IAAI,GAAG,MAAM,cAAc,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC,CAAC;IACtE,IAAI,KAAK,IAAI,CAAC;QAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;;QACtC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IAC3B,OAAO,IAAI,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,EAAU;IAC3C,MAAM,IAAI,GAAG,MAAM,cAAc,EAAE,CAAC;IACpC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7D,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IAC3B,OAAO,IAAI,CAAC;AACb,CAAC","sourcesContent":["/**\n * Persistence for ~/.pi/agent/router.json\n */\n\nimport { mkdir, readFile, rename, unlink, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { getAgentDir } from \"../../config.ts\";\nimport { withFileMutationQueue } from \"../../core/tools/file-mutation-queue.ts\";\nimport { CONFIG_VERSION, isValidRelayId } from \"./constants.ts\";\nimport type { RelayConfig, RelayModelConfig, RouterFile, ThinkingLevelMap } from \"./types.ts\";\n\nexport function getRouterConfigPath(): string {\n\treturn join(getAgentDir(), \"router.json\");\n}\n\nexport function emptyRouterFile(): RouterFile {\n\treturn { version: CONFIG_VERSION, relays: [] };\n}\n\nexport async function loadRouterFile(): Promise<RouterFile> {\n\tconst filePath = getRouterConfigPath();\n\tlet raw: string;\n\ttry {\n\t\traw = await readFile(filePath, \"utf8\");\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return emptyRouterFile();\n\t\tthrow error;\n\t}\n\treturn parseRouterFile(raw);\n}\n\nexport function parseRouterFile(raw: string): RouterFile {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\tthrow new Error(\"router.json is not valid JSON.\");\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(\"router.json must be a JSON object.\");\n\t}\n\tconst root = parsed as Record<string, unknown>;\n\tconst relaysRaw = root.relays;\n\tif (relaysRaw !== undefined && !Array.isArray(relaysRaw)) {\n\t\tthrow new Error(\"router.json relays must be an array.\");\n\t}\n\tconst relays: RelayConfig[] = [];\n\tfor (const item of relaysRaw ?? []) {\n\t\tconst relay = normalizeRelay(item);\n\t\tif (relay) relays.push(relay);\n\t}\n\treturn { version: CONFIG_VERSION, relays };\n}\n\nfunction normalizeRelay(value: unknown): RelayConfig | undefined {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined;\n\tconst record = value as Record<string, unknown>;\n\tconst id = typeof record.id === \"string\" ? record.id.trim() : \"\";\n\tconst baseUrl = typeof record.baseUrl === \"string\" ? record.baseUrl.trim() : \"\";\n\tconst apiKey = typeof record.apiKey === \"string\" ? record.apiKey : \"\";\n\tif (!id || !isValidRelayId(id) || !baseUrl) return undefined;\n\tconst models: RelayModelConfig[] = [];\n\tif (Array.isArray(record.models)) {\n\t\tfor (const model of record.models) {\n\t\t\tconst normalized = normalizeModel(model);\n\t\t\tif (normalized) models.push(normalized);\n\t\t}\n\t}\n\treturn { id, baseUrl, apiKey, models };\n}\n\nfunction normalizeModel(value: unknown): RelayModelConfig | undefined {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined;\n\tconst record = value as Record<string, unknown>;\n\tconst id = typeof record.id === \"string\" ? record.id.trim() : \"\";\n\tif (!id) return undefined;\n\tconst model: RelayModelConfig = { id };\n\tif (typeof record.name === \"string\" && record.name.trim()) model.name = record.name.trim();\n\tif (typeof record.reasoning === \"boolean\") model.reasoning = record.reasoning;\n\tif (Array.isArray(record.input)) {\n\t\tconst input = record.input.filter((item): item is \"text\" | \"image\" => item === \"text\" || item === \"image\");\n\t\tif (input.includes(\"text\")) model.input = input.includes(\"image\") ? [\"text\", \"image\"] : [\"text\"];\n\t}\n\tif (typeof record.contextWindow === \"number\" && Number.isFinite(record.contextWindow) && record.contextWindow > 0) {\n\t\tmodel.contextWindow = Math.floor(record.contextWindow);\n\t}\n\tif (typeof record.maxTokens === \"number\" && Number.isFinite(record.maxTokens) && record.maxTokens > 0) {\n\t\tmodel.maxTokens = Math.floor(record.maxTokens);\n\t}\n\tif (\n\t\trecord.thinkingLevelMap &&\n\t\ttypeof record.thinkingLevelMap === \"object\" &&\n\t\t!Array.isArray(record.thinkingLevelMap)\n\t) {\n\t\tmodel.thinkingLevelMap = record.thinkingLevelMap as ThinkingLevelMap;\n\t}\n\treturn model;\n}\n\nexport async function saveRouterFile(file: RouterFile): Promise<void> {\n\tconst filePath = getRouterConfigPath();\n\tconst payload: RouterFile = {\n\t\tversion: CONFIG_VERSION,\n\t\trelays: file.relays.map((relay) => ({\n\t\t\tid: relay.id,\n\t\t\tbaseUrl: relay.baseUrl,\n\t\t\tapiKey: relay.apiKey,\n\t\t\tmodels: relay.models.map((model) => serializeModel(model)),\n\t\t})),\n\t};\n\tconst serialized = `${JSON.stringify(payload, null, 2)}\\n`;\n\tawait mkdir(dirname(filePath), { recursive: true });\n\tawait withFileMutationQueue(filePath, async () => {\n\t\tconst tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;\n\t\ttry {\n\t\t\tawait writeFile(tempPath, serialized, { encoding: \"utf8\", mode: 0o600 });\n\t\t\tawait rename(tempPath, filePath);\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait unlink(tempPath);\n\t\t\t} catch {\n\t\t\t\t// ignore\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t});\n}\n\nfunction serializeModel(model: RelayModelConfig): RelayModelConfig {\n\tconst out: RelayModelConfig = { id: model.id };\n\tif (model.name) out.name = model.name;\n\tif (model.reasoning !== undefined) out.reasoning = model.reasoning;\n\tif (model.input) out.input = model.input;\n\tif (model.contextWindow !== undefined) out.contextWindow = model.contextWindow;\n\tif (model.maxTokens !== undefined) out.maxTokens = model.maxTokens;\n\tif (model.thinkingLevelMap && Object.keys(model.thinkingLevelMap).length > 0) {\n\t\tout.thinkingLevelMap = model.thinkingLevelMap;\n\t}\n\treturn out;\n}\n\nexport async function upsertRelay(relay: RelayConfig): Promise<RouterFile> {\n\tconst file = await loadRouterFile();\n\tconst index = file.relays.findIndex((entry) => entry.id === relay.id);\n\tif (index >= 0) file.relays[index] = relay;\n\telse file.relays.push(relay);\n\tawait saveRouterFile(file);\n\treturn file;\n}\n\nexport async function removeRelay(id: string): Promise<RouterFile> {\n\tconst file = await loadRouterFile();\n\tfile.relays = file.relays.filter((entry) => entry.id !== id);\n\tawait saveRouterFile(file);\n\treturn file;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/extensions/router/store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Persistence for ~/.pi/agent/router.json\n */\n\nimport { mkdir, readFile, rename, unlink, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { getAgentDir } from \"../../config.ts\";\nimport { withFileMutationQueue } from \"../../core/tools/file-mutation-queue.ts\";\nimport { CONFIG_VERSION, isValidRelayId, THINKING_LEVELS } from \"./constants.ts\";\nimport type { RelayConfig, RelayModelConfig, RouterFile, ThinkingLevelMap } from \"./types.ts\";\n\nconst ROOT_FIELDS = [\"version\", \"relays\"] as const;\nconst RELAY_FIELDS = [\"id\", \"baseUrl\", \"apiKey\", \"models\"] as const;\nconst MODEL_FIELDS = [\"id\", \"name\", \"reasoning\", \"input\", \"contextWindow\", \"maxTokens\", \"thinkingLevelMap\"] as const;\n\nexport function getRouterConfigPath(): string {\n\treturn join(getAgentDir(), \"router.json\");\n}\n\nexport function emptyRouterFile(): RouterFile {\n\treturn { version: CONFIG_VERSION, relays: [] };\n}\n\nexport async function loadRouterFile(): Promise<RouterFile> {\n\tconst filePath = getRouterConfigPath();\n\tlet raw: string;\n\ttry {\n\t\traw = await readFile(filePath, \"utf8\");\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return emptyRouterFile();\n\t\tthrow error;\n\t}\n\treturn parseRouterFile(raw);\n}\n\nfunction expectObject(value: unknown, path: string): Record<string, unknown> {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(`${path} must be an object.`);\n\t}\n\treturn value as Record<string, unknown>;\n}\n\nfunction rejectUnknownFields(record: Record<string, unknown>, allowed: readonly string[], path: string): void {\n\tconst unknown = Object.keys(record).filter((key) => !allowed.includes(key));\n\tif (unknown.length > 0) throw new Error(`${path} has unsupported field(s): ${unknown.join(\", \")}.`);\n}\n\nfunction expectString(value: unknown, path: string, allowEmpty = false): string {\n\tif (typeof value !== \"string\") throw new Error(`${path} must be a string.`);\n\tconst trimmed = value.trim();\n\tif (!allowEmpty && !trimmed) throw new Error(`${path} must not be empty.`);\n\treturn allowEmpty ? value : trimmed;\n}\n\nfunction expectPositiveInteger(value: unknown, path: string): number {\n\tif (typeof value !== \"number\" || !Number.isInteger(value) || value <= 0) {\n\t\tthrow new Error(`${path} must be a positive integer.`);\n\t}\n\treturn value;\n}\n\nexport function parseRouterFile(raw: string): RouterFile {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\tthrow new Error(\"router.json is not valid JSON.\");\n\t}\n\tconst root = expectObject(parsed, \"router.json\");\n\trejectUnknownFields(root, ROOT_FIELDS, \"router.json\");\n\tconst version = root.version ?? CONFIG_VERSION;\n\tif (version !== CONFIG_VERSION) {\n\t\tthrow new Error(`router.json has unsupported version ${String(version)}.`);\n\t}\n\tif (root.relays !== undefined && !Array.isArray(root.relays)) {\n\t\tthrow new Error(\"router.json relays must be an array.\");\n\t}\n\n\tconst relays = ((root.relays as unknown[] | undefined) ?? []).map((value, index) =>\n\t\tparseRelay(value, `router.json relays[${index}]`),\n\t);\n\tconst relayIds = new Set<string>();\n\tfor (const relay of relays) {\n\t\tif (relayIds.has(relay.id)) throw new Error(`router.json contains duplicate relay id \"${relay.id}\".`);\n\t\trelayIds.add(relay.id);\n\t}\n\treturn { version: CONFIG_VERSION, relays };\n}\n\nfunction parseRelay(value: unknown, path: string): RelayConfig {\n\tconst record = expectObject(value, path);\n\trejectUnknownFields(record, RELAY_FIELDS, path);\n\tconst id = expectString(record.id, `${path}.id`);\n\tif (!isValidRelayId(id)) throw new Error(`${path}.id must be a valid provider id without '/'.`);\n\tconst baseUrl = expectString(record.baseUrl, `${path}.baseUrl`);\n\ttry {\n\t\tconst url = new URL(baseUrl);\n\t\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") throw new Error(\"unsupported protocol\");\n\t} catch {\n\t\tthrow new Error(`${path}.baseUrl must be an http or https URL.`);\n\t}\n\tconst apiKey = expectString(record.apiKey, `${path}.apiKey`, true);\n\tif (record.models !== undefined && !Array.isArray(record.models)) {\n\t\tthrow new Error(`${path}.models must be an array.`);\n\t}\n\tconst models = ((record.models as unknown[] | undefined) ?? []).map((model, index) =>\n\t\tparseModel(model, `${path}.models[${index}]`),\n\t);\n\tconst modelIds = new Set<string>();\n\tfor (const model of models) {\n\t\tif (modelIds.has(model.id)) throw new Error(`${path}.models contains duplicate id \"${model.id}\".`);\n\t\tmodelIds.add(model.id);\n\t}\n\treturn { id, baseUrl, apiKey, models };\n}\n\nfunction parseModel(value: unknown, path: string): RelayModelConfig {\n\tconst record = expectObject(value, path);\n\trejectUnknownFields(record, MODEL_FIELDS, path);\n\tconst model: RelayModelConfig = { id: expectString(record.id, `${path}.id`) };\n\tif (record.name !== undefined) {\n\t\tconst name = expectString(record.name, `${path}.name`, true).trim();\n\t\tif (name) model.name = name;\n\t}\n\tif (record.reasoning !== undefined) {\n\t\tif (typeof record.reasoning !== \"boolean\") throw new Error(`${path}.reasoning must be a boolean.`);\n\t\tmodel.reasoning = record.reasoning;\n\t}\n\tif (record.input !== undefined) {\n\t\tif (!Array.isArray(record.input) || record.input.some((item) => item !== \"text\" && item !== \"image\")) {\n\t\t\tthrow new Error(`${path}.input must contain only \"text\" and \"image\".`);\n\t\t}\n\t\tconst input = new Set(record.input as Array<\"text\" | \"image\">);\n\t\tif (!input.has(\"text\")) throw new Error(`${path}.input must include \"text\".`);\n\t\tmodel.input = input.has(\"image\") ? [\"text\", \"image\"] : [\"text\"];\n\t}\n\tif (record.contextWindow !== undefined) {\n\t\tmodel.contextWindow = expectPositiveInteger(record.contextWindow, `${path}.contextWindow`);\n\t}\n\tif (record.maxTokens !== undefined) {\n\t\tmodel.maxTokens = expectPositiveInteger(record.maxTokens, `${path}.maxTokens`);\n\t}\n\tif (record.thinkingLevelMap !== undefined) {\n\t\tmodel.thinkingLevelMap = parseThinkingLevelMap(record.thinkingLevelMap, `${path}.thinkingLevelMap`);\n\t}\n\treturn model;\n}\n\nfunction parseThinkingLevelMap(value: unknown, path: string): ThinkingLevelMap {\n\tconst record = expectObject(value, path);\n\tconst map: ThinkingLevelMap = {};\n\tfor (const [level, target] of Object.entries(record)) {\n\t\tif (!(THINKING_LEVELS as readonly string[]).includes(level)) {\n\t\t\tthrow new Error(`${path} has unsupported thinking level \"${level}\".`);\n\t\t}\n\t\tif (target !== null && (typeof target !== \"string\" || target.trim().length === 0)) {\n\t\t\tthrow new Error(`${path}.${level} must be a non-empty string or null.`);\n\t\t}\n\t\tmap[level as keyof ThinkingLevelMap] = target === null ? null : target.trim();\n\t}\n\treturn map;\n}\n\nexport async function saveRouterFile(file: RouterFile): Promise<void> {\n\tconst filePath = getRouterConfigPath();\n\tconst payload: RouterFile = {\n\t\tversion: CONFIG_VERSION,\n\t\trelays: file.relays.map((relay) => ({\n\t\t\tid: relay.id,\n\t\t\tbaseUrl: relay.baseUrl,\n\t\t\tapiKey: relay.apiKey,\n\t\t\tmodels: relay.models.map((model) => serializeModel(model)),\n\t\t})),\n\t};\n\tconst serialized = `${JSON.stringify(payload, null, 2)}\\n`;\n\tawait mkdir(dirname(filePath), { recursive: true });\n\tawait withFileMutationQueue(filePath, async () => {\n\t\tconst tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;\n\t\ttry {\n\t\t\tawait writeFile(tempPath, serialized, { encoding: \"utf8\", mode: 0o600 });\n\t\t\tawait rename(tempPath, filePath);\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait unlink(tempPath);\n\t\t\t} catch {\n\t\t\t\t// Ignore cleanup errors and preserve the original failure.\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t});\n}\n\nfunction serializeModel(model: RelayModelConfig): RelayModelConfig {\n\tconst out: RelayModelConfig = { id: model.id };\n\tif (model.name) out.name = model.name;\n\tif (model.reasoning !== undefined) out.reasoning = model.reasoning;\n\tif (model.input) out.input = model.input;\n\tif (model.contextWindow !== undefined) out.contextWindow = model.contextWindow;\n\tif (model.maxTokens !== undefined) out.maxTokens = model.maxTokens;\n\tif (model.thinkingLevelMap && Object.keys(model.thinkingLevelMap).length > 0) {\n\t\tout.thinkingLevelMap = model.thinkingLevelMap;\n\t}\n\treturn out;\n}\n\nexport async function upsertRelay(relay: RelayConfig): Promise<RouterFile> {\n\tconst file = await loadRouterFile();\n\tconst index = file.relays.findIndex((entry) => entry.id === relay.id);\n\tif (index >= 0) file.relays[index] = relay;\n\telse file.relays.push(relay);\n\tawait saveRouterFile(file);\n\treturn file;\n}\n\nexport async function removeRelay(id: string): Promise<RouterFile> {\n\tconst file = await loadRouterFile();\n\tfile.relays = file.relays.filter((entry) => entry.id !== id);\n\tawait saveRouterFile(file);\n\treturn file;\n}\n"]}
|
|
@@ -5,11 +5,17 @@
|
|
|
5
5
|
* Searchable pickers follow Pi's native /model interaction pattern.
|
|
6
6
|
*/
|
|
7
7
|
import type { ExtensionAPI, ExtensionCommandContext } from "../../core/extensions/types.ts";
|
|
8
|
+
import { type ModelChecklistItem } from "./dialog.ts";
|
|
9
|
+
import type { RelayModelConfig } from "./types.ts";
|
|
8
10
|
export declare function isCurrentRouterModel(current: {
|
|
9
11
|
provider: string;
|
|
10
12
|
id: string;
|
|
11
13
|
} | undefined, relayId: string, modelId: string): boolean;
|
|
12
14
|
export declare function runRouterCommand(args: string, ctx: ExtensionCommandContext, pi: ExtensionAPI): Promise<void>;
|
|
15
|
+
export declare function mergeCatalogWithConfigured(configured: ReadonlyArray<RelayModelConfig>, catalog: ReadonlyArray<{
|
|
16
|
+
id: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
}>, activeModelId?: string): ModelChecklistItem[];
|
|
13
19
|
/** Resolve only keys that can be safely used by the catalog probe. */
|
|
14
20
|
export declare function resolveProbeApiKey(apiKey: string): {
|
|
15
21
|
value?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/ui.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/ui.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAK5F,OAAO,EAIN,KAAK,kBAAkB,EACvB,MAAM,aAAa,CAAC;AAiBrB,OAAO,KAAK,EAAe,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAkEhE,wBAAgB,oBAAoB,CACnC,OAAO,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EACrD,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACb,OAAO,CAET;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,uBAAuB,EAAE,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBlH;AAmoBD,wBAAgB,0BAA0B,CACzC,UAAU,EAAE,aAAa,CAAC,gBAAgB,CAAC,EAC3C,OAAO,EAAE,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EACrD,aAAa,CAAC,EAAE,MAAM,GACpB,kBAAkB,EAAE,CAuBtB;AAkED,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAiBrF"}
|
|
@@ -307,11 +307,11 @@ async function editRelayFlow(ctx, pi, dialogs, initial) {
|
|
|
307
307
|
continue;
|
|
308
308
|
}
|
|
309
309
|
if (choice === "apiKey") {
|
|
310
|
-
const next = await promptText(ctx, dialogs, `Relay · ${relay.id} · API key`,
|
|
310
|
+
const next = await promptText(ctx, dialogs, `Relay · ${relay.id} · API key`, "Enter a new key · blank keeps the current value");
|
|
311
311
|
if (next === undefined)
|
|
312
312
|
continue;
|
|
313
313
|
const trimmed = next.trim();
|
|
314
|
-
if (trimmed === relay.apiKey)
|
|
314
|
+
if (!trimmed || trimmed === relay.apiKey)
|
|
315
315
|
continue;
|
|
316
316
|
relay.apiKey = trimmed;
|
|
317
317
|
await persistRelay(ctx, pi, relay);
|
|
@@ -564,12 +564,17 @@ async function fetchAndSelectModels(ctx, pi, dialogs, relay) {
|
|
|
564
564
|
return;
|
|
565
565
|
if (result.truncated)
|
|
566
566
|
ctx.ui.notify("Catalog truncated to 2,000 models.", "warning");
|
|
567
|
-
const catalog = mergeCatalogWithConfigured(relay.models, result.models);
|
|
568
|
-
const initiallySelected = new Set(relay.models.map((model) => model.id));
|
|
569
567
|
const activeModelId = ctx.model?.provider === relay.id ? ctx.model.id : undefined;
|
|
570
|
-
const
|
|
568
|
+
const catalog = mergeCatalogWithConfigured(relay.models, result.models, activeModelId);
|
|
569
|
+
const initiallySelected = new Set(relay.models.map((model) => model.id));
|
|
570
|
+
if (activeModelId)
|
|
571
|
+
initiallySelected.add(activeModelId);
|
|
572
|
+
const currentModelId = activeModelId;
|
|
571
573
|
const protectedIds = currentModelId ? new Set([currentModelId]) : undefined;
|
|
572
574
|
const preserved = new Map(relay.models.map((model) => [model.id, structuredClone(model)]));
|
|
575
|
+
if (activeModelId && !preserved.has(activeModelId)) {
|
|
576
|
+
preserved.set(activeModelId, createDefaultModelConfig(activeModelId));
|
|
577
|
+
}
|
|
573
578
|
const saver = new RelayAutoSaver(ctx, pi, relay);
|
|
574
579
|
const applySelection = (selectedIds) => {
|
|
575
580
|
if (currentModelId && !selectedIds.includes(currentModelId)) {
|
|
@@ -642,7 +647,7 @@ function mergeAddedModels(previous, additions) {
|
|
|
642
647
|
}
|
|
643
648
|
return result;
|
|
644
649
|
}
|
|
645
|
-
function mergeCatalogWithConfigured(configured, catalog) {
|
|
650
|
+
export function mergeCatalogWithConfigured(configured, catalog, activeModelId) {
|
|
646
651
|
const items = new Map();
|
|
647
652
|
const configuredById = new Map(configured.map((model) => [model.id, model]));
|
|
648
653
|
for (const model of catalog) {
|
|
@@ -661,6 +666,9 @@ function mergeCatalogWithConfigured(configured, catalog) {
|
|
|
661
666
|
});
|
|
662
667
|
}
|
|
663
668
|
}
|
|
669
|
+
if (activeModelId && !items.has(activeModelId)) {
|
|
670
|
+
items.set(activeModelId, { id: activeModelId, name: activeModelId, unavailable: true });
|
|
671
|
+
}
|
|
664
672
|
return [...items.values()].sort((left, right) => left.id.localeCompare(right.id));
|
|
665
673
|
}
|
|
666
674
|
function applySelectionIfChanged(relay, selectedIds, apply) {
|