@visual-z/xeno 0.8.4 → 0.9.0
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 +8 -0
- package/README.md +31 -746
- package/bin/xeno.exe +26 -0
- package/install.cjs +88 -0
- package/package.json +18 -48
- package/docs/app-server.md +0 -115
- package/docs/foundations.md +0 -88
- package/docs/install.md +0 -244
- package/docs/providers.md +0 -172
- package/docs/research/foundation-clients-2026-10-09.md +0 -27
- package/docs/research/foundation-editing-2026-10-09.md +0 -56
- package/docs/research/foundation-network-2026-10-09.md +0 -37
- package/docs/research/foundation-workflow-2026-10-09.md +0 -37
- package/src/apps/acp-server.ts +0 -41
- package/src/apps/agent-profiles.ts +0 -19
- package/src/apps/app-server.ts +0 -30
- package/src/apps/approve.ts +0 -49
- package/src/apps/cli.ts +0 -99
- package/src/apps/commands.ts +0 -319
- package/src/apps/completions.ts +0 -87
- package/src/apps/control-transport.ts +0 -90
- package/src/apps/export-cli.ts +0 -24
- package/src/apps/goal-flow.ts +0 -70
- package/src/apps/image-draft.ts +0 -46
- package/src/apps/input.ts +0 -312
- package/src/apps/model-catalog.ts +0 -69
- package/src/apps/preferences.ts +0 -20
- package/src/apps/project-trust.ts +0 -9
- package/src/apps/provider-connect.ts +0 -346
- package/src/apps/question-ui.ts +0 -27
- package/src/apps/render.ts +0 -181
- package/src/apps/resources.ts +0 -66
- package/src/apps/review.ts +0 -109
- package/src/apps/session-hub.ts +0 -96
- package/src/apps/session-lifecycle.ts +0 -64
- package/src/apps/shell.ts +0 -2071
- package/src/apps/startup-input.ts +0 -135
- package/src/apps/startup.ts +0 -1677
- package/src/apps/ui/app.ts +0 -1818
- package/src/apps/ui/control-model.ts +0 -43
- package/src/apps/ui/extension-host.ts +0 -194
- package/src/apps/ui/image-cache.ts +0 -121
- package/src/apps/ui/palette.ts +0 -88
- package/src/apps/ui/project.ts +0 -127
- package/src/apps/ui/standalone.ts +0 -148
- package/src/apps/ui/status-model.ts +0 -68
- package/src/apps/ui/surface.ts +0 -91
- package/src/apps/ui/theme.ts +0 -86
- package/src/apps/update-check.ts +0 -112
- package/src/apps/workflow.ts +0 -58
- package/src/core/acceptance.ts +0 -139
- package/src/core/action-defaults.ts +0 -58
- package/src/core/activity-status.ts +0 -52
- package/src/core/agent-profile.ts +0 -130
- package/src/core/attachment-input.ts +0 -17
- package/src/core/blind-checks.ts +0 -72
- package/src/core/boundary.ts +0 -174
- package/src/core/branch-receipt.ts +0 -26
- package/src/core/catalog-merge.ts +0 -19
- package/src/core/checkpoints.ts +0 -85
- package/src/core/churn.ts +0 -61
- package/src/core/command-artifacts.ts +0 -94
- package/src/core/command-contract.ts +0 -151
- package/src/core/completion-action.ts +0 -20
- package/src/core/completion-review.ts +0 -98
- package/src/core/context-detail.ts +0 -37
- package/src/core/context-policy.ts +0 -133
- package/src/core/context-window.ts +0 -54
- package/src/core/continuation.ts +0 -130
- package/src/core/control-protocol.ts +0 -69
- package/src/core/control-view.ts +0 -39
- package/src/core/cycle.ts +0 -17
- package/src/core/data-query.ts +0 -201
- package/src/core/deadline.ts +0 -40
- package/src/core/derive.ts +0 -516
- package/src/core/draft-images.ts +0 -56
- package/src/core/edit-plan.ts +0 -200
- package/src/core/environment.ts +0 -181
- package/src/core/event-validation.ts +0 -220
- package/src/core/events.ts +0 -670
- package/src/core/evidence-ladder.ts +0 -62
- package/src/core/evidence-links.ts +0 -68
- package/src/core/evidence.ts +0 -240
- package/src/core/execution.ts +0 -18
- package/src/core/exhaustive.ts +0 -18
- package/src/core/export.ts +0 -179
- package/src/core/extension-flags.ts +0 -14
- package/src/core/external-effects.ts +0 -488
- package/src/core/failure-recovery.ts +0 -173
- package/src/core/file-precondition.ts +0 -78
- package/src/core/file-references.ts +0 -35
- package/src/core/frontmatter.ts +0 -213
- package/src/core/git-status.ts +0 -29
- package/src/core/goal-view.ts +0 -64
- package/src/core/goal.ts +0 -200
- package/src/core/handoff.ts +0 -479
- package/src/core/history-query.ts +0 -139
- package/src/core/history.ts +0 -237
- package/src/core/image-limits.ts +0 -72
- package/src/core/images.ts +0 -46
- package/src/core/integration-health.ts +0 -34
- package/src/core/json-event.ts +0 -131
- package/src/core/json-pointer.ts +0 -46
- package/src/core/keymap.ts +0 -153
- package/src/core/lsp-framing.ts +0 -34
- package/src/core/mcp-config.ts +0 -68
- package/src/core/model-picker.ts +0 -64
- package/src/core/model-preferences.ts +0 -28
- package/src/core/model-replay.ts +0 -22
- package/src/core/model-scope.ts +0 -53
- package/src/core/note-guidance.ts +0 -34
- package/src/core/oauth-fields.ts +0 -44
- package/src/core/observation-view.ts +0 -152
- package/src/core/outcome.ts +0 -44
- package/src/core/overflow.ts +0 -59
- package/src/core/packages.ts +0 -47
- package/src/core/patch.ts +0 -130
- package/src/core/path-suggestions.ts +0 -59
- package/src/core/permissions.ts +0 -410
- package/src/core/process-receipt.ts +0 -105
- package/src/core/process-state.ts +0 -37
- package/src/core/program-status.ts +0 -40
- package/src/core/progress.ts +0 -150
- package/src/core/project.ts +0 -431
- package/src/core/prompt-policy.ts +0 -46
- package/src/core/prompts.ts +0 -111
- package/src/core/question.ts +0 -94
- package/src/core/queue.ts +0 -78
- package/src/core/read-bounds.ts +0 -24
- package/src/core/read-observation.ts +0 -106
- package/src/core/recovery-sources.ts +0 -74
- package/src/core/regex-dialect.ts +0 -25
- package/src/core/request-budget.ts +0 -23
- package/src/core/request-progress.ts +0 -87
- package/src/core/request-state.ts +0 -273
- package/src/core/resource-selection.ts +0 -36
- package/src/core/response-recovery.ts +0 -59
- package/src/core/resume.ts +0 -59
- package/src/core/review.ts +0 -68
- package/src/core/ripgrep-release.ts +0 -64
- package/src/core/runtime-target.ts +0 -94
- package/src/core/scheduling.ts +0 -8
- package/src/core/search-observation.ts +0 -97
- package/src/core/secrets.ts +0 -188
- package/src/core/session-archive.ts +0 -4
- package/src/core/session-browser.ts +0 -82
- package/src/core/session-entry.ts +0 -61
- package/src/core/session-exit.ts +0 -42
- package/src/core/session-format.ts +0 -169
- package/src/core/session-position.ts +0 -26
- package/src/core/session-tree.ts +0 -147
- package/src/core/settings.ts +0 -192
- package/src/core/skills.ts +0 -165
- package/src/core/sql-query.ts +0 -211
- package/src/core/stall.ts +0 -128
- package/src/core/stop-report.ts +0 -68
- package/src/core/text-normalize.ts +0 -81
- package/src/core/theme.ts +0 -166
- package/src/core/thinking.ts +0 -26
- package/src/core/tokens.ts +0 -151
- package/src/core/tool-contract.ts +0 -153
- package/src/core/tool-discovery.ts +0 -87
- package/src/core/tool-failure.ts +0 -81
- package/src/core/tool-input.ts +0 -44
- package/src/core/transcript.ts +0 -108
- package/src/core/tui-mode.ts +0 -29
- package/src/core/update-check.ts +0 -157
- package/src/core/version.ts +0 -55
- package/src/core/web-content.ts +0 -80
- package/src/core/work-state.ts +0 -154
- package/src/core/workflow-mode.ts +0 -34
- package/src/core/working-set.ts +0 -119
- package/src/core/yaml.ts +0 -282
- package/src/runtime/acp-agent.ts +0 -289
- package/src/runtime/agent-profiles.ts +0 -21
- package/src/runtime/auth.ts +0 -367
- package/src/runtime/blind-check.ts +0 -36
- package/src/runtime/branch-jobs.ts +0 -36
- package/src/runtime/catalog.ts +0 -285
- package/src/runtime/clipboard.ts +0 -125
- package/src/runtime/command-artifacts.ts +0 -64
- package/src/runtime/connection-reuse.ts +0 -40
- package/src/runtime/control-client.ts +0 -149
- package/src/runtime/control-connection.ts +0 -139
- package/src/runtime/counter-check.ts +0 -74
- package/src/runtime/environment-tools.ts +0 -60
- package/src/runtime/evidence-notes.ts +0 -35
- package/src/runtime/exec-sessions.ts +0 -456
- package/src/runtime/execution-control.ts +0 -40
- package/src/runtime/extension-loader.ts +0 -37
- package/src/runtime/extension-ui.ts +0 -47
- package/src/runtime/extensions.ts +0 -370
- package/src/runtime/formatter-tool.ts +0 -38
- package/src/runtime/formatter.ts +0 -50
- package/src/runtime/foundation.ts +0 -116
- package/src/runtime/history-cache.ts +0 -57
- package/src/runtime/history-tools.ts +0 -168
- package/src/runtime/images.ts +0 -80
- package/src/runtime/integrations.ts +0 -216
- package/src/runtime/loop.ts +0 -3108
- package/src/runtime/lsp-client.ts +0 -201
- package/src/runtime/mcp-client.ts +0 -264
- package/src/runtime/mcp-oauth.ts +0 -168
- package/src/runtime/mcp-schema.ts +0 -51
- package/src/runtime/model-config.ts +0 -232
- package/src/runtime/model-data.LICENSE +0 -27
- package/src/runtime/model-data.ts +0 -21
- package/src/runtime/model-discovery.ts +0 -208
- package/src/runtime/model-replay.ts +0 -10
- package/src/runtime/model-scope.ts +0 -20
- package/src/runtime/model-sources.ts +0 -151
- package/src/runtime/model.ts +0 -686
- package/src/runtime/models-fetch.ts +0 -57
- package/src/runtime/oauth-device.ts +0 -86
- package/src/runtime/oauth.ts +0 -853
- package/src/runtime/open-image.ts +0 -42
- package/src/runtime/openai-responses.ts +0 -304
- package/src/runtime/openai.ts +0 -697
- package/src/runtime/output-schema.ts +0 -26
- package/src/runtime/package-manager.ts +0 -125
- package/src/runtime/patch-tool.ts +0 -38
- package/src/runtime/permission-resources.ts +0 -18
- package/src/runtime/pi-provider.ts +0 -423
- package/src/runtime/program-status.ts +0 -38
- package/src/runtime/progress.ts +0 -26
- package/src/runtime/provider-access.ts +0 -21
- package/src/runtime/provider-connect.ts +0 -109
- package/src/runtime/provider-presets.ts +0 -98
- package/src/runtime/provider-protocols.ts +0 -29
- package/src/runtime/provider-request.ts +0 -87
- package/src/runtime/provider-tool-policy.ts +0 -33
- package/src/runtime/provider.ts +0 -580
- package/src/runtime/question-tool.ts +0 -62
- package/src/runtime/retry.ts +0 -447
- package/src/runtime/review-tool.ts +0 -48
- package/src/runtime/rich-text.ts +0 -36
- package/src/runtime/runtime-target.ts +0 -149
- package/src/runtime/secrets.ts +0 -79
- package/src/runtime/self-update.ts +0 -74
- package/src/runtime/session-control.ts +0 -265
- package/src/runtime/session-hub.ts +0 -85
- package/src/runtime/stream-idle.ts +0 -80
- package/src/runtime/tool-broker.ts +0 -137
- package/src/runtime/tool-discovery.ts +0 -58
- package/src/runtime/tool-queue.ts +0 -77
- package/src/runtime/tools.ts +0 -1820
- package/src/runtime/turn-effects.ts +0 -31
- package/src/runtime/update-check.ts +0 -48
- package/src/runtime/usage.ts +0 -253
- package/src/runtime/version.ts +0 -12
- package/src/runtime/web-http.ts +0 -56
- package/src/runtime/web-tools.ts +0 -88
- package/src/runtime/working-notes.ts +0 -60
- package/src/runtime/workspace-lifecycle.ts +0 -141
- package/src/store/acceptance.ts +0 -15
- package/src/store/agent-profile-files.ts +0 -13
- package/src/store/atomic.ts +0 -31
- package/src/store/auth-store.ts +0 -50
- package/src/store/blind-checks.ts +0 -32
- package/src/store/blobs.ts +0 -143
- package/src/store/checkpoint-history.ts +0 -32
- package/src/store/command-artifacts.ts +0 -96
- package/src/store/command.ts +0 -111
- package/src/store/config.ts +0 -69
- package/src/store/context-files.ts +0 -436
- package/src/store/file-checkpoints.ts +0 -108
- package/src/store/file-index.ts +0 -174
- package/src/store/foundation-config.ts +0 -24
- package/src/store/git-checkpoints.ts +0 -67
- package/src/store/git-status.ts +0 -15
- package/src/store/history-search.ts +0 -19
- package/src/store/log.ts +0 -725
- package/src/store/lsp-document.ts +0 -30
- package/src/store/mcp-credentials.ts +0 -85
- package/src/store/models.ts +0 -60
- package/src/store/observations.ts +0 -224
- package/src/store/packages.ts +0 -98
- package/src/store/patch.ts +0 -92
- package/src/store/permission-paths.ts +0 -34
- package/src/store/process-receipts.ts +0 -34
- package/src/store/query-source.ts +0 -49
- package/src/store/recovery.ts +0 -44
- package/src/store/replay.ts +0 -76
- package/src/store/resource-index.ts +0 -170
- package/src/store/resources.ts +0 -285
- package/src/store/restore.ts +0 -110
- package/src/store/review.ts +0 -109
- package/src/store/runtime-target.ts +0 -64
- package/src/store/search.ts +0 -728
- package/src/store/secrets.ts +0 -44
- package/src/store/serial.ts +0 -13
- package/src/store/session-archive.ts +0 -165
- package/src/store/session-browser.ts +0 -68
- package/src/store/session-position.ts +0 -27
- package/src/store/sessions.ts +0 -525
- package/src/store/source-cancellation.ts +0 -6
- package/src/store/tool-binaries.ts +0 -90
- package/src/store/trust.ts +0 -82
- package/src/store/update-cache.ts +0 -36
- package/src/store/user-settings.ts +0 -30
- package/src/store/workspace-clone.ts +0 -42
- package/src/store/workspace-observation.ts +0 -113
- package/src/store/workspace.ts +0 -115
- package/src/store/worktree.ts +0 -278
- package/src/tui/ansi-spans.ts +0 -126
- package/src/tui/diff.ts +0 -160
- package/src/tui/exhaustive.ts +0 -14
- package/src/tui/fuzzy.ts +0 -75
- package/src/tui/style.ts +0 -208
- package/src/tui/ui/atomic-draft.ts +0 -121
- package/src/tui/ui/branch-panel.ts +0 -47
- package/src/tui/ui/canvas.ts +0 -96
- package/src/tui/ui/colors.ts +0 -70
- package/src/tui/ui/composer.ts +0 -199
- package/src/tui/ui/control-panel.ts +0 -25
- package/src/tui/ui/control-sidebar.ts +0 -49
- package/src/tui/ui/dialog.ts +0 -398
- package/src/tui/ui/draft.ts +0 -23
- package/src/tui/ui/duration.ts +0 -16
- package/src/tui/ui/edge.ts +0 -186
- package/src/tui/ui/image-size.ts +0 -44
- package/src/tui/ui/ink.ts +0 -210
- package/src/tui/ui/items.ts +0 -42
- package/src/tui/ui/keys.ts +0 -40
- package/src/tui/ui/layout.ts +0 -74
- package/src/tui/ui/list-model.ts +0 -86
- package/src/tui/ui/list-view.ts +0 -172
- package/src/tui/ui/mascot.ts +0 -67
- package/src/tui/ui/messages.ts +0 -518
- package/src/tui/ui/motion.ts +0 -28
- package/src/tui/ui/paths.ts +0 -10
- package/src/tui/ui/pictures.ts +0 -108
- package/src/tui/ui/prompt-history.ts +0 -60
- package/src/tui/ui/screen.ts +0 -579
- package/src/tui/ui/status.ts +0 -403
- package/src/tui/ui/styled.ts +0 -85
- package/src/tui/ui/tool-card.ts +0 -150
- package/src/tui/width.ts +0 -567
- package/src/vendor/pi-rich/LICENSE.upstream +0 -21
- package/src/vendor/pi-rich/UPSTREAM.json +0 -17
- package/src/vendor/pi-rich/clipboard-command.ts +0 -44
- package/src/vendor/pi-rich/exif-orientation.ts +0 -182
- package/src/vendor/pi-rich/html.ts +0 -51
- package/src/vendor/pi-rich/image-convert.ts +0 -49
- package/src/vendor/pi-rich/image-resize-core.ts +0 -164
- package/src/vendor/pi-rich/image-resize-worker.ts +0 -42
- package/src/vendor/pi-rich/image-resize.ts +0 -123
- package/src/vendor/pi-rich/mime.ts +0 -116
- package/src/vendor/pi-rich/photon.ts +0 -139
- package/src/vendor/pi-rich/syntax-highlight.ts +0 -214
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { encodeProgramStatus, PROGRAM_STATUS_QUERY, programStatusReply, type ProgramStatus } from "../core/program-status.ts";
|
|
2
|
-
|
|
3
|
-
/** Terminal transport only. Capability detection has no relationship to agent evidence. */
|
|
4
|
-
export class ProgramStatusReporter {
|
|
5
|
-
private readonly write: (text: string) => void;
|
|
6
|
-
private readonly id: string;
|
|
7
|
-
private readonly mode: "auto" | "on" | "off";
|
|
8
|
-
private supported = false;
|
|
9
|
-
private started = false;
|
|
10
|
-
private closed = false;
|
|
11
|
-
private last: ProgramStatus = { state: "idle" };
|
|
12
|
-
private emitted = "";
|
|
13
|
-
constructor(options: { write: (text: string) => void; id: string; tty: boolean; mode?: string; multiplexed?: boolean }) {
|
|
14
|
-
this.write = options.write; this.id = options.id;
|
|
15
|
-
this.mode = !options.tty || options.mode === "0" ? "off" : options.mode === "1" ? "on" : options.multiplexed ? "off" : "auto";
|
|
16
|
-
}
|
|
17
|
-
start(): void {
|
|
18
|
-
if (this.started || this.closed) return; this.started = true;
|
|
19
|
-
if (this.mode === "auto") this.write(PROGRAM_STATUS_QUERY);
|
|
20
|
-
if (this.mode === "on") { this.supported = true; this.flush(); }
|
|
21
|
-
}
|
|
22
|
-
receive(sequence: string): void {
|
|
23
|
-
if (this.closed || !this.started || this.mode !== "auto" || !programStatusReply(sequence)) return;
|
|
24
|
-
this.supported = true; this.flush();
|
|
25
|
-
}
|
|
26
|
-
update(status: ProgramStatus): void { this.last = { ...status }; if (this.started) this.flush(); }
|
|
27
|
-
private flush(): void {
|
|
28
|
-
if (this.closed || !this.supported) return;
|
|
29
|
-
const sequence = encodeProgramStatus(this.last, this.id);
|
|
30
|
-
if (sequence !== this.emitted) { this.emitted = sequence; this.write(sequence); }
|
|
31
|
-
}
|
|
32
|
-
close(): void {
|
|
33
|
-
if (this.closed) return;
|
|
34
|
-
// done/error are durable terminal records. Clear only our own transient record.
|
|
35
|
-
if (this.supported && this.last.state !== "done" && this.last.state !== "error") this.write(encodeProgramStatus({ state: "clear" }, this.id));
|
|
36
|
-
this.closed = true;
|
|
37
|
-
}
|
|
38
|
-
}
|
package/src/runtime/progress.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/** Display updates are transient; only the completed operation may become a durable result. */
|
|
2
|
-
export async function* withProgress<T, E>(start: (emit: (event: E) => void) => Promise<T>): AsyncGenerator<E, T> {
|
|
3
|
-
const queue: E[] = [];
|
|
4
|
-
let wake: (() => void) | undefined;
|
|
5
|
-
let accepting = true;
|
|
6
|
-
const box: { result?: { ok: true; value: T } | { ok: false; error: unknown } } = {};
|
|
7
|
-
const pending = start(event => { if (accepting) queue.push(event); wake?.(); }).then(
|
|
8
|
-
value => { box.result = { ok: true, value }; wake?.(); },
|
|
9
|
-
error => { box.result = { ok: false, error }; wake?.(); },
|
|
10
|
-
);
|
|
11
|
-
try {
|
|
12
|
-
while (box.result === undefined || queue.length) {
|
|
13
|
-
if (queue.length) { yield queue.shift()!; continue; }
|
|
14
|
-
await new Promise<void>(resolve => { wake = resolve; });
|
|
15
|
-
wake = undefined;
|
|
16
|
-
}
|
|
17
|
-
} finally {
|
|
18
|
-
accepting = false;
|
|
19
|
-
queue.length = 0;
|
|
20
|
-
await pending;
|
|
21
|
-
}
|
|
22
|
-
await pending;
|
|
23
|
-
if (!box.result) throw new Error("operation settled without a result");
|
|
24
|
-
if (!box.result.ok) throw box.result.error;
|
|
25
|
-
return box.result.value;
|
|
26
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { ModelSpec } from "./model.ts";
|
|
2
|
-
|
|
3
|
-
/** Secrets are not model metadata. Enumerating/serializing a model cannot expose config values. */
|
|
4
|
-
export interface ProviderAccess {
|
|
5
|
-
apiKey?: string;
|
|
6
|
-
headers?: Record<string, string | null>;
|
|
7
|
-
env?: Record<string, string>;
|
|
8
|
-
auth?: false | "ambient";
|
|
9
|
-
authHeader?: boolean | string;
|
|
10
|
-
options?: Record<string, unknown>;
|
|
11
|
-
body?: Record<string, unknown>;
|
|
12
|
-
invalid?: string;
|
|
13
|
-
}
|
|
14
|
-
const access = new WeakMap<ModelSpec, ProviderAccess>();
|
|
15
|
-
export function setProviderAccess(model: ModelSpec, value: ProviderAccess): void { access.set(model, value); }
|
|
16
|
-
export function providerAccess(model: ModelSpec): ProviderAccess { return access.get(model) ?? {}; }
|
|
17
|
-
export function hasProviderAccess(model: ModelSpec): boolean { return access.has(model); }
|
|
18
|
-
export function copyProviderAccess(from: ModelSpec, to: ModelSpec): void {
|
|
19
|
-
const value = access.get(from);
|
|
20
|
-
if (value) access.set(to, value);
|
|
21
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The `models.json` edit `/provider` makes for a connected provider, as a pure transform.
|
|
3
|
-
*
|
|
4
|
-
* The file stays the single source of model configuration and keeps the
|
|
5
|
-
* documented `providers.<id>` shape (docs/providers.md), so a connected
|
|
6
|
-
* provider is indistinguishable from a hand-written one and `/reload`,
|
|
7
|
-
* startup and `--list-models` need no second code path. Secrets never enter
|
|
8
|
-
* it: keys go to `auth.json` (0600) or stay `$ENV` references.
|
|
9
|
-
*
|
|
10
|
-
* - Catalog provider: `allowlist` is the chosen ids, so the picker offers
|
|
11
|
-
* exactly what the user enabled; ids the live listing has but the catalog
|
|
12
|
-
* lacks are added under `models`.
|
|
13
|
-
* - Custom endpoint: `api` + `baseUrl` + `models`. Limits/capabilities are
|
|
14
|
-
* copied from a catalog model with the same id when the listing lacks
|
|
15
|
-
* them (a gateway serving `claude-sonnet-4-5` has that model's limits);
|
|
16
|
-
* price never is, because gateway billing is not the vendor's.
|
|
17
|
-
*/
|
|
18
|
-
import type { ModelSpec } from "./model.ts";
|
|
19
|
-
import type { ProviderApi } from "./provider-protocols.ts";
|
|
20
|
-
import type { DiscoveredModel } from "./model-discovery.ts";
|
|
21
|
-
|
|
22
|
-
export interface ConnectRequest {
|
|
23
|
-
id: string;
|
|
24
|
-
name: string;
|
|
25
|
-
api: ProviderApi;
|
|
26
|
-
baseUrl: string;
|
|
27
|
-
/** True when the provider ships in the catalog with its own models. */
|
|
28
|
-
catalog: boolean;
|
|
29
|
-
/** Catalog default base URL; an equal value is not written as an override. */
|
|
30
|
-
catalogBaseUrl?: string;
|
|
31
|
-
keyless: boolean;
|
|
32
|
-
/** `$VAR` / `{env:VAR}` reference kept in config instead of a stored key. */
|
|
33
|
-
keyReference?: string;
|
|
34
|
-
chosen: readonly DiscoveredModel[];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function record(value: unknown): value is Record<string, unknown> {
|
|
38
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** The bare model name a gateway may prefix: `anthropic/claude-x` → `claude-x`. */
|
|
42
|
-
function bare(id: string): string {
|
|
43
|
-
return id.slice(id.lastIndexOf("/") + 1).toLowerCase();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function catalogTwin(id: string, catalog: readonly ModelSpec[]): ModelSpec | undefined {
|
|
47
|
-
const exact = catalog.find(model => model.id === id);
|
|
48
|
-
if (exact) return exact;
|
|
49
|
-
const name = bare(id);
|
|
50
|
-
return catalog.find(model => bare(model.id) === name);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function modelEntry(model: DiscoveredModel, catalog: readonly ModelSpec[]): Record<string, unknown> {
|
|
54
|
-
const twin = catalogTwin(model.id, catalog);
|
|
55
|
-
const entry: Record<string, unknown> = {};
|
|
56
|
-
const name = model.name ?? twin?.name;
|
|
57
|
-
if (name && name !== model.id) entry["name"] = name;
|
|
58
|
-
const contextWindow = model.contextWindow ?? twin?.contextWindow;
|
|
59
|
-
const maxTokens = model.maxTokens ?? twin?.maxTokens;
|
|
60
|
-
if (contextWindow) entry["contextWindow"] = contextWindow;
|
|
61
|
-
if (maxTokens) entry["maxTokens"] = maxTokens;
|
|
62
|
-
if (twin?.reasoning) entry["reasoning"] = true;
|
|
63
|
-
if (twin?.input?.includes("image")) entry["input"] = [...twin.input];
|
|
64
|
-
return entry;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function applyConnect(json: unknown, request: ConnectRequest, catalog: readonly ModelSpec[]): Record<string, unknown> {
|
|
68
|
-
// The legacy flat array form is still a valid file; keep its rows.
|
|
69
|
-
const root: Record<string, unknown> = Array.isArray(json) ? { models: json } : record(json) ? { ...json } : {};
|
|
70
|
-
const providers = record(root["providers"]) ? { ...root["providers"] } : {};
|
|
71
|
-
const previous = record(providers[request.id]) ? providers[request.id] as Record<string, unknown> : {};
|
|
72
|
-
const known = new Set(catalog.filter(model => model.provider === request.id).map(model => model.id));
|
|
73
|
-
const entry: Record<string, unknown> = { ...previous };
|
|
74
|
-
for (const key of ["allowlist", "whitelist", "models", "disabled", "enabled"]) delete entry[key];
|
|
75
|
-
if (!request.catalog) {
|
|
76
|
-
entry["name"] = request.name;
|
|
77
|
-
entry["api"] = request.api;
|
|
78
|
-
// Unknown Chat Completions gateways: the lowest common denominator. The
|
|
79
|
-
// `developer` role, `store` and `max_completion_tokens` are OpenAI-only
|
|
80
|
-
// and are the usual 400s from DeepSeek-, vLLM- and one-api-style servers.
|
|
81
|
-
if (request.api === "openai-completions" && !record(entry["compat"])) entry["compat"] = { supportsDeveloperRole: false, supportsStore: false, maxTokensField: "max_tokens" };
|
|
82
|
-
}
|
|
83
|
-
if (!request.catalog || request.baseUrl !== request.catalogBaseUrl) entry["baseUrl"] = request.baseUrl;
|
|
84
|
-
else delete entry["baseUrl"];
|
|
85
|
-
if (request.keyless) entry["auth"] = false;
|
|
86
|
-
else if (entry["auth"] === false) delete entry["auth"];
|
|
87
|
-
if (request.keyReference) entry["apiKey"] = request.keyReference;
|
|
88
|
-
const models: Record<string, unknown> = {};
|
|
89
|
-
for (const model of request.chosen) {
|
|
90
|
-
if (request.catalog && known.has(model.id)) continue;
|
|
91
|
-
models[model.id] = modelEntry(model, catalog);
|
|
92
|
-
}
|
|
93
|
-
if (Object.keys(models).length) entry["models"] = models;
|
|
94
|
-
if (request.catalog) entry["allowlist"] = request.chosen.map(model => model.id);
|
|
95
|
-
providers[request.id] = entry;
|
|
96
|
-
root["providers"] = providers;
|
|
97
|
-
return root;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** Remove what `/provider` wrote for a provider; other providers and flat rows are untouched. */
|
|
101
|
-
export function applyDisconnect(json: unknown, id: string): Record<string, unknown> {
|
|
102
|
-
const root: Record<string, unknown> = Array.isArray(json) ? { models: json } : record(json) ? { ...json } : {};
|
|
103
|
-
if (record(root["providers"])) {
|
|
104
|
-
const providers = { ...root["providers"] };
|
|
105
|
-
delete providers[id];
|
|
106
|
-
root["providers"] = providers;
|
|
107
|
-
}
|
|
108
|
-
return root;
|
|
109
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What `/provider` offers for custom endpoints before the user types anything.
|
|
3
|
-
*
|
|
4
|
-
* A preset names a catalog provider (whose API, base URL and model metadata
|
|
5
|
-
* already ship in model-data) or a custom endpoint family. Order is the
|
|
6
|
-
* "Popular" section, modelled on OpenCode's PROVIDER_PRIORITY and magpie's
|
|
7
|
-
* vendor list; everything else in the catalog stays reachable by search.
|
|
8
|
-
* Key URLs are where a user actually gets a key, shown as a hint.
|
|
9
|
-
*/
|
|
10
|
-
import { SOURCE_PROVIDERS } from "./model-data.ts";
|
|
11
|
-
import type { ProviderApi } from "./provider-protocols.ts";
|
|
12
|
-
|
|
13
|
-
export interface ProviderPreset {
|
|
14
|
-
/** Catalog provider id, or the suggested id for a custom endpoint. */
|
|
15
|
-
id: string;
|
|
16
|
-
label: string;
|
|
17
|
-
api: ProviderApi;
|
|
18
|
-
baseUrl: string;
|
|
19
|
-
/** Present for catalog providers: their models carry metadata already. */
|
|
20
|
-
catalog: boolean;
|
|
21
|
-
/** Custom endpoints ask for id and URL; keyless ones skip the key. */
|
|
22
|
-
custom: boolean;
|
|
23
|
-
keyless?: boolean;
|
|
24
|
-
keyUrl?: string;
|
|
25
|
-
hint?: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const POPULAR: readonly { id: string; keyUrl?: string; hint?: string }[] = [
|
|
29
|
-
{ id: "anthropic", keyUrl: "https://console.anthropic.com/settings/keys" },
|
|
30
|
-
{ id: "openai", keyUrl: "https://platform.openai.com/api-keys" },
|
|
31
|
-
{ id: "google", keyUrl: "https://aistudio.google.com/apikey", hint: "Gemini API" },
|
|
32
|
-
{ id: "deepseek", keyUrl: "https://platform.deepseek.com/api_keys" },
|
|
33
|
-
{ id: "openrouter", keyUrl: "https://openrouter.ai/keys", hint: "one key, many vendors" },
|
|
34
|
-
{ id: "moonshotai-cn", keyUrl: "https://platform.moonshot.cn/console/api-keys", hint: "Kimi" },
|
|
35
|
-
{ id: "kimi-coding", keyUrl: "https://www.kimi.com/coding", hint: "Kimi Coding plan" },
|
|
36
|
-
{ id: "zhipuai", keyUrl: "https://open.bigmodel.cn/usercenter/apikeys", hint: "GLM" },
|
|
37
|
-
{ id: "zhipuai-coding-plan", keyUrl: "https://open.bigmodel.cn/usercenter/apikeys", hint: "GLM Coding plan" },
|
|
38
|
-
{ id: "siliconflow-cn", keyUrl: "https://cloud.siliconflow.cn/account/ak" },
|
|
39
|
-
{ id: "alibaba-cn", keyUrl: "https://bailian.console.aliyun.com/?apiKey=1", hint: "Qwen / DashScope" },
|
|
40
|
-
{ id: "volcengine", keyUrl: "https://console.volcengine.com/ark", hint: "Doubao / Ark" },
|
|
41
|
-
{ id: "minimax-cn", keyUrl: "https://platform.minimaxi.com/user-center/basic-information/interface-key" },
|
|
42
|
-
{ id: "xai", keyUrl: "https://console.x.ai" },
|
|
43
|
-
{ id: "groq", keyUrl: "https://console.groq.com/keys" },
|
|
44
|
-
{ id: "mistral", keyUrl: "https://console.mistral.ai/api-keys" },
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
/** Custom families: the four wire formats a generic endpoint can speak. */
|
|
48
|
-
export const CUSTOM_PRESETS: readonly ProviderPreset[] = [
|
|
49
|
-
{ id: "custom-openai", label: "OpenAI-compatible endpoint", api: "openai-completions", baseUrl: "https://", catalog: false, custom: true, hint: "Chat Completions · /v1/chat/completions" },
|
|
50
|
-
{ id: "custom-responses", label: "OpenAI Responses endpoint", api: "openai-responses", baseUrl: "https://", catalog: false, custom: true, hint: "Responses API · /v1/responses" },
|
|
51
|
-
{ id: "custom-anthropic", label: "Anthropic-compatible endpoint", api: "anthropic-messages", baseUrl: "https://", catalog: false, custom: true, hint: "Messages API · /v1/messages" },
|
|
52
|
-
{ id: "custom-gemini", label: "Gemini-compatible endpoint", api: "google-generative-ai", baseUrl: "https://generativelanguage.googleapis.com/v1beta", catalog: false, custom: true, hint: "generateContent" },
|
|
53
|
-
{ id: "ollama", label: "Ollama (local)", api: "openai-completions", baseUrl: "http://127.0.0.1:11434/v1", catalog: false, custom: true, keyless: true, hint: "no key needed" },
|
|
54
|
-
{ id: "lmstudio", label: "LM Studio (local)", api: "openai-completions", baseUrl: "http://127.0.0.1:1234/v1", catalog: false, custom: true, keyless: true, hint: "no key needed" },
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
function fromCatalog(id: string, extra: { keyUrl?: string; hint?: string } = {}): ProviderPreset | undefined {
|
|
58
|
-
const source = SOURCE_PROVIDERS[id];
|
|
59
|
-
if (!source?.api || !source.baseUrl) return undefined;
|
|
60
|
-
return { id, label: source.name, api: source.api, baseUrl: source.baseUrl, catalog: true, custom: false,
|
|
61
|
-
...(extra.keyUrl ? { keyUrl: extra.keyUrl } : {}), ...(extra.hint ? { hint: extra.hint } : {}) };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function popularPresets(): ProviderPreset[] {
|
|
65
|
-
return POPULAR.flatMap(entry => fromCatalog(entry.id, entry) ?? []);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function presetById(id: string): ProviderPreset | undefined {
|
|
69
|
-
return CUSTOM_PRESETS.find(preset => preset.id === id) ?? fromCatalog(id, POPULAR.find(entry => entry.id === id));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Provider ids are config keys and auth.json keys: OpenCode's rule. */
|
|
73
|
-
export function validProviderId(id: string): boolean {
|
|
74
|
-
return /^[a-z0-9][a-z0-9_-]{0,63}$/.test(id);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* The valid id a rejected one most likely meant ("My Gateway" → "my-gateway"),
|
|
79
|
-
* or "" when nothing Latin survives ("网关"). Only offered in the error, never
|
|
80
|
-
* applied silently: the id becomes a config and auth.json key the user will
|
|
81
|
-
* type in /model, so they should see it before it is saved.
|
|
82
|
-
*/
|
|
83
|
-
export function slugProviderId(raw: string): string {
|
|
84
|
-
if (validProviderId(raw)) return raw;
|
|
85
|
-
return raw.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^[^a-z0-9]+/, "").slice(0, 64).replace(/-+$/, "");
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** A readable default id from a URL host: api.example.com → example. */
|
|
89
|
-
export function suggestProviderId(baseUrl: string, taken: ReadonlySet<string>): string {
|
|
90
|
-
let host = "custom";
|
|
91
|
-
try { host = new URL(baseUrl).hostname; } catch { /* keep default */ }
|
|
92
|
-
const parts = host.split(".").filter(part => !["api", "www", "openai", "gateway", "com", "cn", "net", "io", "ai", "org", "dev", "co"].includes(part));
|
|
93
|
-
let base = (parts.at(-1) ?? "custom").toLowerCase().replace(/[^a-z0-9_-]/g, "-").replace(/^-+/, "") || "custom";
|
|
94
|
-
if (/^\d/.test(base) || base === "127" || host === "localhost") base = "local";
|
|
95
|
-
let id = base, n = 2;
|
|
96
|
-
while (taken.has(id)) id = `${base}-${n++}`;
|
|
97
|
-
return id;
|
|
98
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/** Protocol vocabulary is local; SDK types and IO never enter core (D13). */
|
|
2
|
-
export const PROVIDER_APIS = [
|
|
3
|
-
"anthropic-messages", "openai-completions", "openai-responses", "google-generative-ai",
|
|
4
|
-
"google-vertex", "bedrock-converse-stream", "azure-openai-responses", "openai-codex-responses",
|
|
5
|
-
"mistral-conversations", "pi-messages",
|
|
6
|
-
] as const;
|
|
7
|
-
export type ProviderApi = typeof PROVIDER_APIS[number];
|
|
8
|
-
export function isProviderApi(value: unknown): value is ProviderApi {
|
|
9
|
-
return typeof value === "string" && (PROVIDER_APIS as readonly string[]).includes(value);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/** SDK dispatch from OpenCode's model-level `provider.npm` before provider defaults. */
|
|
13
|
-
export const SDK_APIS: Readonly<Record<string, ProviderApi>> = {
|
|
14
|
-
"@ai-sdk/anthropic": "anthropic-messages",
|
|
15
|
-
"@ai-sdk/openai": "openai-responses",
|
|
16
|
-
"@ai-sdk/openai-compatible": "openai-completions",
|
|
17
|
-
"@openrouter/ai-sdk-provider": "openai-completions",
|
|
18
|
-
"@ai-sdk/groq": "openai-completions",
|
|
19
|
-
"@ai-sdk/cerebras": "openai-completions",
|
|
20
|
-
"@ai-sdk/deepinfra": "openai-completions",
|
|
21
|
-
"@ai-sdk/togetherai": "openai-completions",
|
|
22
|
-
"@ai-sdk/xai": "openai-completions",
|
|
23
|
-
"@ai-sdk/mistral": "mistral-conversations",
|
|
24
|
-
"@ai-sdk/google": "google-generative-ai",
|
|
25
|
-
"@ai-sdk/google-vertex": "google-vertex",
|
|
26
|
-
"@ai-sdk/amazon-bedrock": "bedrock-converse-stream",
|
|
27
|
-
"@ai-sdk/azure": "azure-openai-responses",
|
|
28
|
-
"@ai-sdk/gateway": "anthropic-messages",
|
|
29
|
-
};
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { providerEnvironment, resolveKeyValue, type ResolveEffects } from "./auth.ts";
|
|
2
|
-
import { providerAccess } from "./provider-access.ts";
|
|
3
|
-
import type { ModelSpec } from "./model.ts";
|
|
4
|
-
import { GROK_PROVIDER, GROK_BASE_URL, GROK_PROTOCOL_VERSION } from "./oauth.ts";
|
|
5
|
-
import { XENO_VERSION } from "./version.ts";
|
|
6
|
-
|
|
7
|
-
const SDK_IDENTITY_HEADERS = ["x-app", "editor-version", "editor-plugin-version", "copilot-integration-id", "http-referer", "x-title"];
|
|
8
|
-
|
|
9
|
-
/** D18/D16: a protocol SDK may not silently identify xeno as a different product. */
|
|
10
|
-
function clientIdentity(headers: Headers): void {
|
|
11
|
-
headers.set("User-Agent", `xeno/${XENO_VERSION}`);
|
|
12
|
-
for (const name of SDK_IDENTITY_HEADERS) headers.delete(name);
|
|
13
|
-
if (headers.has("originator")) headers.set("originator", "xeno");
|
|
14
|
-
const beta = headers.get("anthropic-beta");
|
|
15
|
-
if (beta) headers.set("anthropic-beta", beta.split(",").filter(value => !value.trim().startsWith("claude-code-")).join(","));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function requestEffects(): ResolveEffects {
|
|
19
|
-
return { env: name => process.env[name], run: command => {
|
|
20
|
-
const result = Bun.spawnSync(["bash", "-lc", command]);
|
|
21
|
-
if (result.exitCode !== 0) throw new Error("credential command failed");
|
|
22
|
-
return new TextDecoder().decode(result.stdout);
|
|
23
|
-
} };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function providerRequest(spec: ModelSpec, key: string, effects: ResolveEffects = requestEffects(), fetchImpl: typeof fetch = globalThis.fetch, oauth = false): {
|
|
27
|
-
baseUrl: string; env: Record<string, string>; headers: Record<string, string | null>; fetch: typeof fetch;
|
|
28
|
-
options: Record<string, unknown>; body: Record<string, unknown>; key?: string;
|
|
29
|
-
} {
|
|
30
|
-
const access = providerAccess(spec);
|
|
31
|
-
if (access.invalid) throw new Error(access.invalid);
|
|
32
|
-
const scoped = providerEnvironment(spec, effects);
|
|
33
|
-
const env = scoped.env;
|
|
34
|
-
const resolve = (value: string, field: string) => {
|
|
35
|
-
const resolved = resolveKeyValue(value, scoped.effects);
|
|
36
|
-
if (!resolved.ok) throw new Error(`${spec.provider} ${field}: could not resolve configured value`);
|
|
37
|
-
return resolved.key;
|
|
38
|
-
};
|
|
39
|
-
let baseUrl = spec.baseUrl ?? (spec.api === "anthropic-messages" ? "https://api.anthropic.com" : "");
|
|
40
|
-
if (baseUrl) baseUrl = resolve(baseUrl, "baseUrl");
|
|
41
|
-
if (baseUrl && !/^https?:\/\//.test(baseUrl)) throw new Error(`${spec.provider} baseUrl must use http or https`);
|
|
42
|
-
const headers: Record<string, string | null> = { ...spec.defaultHeaders };
|
|
43
|
-
for (const [name, value] of Object.entries(access.headers ?? {})) headers[name] = value === null ? null : resolve(value, `headers.${name}`);
|
|
44
|
-
if (spec.provider === GROK_PROVIDER) {
|
|
45
|
-
if (baseUrl.replace(/\/$/, "") !== GROK_BASE_URL) throw new Error("Grok account tokens require the official inference proxy");
|
|
46
|
-
// These select the auth protocol and backend; the User-Agent still identifies xeno (D18).
|
|
47
|
-
headers["X-XAI-Token-Auth"] = "xai-grok-cli";
|
|
48
|
-
headers["x-grok-model-override"] = spec.wireId ?? spec.id;
|
|
49
|
-
headers["x-grok-client-version"] = GROK_PROTOCOL_VERSION;
|
|
50
|
-
headers["x-grok-client-identifier"] = "xeno";
|
|
51
|
-
}
|
|
52
|
-
const anthropicOAuth = spec.api === "anthropic-messages" && spec.provider !== "github-copilot" && (oauth || key.includes("sk-ant-oat"));
|
|
53
|
-
const noAutomaticAuth = access.auth === false || access.authHeader === false || typeof access.authHeader === "string" || anthropicOAuth;
|
|
54
|
-
if (noAutomaticAuth && (spec.api === "google-generative-ai" || spec.api === "google-vertex")) {
|
|
55
|
-
throw new Error(`${spec.api} owns API-key authentication; use apiKey or an OpenAI-compatible local endpoint`);
|
|
56
|
-
}
|
|
57
|
-
if (noAutomaticAuth && spec.api === "bedrock-converse-stream") env["AWS_BEDROCK_SKIP_AUTH"] = "1";
|
|
58
|
-
if (typeof access.authHeader === "string") headers[access.authHeader] = key;
|
|
59
|
-
if (anthropicOAuth && access.auth !== false && access.authHeader !== false) {
|
|
60
|
-
headers["authorization"] = `Bearer ${key}`;
|
|
61
|
-
headers["anthropic-beta"] = "oauth-2025-04-20";
|
|
62
|
-
}
|
|
63
|
-
// Apply the same identity to native SDKs which own their HTTP stack.
|
|
64
|
-
const identity = new Headers();
|
|
65
|
-
for (const [name, value] of Object.entries(headers)) if (value !== null) identity.set(name, value);
|
|
66
|
-
clientIdentity(identity);
|
|
67
|
-
for (const name of Object.keys(headers)) if (!identity.has(name)) headers[name] = null;
|
|
68
|
-
identity.forEach((value, name) => { headers[name] = value; });
|
|
69
|
-
delete headers["user-agent"];
|
|
70
|
-
headers["User-Agent"] = `xeno/${XENO_VERSION}`;
|
|
71
|
-
// SDKs still require a key to construct local clients. The placeholder never leaves this boundary.
|
|
72
|
-
const privateKey = noAutomaticAuth ? "xeno-keyless-local" : key || undefined;
|
|
73
|
-
const transport = (async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
74
|
-
const request = new Request(input, init);
|
|
75
|
-
const grokAccount = spec.provider === GROK_PROVIDER;
|
|
76
|
-
// Check the SDK's final target too, and never forward an account token through a redirect.
|
|
77
|
-
if (grokAccount && new URL(request.url).origin !== new URL(GROK_BASE_URL).origin) {
|
|
78
|
-
throw new Error("Grok account tokens require the official inference proxy");
|
|
79
|
-
}
|
|
80
|
-
const nextHeaders = new Headers(request.headers);
|
|
81
|
-
if (noAutomaticAuth) for (const name of ["authorization", "x-api-key", "api-key", "x-goog-api-key"]) nextHeaders.delete(name);
|
|
82
|
-
for (const [name, value] of Object.entries(headers)) { if (value === null) nextHeaders.delete(name); else nextHeaders.set(name, value); }
|
|
83
|
-
clientIdentity(nextHeaders);
|
|
84
|
-
return fetchImpl(new Request(request, { headers: nextHeaders, ...(grokAccount ? { redirect: "error" } : {}) }));
|
|
85
|
-
}) as typeof fetch;
|
|
86
|
-
return { baseUrl, env, headers, fetch: transport, options: access.options ?? {}, body: access.body ?? {}, ...(privateKey ? { key: privateKey } : {}) };
|
|
87
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/** D6: native request controls may change; frozen system and tool declarations may not. */
|
|
2
|
-
import { assertNever } from "../core/exhaustive.ts";
|
|
3
|
-
import type { Api } from "./model.ts";
|
|
4
|
-
|
|
5
|
-
export interface ProviderSendOptions { toolUse: "disabled" }
|
|
6
|
-
|
|
7
|
-
export function supportsToolDisabling(api: Api): boolean {
|
|
8
|
-
// Bedrock's SDK implements none by deleting toolConfig. It cannot preserve D6.
|
|
9
|
-
switch (api) {
|
|
10
|
-
case "anthropic-messages": case "openai-completions": case "openai-responses": case "azure-openai-responses": case "openai-codex-responses":
|
|
11
|
-
case "google-generative-ai": case "google-vertex": case "mistral-conversations": case "pi-messages": return true;
|
|
12
|
-
case "bedrock-converse-stream": return false;
|
|
13
|
-
default: return assertNever(api, "tool disabling capability");
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
const object = (value: unknown): Record<string, unknown> => value !== null && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : {};
|
|
17
|
-
|
|
18
|
-
/** Called after provider body overrides, at the last native payload boundary. */
|
|
19
|
-
export function disablePayloadTools(api: Api, payload: Record<string, unknown>): Record<string, unknown> {
|
|
20
|
-
switch (api) {
|
|
21
|
-
case "anthropic-messages": return { ...payload, tool_choice: { type: "none" } };
|
|
22
|
-
case "openai-completions": case "openai-responses": case "azure-openai-responses": case "openai-codex-responses":
|
|
23
|
-
return { ...payload, tool_choice: "none" };
|
|
24
|
-
case "google-generative-ai": case "google-vertex": {
|
|
25
|
-
const config = object(payload["config"]), toolConfig = object(config["toolConfig"]);
|
|
26
|
-
return { ...payload, config: { ...config, toolConfig: { ...toolConfig, functionCallingConfig: { mode: "NONE" } } } };
|
|
27
|
-
}
|
|
28
|
-
case "mistral-conversations": return { ...payload, toolChoice: "none" };
|
|
29
|
-
case "pi-messages": return { ...payload, options: { ...object(payload["options"]), toolChoice: "none" } };
|
|
30
|
-
case "bedrock-converse-stream": throw new Error("Bedrock cannot disable tools while preserving frozen definitions");
|
|
31
|
-
default: return assertNever(api, "tool disabling protocol");
|
|
32
|
-
}
|
|
33
|
-
}
|