@astralyn/pi 0.85.1 → 0.85.2
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 +28 -0
- package/dist/cli.js +94 -91
- package/dist/core/agent-session.js +2 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/background/history.d.ts.map +1 -1
- package/dist/core/background/history.js +6 -0
- package/dist/core/background/history.js.map +1 -1
- package/dist/core/background/presentation.d.ts.map +1 -1
- package/dist/core/background/presentation.js +41 -4
- package/dist/core/background/presentation.js.map +1 -1
- package/dist/core/background/service.d.ts +2 -2
- package/dist/core/background/service.d.ts.map +1 -1
- package/dist/core/background/service.js +38 -15
- package/dist/core/background/service.js.map +1 -1
- package/dist/core/background/types.d.ts +9 -0
- package/dist/core/background/types.d.ts.map +1 -1
- package/dist/core/background/types.js +4 -0
- package/dist/core/background/types.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +5 -12
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +11 -19
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/settings.d.ts +27 -0
- package/dist/core/compaction/settings.d.ts.map +1 -0
- package/dist/core/compaction/settings.js +40 -0
- package/dist/core/compaction/settings.js.map +1 -0
- package/dist/core/keybindings.d.ts +15 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +12 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-config.d.ts +32 -10
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +38 -1
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-runtime.d.ts +2 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +4 -0
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/settings-manager.d.ts +4 -7
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +7 -6
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/bash.js +1 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/shell-execution.d.ts.map +1 -1
- package/dist/core/tools/shell-execution.js +3 -1
- package/dist/core/tools/shell-execution.js.map +1 -1
- package/dist/extensions/background/manager.d.ts +8 -5
- package/dist/extensions/background/manager.d.ts.map +1 -1
- package/dist/extensions/background/manager.js +115 -39
- package/dist/extensions/background/manager.js.map +1 -1
- package/dist/extensions/background/task-view.d.ts +5 -0
- package/dist/extensions/background/task-view.d.ts.map +1 -1
- package/dist/extensions/background/task-view.js +4 -0
- package/dist/extensions/background/task-view.js.map +1 -1
- package/dist/extensions/btw/controller.d.ts +1 -1
- package/dist/extensions/btw/controller.d.ts.map +1 -1
- package/dist/extensions/btw/controller.js +4 -4
- package/dist/extensions/btw/controller.js.map +1 -1
- package/dist/extensions/btw/index.js +3 -3
- package/dist/extensions/btw/index.js.map +1 -1
- package/dist/extensions/index.js +2 -2
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/provider/catalog.d.ts +57 -0
- package/dist/extensions/provider/catalog.d.ts.map +1 -0
- package/dist/extensions/provider/catalog.js +181 -0
- package/dist/extensions/provider/catalog.js.map +1 -0
- package/dist/extensions/provider/compat-fields.d.ts +25 -0
- package/dist/extensions/provider/compat-fields.d.ts.map +1 -0
- package/dist/extensions/provider/compat-fields.js +148 -0
- package/dist/extensions/provider/compat-fields.js.map +1 -0
- package/dist/extensions/provider/configuration.d.ts +8 -0
- package/dist/extensions/provider/configuration.d.ts.map +1 -0
- package/dist/extensions/provider/configuration.js +21 -0
- package/dist/extensions/provider/configuration.js.map +1 -0
- package/dist/extensions/provider/connection.d.ts +14 -0
- package/dist/extensions/provider/connection.d.ts.map +1 -0
- package/dist/extensions/provider/connection.js +86 -0
- package/dist/extensions/provider/connection.js.map +1 -0
- package/dist/extensions/provider/constants.d.ts +38 -0
- package/dist/extensions/provider/constants.d.ts.map +1 -0
- package/dist/extensions/provider/constants.js +75 -0
- package/dist/extensions/provider/constants.js.map +1 -0
- package/dist/extensions/provider/index.d.ts +4 -0
- package/dist/extensions/provider/index.d.ts.map +1 -0
- package/dist/extensions/provider/index.js +65 -0
- package/dist/extensions/provider/index.js.map +1 -0
- package/dist/extensions/provider/probe.d.ts +34 -0
- package/dist/extensions/provider/probe.d.ts.map +1 -0
- package/dist/extensions/provider/probe.js +178 -0
- package/dist/extensions/provider/probe.js.map +1 -0
- package/dist/extensions/provider/refresh.d.ts +30 -0
- package/dist/extensions/provider/refresh.d.ts.map +1 -0
- package/dist/extensions/provider/refresh.js +66 -0
- package/dist/extensions/provider/refresh.js.map +1 -0
- package/dist/extensions/provider/store.d.ts +131 -0
- package/dist/extensions/provider/store.d.ts.map +1 -0
- package/dist/extensions/provider/store.js +503 -0
- package/dist/extensions/provider/store.js.map +1 -0
- package/dist/extensions/provider/ui/app.d.ts +25 -0
- package/dist/extensions/provider/ui/app.d.ts.map +1 -0
- package/dist/extensions/provider/ui/app.js +153 -0
- package/dist/extensions/provider/ui/app.js.map +1 -0
- package/dist/extensions/provider/ui/builtin-data.d.ts +53 -0
- package/dist/extensions/provider/ui/builtin-data.d.ts.map +1 -0
- package/dist/extensions/provider/ui/builtin-data.js +315 -0
- package/dist/extensions/provider/ui/builtin-data.js.map +1 -0
- package/dist/extensions/provider/ui/compat.d.ts +57 -0
- package/dist/extensions/provider/ui/compat.d.ts.map +1 -0
- package/dist/extensions/provider/ui/compat.js +427 -0
- package/dist/extensions/provider/ui/compat.js.map +1 -0
- package/dist/extensions/provider/ui/dialogs.d.ts +30 -0
- package/dist/extensions/provider/ui/dialogs.d.ts.map +1 -0
- package/dist/extensions/provider/ui/dialogs.js +89 -0
- package/dist/extensions/provider/ui/dialogs.js.map +1 -0
- package/dist/extensions/provider/ui/dictionary.d.ts +29 -0
- package/dist/extensions/provider/ui/dictionary.d.ts.map +1 -0
- package/dist/extensions/provider/ui/dictionary.js +385 -0
- package/dist/extensions/provider/ui/dictionary.js.map +1 -0
- package/dist/extensions/provider/ui/editor.d.ts +91 -0
- package/dist/extensions/provider/ui/editor.d.ts.map +1 -0
- package/dist/extensions/provider/ui/editor.js +667 -0
- package/dist/extensions/provider/ui/editor.js.map +1 -0
- package/dist/extensions/provider/ui/fetch-models.d.ts +39 -0
- package/dist/extensions/provider/ui/fetch-models.d.ts.map +1 -0
- package/dist/extensions/provider/ui/fetch-models.js +320 -0
- package/dist/extensions/provider/ui/fetch-models.js.map +1 -0
- package/dist/extensions/provider/ui/model-fields.d.ts +43 -0
- package/dist/extensions/provider/ui/model-fields.d.ts.map +1 -0
- package/dist/extensions/provider/ui/model-fields.js +441 -0
- package/dist/extensions/provider/ui/model-fields.js.map +1 -0
- package/dist/extensions/provider/ui/model-options.d.ts +93 -0
- package/dist/extensions/provider/ui/model-options.d.ts.map +1 -0
- package/dist/extensions/provider/ui/model-options.js +529 -0
- package/dist/extensions/provider/ui/model-options.js.map +1 -0
- package/dist/extensions/provider/ui/pane.d.ts +81 -0
- package/dist/extensions/provider/ui/pane.d.ts.map +1 -0
- package/dist/extensions/provider/ui/pane.js +3 -0
- package/dist/extensions/provider/ui/pane.js.map +1 -0
- package/dist/extensions/provider/ui/provider-fields.d.ts +60 -0
- package/dist/extensions/provider/ui/provider-fields.d.ts.map +1 -0
- package/dist/extensions/provider/ui/provider-fields.js +326 -0
- package/dist/extensions/provider/ui/provider-fields.js.map +1 -0
- package/dist/extensions/provider/ui/provider-list.d.ts +34 -0
- package/dist/extensions/provider/ui/provider-list.d.ts.map +1 -0
- package/dist/extensions/provider/ui/provider-list.js +162 -0
- package/dist/extensions/provider/ui/provider-list.js.map +1 -0
- package/dist/extensions/provider/ui/session.d.ts +20 -0
- package/dist/extensions/provider/ui/session.d.ts.map +1 -0
- package/dist/extensions/provider/ui/session.js +52 -0
- package/dist/extensions/provider/ui/session.js.map +1 -0
- package/dist/extensions/provider/ui/thinking-map.d.ts +20 -0
- package/dist/extensions/provider/ui/thinking-map.d.ts.map +1 -0
- package/dist/extensions/provider/ui/thinking-map.js +166 -0
- package/dist/extensions/provider/ui/thinking-map.js.map +1 -0
- package/dist/extensions/provider/ui/value-row.d.ts +88 -0
- package/dist/extensions/provider/ui/value-row.d.ts.map +1 -0
- package/dist/extensions/provider/ui/value-row.js +158 -0
- package/dist/extensions/provider/ui/value-row.js.map +1 -0
- package/dist/extensions/statusline/index.js +2 -2
- package/dist/extensions/statusline/index.js.map +1 -1
- package/dist/extensions/subagent/index.d.ts.map +1 -1
- package/dist/extensions/subagent/index.js +4 -2
- package/dist/extensions/subagent/index.js.map +1 -1
- package/dist/extensions/subagent/resolve.d.ts +5 -0
- package/dist/extensions/subagent/resolve.d.ts.map +1 -1
- package/dist/extensions/subagent/resolve.js +15 -7
- package/dist/extensions/subagent/resolve.js.map +1 -1
- package/dist/extensions/subagent/schema.d.ts +2 -0
- package/dist/extensions/subagent/schema.d.ts.map +1 -1
- package/dist/extensions/subagent/schema.js +1 -0
- package/dist/extensions/subagent/schema.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +10 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +20 -2
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +6 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/rpc-entry.js +94 -91
- package/docs/bundled/README.md +1 -1
- package/docs/bundled/extensions/background.md +5 -5
- package/docs/bundled/extensions/provider.md +117 -0
- package/docs/bundled/extensions/statusline.md +1 -1
- package/docs/bundled/extensions/subagent.md +7 -3
- package/docs/compaction.md +16 -6
- package/docs/docs.json +2 -2
- package/docs/keybindings.md +3 -0
- package/docs/settings.md +11 -7
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/extensions/router/constants.d.ts +0 -23
- package/dist/extensions/router/constants.d.ts.map +0 -1
- package/dist/extensions/router/constants.js +0 -30
- package/dist/extensions/router/constants.js.map +0 -1
- package/dist/extensions/router/dialog-host.d.ts +0 -60
- package/dist/extensions/router/dialog-host.d.ts.map +0 -1
- package/dist/extensions/router/dialog-host.js +0 -196
- package/dist/extensions/router/dialog-host.js.map +0 -1
- package/dist/extensions/router/dialog.d.ts +0 -45
- package/dist/extensions/router/dialog.d.ts.map +0 -1
- package/dist/extensions/router/dialog.js +0 -378
- package/dist/extensions/router/dialog.js.map +0 -1
- package/dist/extensions/router/identity.d.ts +0 -15
- package/dist/extensions/router/identity.d.ts.map +0 -1
- package/dist/extensions/router/identity.js +0 -173
- package/dist/extensions/router/identity.js.map +0 -1
- package/dist/extensions/router/index.d.ts +0 -15
- package/dist/extensions/router/index.d.ts.map +0 -1
- package/dist/extensions/router/index.js +0 -70
- package/dist/extensions/router/index.js.map +0 -1
- package/dist/extensions/router/presets.d.ts +0 -51
- package/dist/extensions/router/presets.d.ts.map +0 -1
- package/dist/extensions/router/presets.js +0 -108
- package/dist/extensions/router/presets.js.map +0 -1
- package/dist/extensions/router/probe.d.ts +0 -26
- package/dist/extensions/router/probe.d.ts.map +0 -1
- package/dist/extensions/router/probe.js +0 -216
- package/dist/extensions/router/probe.js.map +0 -1
- package/dist/extensions/router/register.d.ts +0 -12
- package/dist/extensions/router/register.d.ts.map +0 -1
- package/dist/extensions/router/register.js +0 -90
- package/dist/extensions/router/register.js.map +0 -1
- package/dist/extensions/router/state.d.ts +0 -20
- package/dist/extensions/router/state.d.ts.map +0 -1
- package/dist/extensions/router/state.js +0 -169
- package/dist/extensions/router/state.js.map +0 -1
- package/dist/extensions/router/store.d.ts +0 -12
- package/dist/extensions/router/store.d.ts.map +0 -1
- package/dist/extensions/router/store.js +0 -266
- package/dist/extensions/router/store.js.map +0 -1
- package/dist/extensions/router/stream.d.ts +0 -12
- package/dist/extensions/router/stream.d.ts.map +0 -1
- package/dist/extensions/router/stream.js +0 -233
- package/dist/extensions/router/stream.js.map +0 -1
- package/dist/extensions/router/transport.d.ts +0 -9
- package/dist/extensions/router/transport.d.ts.map +0 -1
- package/dist/extensions/router/transport.js +0 -81
- package/dist/extensions/router/transport.js.map +0 -1
- package/dist/extensions/router/types.d.ts +0 -39
- package/dist/extensions/router/types.d.ts.map +0 -1
- package/dist/extensions/router/types.js +0 -2
- package/dist/extensions/router/types.js.map +0 -1
- package/dist/extensions/router/ui.d.ts +0 -26
- package/dist/extensions/router/ui.d.ts.map +0 -1
- package/dist/extensions/router/ui.js +0 -897
- package/dist/extensions/router/ui.js.map +0 -1
- package/docs/bundled/extensions/router.md +0 -197
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/probe.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAE1E,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAI5E,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,YAAY,CAAC;AAErE,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,gBAAgB,EAAE,IAAI,GAAG,MAAM,CAAC;IACxE,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC;CAC1D;AAED,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,UAAU,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC7B,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,WAAW,CAAC,CAuGvB"}
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
/** Fetch a bounded OpenAI or Codex model catalog from a relay baseUrl. */
|
|
2
|
-
import { readResponseTextBounded } from "../../utils/http-response.js";
|
|
3
|
-
import { DEFAULTS, formatError, THINKING_LEVELS } from "./constants.js";
|
|
4
|
-
import { buildCodexHeaders, CODEX_VERSION, createCodexFetch } from "./identity.js";
|
|
5
|
-
export async function probeRelayModels(opts) {
|
|
6
|
-
let baseUrl;
|
|
7
|
-
try {
|
|
8
|
-
baseUrl = new URL(opts.baseUrl);
|
|
9
|
-
}
|
|
10
|
-
catch {
|
|
11
|
-
return { ok: false, error: "Base URL is not a valid URL." };
|
|
12
|
-
}
|
|
13
|
-
if (baseUrl.protocol !== "http:" && baseUrl.protocol !== "https:") {
|
|
14
|
-
return { ok: false, error: `Unsupported protocol: ${baseUrl.protocol}` };
|
|
15
|
-
}
|
|
16
|
-
if (baseUrl.username || baseUrl.password || baseUrl.hash) {
|
|
17
|
-
return { ok: false, error: "Base URL must not contain credentials or a fragment." };
|
|
18
|
-
}
|
|
19
|
-
if (opts.signal?.aborted)
|
|
20
|
-
return { ok: false, error: "Cancelled." };
|
|
21
|
-
const controller = new AbortController();
|
|
22
|
-
const timeoutMs = opts.timeoutMs ?? DEFAULTS.probeTimeoutMs;
|
|
23
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
24
|
-
const onOuterAbort = () => controller.abort();
|
|
25
|
-
opts.signal?.addEventListener("abort", onOuterAbort, { once: true });
|
|
26
|
-
try {
|
|
27
|
-
const url = appendPath(baseUrl, "models");
|
|
28
|
-
// Codex models-manager uses Cargo major.minor.patch, dropping prerelease only.
|
|
29
|
-
if (opts.catalog === "codex") {
|
|
30
|
-
// Keep unrelated query bytes intact (including %20, ~ and repeated parameters).
|
|
31
|
-
const query = url.search.slice(1).split("&").filter(Boolean);
|
|
32
|
-
const version = `client_version=${CODEX_VERSION}`;
|
|
33
|
-
const existing = query.findIndex((part) => new URLSearchParams(part).has("client_version"));
|
|
34
|
-
if (existing < 0)
|
|
35
|
-
query.push(version);
|
|
36
|
-
else {
|
|
37
|
-
query[existing] = version;
|
|
38
|
-
for (let index = query.length - 1; index > existing; index--) {
|
|
39
|
-
if (new URLSearchParams(query[index]).has("client_version"))
|
|
40
|
-
query.splice(index, 1);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
url.search = query.join("&");
|
|
44
|
-
}
|
|
45
|
-
const headers = new Headers();
|
|
46
|
-
for (const [key, value] of Object.entries(buildCodexHeaders({
|
|
47
|
-
"content-type": null,
|
|
48
|
-
...(opts.apiKey ? { authorization: `Bearer ${opts.apiKey}` } : {}),
|
|
49
|
-
...opts.headers,
|
|
50
|
-
}))) {
|
|
51
|
-
if (typeof value === "string")
|
|
52
|
-
headers.set(key, value);
|
|
53
|
-
}
|
|
54
|
-
headers.set("accept", "application/json");
|
|
55
|
-
const response = await createCodexFetch(opts.fetch)(url, {
|
|
56
|
-
method: "GET",
|
|
57
|
-
headers,
|
|
58
|
-
signal: controller.signal,
|
|
59
|
-
});
|
|
60
|
-
if (!response.ok) {
|
|
61
|
-
const body = await readResponseTextBounded(response, {
|
|
62
|
-
maxBytes: 4_096,
|
|
63
|
-
signal: controller.signal,
|
|
64
|
-
});
|
|
65
|
-
return {
|
|
66
|
-
ok: false,
|
|
67
|
-
error: `HTTP ${response.status}${body ? `: ${body.slice(0, 400)}` : ""}`,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
const text = await readResponseTextBounded(response, {
|
|
71
|
-
maxBytes: DEFAULTS.probeBodyBytes,
|
|
72
|
-
overflowMessage: `Response exceeds ${DEFAULTS.probeBodyBytes} bytes.`,
|
|
73
|
-
signal: controller.signal,
|
|
74
|
-
});
|
|
75
|
-
let json;
|
|
76
|
-
try {
|
|
77
|
-
json = JSON.parse(text);
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
return { ok: false, error: "Model catalog response is not JSON." };
|
|
81
|
-
}
|
|
82
|
-
const models = opts.catalog === "codex" ? parseCodexModels(json) : parseOpenAIModels(json);
|
|
83
|
-
if (models === null) {
|
|
84
|
-
return {
|
|
85
|
-
ok: false,
|
|
86
|
-
error: opts.catalog === "codex"
|
|
87
|
-
? "JSON has no Codex-style `models` array of model slugs. Check the base URL and catalog setting."
|
|
88
|
-
: "JSON has no OpenAI-style `data` array of model ids. Check the base URL and catalog setting.",
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
const sorted = dedupeSort(models);
|
|
92
|
-
const truncated = sorted.length > DEFAULTS.probeMaxModels;
|
|
93
|
-
return {
|
|
94
|
-
ok: true,
|
|
95
|
-
models: sorted.slice(0, DEFAULTS.probeMaxModels),
|
|
96
|
-
truncated,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
catch (error) {
|
|
100
|
-
if (controller.signal.aborted) {
|
|
101
|
-
return { ok: false, error: opts.signal?.aborted ? "Cancelled." : `Timed out after ${timeoutMs}ms.` };
|
|
102
|
-
}
|
|
103
|
-
return { ok: false, error: formatError(error) };
|
|
104
|
-
}
|
|
105
|
-
finally {
|
|
106
|
-
clearTimeout(timer);
|
|
107
|
-
opts.signal?.removeEventListener("abort", onOuterAbort);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
function appendPath(base, segment) {
|
|
111
|
-
const url = new URL(base.href);
|
|
112
|
-
const path = url.pathname.replace(/\/+$/, "");
|
|
113
|
-
url.pathname = `${path}/${segment}`;
|
|
114
|
-
return url;
|
|
115
|
-
}
|
|
116
|
-
function parseOpenAIModels(json) {
|
|
117
|
-
if (!json || typeof json !== "object")
|
|
118
|
-
return null;
|
|
119
|
-
const data = json.data;
|
|
120
|
-
if (!Array.isArray(data))
|
|
121
|
-
return null;
|
|
122
|
-
const models = [];
|
|
123
|
-
for (const item of data) {
|
|
124
|
-
if (!item || typeof item !== "object")
|
|
125
|
-
continue;
|
|
126
|
-
const record = item;
|
|
127
|
-
const id = typeof record.id === "string" ? record.id.trim() : "";
|
|
128
|
-
if (!id)
|
|
129
|
-
continue;
|
|
130
|
-
const name = typeof record.name === "string" && record.name.trim() && record.name.trim() !== id
|
|
131
|
-
? record.name.trim()
|
|
132
|
-
: undefined;
|
|
133
|
-
models.push(name ? { id, name } : { id });
|
|
134
|
-
}
|
|
135
|
-
return models;
|
|
136
|
-
}
|
|
137
|
-
function dedupeSort(models) {
|
|
138
|
-
const map = new Map();
|
|
139
|
-
for (const model of models) {
|
|
140
|
-
if (!map.has(model.id))
|
|
141
|
-
map.set(model.id, model);
|
|
142
|
-
}
|
|
143
|
-
return [...map.values()].sort((a, b) => a.id.localeCompare(b.id));
|
|
144
|
-
}
|
|
145
|
-
function positiveInteger(value) {
|
|
146
|
-
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
147
|
-
}
|
|
148
|
-
function parseCodexModels(json) {
|
|
149
|
-
if (!json || typeof json !== "object")
|
|
150
|
-
return null;
|
|
151
|
-
const data = json.models;
|
|
152
|
-
if (!Array.isArray(data))
|
|
153
|
-
return null;
|
|
154
|
-
const models = [];
|
|
155
|
-
for (const item of data) {
|
|
156
|
-
if (!item || typeof item !== "object")
|
|
157
|
-
continue;
|
|
158
|
-
const record = item;
|
|
159
|
-
const id = typeof record.slug === "string" ? record.slug.trim() : "";
|
|
160
|
-
if (!id)
|
|
161
|
-
continue;
|
|
162
|
-
const model = { id };
|
|
163
|
-
if (typeof record.display_name === "string" && record.display_name.trim() && record.display_name.trim() !== id)
|
|
164
|
-
model.name = record.display_name.trim();
|
|
165
|
-
const metadata = {};
|
|
166
|
-
const context = positiveInteger(record.context_window);
|
|
167
|
-
const maxContext = positiveInteger(record.max_context_window);
|
|
168
|
-
if (context !== undefined)
|
|
169
|
-
metadata.contextWindow = Math.min(context, maxContext ?? context);
|
|
170
|
-
// max_context_window is NOT a max output token count. Never infer maxTokens from it.
|
|
171
|
-
if (Array.isArray(record.supported_reasoning_levels)) {
|
|
172
|
-
const efforts = new Set(record.supported_reasoning_levels.flatMap((entry) => {
|
|
173
|
-
const effort = typeof entry === "string"
|
|
174
|
-
? entry
|
|
175
|
-
: entry && typeof entry === "object"
|
|
176
|
-
? entry.effort
|
|
177
|
-
: undefined;
|
|
178
|
-
return typeof effort === "string" ? [effort] : [];
|
|
179
|
-
}));
|
|
180
|
-
const map = {};
|
|
181
|
-
for (const level of THINKING_LEVELS) {
|
|
182
|
-
const effort = level === "off" ? "none" : level;
|
|
183
|
-
map[level] = efforts.has(effort) ? effort : null;
|
|
184
|
-
}
|
|
185
|
-
metadata.thinkingLevelMap = map;
|
|
186
|
-
metadata.reasoning = THINKING_LEVELS.some((level) => level !== "off" && map[level] !== null);
|
|
187
|
-
}
|
|
188
|
-
const codex = {};
|
|
189
|
-
if (record.supports_reasoning_summary_parameter === false)
|
|
190
|
-
codex.reasoningSummary = null;
|
|
191
|
-
else if (record.supports_reasoning_summary_parameter === true) {
|
|
192
|
-
const summary = record.default_reasoning_summary;
|
|
193
|
-
if (summary === "auto" || summary === "concise" || summary === "detailed")
|
|
194
|
-
codex.reasoningSummary = summary;
|
|
195
|
-
else if (summary === "none")
|
|
196
|
-
codex.reasoningSummary = null;
|
|
197
|
-
}
|
|
198
|
-
if (record.support_verbosity === false)
|
|
199
|
-
codex.verbosity = null;
|
|
200
|
-
else if (record.support_verbosity === true) {
|
|
201
|
-
const verbosity = record.default_verbosity;
|
|
202
|
-
if (verbosity === "low" || verbosity === "medium" || verbosity === "high")
|
|
203
|
-
codex.verbosity = verbosity;
|
|
204
|
-
}
|
|
205
|
-
if (Object.keys(codex).length)
|
|
206
|
-
metadata.codex = codex;
|
|
207
|
-
if (Array.isArray(record.input_modalities) && record.input_modalities.includes("text")) {
|
|
208
|
-
metadata.input = record.input_modalities.includes("image") ? ["text", "image"] : ["text"];
|
|
209
|
-
}
|
|
210
|
-
if (Object.keys(metadata).length)
|
|
211
|
-
model.metadata = metadata;
|
|
212
|
-
models.push(model);
|
|
213
|
-
}
|
|
214
|
-
return models;
|
|
215
|
-
}
|
|
216
|
-
//# sourceMappingURL=probe.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"probe.js","sourceRoot":"","sources":["../../../src/extensions/router/probe.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAG1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAUnF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAStC;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,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QAC1D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,sDAAsD,EAAE,CAAC;IACrF,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,+EAA+E;QAC/E,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YAC9B,gFAAgF;YAChF,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC7D,MAAM,OAAO,GAAG,kBAAkB,aAAa,EAAE,CAAC;YAClD,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;YAC5F,IAAI,QAAQ,GAAG,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;iBACjC,CAAC;gBACL,KAAK,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC;gBAC1B,KAAK,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC;oBAC9D,IAAI,IAAI,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC;wBAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBACrF,CAAC;YACF,CAAC;YACD,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;QAC9B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CACxC,iBAAiB,CAAC;YACjB,cAAc,EAAE,IAAI;YACpB,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,GAAG,IAAI,CAAC,OAAO;SACf,CAAC,CACF,EAAE,CAAC;YACH,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;QAE1C,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE;YACxD,MAAM,EAAE,KAAK;YACb,OAAO;YACP,MAAM,EAAE,UAAU,CAAC,MAAM;SACzB,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,IAAI,GAAG,MAAM,uBAAuB,CAAC,QAAQ,EAAE;gBACpD,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,UAAU,CAAC,MAAM;aACzB,CAAC,CAAC;YACH,OAAO;gBACN,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,QAAQ,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;aACxE,CAAC;QACH,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,uBAAuB,CAAC,QAAQ,EAAE;YACpD,QAAQ,EAAE,QAAQ,CAAC,cAAc;YACjC,eAAe,EAAE,oBAAoB,QAAQ,CAAC,cAAc,SAAS;YACrE,MAAM,EAAE,UAAU,CAAC,MAAM;SACzB,CAAC,CAAC;QACH,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACJ,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,qCAAqC,EAAE,CAAC;QACpE,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAC3F,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACrB,OAAO;gBACN,EAAE,EAAE,KAAK;gBACT,KAAK,EACJ,IAAI,CAAC,OAAO,KAAK,OAAO;oBACvB,CAAC,CAAC,gGAAgG;oBAClG,CAAC,CAAC,6FAA6F;aACjG,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC;QAC1D,OAAO;YACN,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC;YAChD,SAAS;SACT,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAC/B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,mBAAmB,SAAS,KAAK,EAAE,CAAC;QACtG,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;IACjD,CAAC;YAAS,CAAC;QACV,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,IAAI,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACzD,CAAC;AACF,CAAC;AAED,SAAS,UAAU,CAAC,IAAS,EAAE,OAAe;IAC7C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9C,GAAG,CAAC,QAAQ,GAAG,GAAG,IAAI,IAAI,OAAO,EAAE,CAAC;IACpC,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAa;IACvC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,IAAI,GAAI,IAA2B,CAAC,IAAI,CAAC;IAC/C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,SAAS;QAChD,MAAM,MAAM,GAAG,IAA+B,CAAC;QAC/C,MAAM,EAAE,GAAG,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,IAAI,CAAC,EAAE;YAAE,SAAS;QAClB,MAAM,IAAI,GACT,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;YACjF,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE;YACpB,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CAAC,MAAoB;IACvC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAClG,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAa;IACtC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,IAAI,GAAI,IAA6B,CAAC,MAAM,CAAC;IACnD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,SAAS;QAChD,MAAM,MAAM,GAAG,IAA+B,CAAC;QAC/C,MAAM,EAAE,GAAG,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,IAAI,CAAC,EAAE;YAAE,SAAS;QAClB,MAAM,KAAK,GAAe,EAAE,EAAE,EAAE,CAAC;QACjC,IAAI,OAAO,MAAM,CAAC,YAAY,KAAK,QAAQ,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE;YAC7G,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;QACzC,MAAM,QAAQ,GAAwC,EAAE,CAAC;QACzD,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QACvD,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAC9D,IAAI,OAAO,KAAK,SAAS;YAAE,QAAQ,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,IAAI,OAAO,CAAC,CAAC;QAC7F,qFAAqF;QACrF,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,0BAA0B,CAAC,EAAE,CAAC;YACtD,MAAM,OAAO,GAAG,IAAI,GAAG,CACtB,MAAM,CAAC,0BAA0B,CAAC,OAAO,CAAC,CAAC,KAAc,EAAE,EAAE;gBAC5D,MAAM,MAAM,GACX,OAAO,KAAK,KAAK,QAAQ;oBACxB,CAAC,CAAC,KAAK;oBACP,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;wBACnC,CAAC,CAAE,KAA8B,CAAC,MAAM;wBACxC,CAAC,CAAC,SAAS,CAAC;gBACf,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACnD,CAAC,CAAC,CACF,CAAC;YACF,MAAM,GAAG,GAAqB,EAAE,CAAC;YACjC,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;gBACrC,MAAM,MAAM,GAAG,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;gBAChD,GAAG,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YAClD,CAAC;YACD,QAAQ,CAAC,gBAAgB,GAAG,GAAG,CAAC;YAChC,QAAQ,CAAC,SAAS,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;QAC9F,CAAC;QACD,MAAM,KAAK,GAA2C,EAAE,CAAC;QACzD,IAAI,MAAM,CAAC,oCAAoC,KAAK,KAAK;YAAE,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC;aACpF,IAAI,MAAM,CAAC,oCAAoC,KAAK,IAAI,EAAE,CAAC;YAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,yBAAyB,CAAC;YACjD,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,UAAU;gBAAE,KAAK,CAAC,gBAAgB,GAAG,OAAO,CAAC;iBACvG,IAAI,OAAO,KAAK,MAAM;gBAAE,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC5D,CAAC;QACD,IAAI,MAAM,CAAC,iBAAiB,KAAK,KAAK;YAAE,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;aAC1D,IAAI,MAAM,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;YAC5C,MAAM,SAAS,GAAG,MAAM,CAAC,iBAAiB,CAAC;YAC3C,IAAI,SAAS,KAAK,KAAK,IAAI,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,MAAM;gBAAE,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;QACxG,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM;YAAE,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;QACtD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACxF,QAAQ,CAAC,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC3F,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM;YAAE,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC5D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC","sourcesContent":["/** Fetch a bounded OpenAI or Codex model catalog from a relay baseUrl. */\n\nimport type { FetchFunction, ProviderHeaders } from \"@earendil-works/pi-ai\";\nimport { readResponseTextBounded } from \"../../utils/http-response.ts\";\nimport { DEFAULTS, formatError, THINKING_LEVELS } from \"./constants.ts\";\nimport { buildCodexHeaders, CODEX_VERSION, createCodexFetch } from \"./identity.ts\";\nimport type { RelayModelConfig, ThinkingLevelMap } from \"./types.ts\";\n\nexport interface ProbeModel extends Pick<RelayModelConfig, \"id\" | \"name\"> {\n\t/** Merge into local defaults, then cap default maxTokens to the resulting contextWindow. */\n\tmetadata?: Partial<Omit<RelayModelConfig, \"id\" | \"name\">>;\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\t/** Resolved values only: config/env/command resolution belongs to the caller. */\n\theaders?: ProviderHeaders;\n\tcatalog?: \"openai\" | \"codex\";\n\tfetch?: FetchFunction;\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 (baseUrl.username || baseUrl.password || baseUrl.hash) {\n\t\treturn { ok: false, error: \"Base URL must not contain credentials or a fragment.\" };\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\t// Codex models-manager uses Cargo major.minor.patch, dropping prerelease only.\n\t\tif (opts.catalog === \"codex\") {\n\t\t\t// Keep unrelated query bytes intact (including %20, ~ and repeated parameters).\n\t\t\tconst query = url.search.slice(1).split(\"&\").filter(Boolean);\n\t\t\tconst version = `client_version=${CODEX_VERSION}`;\n\t\t\tconst existing = query.findIndex((part) => new URLSearchParams(part).has(\"client_version\"));\n\t\t\tif (existing < 0) query.push(version);\n\t\t\telse {\n\t\t\t\tquery[existing] = version;\n\t\t\t\tfor (let index = query.length - 1; index > existing; index--) {\n\t\t\t\t\tif (new URLSearchParams(query[index]).has(\"client_version\")) query.splice(index, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\turl.search = query.join(\"&\");\n\t\t}\n\t\tconst headers = new Headers();\n\t\tfor (const [key, value] of Object.entries(\n\t\t\tbuildCodexHeaders({\n\t\t\t\t\"content-type\": null,\n\t\t\t\t...(opts.apiKey ? { authorization: `Bearer ${opts.apiKey}` } : {}),\n\t\t\t\t...opts.headers,\n\t\t\t}),\n\t\t)) {\n\t\t\tif (typeof value === \"string\") headers.set(key, value);\n\t\t}\n\t\theaders.set(\"accept\", \"application/json\");\n\n\t\tconst response = await createCodexFetch(opts.fetch)(url, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders,\n\t\t\tsignal: controller.signal,\n\t\t});\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 = opts.catalog === \"codex\" ? parseCodexModels(json) : parseOpenAIModels(json);\n\t\tif (models === null) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror:\n\t\t\t\t\topts.catalog === \"codex\"\n\t\t\t\t\t\t? \"JSON has no Codex-style `models` array of model slugs. Check the base URL and catalog setting.\"\n\t\t\t\t\t\t: \"JSON has no OpenAI-style `data` array of model ids. Check the base URL and catalog setting.\",\n\t\t\t};\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\nfunction positiveInteger(value: unknown): number | undefined {\n\treturn typeof value === \"number\" && Number.isSafeInteger(value) && value > 0 ? value : undefined;\n}\n\nfunction parseCodexModels(json: unknown): ProbeModel[] | null {\n\tif (!json || typeof json !== \"object\") return null;\n\tconst data = (json as { models?: unknown }).models;\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.slug === \"string\" ? record.slug.trim() : \"\";\n\t\tif (!id) continue;\n\t\tconst model: ProbeModel = { id };\n\t\tif (typeof record.display_name === \"string\" && record.display_name.trim() && record.display_name.trim() !== id)\n\t\t\tmodel.name = record.display_name.trim();\n\t\tconst metadata: NonNullable<ProbeModel[\"metadata\"]> = {};\n\t\tconst context = positiveInteger(record.context_window);\n\t\tconst maxContext = positiveInteger(record.max_context_window);\n\t\tif (context !== undefined) metadata.contextWindow = Math.min(context, maxContext ?? context);\n\t\t// max_context_window is NOT a max output token count. Never infer maxTokens from it.\n\t\tif (Array.isArray(record.supported_reasoning_levels)) {\n\t\t\tconst efforts = new Set(\n\t\t\t\trecord.supported_reasoning_levels.flatMap((entry: unknown) => {\n\t\t\t\t\tconst effort =\n\t\t\t\t\t\ttypeof entry === \"string\"\n\t\t\t\t\t\t\t? entry\n\t\t\t\t\t\t\t: entry && typeof entry === \"object\"\n\t\t\t\t\t\t\t\t? (entry as { effort?: unknown }).effort\n\t\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\treturn typeof effort === \"string\" ? [effort] : [];\n\t\t\t\t}),\n\t\t\t);\n\t\t\tconst map: ThinkingLevelMap = {};\n\t\t\tfor (const level of THINKING_LEVELS) {\n\t\t\t\tconst effort = level === \"off\" ? \"none\" : level;\n\t\t\t\tmap[level] = efforts.has(effort) ? effort : null;\n\t\t\t}\n\t\t\tmetadata.thinkingLevelMap = map;\n\t\t\tmetadata.reasoning = THINKING_LEVELS.some((level) => level !== \"off\" && map[level] !== null);\n\t\t}\n\t\tconst codex: NonNullable<RelayModelConfig[\"codex\"]> = {};\n\t\tif (record.supports_reasoning_summary_parameter === false) codex.reasoningSummary = null;\n\t\telse if (record.supports_reasoning_summary_parameter === true) {\n\t\t\tconst summary = record.default_reasoning_summary;\n\t\t\tif (summary === \"auto\" || summary === \"concise\" || summary === \"detailed\") codex.reasoningSummary = summary;\n\t\t\telse if (summary === \"none\") codex.reasoningSummary = null;\n\t\t}\n\t\tif (record.support_verbosity === false) codex.verbosity = null;\n\t\telse if (record.support_verbosity === true) {\n\t\t\tconst verbosity = record.default_verbosity;\n\t\t\tif (verbosity === \"low\" || verbosity === \"medium\" || verbosity === \"high\") codex.verbosity = verbosity;\n\t\t}\n\t\tif (Object.keys(codex).length) metadata.codex = codex;\n\t\tif (Array.isArray(record.input_modalities) && record.input_modalities.includes(\"text\")) {\n\t\t\tmetadata.input = record.input_modalities.includes(\"image\") ? [\"text\", \"image\"] : [\"text\"];\n\t\t}\n\t\tif (Object.keys(metadata).length) model.metadata = metadata;\n\t\tmodels.push(model);\n\t}\n\treturn models;\n}\n"]}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/** Apply router.json using provider-scoped public Responses stream wrappers. */
|
|
2
|
-
import type { ExtensionAPI, ProviderConfig } from "../../core/extensions/types.ts";
|
|
3
|
-
import { RouterRequestState } from "./state.ts";
|
|
4
|
-
import type { RelayConfig, RouterFile } from "./types.ts";
|
|
5
|
-
export declare function initializeRouterState(pi: ExtensionAPI): Promise<void>;
|
|
6
|
-
export declare function routerStateFor(pi: ExtensionAPI): RouterRequestState;
|
|
7
|
-
export declare function setRouterState(pi: ExtensionAPI, state: RouterRequestState): void;
|
|
8
|
-
export declare function toProviderConfig(relay: RelayConfig, state?: RouterRequestState): ProviderConfig;
|
|
9
|
-
export declare function applyRouterFile(pi: ExtensionAPI, file: RouterFile): void;
|
|
10
|
-
export declare function registerOneRelay(pi: ExtensionAPI, relay: RelayConfig): void;
|
|
11
|
-
export declare function unregisterOneRelay(pi: ExtensionAPI, id: string): void;
|
|
12
|
-
//# sourceMappingURL=register.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/register.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAGnF,OAAO,EAA4B,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE1E,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAM1D,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAcrE;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,YAAY,GAAG,kBAAkB,CAOnE;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAEhF;AAWD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,qBAA2B,GAAG,cAAc,CAgBrG;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAQxE;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAS3E;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAQrE"}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { ROUTER_API } from "./constants.js";
|
|
2
|
-
import { toRegisterModel } from "./presets.js";
|
|
3
|
-
import { loadRouterInstallationId, RouterRequestState } from "./state.js";
|
|
4
|
-
import { streamRouterCodex } from "./stream.js";
|
|
5
|
-
const registeredIdsByApi = new WeakMap();
|
|
6
|
-
const requestStates = new WeakMap();
|
|
7
|
-
const initializations = new WeakMap();
|
|
8
|
-
export function initializeRouterState(pi) {
|
|
9
|
-
let initialization = initializations.get(pi);
|
|
10
|
-
if (!initialization) {
|
|
11
|
-
initialization = loadRouterInstallationId()
|
|
12
|
-
.then((id) => {
|
|
13
|
-
setRouterState(pi, new RouterRequestState(id));
|
|
14
|
-
})
|
|
15
|
-
.catch((error) => {
|
|
16
|
-
initializations.delete(pi);
|
|
17
|
-
throw error;
|
|
18
|
-
});
|
|
19
|
-
initializations.set(pi, initialization);
|
|
20
|
-
}
|
|
21
|
-
return initialization;
|
|
22
|
-
}
|
|
23
|
-
export function routerStateFor(pi) {
|
|
24
|
-
let state = requestStates.get(pi);
|
|
25
|
-
if (!state) {
|
|
26
|
-
state = new RouterRequestState();
|
|
27
|
-
requestStates.set(pi, state);
|
|
28
|
-
}
|
|
29
|
-
return state;
|
|
30
|
-
}
|
|
31
|
-
export function setRouterState(pi, state) {
|
|
32
|
-
requestStates.set(pi, state);
|
|
33
|
-
}
|
|
34
|
-
function registeredIdsFor(pi) {
|
|
35
|
-
let ids = registeredIdsByApi.get(pi);
|
|
36
|
-
if (!ids) {
|
|
37
|
-
ids = new Set();
|
|
38
|
-
registeredIdsByApi.set(pi, ids);
|
|
39
|
-
}
|
|
40
|
-
return ids;
|
|
41
|
-
}
|
|
42
|
-
export function toProviderConfig(relay, state = new RouterRequestState()) {
|
|
43
|
-
const models = structuredClone(relay.models);
|
|
44
|
-
return {
|
|
45
|
-
name: relay.name ?? relay.id,
|
|
46
|
-
// Named registrations merge defined fields; an empty snapshot clears prior router headers.
|
|
47
|
-
headers: { ...relay.headers },
|
|
48
|
-
baseUrl: relay.baseUrl.replace(/\/+$/, ""),
|
|
49
|
-
apiKey: relay.apiKey,
|
|
50
|
-
api: ROUTER_API,
|
|
51
|
-
models: models.map((model) => ({ ...toRegisterModel(model), api: ROUTER_API })),
|
|
52
|
-
streamSimple: (model, context, options) => streamRouterCodex(model, context, options, {
|
|
53
|
-
state,
|
|
54
|
-
codex: models.find((entry) => entry.id === model.id)?.codex,
|
|
55
|
-
}),
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
export function applyRouterFile(pi, file) {
|
|
59
|
-
routerStateFor(pi).reset();
|
|
60
|
-
const registeredIds = registeredIdsFor(pi);
|
|
61
|
-
const nextIds = new Set(file.relays.map((relay) => relay.id));
|
|
62
|
-
for (const id of [...registeredIds]) {
|
|
63
|
-
if (!nextIds.has(id))
|
|
64
|
-
unregisterOneRelay(pi, id);
|
|
65
|
-
}
|
|
66
|
-
for (const relay of file.relays)
|
|
67
|
-
registerOneRelay(pi, relay);
|
|
68
|
-
}
|
|
69
|
-
export function registerOneRelay(pi, relay) {
|
|
70
|
-
routerStateFor(pi).reset();
|
|
71
|
-
const registeredIds = registeredIdsFor(pi);
|
|
72
|
-
if (relay.models.length === 0) {
|
|
73
|
-
if (registeredIds.has(relay.id))
|
|
74
|
-
unregisterOneRelay(pi, relay.id);
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
pi.registerProvider(relay.id, toProviderConfig(relay, routerStateFor(pi)));
|
|
78
|
-
registeredIds.add(relay.id);
|
|
79
|
-
}
|
|
80
|
-
export function unregisterOneRelay(pi, id) {
|
|
81
|
-
routerStateFor(pi).reset();
|
|
82
|
-
try {
|
|
83
|
-
pi.unregisterProvider(id);
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
// Ignore stale registrations after /reload.
|
|
87
|
-
}
|
|
88
|
-
registeredIdsFor(pi).delete(id);
|
|
89
|
-
}
|
|
90
|
-
//# sourceMappingURL=register.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/extensions/router/register.ts"],"names":[],"mappings":"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","sourcesContent":["/** Apply router.json using provider-scoped public Responses stream wrappers. */\nimport type { ExtensionAPI, ProviderConfig } from \"../../core/extensions/types.ts\";\nimport { ROUTER_API } from \"./constants.ts\";\nimport { toRegisterModel } from \"./presets.ts\";\nimport { loadRouterInstallationId, RouterRequestState } from \"./state.ts\";\nimport { streamRouterCodex } from \"./stream.ts\";\nimport type { RelayConfig, RouterFile } from \"./types.ts\";\n\nconst registeredIdsByApi = new WeakMap<ExtensionAPI, Set<string>>();\nconst requestStates = new WeakMap<ExtensionAPI, RouterRequestState>();\nconst initializations = new WeakMap<ExtensionAPI, Promise<void>>();\n\nexport function initializeRouterState(pi: ExtensionAPI): Promise<void> {\n\tlet initialization = initializations.get(pi);\n\tif (!initialization) {\n\t\tinitialization = loadRouterInstallationId()\n\t\t\t.then((id) => {\n\t\t\t\tsetRouterState(pi, new RouterRequestState(id));\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tinitializations.delete(pi);\n\t\t\t\tthrow error;\n\t\t\t});\n\t\tinitializations.set(pi, initialization);\n\t}\n\treturn initialization;\n}\n\nexport function routerStateFor(pi: ExtensionAPI): RouterRequestState {\n\tlet state = requestStates.get(pi);\n\tif (!state) {\n\t\tstate = new RouterRequestState();\n\t\trequestStates.set(pi, state);\n\t}\n\treturn state;\n}\n\nexport function setRouterState(pi: ExtensionAPI, state: RouterRequestState): void {\n\trequestStates.set(pi, state);\n}\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, state = new RouterRequestState()): ProviderConfig {\n\tconst models = structuredClone(relay.models);\n\treturn {\n\t\tname: relay.name ?? relay.id,\n\t\t// Named registrations merge defined fields; an empty snapshot clears prior router headers.\n\t\theaders: { ...relay.headers },\n\t\tbaseUrl: relay.baseUrl.replace(/\\/+$/, \"\"),\n\t\tapiKey: relay.apiKey,\n\t\tapi: ROUTER_API,\n\t\tmodels: models.map((model) => ({ ...toRegisterModel(model), api: ROUTER_API })),\n\t\tstreamSimple: (model, context, options) =>\n\t\t\tstreamRouterCodex(model, context, options, {\n\t\t\t\tstate,\n\t\t\t\tcodex: models.find((entry) => entry.id === model.id)?.codex,\n\t\t\t}),\n\t};\n}\n\nexport function applyRouterFile(pi: ExtensionAPI, file: RouterFile): void {\n\trouterStateFor(pi).reset();\n\tconst registeredIds = registeredIdsFor(pi);\n\tconst nextIds = new Set(file.relays.map((relay) => relay.id));\n\tfor (const id of [...registeredIds]) {\n\t\tif (!nextIds.has(id)) unregisterOneRelay(pi, id);\n\t}\n\tfor (const relay of file.relays) registerOneRelay(pi, relay);\n}\n\nexport function registerOneRelay(pi: ExtensionAPI, relay: RelayConfig): void {\n\trouterStateFor(pi).reset();\n\tconst registeredIds = registeredIdsFor(pi);\n\tif (relay.models.length === 0) {\n\t\tif (registeredIds.has(relay.id)) unregisterOneRelay(pi, relay.id);\n\t\treturn;\n\t}\n\tpi.registerProvider(relay.id, toProviderConfig(relay, routerStateFor(pi)));\n\tregisteredIds.add(relay.id);\n}\n\nexport function unregisterOneRelay(pi: ExtensionAPI, id: string): void {\n\trouterStateFor(pi).reset();\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,20 +0,0 @@
|
|
|
1
|
-
import type { Api, Context, Model, ProviderHeaders, ProviderResponse } from "@earendil-works/pi-ai";
|
|
2
|
-
/** Non-secret installation identity. Never read Codex credentials or invent an account/attestation. */
|
|
3
|
-
export declare function loadRouterInstallationId(): Promise<string>;
|
|
4
|
-
export interface CodexRequestSnapshot {
|
|
5
|
-
headers: ProviderHeaders;
|
|
6
|
-
clientMetadata: Record<string, string>;
|
|
7
|
-
promptCacheKey: string;
|
|
8
|
-
acceptResponse(response: ProviderResponse): void;
|
|
9
|
-
}
|
|
10
|
-
/** Per-extension-host state. A tool continuation is not a new Codex user turn. */
|
|
11
|
-
export declare class RouterRequestState {
|
|
12
|
-
private readonly windowId;
|
|
13
|
-
private readonly scopes;
|
|
14
|
-
private readonly installationId;
|
|
15
|
-
constructor(installationId?: string);
|
|
16
|
-
/** Called on user-task start, navigation, model changes and shutdown, not each Pi tool-loop turn. */
|
|
17
|
-
reset(): void;
|
|
18
|
-
request(model: Model<Api>, context: Context, suppliedSessionId?: string): CodexRequestSnapshot;
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=state.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAKpG,uGAAuG;AACvG,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,CAAC,CAsEhE;AAQD,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,eAAe,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACjD;AAED,kFAAkF;AAClF,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAE1D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,cAAc,GAAE,MAAqB;IAIjD,qGAAqG;IACrG,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,oBAAoB;CAsE9F"}
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import lockfile from "proper-lockfile";
|
|
5
|
-
import { getAgentDir } from "../../config.js";
|
|
6
|
-
import { withFileMutationQueue } from "../../core/tools/file-mutation-queue.js";
|
|
7
|
-
/** Non-secret installation identity. Never read Codex credentials or invent an account/attestation. */
|
|
8
|
-
export async function loadRouterInstallationId() {
|
|
9
|
-
const directory = getAgentDir();
|
|
10
|
-
const path = join(directory, "router-client.json");
|
|
11
|
-
return withFileMutationQueue(path, async () => {
|
|
12
|
-
await mkdir(directory, { recursive: true });
|
|
13
|
-
let compromised;
|
|
14
|
-
const assertLock = () => {
|
|
15
|
-
if (compromised)
|
|
16
|
-
throw compromised;
|
|
17
|
-
};
|
|
18
|
-
// A dedicated identity lock also covers the missing-file case. Never read before acquiring it:
|
|
19
|
-
// another process may still be publishing the identity. Bound contention to about five seconds.
|
|
20
|
-
const release = await lockfile.lock(path, {
|
|
21
|
-
realpath: false,
|
|
22
|
-
stale: 30_000,
|
|
23
|
-
retries: { retries: 50, factor: 1, minTimeout: 100, maxTimeout: 100, randomize: false },
|
|
24
|
-
onCompromised: (error) => {
|
|
25
|
-
compromised = error;
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
let temporary;
|
|
29
|
-
try {
|
|
30
|
-
assertLock();
|
|
31
|
-
let current;
|
|
32
|
-
try {
|
|
33
|
-
current = await readFile(path, "utf8");
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
if (error.code !== "ENOENT")
|
|
37
|
-
throw error;
|
|
38
|
-
}
|
|
39
|
-
assertLock();
|
|
40
|
-
if (current !== undefined) {
|
|
41
|
-
const value = JSON.parse(current);
|
|
42
|
-
if (!value ||
|
|
43
|
-
typeof value !== "object" ||
|
|
44
|
-
!("installationId" in value) ||
|
|
45
|
-
typeof value.installationId !== "string" ||
|
|
46
|
-
value.installationId.length !== 36 ||
|
|
47
|
-
!/^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(value.installationId))
|
|
48
|
-
throw new Error("router-client.json has an invalid installation identity.");
|
|
49
|
-
return value.installationId;
|
|
50
|
-
}
|
|
51
|
-
const installationId = randomUUID();
|
|
52
|
-
temporary = join(directory, `.router-client.${randomUUID()}.tmp`);
|
|
53
|
-
try {
|
|
54
|
-
await writeFile(temporary, `${JSON.stringify({ version: 1, installationId }, null, 2)}\n`, {
|
|
55
|
-
encoding: "utf8",
|
|
56
|
-
mode: 0o600,
|
|
57
|
-
flag: "wx",
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
// Do not remove a pre-existing file in the extremely unlikely event of a UUID collision.
|
|
62
|
-
if (error.code === "EEXIST")
|
|
63
|
-
temporary = undefined;
|
|
64
|
-
throw error;
|
|
65
|
-
}
|
|
66
|
-
assertLock();
|
|
67
|
-
await rename(temporary, path);
|
|
68
|
-
assertLock();
|
|
69
|
-
return installationId;
|
|
70
|
-
}
|
|
71
|
-
finally {
|
|
72
|
-
try {
|
|
73
|
-
if (temporary)
|
|
74
|
-
await rm(temporary, { force: true });
|
|
75
|
-
}
|
|
76
|
-
finally {
|
|
77
|
-
await release().catch((error) => {
|
|
78
|
-
// A compromised lock is already released by proper-lockfile; retain the original error.
|
|
79
|
-
if (!compromised)
|
|
80
|
-
throw error;
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
/** Per-extension-host state. A tool continuation is not a new Codex user turn. */
|
|
87
|
-
export class RouterRequestState {
|
|
88
|
-
constructor(installationId = randomUUID()) {
|
|
89
|
-
this.windowId = randomUUID();
|
|
90
|
-
this.scopes = new Map();
|
|
91
|
-
this.installationId = installationId;
|
|
92
|
-
}
|
|
93
|
-
/** Called on user-task start, navigation, model changes and shutdown, not each Pi tool-loop turn. */
|
|
94
|
-
reset() {
|
|
95
|
-
this.scopes.clear();
|
|
96
|
-
}
|
|
97
|
-
request(model, context, suppliedSessionId) {
|
|
98
|
-
// Cache keys are limited to 64 characters; HTTP headers also trim surrounding spaces.
|
|
99
|
-
const sessionId = suppliedSessionId &&
|
|
100
|
-
suppliedSessionId.length <= 64 &&
|
|
101
|
-
suppliedSessionId.trim() === suppliedSessionId &&
|
|
102
|
-
!/[^\x20-\x7e]/.test(suppliedSessionId)
|
|
103
|
-
? suppliedSessionId
|
|
104
|
-
: suppliedSessionId
|
|
105
|
-
? createHash("sha256").update(suppliedSessionId).digest("hex")
|
|
106
|
-
: randomUUID();
|
|
107
|
-
// Pi sessions are conversation branches; use their identity as both root session and thread.
|
|
108
|
-
// Nested callers should pass their own sessionId. No shared mutable global provider state.
|
|
109
|
-
const threadId = sessionId;
|
|
110
|
-
let userKey = "empty";
|
|
111
|
-
for (let index = context.messages.length - 1; index >= 0; index--) {
|
|
112
|
-
const message = context.messages[index];
|
|
113
|
-
if (message.role === "user") {
|
|
114
|
-
userKey = createHash("sha256")
|
|
115
|
-
.update(JSON.stringify([index, message]))
|
|
116
|
-
.digest("hex");
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
const key = JSON.stringify([sessionId, model.provider, model.baseUrl, model.id, userKey]);
|
|
121
|
-
let scope = this.scopes.get(key);
|
|
122
|
-
if (!scope) {
|
|
123
|
-
if (this.scopes.size >= 128)
|
|
124
|
-
this.scopes.delete(this.scopes.keys().next().value);
|
|
125
|
-
scope = { turnId: randomUUID(), startedAt: Date.now() };
|
|
126
|
-
this.scopes.set(key, scope);
|
|
127
|
-
}
|
|
128
|
-
const turnMetadata = JSON.stringify({
|
|
129
|
-
installation_id: this.installationId,
|
|
130
|
-
session_id: sessionId,
|
|
131
|
-
thread_id: threadId,
|
|
132
|
-
turn_id: scope.turnId,
|
|
133
|
-
window_id: this.windowId,
|
|
134
|
-
request_kind: "turn",
|
|
135
|
-
turn_started_at_unix_ms: scope.startedAt,
|
|
136
|
-
});
|
|
137
|
-
const headers = {
|
|
138
|
-
"session-id": sessionId,
|
|
139
|
-
"thread-id": threadId,
|
|
140
|
-
"x-client-request-id": threadId,
|
|
141
|
-
"x-codex-window-id": this.windowId,
|
|
142
|
-
"x-codex-turn-metadata": turnMetadata,
|
|
143
|
-
};
|
|
144
|
-
if (scope.turnState)
|
|
145
|
-
headers["x-codex-turn-state"] = scope.turnState;
|
|
146
|
-
const activeScope = scope;
|
|
147
|
-
return {
|
|
148
|
-
headers,
|
|
149
|
-
promptCacheKey: sessionId,
|
|
150
|
-
clientMetadata: {
|
|
151
|
-
"x-codex-installation-id": this.installationId,
|
|
152
|
-
session_id: sessionId,
|
|
153
|
-
thread_id: threadId,
|
|
154
|
-
turn_id: scope.turnId,
|
|
155
|
-
"x-codex-window-id": this.windowId,
|
|
156
|
-
"x-codex-turn-metadata": turnMetadata,
|
|
157
|
-
},
|
|
158
|
-
acceptResponse: (response) => {
|
|
159
|
-
if (response.status < 200 || response.status >= 300 || activeScope.turnState !== undefined)
|
|
160
|
-
return;
|
|
161
|
-
const token = Object.entries(response.headers).find(([name]) => name.toLowerCase() === "x-codex-turn-state")?.[1];
|
|
162
|
-
// Response headers are untrusted and tokens must stay bounded, opaque, and turn-local.
|
|
163
|
-
if (token && token.length <= 8192 && /^[\x20-\x7e]+$/.test(token))
|
|
164
|
-
activeScope.turnState = token;
|
|
165
|
-
},
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
//# sourceMappingURL=state.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/extensions/router/state.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { Api, Context, Model, ProviderHeaders, ProviderResponse } from \"@earendil-works/pi-ai\";\nimport lockfile from \"proper-lockfile\";\nimport { getAgentDir } from \"../../config.ts\";\nimport { withFileMutationQueue } from \"../../core/tools/file-mutation-queue.ts\";\n\n/** Non-secret installation identity. Never read Codex credentials or invent an account/attestation. */\nexport async function loadRouterInstallationId(): Promise<string> {\n\tconst directory = getAgentDir();\n\tconst path = join(directory, \"router-client.json\");\n\treturn withFileMutationQueue(path, async () => {\n\t\tawait mkdir(directory, { recursive: true });\n\t\tlet compromised: Error | undefined;\n\t\tconst assertLock = () => {\n\t\t\tif (compromised) throw compromised;\n\t\t};\n\t\t// A dedicated identity lock also covers the missing-file case. Never read before acquiring it:\n\t\t// another process may still be publishing the identity. Bound contention to about five seconds.\n\t\tconst release = await lockfile.lock(path, {\n\t\t\trealpath: false,\n\t\t\tstale: 30_000,\n\t\t\tretries: { retries: 50, factor: 1, minTimeout: 100, maxTimeout: 100, randomize: false },\n\t\t\tonCompromised: (error) => {\n\t\t\t\tcompromised = error;\n\t\t\t},\n\t\t});\n\t\tlet temporary: string | undefined;\n\t\ttry {\n\t\t\tassertLock();\n\t\t\tlet current: string | undefined;\n\t\t\ttry {\n\t\t\t\tcurrent = await readFile(path, \"utf8\");\n\t\t\t} catch (error) {\n\t\t\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t\t\t}\n\t\t\tassertLock();\n\t\t\tif (current !== undefined) {\n\t\t\t\tconst value: unknown = JSON.parse(current);\n\t\t\t\tif (\n\t\t\t\t\t!value ||\n\t\t\t\t\ttypeof value !== \"object\" ||\n\t\t\t\t\t!(\"installationId\" in value) ||\n\t\t\t\t\ttypeof value.installationId !== \"string\" ||\n\t\t\t\t\tvalue.installationId.length !== 36 ||\n\t\t\t\t\t!/^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(value.installationId)\n\t\t\t\t)\n\t\t\t\t\tthrow new Error(\"router-client.json has an invalid installation identity.\");\n\t\t\t\treturn value.installationId;\n\t\t\t}\n\t\t\tconst installationId = randomUUID();\n\t\t\ttemporary = join(directory, `.router-client.${randomUUID()}.tmp`);\n\t\t\ttry {\n\t\t\t\tawait writeFile(temporary, `${JSON.stringify({ version: 1, installationId }, null, 2)}\\n`, {\n\t\t\t\t\tencoding: \"utf8\",\n\t\t\t\t\tmode: 0o600,\n\t\t\t\t\tflag: \"wx\",\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\t// Do not remove a pre-existing file in the extremely unlikely event of a UUID collision.\n\t\t\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") temporary = undefined;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tassertLock();\n\t\t\tawait rename(temporary, path);\n\t\t\tassertLock();\n\t\t\treturn installationId;\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (temporary) await rm(temporary, { force: true });\n\t\t\t} finally {\n\t\t\t\tawait release().catch((error: unknown) => {\n\t\t\t\t\t// A compromised lock is already released by proper-lockfile; retain the original error.\n\t\t\t\t\tif (!compromised) throw error;\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n}\n\ninterface RequestScope {\n\tturnId: string;\n\tstartedAt: number;\n\tturnState?: string;\n}\n\nexport interface CodexRequestSnapshot {\n\theaders: ProviderHeaders;\n\tclientMetadata: Record<string, string>;\n\tpromptCacheKey: string;\n\tacceptResponse(response: ProviderResponse): void;\n}\n\n/** Per-extension-host state. A tool continuation is not a new Codex user turn. */\nexport class RouterRequestState {\n\tprivate readonly windowId = randomUUID();\n\tprivate readonly scopes = new Map<string, RequestScope>();\n\n\tprivate readonly installationId: string;\n\n\tconstructor(installationId: string = randomUUID()) {\n\t\tthis.installationId = installationId;\n\t}\n\n\t/** Called on user-task start, navigation, model changes and shutdown, not each Pi tool-loop turn. */\n\treset(): void {\n\t\tthis.scopes.clear();\n\t}\n\n\trequest(model: Model<Api>, context: Context, suppliedSessionId?: string): CodexRequestSnapshot {\n\t\t// Cache keys are limited to 64 characters; HTTP headers also trim surrounding spaces.\n\t\tconst sessionId =\n\t\t\tsuppliedSessionId &&\n\t\t\tsuppliedSessionId.length <= 64 &&\n\t\t\tsuppliedSessionId.trim() === suppliedSessionId &&\n\t\t\t!/[^\\x20-\\x7e]/.test(suppliedSessionId)\n\t\t\t\t? suppliedSessionId\n\t\t\t\t: suppliedSessionId\n\t\t\t\t\t? createHash(\"sha256\").update(suppliedSessionId).digest(\"hex\")\n\t\t\t\t\t: randomUUID();\n\t\t// Pi sessions are conversation branches; use their identity as both root session and thread.\n\t\t// Nested callers should pass their own sessionId. No shared mutable global provider state.\n\t\tconst threadId = sessionId;\n\t\tlet userKey = \"empty\";\n\t\tfor (let index = context.messages.length - 1; index >= 0; index--) {\n\t\t\tconst message = context.messages[index];\n\t\t\tif (message.role === \"user\") {\n\t\t\t\tuserKey = createHash(\"sha256\")\n\t\t\t\t\t.update(JSON.stringify([index, message]))\n\t\t\t\t\t.digest(\"hex\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tconst key = JSON.stringify([sessionId, model.provider, model.baseUrl, model.id, userKey]);\n\t\tlet scope = this.scopes.get(key);\n\t\tif (!scope) {\n\t\t\tif (this.scopes.size >= 128) this.scopes.delete(this.scopes.keys().next().value!);\n\t\t\tscope = { turnId: randomUUID(), startedAt: Date.now() };\n\t\t\tthis.scopes.set(key, scope);\n\t\t}\n\t\tconst turnMetadata = JSON.stringify({\n\t\t\tinstallation_id: this.installationId,\n\t\t\tsession_id: sessionId,\n\t\t\tthread_id: threadId,\n\t\t\tturn_id: scope.turnId,\n\t\t\twindow_id: this.windowId,\n\t\t\trequest_kind: \"turn\",\n\t\t\tturn_started_at_unix_ms: scope.startedAt,\n\t\t});\n\t\tconst headers: ProviderHeaders = {\n\t\t\t\"session-id\": sessionId,\n\t\t\t\"thread-id\": threadId,\n\t\t\t\"x-client-request-id\": threadId,\n\t\t\t\"x-codex-window-id\": this.windowId,\n\t\t\t\"x-codex-turn-metadata\": turnMetadata,\n\t\t};\n\t\tif (scope.turnState) headers[\"x-codex-turn-state\"] = scope.turnState;\n\t\tconst activeScope = scope;\n\t\treturn {\n\t\t\theaders,\n\t\t\tpromptCacheKey: sessionId,\n\t\t\tclientMetadata: {\n\t\t\t\t\"x-codex-installation-id\": this.installationId,\n\t\t\t\tsession_id: sessionId,\n\t\t\t\tthread_id: threadId,\n\t\t\t\tturn_id: scope.turnId,\n\t\t\t\t\"x-codex-window-id\": this.windowId,\n\t\t\t\t\"x-codex-turn-metadata\": turnMetadata,\n\t\t\t},\n\t\t\tacceptResponse: (response) => {\n\t\t\t\tif (response.status < 200 || response.status >= 300 || activeScope.turnState !== undefined) return;\n\t\t\t\tconst token = Object.entries(response.headers).find(\n\t\t\t\t\t([name]) => name.toLowerCase() === \"x-codex-turn-state\",\n\t\t\t\t)?.[1];\n\t\t\t\t// Response headers are untrusted and tokens must stay bounded, opaque, and turn-local.\n\t\t\t\tif (token && token.length <= 8192 && /^[\\x20-\\x7e]+$/.test(token)) activeScope.turnState = token;\n\t\t\t},\n\t\t};\n\t}\n}\n"]}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persistence for ~/.pi/agent/router.json
|
|
3
|
-
*/
|
|
4
|
-
import type { RelayConfig, RouterFile } from "./types.ts";
|
|
5
|
-
export declare function getRouterConfigPath(): string;
|
|
6
|
-
export declare function emptyRouterFile(): RouterFile;
|
|
7
|
-
export declare function loadRouterFile(): Promise<RouterFile>;
|
|
8
|
-
export declare function parseRouterFile(raw: string): RouterFile;
|
|
9
|
-
export declare function saveRouterFile(file: RouterFile): Promise<void>;
|
|
10
|
-
export declare function upsertRelay(relay: RelayConfig): Promise<RouterFile>;
|
|
11
|
-
export declare function removeRelay(id: string): Promise<RouterFile>;
|
|
12
|
-
//# sourceMappingURL=store.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
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;AAiB9F,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;AA8HD,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpE;AAqBD,wBAAsB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAUzE;AAED,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAOjE"}
|