@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,266 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persistence for ~/.pi/agent/router.json
|
|
3
|
-
*/
|
|
4
|
-
import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
5
|
-
import { dirname, join } from "node:path";
|
|
6
|
-
import { getAgentDir } from "../../config.js";
|
|
7
|
-
import { withFileMutationQueue } from "../../core/tools/file-mutation-queue.js";
|
|
8
|
-
import { CONFIG_VERSION, DEFAULTS, isValidRelayId, THINKING_LEVELS } from "./constants.js";
|
|
9
|
-
const ROOT_FIELDS = ["version", "relays"];
|
|
10
|
-
const RELAY_FIELDS = ["id", "name", "baseUrl", "apiKey", "models", "headers", "catalog"];
|
|
11
|
-
const MODEL_FIELDS = [
|
|
12
|
-
"id",
|
|
13
|
-
"name",
|
|
14
|
-
"reasoning",
|
|
15
|
-
"input",
|
|
16
|
-
"contextWindow",
|
|
17
|
-
"maxTokens",
|
|
18
|
-
"thinkingLevelMap",
|
|
19
|
-
"codex",
|
|
20
|
-
"headers",
|
|
21
|
-
"cost",
|
|
22
|
-
];
|
|
23
|
-
export function getRouterConfigPath() {
|
|
24
|
-
return join(getAgentDir(), "router.json");
|
|
25
|
-
}
|
|
26
|
-
export function emptyRouterFile() {
|
|
27
|
-
return { version: CONFIG_VERSION, relays: [] };
|
|
28
|
-
}
|
|
29
|
-
export async function loadRouterFile() {
|
|
30
|
-
const filePath = getRouterConfigPath();
|
|
31
|
-
let raw;
|
|
32
|
-
try {
|
|
33
|
-
raw = await readFile(filePath, "utf8");
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
if (error.code === "ENOENT")
|
|
37
|
-
return emptyRouterFile();
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
return parseRouterFile(raw);
|
|
41
|
-
}
|
|
42
|
-
function expectObject(value, path) {
|
|
43
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
44
|
-
throw new Error(`${path} must be an object.`);
|
|
45
|
-
}
|
|
46
|
-
return value;
|
|
47
|
-
}
|
|
48
|
-
function rejectUnknownFields(record, allowed, path) {
|
|
49
|
-
const unknown = Object.keys(record).filter((key) => !allowed.includes(key));
|
|
50
|
-
if (unknown.length > 0)
|
|
51
|
-
throw new Error(`${path} has unsupported field(s): ${unknown.join(", ")}.`);
|
|
52
|
-
}
|
|
53
|
-
function expectString(value, path, allowEmpty = false) {
|
|
54
|
-
if (typeof value !== "string")
|
|
55
|
-
throw new Error(`${path} must be a string.`);
|
|
56
|
-
const trimmed = value.trim();
|
|
57
|
-
if (!allowEmpty && !trimmed)
|
|
58
|
-
throw new Error(`${path} must not be empty.`);
|
|
59
|
-
return allowEmpty ? value : trimmed;
|
|
60
|
-
}
|
|
61
|
-
function expectPositiveInteger(value, path) {
|
|
62
|
-
if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0) {
|
|
63
|
-
throw new Error(`${path} must be a positive integer.`);
|
|
64
|
-
}
|
|
65
|
-
return value;
|
|
66
|
-
}
|
|
67
|
-
export function parseRouterFile(raw) {
|
|
68
|
-
let parsed;
|
|
69
|
-
try {
|
|
70
|
-
parsed = JSON.parse(raw);
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
throw new Error("router.json is not valid JSON.");
|
|
74
|
-
}
|
|
75
|
-
const root = expectObject(parsed, "router.json");
|
|
76
|
-
rejectUnknownFields(root, ROOT_FIELDS, "router.json");
|
|
77
|
-
const version = root.version ?? CONFIG_VERSION;
|
|
78
|
-
if (version !== CONFIG_VERSION) {
|
|
79
|
-
throw new Error(`router.json has unsupported version ${String(version)}.`);
|
|
80
|
-
}
|
|
81
|
-
if (root.relays !== undefined && !Array.isArray(root.relays)) {
|
|
82
|
-
throw new Error("router.json relays must be an array.");
|
|
83
|
-
}
|
|
84
|
-
const relays = (root.relays ?? []).map((value, index) => parseRelay(value, `router.json relays[${index}]`));
|
|
85
|
-
const relayIds = new Set();
|
|
86
|
-
for (const relay of relays) {
|
|
87
|
-
if (relayIds.has(relay.id))
|
|
88
|
-
throw new Error(`router.json contains duplicate relay id "${relay.id}".`);
|
|
89
|
-
relayIds.add(relay.id);
|
|
90
|
-
}
|
|
91
|
-
return { version: CONFIG_VERSION, relays };
|
|
92
|
-
}
|
|
93
|
-
function parseRelay(value, path) {
|
|
94
|
-
const record = expectObject(value, path);
|
|
95
|
-
rejectUnknownFields(record, RELAY_FIELDS, path);
|
|
96
|
-
const id = expectString(record.id, `${path}.id`);
|
|
97
|
-
if (!isValidRelayId(id))
|
|
98
|
-
throw new Error(`${path}.id must be a valid provider id without '/'.`);
|
|
99
|
-
const baseUrl = expectString(record.baseUrl, `${path}.baseUrl`);
|
|
100
|
-
try {
|
|
101
|
-
const url = new URL(baseUrl);
|
|
102
|
-
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
103
|
-
throw new Error("unsupported protocol");
|
|
104
|
-
if (url.username || url.password || url.hash)
|
|
105
|
-
throw new Error("credentials or fragment");
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
throw new Error(`${path}.baseUrl must be an http or https URL without embedded credentials or a fragment.`);
|
|
109
|
-
}
|
|
110
|
-
const apiKey = expectString(record.apiKey, `${path}.apiKey`, true);
|
|
111
|
-
if (record.models !== undefined && !Array.isArray(record.models)) {
|
|
112
|
-
throw new Error(`${path}.models must be an array.`);
|
|
113
|
-
}
|
|
114
|
-
const models = (record.models ?? []).map((model, index) => parseModel(model, `${path}.models[${index}]`));
|
|
115
|
-
const modelIds = new Set();
|
|
116
|
-
for (const model of models) {
|
|
117
|
-
if (modelIds.has(model.id))
|
|
118
|
-
throw new Error(`${path}.models contains duplicate id "${model.id}".`);
|
|
119
|
-
modelIds.add(model.id);
|
|
120
|
-
}
|
|
121
|
-
const relay = { id, baseUrl, apiKey, models };
|
|
122
|
-
if (record.name !== undefined)
|
|
123
|
-
relay.name = expectString(record.name, `${path}.name`);
|
|
124
|
-
if (record.headers !== undefined)
|
|
125
|
-
relay.headers = parseHeaders(record.headers, `${path}.headers`);
|
|
126
|
-
if (record.catalog !== undefined) {
|
|
127
|
-
if (record.catalog !== "openai" && record.catalog !== "codex")
|
|
128
|
-
throw new Error(`${path}.catalog must be openai or codex.`);
|
|
129
|
-
relay.catalog = record.catalog;
|
|
130
|
-
}
|
|
131
|
-
return relay;
|
|
132
|
-
}
|
|
133
|
-
function parseModel(value, path) {
|
|
134
|
-
const record = expectObject(value, path);
|
|
135
|
-
rejectUnknownFields(record, MODEL_FIELDS, path);
|
|
136
|
-
const model = { id: expectString(record.id, `${path}.id`) };
|
|
137
|
-
if (record.name !== undefined) {
|
|
138
|
-
const name = expectString(record.name, `${path}.name`, true).trim();
|
|
139
|
-
if (name)
|
|
140
|
-
model.name = name;
|
|
141
|
-
}
|
|
142
|
-
if (record.reasoning !== undefined) {
|
|
143
|
-
if (typeof record.reasoning !== "boolean")
|
|
144
|
-
throw new Error(`${path}.reasoning must be a boolean.`);
|
|
145
|
-
model.reasoning = record.reasoning;
|
|
146
|
-
}
|
|
147
|
-
if (record.input !== undefined) {
|
|
148
|
-
if (!Array.isArray(record.input) || record.input.some((item) => item !== "text" && item !== "image")) {
|
|
149
|
-
throw new Error(`${path}.input must contain only "text" and "image".`);
|
|
150
|
-
}
|
|
151
|
-
const input = new Set(record.input);
|
|
152
|
-
if (!input.has("text"))
|
|
153
|
-
throw new Error(`${path}.input must include "text".`);
|
|
154
|
-
model.input = input.has("image") ? ["text", "image"] : ["text"];
|
|
155
|
-
}
|
|
156
|
-
if (record.contextWindow !== undefined) {
|
|
157
|
-
model.contextWindow = expectPositiveInteger(record.contextWindow, `${path}.contextWindow`);
|
|
158
|
-
}
|
|
159
|
-
if (record.maxTokens !== undefined) {
|
|
160
|
-
model.maxTokens = expectPositiveInteger(record.maxTokens, `${path}.maxTokens`);
|
|
161
|
-
}
|
|
162
|
-
if (record.thinkingLevelMap !== undefined) {
|
|
163
|
-
model.thinkingLevelMap = parseThinkingLevelMap(record.thinkingLevelMap, `${path}.thinkingLevelMap`);
|
|
164
|
-
}
|
|
165
|
-
if (model.maxTokens !== undefined && model.maxTokens > (model.contextWindow ?? DEFAULTS.contextWindow))
|
|
166
|
-
throw new Error(`${path}.maxTokens must not exceed contextWindow.`);
|
|
167
|
-
if (record.headers !== undefined)
|
|
168
|
-
model.headers = parseHeaders(record.headers, `${path}.headers`);
|
|
169
|
-
if (record.codex !== undefined) {
|
|
170
|
-
const codex = expectObject(record.codex, `${path}.codex`);
|
|
171
|
-
rejectUnknownFields(codex, ["reasoningSummary", "verbosity", "parallelToolCalls"], `${path}.codex`);
|
|
172
|
-
for (const field of ["reasoningSummary", "verbosity"]) {
|
|
173
|
-
const value = codex[field];
|
|
174
|
-
const allowed = field === "reasoningSummary" ? ["auto", "concise", "detailed"] : ["low", "medium", "high"];
|
|
175
|
-
if (value === undefined)
|
|
176
|
-
continue;
|
|
177
|
-
if (value !== null && (typeof value !== "string" || !allowed.includes(value)))
|
|
178
|
-
throw new Error(`${path}.codex.${field} has an invalid value.`);
|
|
179
|
-
}
|
|
180
|
-
if (codex.parallelToolCalls !== undefined && typeof codex.parallelToolCalls !== "boolean")
|
|
181
|
-
throw new Error(`${path}.codex.parallelToolCalls must be a boolean.`);
|
|
182
|
-
model.codex = codex;
|
|
183
|
-
}
|
|
184
|
-
if (record.cost !== undefined) {
|
|
185
|
-
const cost = expectObject(record.cost, `${path}.cost`);
|
|
186
|
-
const fields = ["input", "output", "cacheRead", "cacheWrite"];
|
|
187
|
-
rejectUnknownFields(cost, fields, `${path}.cost`);
|
|
188
|
-
for (const field of fields) {
|
|
189
|
-
const value = cost[field];
|
|
190
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0)
|
|
191
|
-
throw new Error(`${path}.cost.${field} must be a finite non-negative number.`);
|
|
192
|
-
}
|
|
193
|
-
model.cost = cost;
|
|
194
|
-
}
|
|
195
|
-
return model;
|
|
196
|
-
}
|
|
197
|
-
function parseThinkingLevelMap(value, path) {
|
|
198
|
-
const record = expectObject(value, path);
|
|
199
|
-
const map = {};
|
|
200
|
-
for (const [level, target] of Object.entries(record)) {
|
|
201
|
-
if (!THINKING_LEVELS.includes(level)) {
|
|
202
|
-
throw new Error(`${path} has unsupported thinking level "${level}".`);
|
|
203
|
-
}
|
|
204
|
-
if (target !== null && (typeof target !== "string" || target.trim().length === 0)) {
|
|
205
|
-
throw new Error(`${path}.${level} must be a non-empty string or null.`);
|
|
206
|
-
}
|
|
207
|
-
map[level] = target === null ? null : target.trim();
|
|
208
|
-
}
|
|
209
|
-
return map;
|
|
210
|
-
}
|
|
211
|
-
function parseHeaders(value, path) {
|
|
212
|
-
const record = expectObject(value, path);
|
|
213
|
-
for (const [key, value] of Object.entries(record)) {
|
|
214
|
-
if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(key) ||
|
|
215
|
-
typeof value !== "string" ||
|
|
216
|
-
[...value].some((char) => [0, 10, 13].includes(char.charCodeAt(0))))
|
|
217
|
-
throw new Error(`${path}.${key} must be a valid header with a string value.`);
|
|
218
|
-
}
|
|
219
|
-
return record;
|
|
220
|
-
}
|
|
221
|
-
export async function saveRouterFile(file) {
|
|
222
|
-
const snapshot = parseRouterFile(JSON.stringify(file));
|
|
223
|
-
await withFileMutationQueue(getRouterConfigPath(), () => writeRouterFile(snapshot));
|
|
224
|
-
}
|
|
225
|
-
async function writeRouterFile(file) {
|
|
226
|
-
const filePath = getRouterConfigPath();
|
|
227
|
-
const serialized = `${JSON.stringify(parseRouterFile(JSON.stringify(file)), null, 2)}
|
|
228
|
-
`;
|
|
229
|
-
await mkdir(dirname(filePath), { recursive: true });
|
|
230
|
-
const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
231
|
-
try {
|
|
232
|
-
await writeFile(tempPath, serialized, { encoding: "utf8", mode: 0o600 });
|
|
233
|
-
await rename(tempPath, filePath);
|
|
234
|
-
}
|
|
235
|
-
catch (error) {
|
|
236
|
-
try {
|
|
237
|
-
await unlink(tempPath);
|
|
238
|
-
}
|
|
239
|
-
catch {
|
|
240
|
-
/* Preserve original failure. */
|
|
241
|
-
}
|
|
242
|
-
throw error;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
export async function upsertRelay(relay) {
|
|
246
|
-
const snapshot = structuredClone(relay);
|
|
247
|
-
return withFileMutationQueue(getRouterConfigPath(), async () => {
|
|
248
|
-
const file = await loadRouterFile();
|
|
249
|
-
const index = file.relays.findIndex((entry) => entry.id === snapshot.id);
|
|
250
|
-
if (index >= 0)
|
|
251
|
-
file.relays[index] = snapshot;
|
|
252
|
-
else
|
|
253
|
-
file.relays.push(snapshot);
|
|
254
|
-
await writeRouterFile(file);
|
|
255
|
-
return file;
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
export async function removeRelay(id) {
|
|
259
|
-
return withFileMutationQueue(getRouterConfigPath(), async () => {
|
|
260
|
-
const file = await loadRouterFile();
|
|
261
|
-
file.relays = file.relays.filter((entry) => entry.id !== id);
|
|
262
|
-
await writeRouterFile(file);
|
|
263
|
-
return file;
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
//# sourceMappingURL=store.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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, DEFAULTS, 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\", \"name\", \"baseUrl\", \"apiKey\", \"models\", \"headers\", \"catalog\"] as const;\nconst MODEL_FIELDS = [\n\t\"id\",\n\t\"name\",\n\t\"reasoning\",\n\t\"input\",\n\t\"contextWindow\",\n\t\"maxTokens\",\n\t\"thinkingLevelMap\",\n\t\"codex\",\n\t\"headers\",\n\t\"cost\",\n] 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.isSafeInteger(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\tif (url.username || url.password || url.hash) throw new Error(\"credentials or fragment\");\n\t} catch {\n\t\tthrow new Error(`${path}.baseUrl must be an http or https URL without embedded credentials or a fragment.`);\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\tconst relay: RelayConfig = { id, baseUrl, apiKey, models };\n\tif (record.name !== undefined) relay.name = expectString(record.name, `${path}.name`);\n\tif (record.headers !== undefined) relay.headers = parseHeaders(record.headers, `${path}.headers`);\n\tif (record.catalog !== undefined) {\n\t\tif (record.catalog !== \"openai\" && record.catalog !== \"codex\")\n\t\t\tthrow new Error(`${path}.catalog must be openai or codex.`);\n\t\trelay.catalog = record.catalog;\n\t}\n\treturn relay;\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\tif (model.maxTokens !== undefined && model.maxTokens > (model.contextWindow ?? DEFAULTS.contextWindow))\n\t\tthrow new Error(`${path}.maxTokens must not exceed contextWindow.`);\n\tif (record.headers !== undefined) model.headers = parseHeaders(record.headers, `${path}.headers`);\n\tif (record.codex !== undefined) {\n\t\tconst codex = expectObject(record.codex, `${path}.codex`);\n\t\trejectUnknownFields(codex, [\"reasoningSummary\", \"verbosity\", \"parallelToolCalls\"], `${path}.codex`);\n\t\tfor (const field of [\"reasoningSummary\", \"verbosity\"] as const) {\n\t\t\tconst value = codex[field];\n\t\t\tconst allowed = field === \"reasoningSummary\" ? [\"auto\", \"concise\", \"detailed\"] : [\"low\", \"medium\", \"high\"];\n\t\t\tif (value === undefined) continue;\n\t\t\tif (value !== null && (typeof value !== \"string\" || !allowed.includes(value)))\n\t\t\t\tthrow new Error(`${path}.codex.${field} has an invalid value.`);\n\t\t}\n\t\tif (codex.parallelToolCalls !== undefined && typeof codex.parallelToolCalls !== \"boolean\")\n\t\t\tthrow new Error(`${path}.codex.parallelToolCalls must be a boolean.`);\n\t\tmodel.codex = codex as NonNullable<RelayModelConfig[\"codex\"]>;\n\t}\n\tif (record.cost !== undefined) {\n\t\tconst cost = expectObject(record.cost, `${path}.cost`);\n\t\tconst fields = [\"input\", \"output\", \"cacheRead\", \"cacheWrite\"] as const;\n\t\trejectUnknownFields(cost, fields, `${path}.cost`);\n\t\tfor (const field of fields) {\n\t\t\tconst value = cost[field];\n\t\t\tif (typeof value !== \"number\" || !Number.isFinite(value) || value < 0)\n\t\t\t\tthrow new Error(`${path}.cost.${field} must be a finite non-negative number.`);\n\t\t}\n\t\tmodel.cost = cost as NonNullable<RelayModelConfig[\"cost\"]>;\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\nfunction parseHeaders(value: unknown, path: string): Record<string, string> {\n\tconst record = expectObject(value, path);\n\tfor (const [key, value] of Object.entries(record)) {\n\t\tif (\n\t\t\t!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(key) ||\n\t\t\ttypeof value !== \"string\" ||\n\t\t\t[...value].some((char) => [0, 10, 13].includes(char.charCodeAt(0)))\n\t\t)\n\t\t\tthrow new Error(`${path}.${key} must be a valid header with a string value.`);\n\t}\n\treturn record as Record<string, string>;\n}\n\nexport async function saveRouterFile(file: RouterFile): Promise<void> {\n\tconst snapshot = parseRouterFile(JSON.stringify(file));\n\tawait withFileMutationQueue(getRouterConfigPath(), () => writeRouterFile(snapshot));\n}\n\nasync function writeRouterFile(file: RouterFile): Promise<void> {\n\tconst filePath = getRouterConfigPath();\n\tconst serialized = `${JSON.stringify(parseRouterFile(JSON.stringify(file)), null, 2)}\n`;\n\tawait mkdir(dirname(filePath), { recursive: true });\n\tconst tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;\n\ttry {\n\t\tawait writeFile(tempPath, serialized, { encoding: \"utf8\", mode: 0o600 });\n\t\tawait rename(tempPath, filePath);\n\t} catch (error) {\n\t\ttry {\n\t\t\tawait unlink(tempPath);\n\t\t} catch {\n\t\t\t/* Preserve original failure. */\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nexport async function upsertRelay(relay: RelayConfig): Promise<RouterFile> {\n\tconst snapshot = structuredClone(relay);\n\treturn withFileMutationQueue(getRouterConfigPath(), async () => {\n\t\tconst file = await loadRouterFile();\n\t\tconst index = file.relays.findIndex((entry) => entry.id === snapshot.id);\n\t\tif (index >= 0) file.relays[index] = snapshot;\n\t\telse file.relays.push(snapshot);\n\t\tawait writeRouterFile(file);\n\t\treturn file;\n\t});\n}\n\nexport async function removeRelay(id: string): Promise<RouterFile> {\n\treturn withFileMutationQueue(getRouterConfigPath(), async () => {\n\t\tconst file = await loadRouterFile();\n\t\tfile.relays = file.relays.filter((entry) => entry.id !== id);\n\t\tawait writeRouterFile(file);\n\t\treturn file;\n\t});\n}\n"]}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/** Codex 0.153.4 normal Responses/SSE request adaptation; pi-ai owns conversion and stream parsing. */
|
|
2
|
-
import { type Api, type Context, createAssistantMessageEventStream, type Model, type SimpleStreamOptions } from "@earendil-works/pi-ai/compat";
|
|
3
|
-
import { type CodexRequestSnapshot, RouterRequestState } from "./state.ts";
|
|
4
|
-
import type { CodexModelConfig } from "./types.ts";
|
|
5
|
-
export declare function streamRouterCodex(model: Model<Api>, context: Context, options?: SimpleStreamOptions, configuration?: {
|
|
6
|
-
state?: RouterRequestState;
|
|
7
|
-
codex?: CodexModelConfig;
|
|
8
|
-
}): ReturnType<typeof createAssistantMessageEventStream>;
|
|
9
|
-
export declare function reshapePayloadForCodex(payload: unknown, context: Context, model: Model<"openai-responses">, snapshot: CodexRequestSnapshot, configuration?: CodexModelConfig): Record<string, unknown>;
|
|
10
|
-
/** Codex0.153.4 ResponseItemId::is_prefixed checks only nonempty sides of the first underscore. */
|
|
11
|
-
export declare function sanitizeInputItemsForCodex(input: unknown): void;
|
|
12
|
-
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/stream.ts"],"names":[],"mappings":"AAAA,uGAAuG;AACvG,OAAO,EACN,KAAK,GAAG,EACR,KAAK,OAAO,EACZ,iCAAiC,EAEjC,KAAK,KAAK,EAEV,KAAK,mBAAmB,EACxB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,KAAK,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,EAC7B,aAAa,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAAC,KAAK,CAAC,EAAE,gBAAgB,CAAA;CAAE,GACtE,UAAU,CAAC,OAAO,iCAAiC,CAAC,CAkGtD;AAMD,wBAAgB,sBAAsB,CACrC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,CAAC,kBAAkB,CAAC,EAChC,QAAQ,EAAE,oBAAoB,EAC9B,aAAa,GAAE,gBAAqB,GAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgDzB;AA4BD,mGAAmG;AACnG,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAiB/D"}
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
/** Codex 0.153.4 normal Responses/SSE request adaptation; pi-ai owns conversion and stream parsing. */
|
|
2
|
-
import { createAssistantMessageEventStream, openAIResponsesApi, } from "@earendil-works/pi-ai/compat";
|
|
3
|
-
import { formatError, ROUTER_API } from "./constants.js";
|
|
4
|
-
import { buildCodexHeaders, createCodexFetch } from "./identity.js";
|
|
5
|
-
import { RouterRequestState } from "./state.js";
|
|
6
|
-
import { createCodexTransport } from "./transport.js";
|
|
7
|
-
const responsesApi = openAIResponsesApi();
|
|
8
|
-
export function streamRouterCodex(model, context, options, configuration) {
|
|
9
|
-
const stream = createAssistantMessageEventStream();
|
|
10
|
-
void (async () => {
|
|
11
|
-
try {
|
|
12
|
-
const baseUrl = new URL(model.baseUrl);
|
|
13
|
-
if (!["http:", "https:"].includes(baseUrl.protocol) || baseUrl.username || baseUrl.password || baseUrl.hash) {
|
|
14
|
-
throw new Error("Router base URL must be HTTP(S) without embedded credentials or a fragment.");
|
|
15
|
-
}
|
|
16
|
-
const query = baseUrl.search;
|
|
17
|
-
baseUrl.search = "";
|
|
18
|
-
const requestModel = {
|
|
19
|
-
...model,
|
|
20
|
-
baseUrl: baseUrl.href.replace(/\/+$/, ""),
|
|
21
|
-
api: ROUTER_API,
|
|
22
|
-
compat: {
|
|
23
|
-
...(model.compat ?? {}),
|
|
24
|
-
sessionAffinityFormat: "openai-nosession",
|
|
25
|
-
supportsLongCacheRetention: false,
|
|
26
|
-
supportsMaxOutputTokens: false,
|
|
27
|
-
// Codex explicitly sends strict:false for ordinary function tools; omission is not equivalent.
|
|
28
|
-
// The public adapter still owns schemas and explicit constrained-sampling requests.
|
|
29
|
-
supportsStrictMode: true,
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
const snapshot = (configuration?.state ?? new RouterRequestState()).request(model, context, options?.sessionId);
|
|
33
|
-
const headers = buildCodexHeaders({ ...snapshot.headers, ...options?.headers });
|
|
34
|
-
const codexFetch = createCodexFetch(options?.fetch);
|
|
35
|
-
// OpenAI SDK concatenates baseURL and /responses before parsing. Keep query parameters
|
|
36
|
-
// out of that concatenation, then restore them at the scoped HTTP boundary.
|
|
37
|
-
const send = (input, init) => {
|
|
38
|
-
if (!query)
|
|
39
|
-
return codexFetch(input, init);
|
|
40
|
-
const url = new URL(input instanceof Request ? input.url : String(input));
|
|
41
|
-
url.search = query;
|
|
42
|
-
return codexFetch(input instanceof Request ? new Request(url, input) : url, init);
|
|
43
|
-
};
|
|
44
|
-
const fetch = createCodexTransport(send, {
|
|
45
|
-
maxRetries: options?.maxRetries,
|
|
46
|
-
maxRetryDelayMs: options?.maxRetryDelayMs,
|
|
47
|
-
signal: options?.signal,
|
|
48
|
-
onErrorResponse: async (response) => {
|
|
49
|
-
const responseHeaders = {};
|
|
50
|
-
response.headers.forEach((value, name) => {
|
|
51
|
-
responseHeaders[name] = value;
|
|
52
|
-
});
|
|
53
|
-
await options?.onResponse?.({ status: response.status, headers: responseHeaders }, requestModel);
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
// Delegate credential validation too: the adapter supports resolved header-only authentication.
|
|
57
|
-
const inner = responsesApi.streamSimple(requestModel, context, {
|
|
58
|
-
...options,
|
|
59
|
-
headers,
|
|
60
|
-
fetch,
|
|
61
|
-
// Own only Codex HTTP retry policy. Disable the adapter's different HTTP retry layer.
|
|
62
|
-
maxRetries: 0,
|
|
63
|
-
onPayload: async (payload) => {
|
|
64
|
-
const shaped = reshapePayloadForCodex(payload, context, requestModel, snapshot, configuration?.codex);
|
|
65
|
-
const replacement = await options?.onPayload?.(shaped, requestModel);
|
|
66
|
-
return replacement === undefined ? shaped : replacement;
|
|
67
|
-
},
|
|
68
|
-
onResponse: async (response, responseModel) => {
|
|
69
|
-
snapshot.acceptResponse(response);
|
|
70
|
-
await options?.onResponse?.(response, responseModel);
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
for await (const event of inner)
|
|
74
|
-
stream.push(event);
|
|
75
|
-
stream.end();
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
const reason = options?.signal?.aborted ? "aborted" : "error";
|
|
79
|
-
stream.push({
|
|
80
|
-
type: "error",
|
|
81
|
-
reason,
|
|
82
|
-
error: {
|
|
83
|
-
role: "assistant",
|
|
84
|
-
content: [],
|
|
85
|
-
api: ROUTER_API,
|
|
86
|
-
provider: model.provider,
|
|
87
|
-
model: model.id,
|
|
88
|
-
usage: {
|
|
89
|
-
input: 0,
|
|
90
|
-
output: 0,
|
|
91
|
-
cacheRead: 0,
|
|
92
|
-
cacheWrite: 0,
|
|
93
|
-
totalTokens: 0,
|
|
94
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
95
|
-
},
|
|
96
|
-
stopReason: reason,
|
|
97
|
-
errorMessage: formatError(error),
|
|
98
|
-
timestamp: Date.now(),
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
stream.end();
|
|
102
|
-
}
|
|
103
|
-
})();
|
|
104
|
-
return stream;
|
|
105
|
-
}
|
|
106
|
-
function isRecord(value) {
|
|
107
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
108
|
-
}
|
|
109
|
-
export function reshapePayloadForCodex(payload, context, model, snapshot, configuration = {}) {
|
|
110
|
-
if (!isRecord(payload))
|
|
111
|
-
throw new Error("Responses payload must be an object.");
|
|
112
|
-
// Do not mutate signatures/history or the adapter's original payload.
|
|
113
|
-
const base = structuredClone(payload);
|
|
114
|
-
const { instructions, input } = extractInstructions(base.input, context.systemPrompt);
|
|
115
|
-
if (instructions)
|
|
116
|
-
base.instructions = instructions;
|
|
117
|
-
else
|
|
118
|
-
delete base.instructions;
|
|
119
|
-
base.input = input;
|
|
120
|
-
sanitizeInputItemsForCodex(base.input);
|
|
121
|
-
base.store = false;
|
|
122
|
-
base.stream = true;
|
|
123
|
-
base.tools ??= [];
|
|
124
|
-
base.tool_choice = "auto";
|
|
125
|
-
base.parallel_tool_calls = configuration.parallelToolCalls ?? true;
|
|
126
|
-
base.include = ["reasoning.encrypted_content"];
|
|
127
|
-
base.prompt_cache_key = snapshot.promptCacheKey;
|
|
128
|
-
base.client_metadata = snapshot.clientMetadata;
|
|
129
|
-
const reasoning = model.reasoning && isRecord(base.reasoning) ? base.reasoning : {};
|
|
130
|
-
// Summary/verbosity support comes from catalog metadata or explicit model settings, not its id.
|
|
131
|
-
const summary = configuration.reasoningSummary === undefined ? (model.reasoning ? "auto" : null) : configuration.reasoningSummary;
|
|
132
|
-
if (summary !== null)
|
|
133
|
-
reasoning.summary = summary;
|
|
134
|
-
else
|
|
135
|
-
delete reasoning.summary;
|
|
136
|
-
if (reasoning.effort === "persistent")
|
|
137
|
-
reasoning.effort = "disabled";
|
|
138
|
-
base.reasoning = reasoning;
|
|
139
|
-
const text = isRecord(base.text) ? base.text : {};
|
|
140
|
-
if (configuration.verbosity != null)
|
|
141
|
-
text.verbosity = configuration.verbosity;
|
|
142
|
-
else
|
|
143
|
-
delete text.verbosity;
|
|
144
|
-
if (Object.keys(text).length)
|
|
145
|
-
base.text = text;
|
|
146
|
-
else
|
|
147
|
-
delete base.text;
|
|
148
|
-
// These are absent from normal Codex Responses DTOs. maxTokens remains local model metadata.
|
|
149
|
-
for (const name of [
|
|
150
|
-
"prompt_cache_retention",
|
|
151
|
-
"prompt_cache_options",
|
|
152
|
-
"max_output_tokens",
|
|
153
|
-
"temperature",
|
|
154
|
-
"top_p",
|
|
155
|
-
"user",
|
|
156
|
-
"metadata",
|
|
157
|
-
"truncation",
|
|
158
|
-
"context_management",
|
|
159
|
-
"safety_identifier",
|
|
160
|
-
"stream_options",
|
|
161
|
-
])
|
|
162
|
-
delete base[name];
|
|
163
|
-
return base;
|
|
164
|
-
}
|
|
165
|
-
const RESPONSE_ITEM_ID_TYPES = new Set([
|
|
166
|
-
"additional_tools",
|
|
167
|
-
"message",
|
|
168
|
-
"agent_message",
|
|
169
|
-
"reasoning",
|
|
170
|
-
"local_shell_call",
|
|
171
|
-
"function_call",
|
|
172
|
-
"tool_search_call",
|
|
173
|
-
"function_call_output",
|
|
174
|
-
"custom_tool_call",
|
|
175
|
-
"custom_tool_call_output",
|
|
176
|
-
"tool_search_output",
|
|
177
|
-
"web_search_call",
|
|
178
|
-
"image_generation_call",
|
|
179
|
-
"compaction",
|
|
180
|
-
"compaction_summary",
|
|
181
|
-
"context_compaction",
|
|
182
|
-
]);
|
|
183
|
-
const STATUS_LESS_ITEM_TYPES = new Set([
|
|
184
|
-
"message",
|
|
185
|
-
"reasoning",
|
|
186
|
-
"function_call",
|
|
187
|
-
"function_call_output",
|
|
188
|
-
"custom_tool_call_output",
|
|
189
|
-
]);
|
|
190
|
-
/** Codex0.153.4 ResponseItemId::is_prefixed checks only nonempty sides of the first underscore. */
|
|
191
|
-
export function sanitizeInputItemsForCodex(input) {
|
|
192
|
-
if (!Array.isArray(input))
|
|
193
|
-
return;
|
|
194
|
-
for (const item of input) {
|
|
195
|
-
if (!isRecord(item))
|
|
196
|
-
continue;
|
|
197
|
-
if (item.type === undefined && typeof item.role === "string")
|
|
198
|
-
item.type = "message";
|
|
199
|
-
const type = typeof item.type === "string" ? item.type : undefined;
|
|
200
|
-
if (type && RESPONSE_ITEM_ID_TYPES.has(type) && typeof item.id === "string") {
|
|
201
|
-
const separator = item.id.indexOf("_");
|
|
202
|
-
if (separator <= 0 || separator === item.id.length - 1)
|
|
203
|
-
delete item.id;
|
|
204
|
-
}
|
|
205
|
-
if (type && STATUS_LESS_ITEM_TYPES.has(type))
|
|
206
|
-
delete item.status;
|
|
207
|
-
if (Array.isArray(item.content)) {
|
|
208
|
-
for (const part of item.content) {
|
|
209
|
-
if (isRecord(part) && part.type === "output_text")
|
|
210
|
-
delete part.annotations;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
function extractInstructions(input, systemPrompt) {
|
|
216
|
-
if (!Array.isArray(input))
|
|
217
|
-
return { instructions: systemPrompt, input };
|
|
218
|
-
const first = input[0];
|
|
219
|
-
if (isRecord(first) && (first.role === "system" || first.role === "developer")) {
|
|
220
|
-
const content = first.content;
|
|
221
|
-
const text = typeof content === "string"
|
|
222
|
-
? content
|
|
223
|
-
: Array.isArray(content)
|
|
224
|
-
? content
|
|
225
|
-
.map((part) => (isRecord(part) && typeof part.text === "string" ? part.text : ""))
|
|
226
|
-
.join("")
|
|
227
|
-
: "";
|
|
228
|
-
// Only the adapter's leading system prompt moves. Later developer messages remain ordered input.
|
|
229
|
-
return { instructions: systemPrompt || text || undefined, input: input.slice(1) };
|
|
230
|
-
}
|
|
231
|
-
return { instructions: systemPrompt, input };
|
|
232
|
-
}
|
|
233
|
-
//# sourceMappingURL=stream.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../../src/extensions/router/stream.ts"],"names":[],"mappings":"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","sourcesContent":["/** Codex 0.153.4 normal Responses/SSE request adaptation; pi-ai owns conversion and stream parsing. */\nimport {\n\ttype Api,\n\ttype Context,\n\tcreateAssistantMessageEventStream,\n\ttype FetchFunction,\n\ttype Model,\n\topenAIResponsesApi,\n\ttype SimpleStreamOptions,\n} from \"@earendil-works/pi-ai/compat\";\nimport { formatError, ROUTER_API } from \"./constants.ts\";\nimport { buildCodexHeaders, createCodexFetch } from \"./identity.ts\";\nimport { type CodexRequestSnapshot, RouterRequestState } from \"./state.ts\";\nimport { createCodexTransport } from \"./transport.ts\";\nimport type { CodexModelConfig } from \"./types.ts\";\n\nconst responsesApi = openAIResponsesApi();\n\nexport function streamRouterCodex(\n\tmodel: Model<Api>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n\tconfiguration?: { state?: RouterRequestState; codex?: CodexModelConfig },\n): ReturnType<typeof createAssistantMessageEventStream> {\n\tconst stream = createAssistantMessageEventStream();\n\tvoid (async () => {\n\t\ttry {\n\t\t\tconst baseUrl = new URL(model.baseUrl);\n\t\t\tif (![\"http:\", \"https:\"].includes(baseUrl.protocol) || baseUrl.username || baseUrl.password || baseUrl.hash) {\n\t\t\t\tthrow new Error(\"Router base URL must be HTTP(S) without embedded credentials or a fragment.\");\n\t\t\t}\n\t\t\tconst query = baseUrl.search;\n\t\t\tbaseUrl.search = \"\";\n\t\t\tconst requestModel = {\n\t\t\t\t...model,\n\t\t\t\tbaseUrl: baseUrl.href.replace(/\\/+$/, \"\"),\n\t\t\t\tapi: ROUTER_API,\n\t\t\t\tcompat: {\n\t\t\t\t\t...(model.compat ?? {}),\n\t\t\t\t\tsessionAffinityFormat: \"openai-nosession\",\n\t\t\t\t\tsupportsLongCacheRetention: false,\n\t\t\t\t\tsupportsMaxOutputTokens: false,\n\t\t\t\t\t// Codex explicitly sends strict:false for ordinary function tools; omission is not equivalent.\n\t\t\t\t\t// The public adapter still owns schemas and explicit constrained-sampling requests.\n\t\t\t\t\tsupportsStrictMode: true,\n\t\t\t\t},\n\t\t\t} as Model<\"openai-responses\">;\n\t\t\tconst snapshot = (configuration?.state ?? new RouterRequestState()).request(\n\t\t\t\tmodel,\n\t\t\t\tcontext,\n\t\t\t\toptions?.sessionId,\n\t\t\t);\n\t\t\tconst headers = buildCodexHeaders({ ...snapshot.headers, ...options?.headers });\n\t\t\tconst codexFetch = createCodexFetch(options?.fetch);\n\t\t\t// OpenAI SDK concatenates baseURL and /responses before parsing. Keep query parameters\n\t\t\t// out of that concatenation, then restore them at the scoped HTTP boundary.\n\t\t\tconst send: FetchFunction = (input, init) => {\n\t\t\t\tif (!query) return codexFetch(input, init);\n\t\t\t\tconst url = new URL(input instanceof Request ? input.url : String(input));\n\t\t\t\turl.search = query;\n\t\t\t\treturn codexFetch(input instanceof Request ? new Request(url, input) : url, init);\n\t\t\t};\n\t\t\tconst fetch = createCodexTransport(send, {\n\t\t\t\tmaxRetries: options?.maxRetries,\n\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\t\t\tsignal: options?.signal,\n\t\t\t\tonErrorResponse: async (response) => {\n\t\t\t\t\tconst responseHeaders: Record<string, string> = {};\n\t\t\t\t\tresponse.headers.forEach((value, name) => {\n\t\t\t\t\t\tresponseHeaders[name] = value;\n\t\t\t\t\t});\n\t\t\t\t\tawait options?.onResponse?.({ status: response.status, headers: responseHeaders }, requestModel);\n\t\t\t\t},\n\t\t\t});\n\t\t\t// Delegate credential validation too: the adapter supports resolved header-only authentication.\n\t\t\tconst inner = responsesApi.streamSimple(requestModel, context, {\n\t\t\t\t...options,\n\t\t\t\theaders,\n\t\t\t\tfetch,\n\t\t\t\t// Own only Codex HTTP retry policy. Disable the adapter's different HTTP retry layer.\n\t\t\t\tmaxRetries: 0,\n\t\t\t\tonPayload: async (payload) => {\n\t\t\t\t\tconst shaped = reshapePayloadForCodex(payload, context, requestModel, snapshot, configuration?.codex);\n\t\t\t\t\tconst replacement = await options?.onPayload?.(shaped, requestModel);\n\t\t\t\t\treturn replacement === undefined ? shaped : replacement;\n\t\t\t\t},\n\t\t\t\tonResponse: async (response, responseModel) => {\n\t\t\t\t\tsnapshot.acceptResponse(response);\n\t\t\t\t\tawait options?.onResponse?.(response, responseModel);\n\t\t\t\t},\n\t\t\t});\n\t\t\tfor await (const event of inner) stream.push(event);\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tconst reason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tstream.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason,\n\t\t\t\terror: {\n\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\tcontent: [],\n\t\t\t\t\tapi: ROUTER_API,\n\t\t\t\t\tprovider: model.provider,\n\t\t\t\t\tmodel: model.id,\n\t\t\t\t\tusage: {\n\t\t\t\t\t\tinput: 0,\n\t\t\t\t\t\toutput: 0,\n\t\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\t\ttotalTokens: 0,\n\t\t\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t\t\t},\n\t\t\t\t\tstopReason: reason,\n\t\t\t\t\terrorMessage: formatError(error),\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t},\n\t\t\t});\n\t\t\tstream.end();\n\t\t}\n\t})();\n\treturn stream;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function reshapePayloadForCodex(\n\tpayload: unknown,\n\tcontext: Context,\n\tmodel: Model<\"openai-responses\">,\n\tsnapshot: CodexRequestSnapshot,\n\tconfiguration: CodexModelConfig = {},\n): Record<string, unknown> {\n\tif (!isRecord(payload)) throw new Error(\"Responses payload must be an object.\");\n\t// Do not mutate signatures/history or the adapter's original payload.\n\tconst base = structuredClone(payload);\n\tconst { instructions, input } = extractInstructions(base.input, context.systemPrompt);\n\tif (instructions) base.instructions = instructions;\n\telse delete base.instructions;\n\tbase.input = input;\n\tsanitizeInputItemsForCodex(base.input);\n\tbase.store = false;\n\tbase.stream = true;\n\tbase.tools ??= [];\n\tbase.tool_choice = \"auto\";\n\tbase.parallel_tool_calls = configuration.parallelToolCalls ?? true;\n\tbase.include = [\"reasoning.encrypted_content\"];\n\tbase.prompt_cache_key = snapshot.promptCacheKey;\n\tbase.client_metadata = snapshot.clientMetadata;\n\n\tconst reasoning = model.reasoning && isRecord(base.reasoning) ? base.reasoning : {};\n\t// Summary/verbosity support comes from catalog metadata or explicit model settings, not its id.\n\tconst summary =\n\t\tconfiguration.reasoningSummary === undefined ? (model.reasoning ? \"auto\" : null) : configuration.reasoningSummary;\n\tif (summary !== null) reasoning.summary = summary;\n\telse delete reasoning.summary;\n\tif (reasoning.effort === \"persistent\") reasoning.effort = \"disabled\";\n\tbase.reasoning = reasoning;\n\tconst text = isRecord(base.text) ? base.text : {};\n\tif (configuration.verbosity != null) text.verbosity = configuration.verbosity;\n\telse delete text.verbosity;\n\tif (Object.keys(text).length) base.text = text;\n\telse delete base.text;\n\n\t// These are absent from normal Codex Responses DTOs. maxTokens remains local model metadata.\n\tfor (const name of [\n\t\t\"prompt_cache_retention\",\n\t\t\"prompt_cache_options\",\n\t\t\"max_output_tokens\",\n\t\t\"temperature\",\n\t\t\"top_p\",\n\t\t\"user\",\n\t\t\"metadata\",\n\t\t\"truncation\",\n\t\t\"context_management\",\n\t\t\"safety_identifier\",\n\t\t\"stream_options\",\n\t])\n\t\tdelete base[name];\n\treturn base;\n}\n\nconst RESPONSE_ITEM_ID_TYPES = new Set([\n\t\"additional_tools\",\n\t\"message\",\n\t\"agent_message\",\n\t\"reasoning\",\n\t\"local_shell_call\",\n\t\"function_call\",\n\t\"tool_search_call\",\n\t\"function_call_output\",\n\t\"custom_tool_call\",\n\t\"custom_tool_call_output\",\n\t\"tool_search_output\",\n\t\"web_search_call\",\n\t\"image_generation_call\",\n\t\"compaction\",\n\t\"compaction_summary\",\n\t\"context_compaction\",\n]);\nconst STATUS_LESS_ITEM_TYPES = new Set([\n\t\"message\",\n\t\"reasoning\",\n\t\"function_call\",\n\t\"function_call_output\",\n\t\"custom_tool_call_output\",\n]);\n\n/** Codex0.153.4 ResponseItemId::is_prefixed checks only nonempty sides of the first underscore. */\nexport function sanitizeInputItemsForCodex(input: unknown): void {\n\tif (!Array.isArray(input)) return;\n\tfor (const item of input) {\n\t\tif (!isRecord(item)) continue;\n\t\tif (item.type === undefined && typeof item.role === \"string\") item.type = \"message\";\n\t\tconst type = typeof item.type === \"string\" ? item.type : undefined;\n\t\tif (type && RESPONSE_ITEM_ID_TYPES.has(type) && typeof item.id === \"string\") {\n\t\t\tconst separator = item.id.indexOf(\"_\");\n\t\t\tif (separator <= 0 || separator === item.id.length - 1) delete item.id;\n\t\t}\n\t\tif (type && STATUS_LESS_ITEM_TYPES.has(type)) delete item.status;\n\t\tif (Array.isArray(item.content)) {\n\t\t\tfor (const part of item.content) {\n\t\t\t\tif (isRecord(part) && part.type === \"output_text\") delete part.annotations;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction extractInstructions(\n\tinput: unknown,\n\tsystemPrompt: string | undefined,\n): { instructions?: string; input: unknown } {\n\tif (!Array.isArray(input)) return { instructions: systemPrompt, input };\n\tconst first: unknown = input[0];\n\tif (isRecord(first) && (first.role === \"system\" || first.role === \"developer\")) {\n\t\tconst content = first.content;\n\t\tconst text =\n\t\t\ttypeof content === \"string\"\n\t\t\t\t? content\n\t\t\t\t: Array.isArray(content)\n\t\t\t\t\t? content\n\t\t\t\t\t\t\t.map((part: unknown) => (isRecord(part) && typeof part.text === \"string\" ? part.text : \"\"))\n\t\t\t\t\t\t\t.join(\"\")\n\t\t\t\t\t: \"\";\n\t\t// Only the adapter's leading system prompt moves. Later developer messages remain ordered input.\n\t\treturn { instructions: systemPrompt || text || undefined, input: input.slice(1) };\n\t}\n\treturn { instructions: systemPrompt, input };\n}\n"]}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { FetchFunction } from "@earendil-works/pi-ai";
|
|
2
|
-
/** Codex 0.153.4 HTTP policy only; pi-ai owns successful Responses bodies and all SSE handling. */
|
|
3
|
-
export declare function createCodexTransport(fetch: FetchFunction, options?: {
|
|
4
|
-
maxRetries?: number;
|
|
5
|
-
maxRetryDelayMs?: number;
|
|
6
|
-
signal?: AbortSignal;
|
|
7
|
-
onErrorResponse?: (response: Response) => void | Promise<void>;
|
|
8
|
-
}): FetchFunction;
|
|
9
|
-
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAoC3D,mGAAmG;AACnG,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,aAAa,EACpB,OAAO,GAAE;IACR,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1D,GACJ,aAAa,CAqDf"}
|