@evomap/evolver-proxy 2.0.0-beta.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.
Files changed (82) hide show
  1. package/README.md +49 -0
  2. package/dist/bin/envFile.d.ts +10 -0
  3. package/dist/bin/envFile.js +68 -0
  4. package/dist/bin/evolver-llm-proxy.d.ts +2 -0
  5. package/dist/bin/evolver-llm-proxy.js +111 -0
  6. package/dist/bin/evolver-proxy.d.ts +83 -0
  7. package/dist/bin/evolver-proxy.js +511 -0
  8. package/dist/bin/proxySettings.d.ts +15 -0
  9. package/dist/bin/proxySettings.js +84 -0
  10. package/dist/bin/proxyStorePath.d.ts +1 -0
  11. package/dist/bin/proxyStorePath.js +16 -0
  12. package/dist/daemon/atpConsent.d.ts +13 -0
  13. package/dist/daemon/atpConsent.js +60 -0
  14. package/dist/daemon/ipcConfig.d.ts +1 -0
  15. package/dist/daemon/ipcConfig.js +13 -0
  16. package/dist/daemon/proxyDaemon.d.ts +191 -0
  17. package/dist/daemon/proxyDaemon.js +1015 -0
  18. package/dist/daemon/selectHub.d.ts +16 -0
  19. package/dist/daemon/selectHub.js +30 -0
  20. package/dist/index.d.ts +8 -0
  21. package/dist/index.js +8 -0
  22. package/dist/lifecycle/deployGuard.d.ts +46 -0
  23. package/dist/lifecycle/deployGuard.js +53 -0
  24. package/dist/lifecycle/legacyNodeId.d.ts +96 -0
  25. package/dist/lifecycle/legacyNodeId.js +163 -0
  26. package/dist/lifecycle/manager.d.ts +106 -0
  27. package/dist/lifecycle/manager.js +390 -0
  28. package/dist/llm/bodyCapture.d.ts +31 -0
  29. package/dist/llm/bodyCapture.js +293 -0
  30. package/dist/llm/index.d.ts +3 -0
  31. package/dist/llm/index.js +3 -0
  32. package/dist/llm/server.d.ts +35 -0
  33. package/dist/llm/server.js +359 -0
  34. package/dist/llm/traceBackfill.d.ts +53 -0
  35. package/dist/llm/traceBackfill.js +525 -0
  36. package/dist/llm/traceConfig.d.ts +7 -0
  37. package/dist/llm/traceConfig.js +44 -0
  38. package/dist/llm/traceControl.d.ts +16 -0
  39. package/dist/llm/traceControl.js +85 -0
  40. package/dist/llm/traceEnvelope.d.ts +75 -0
  41. package/dist/llm/traceEnvelope.js +286 -0
  42. package/dist/llm/traceSink.d.ts +61 -0
  43. package/dist/llm/traceSink.js +278 -0
  44. package/dist/llm/traceUploadPayload.d.ts +14 -0
  45. package/dist/llm/traceUploadPayload.js +27 -0
  46. package/dist/llm/upstream.d.ts +68 -0
  47. package/dist/llm/upstream.js +491 -0
  48. package/dist/private/adapterLoader.d.ts +46 -0
  49. package/dist/private/adapterLoader.js +62 -0
  50. package/dist/private/privateRuntimeSmokeOptions.d.ts +15 -0
  51. package/dist/private/privateRuntimeSmokeOptions.js +132 -0
  52. package/dist/router/cachePassthrough.d.ts +3 -0
  53. package/dist/router/cachePassthrough.js +13 -0
  54. package/dist/router/features.d.ts +9 -0
  55. package/dist/router/features.js +52 -0
  56. package/dist/router/index.d.ts +6 -0
  57. package/dist/router/index.js +6 -0
  58. package/dist/router/messagesRoute.d.ts +138 -0
  59. package/dist/router/messagesRoute.js +753 -0
  60. package/dist/router/modelRouter.d.ts +49 -0
  61. package/dist/router/modelRouter.js +66 -0
  62. package/dist/router/providerRoutes.d.ts +42 -0
  63. package/dist/router/providerRoutes.js +1579 -0
  64. package/dist/router/sseScan.d.ts +56 -0
  65. package/dist/router/sseScan.js +543 -0
  66. package/dist/selfUpdate/executor.d.ts +90 -0
  67. package/dist/selfUpdate/executor.js +179 -0
  68. package/dist/selfUpdate/failureCodes.d.ts +33 -0
  69. package/dist/selfUpdate/failureCodes.js +84 -0
  70. package/dist/selfUpdate/index.d.ts +5 -0
  71. package/dist/selfUpdate/index.js +5 -0
  72. package/dist/selfUpdate/lastUpdate.d.ts +43 -0
  73. package/dist/selfUpdate/lastUpdate.js +195 -0
  74. package/dist/selfUpdate/policy.d.ts +3 -0
  75. package/dist/selfUpdate/policy.js +9 -0
  76. package/dist/selfUpdate/releaseBinary.d.ts +56 -0
  77. package/dist/selfUpdate/releaseBinary.js +498 -0
  78. package/dist/selfUpdate/version.d.ts +2 -0
  79. package/dist/selfUpdate/version.js +14 -0
  80. package/dist/sync/engine.d.ts +65 -0
  81. package/dist/sync/engine.js +461 -0
  82. package/package.json +41 -0
@@ -0,0 +1,278 @@
1
+ // LLM trace capture — the reason the proxy sits on the wire at all. Every /v1/messages turn produces one trace
2
+ // record (models, tier decision, status, latency, token usage, stop_reason) appended as JSONL so the ingest
3
+ // pipeline can mine routing/economics signals the session transcripts can't see.
4
+ //
5
+ // Native request/response body capture is v1-compatible default full unless explicitly downgraded (see
6
+ // bodyCapture.ts). Body fields are redacted+capped. If encryption material is missing, the sink still writes the
7
+ // metadata row with bodies stripped so trace coverage stays auditable without falling back to plaintext bodies.
8
+ import { mkdirSync, readFileSync, statSync } from 'node:fs';
9
+ import { appendFile, chmod } from 'node:fs/promises';
10
+ import { homedir } from 'node:os';
11
+ import { join } from 'node:path';
12
+ import { isNodeSecret, parseNodeSecretVersion } from '@evomap/evolver-adapter-public';
13
+ import { captureBodiesEnabled } from './bodyCapture.js';
14
+ import { traceCollectionEnabled, traceHubPublicKey, traceProfileAnalysisEnabled } from './traceConfig.js';
15
+ import { materializeTraceForStorage } from './traceEnvelope.js';
16
+ import { backfillProxyTraceUploads, enqueueTraceEnvelope, isHubDecryptableTraceEnvelope, } from './traceBackfill.js';
17
+ export const DEFAULT_TRACE_FILE_CAP_BYTES = 64 * 1024 * 1024;
18
+ function dayStamp(ms) {
19
+ const d = new Date(ms);
20
+ const p = (n) => String(n).padStart(2, '0');
21
+ return `${d.getUTCFullYear()}${p(d.getUTCMonth() + 1)}${p(d.getUTCDate())}`;
22
+ }
23
+ function evomapHome(env = process.env) {
24
+ return String(env['EVOLVER_HOME'] ?? env['EVOMAP_HOME'] ?? join(env['HOME'] || homedir(), '.evomap'));
25
+ }
26
+ function readTrimmedFile(path) {
27
+ try {
28
+ const value = readFileSync(path, 'utf8').trim();
29
+ return value || undefined;
30
+ }
31
+ catch {
32
+ return undefined;
33
+ }
34
+ }
35
+ function traceEncryptionExplicitlyDisabled(env = process.env) {
36
+ const raw = String(env['EVOLVER_LLM_TRACE_ENCRYPTION'] ?? env['EVOMAP_PROXY_TRACE_ENCRYPTION'] ?? '').trim().toLowerCase();
37
+ return raw === '0' || raw === 'false' || raw === 'off' || raw === 'none';
38
+ }
39
+ function traceFlagEnabled(value) {
40
+ const raw = String(value ?? '').trim().toLowerCase();
41
+ return raw === '1' || raw === 'true' || raw === 'on' || raw === 'yes';
42
+ }
43
+ function metadataOnlyFallbackAllowed(env = process.env, profileAnalysisEnabled = false) {
44
+ return captureBodiesEnabled(env)
45
+ && !traceFlagEnabled(env['EVOLVER_LLM_TRACE_ENCRYPTION'])
46
+ && !traceFlagEnabled(env['EVOMAP_PROXY_TRACE_ENCRYPTION'])
47
+ && !traceFlagEnabled(env['EVOLVER_LLM_TRACE_PROFILE_ANALYSIS'])
48
+ && !traceFlagEnabled(env['EVOMAP_PROXY_TRACE_PROFILE_ANALYSIS'])
49
+ && !profileAnalysisEnabled;
50
+ }
51
+ export function resolveTraceNodeSecretMaterial(env = process.env, store, explicitNodeSecretVersion) {
52
+ const explicitVersion = explicitNodeSecretVersion !== undefined ? parseNodeSecretVersion(explicitNodeSecretVersion) : undefined;
53
+ const envSecretRaw = env['EVOMAP_NODE_SECRET'] ?? env['A2A_NODE_SECRET'];
54
+ const envSecret = envSecretRaw && isNodeSecret(envSecretRaw) ? envSecretRaw : undefined;
55
+ // EVOMAP-first to match the node_secret env precedence above, keeping (secret, version) paired.
56
+ const envVersion = parseNodeSecretVersion(env['EVOMAP_NODE_SECRET_VERSION'] ?? env['A2A_NODE_SECRET_VERSION']);
57
+ const storeSecretRaw = store?.getState?.('node_secret');
58
+ const storeSecret = storeSecretRaw && isNodeSecret(storeSecretRaw) ? storeSecretRaw : undefined;
59
+ const storeSource = store?.getState?.('node_secret_source');
60
+ const storeVersion = parseNodeSecretVersion(store?.getState?.('node_secret_version'));
61
+ if (storeSource === 'hub_rotate' && storeSecret) {
62
+ return { nodeSecret: storeSecret, nodeSecretVersion: explicitVersion ?? storeVersion };
63
+ }
64
+ if (envSecret) {
65
+ return {
66
+ nodeSecret: envSecret,
67
+ nodeSecretVersion: explicitVersion ?? envVersion ?? (envSecret === storeSecret ? storeVersion : undefined),
68
+ };
69
+ }
70
+ if (storeSecret)
71
+ return { nodeSecret: storeSecret, nodeSecretVersion: explicitVersion ?? storeVersion };
72
+ const home = evomapHome(env);
73
+ const legacySecret = readTrimmedFile(join(home, 'node_secret'));
74
+ if (!legacySecret || !isNodeSecret(legacySecret))
75
+ return { ...(explicitVersion !== undefined ? { nodeSecretVersion: explicitVersion } : {}) };
76
+ const legacyVersion = parseNodeSecretVersion(readTrimmedFile(join(home, 'node_secret_version')));
77
+ return { nodeSecret: legacySecret, nodeSecretVersion: explicitVersion ?? legacyVersion };
78
+ }
79
+ export function resolveTraceNodeSecretVersion(env = process.env, store, explicitNodeSecretVersion) {
80
+ return resolveTraceNodeSecretMaterial(env, store, explicitNodeSecretVersion).nodeSecretVersion;
81
+ }
82
+ function metadataOnlyTraceRecord(record) {
83
+ const { requestBody: _requestBody, responseBody: _responseBody, request_headers: _requestHeaders, response_headers: _responseHeaders, transport_metadata: _transportMetadata, attempts, ...rest } = record;
84
+ const strippedAttempts = attempts?.map((attempt) => {
85
+ const { requestBody: _attemptRequestBody, responseBody: _attemptResponseBody, ...attemptMeta } = attempt;
86
+ return { ...attemptMeta, body_truncated: true };
87
+ });
88
+ return {
89
+ ...rest,
90
+ body_truncated: true,
91
+ ...(strippedAttempts && strippedAttempts.length > 0 ? { attempts: strippedAttempts } : {}),
92
+ };
93
+ }
94
+ /**
95
+ * Append-only NDJSON sink, one file per UTC day (`llm-trace-YYYYMMDD.jsonl`). Fire-and-forget writes; any
96
+ * failure (bad dir, full disk, cap reached) degrades to a single warn and NEVER propagates — trace capture
97
+ * must not be able to break serving.
98
+ */
99
+ export class JsonlTraceSink {
100
+ opts;
101
+ now;
102
+ cap;
103
+ log;
104
+ warned = false;
105
+ chmodWarned = false;
106
+ envelopeWarned = false;
107
+ plaintextWarned = false;
108
+ mailboxWarned = false;
109
+ cappedDay = null;
110
+ securedFiles = new Set();
111
+ /** Appends are chained, not raced: two in-flight fs appends to one path have no ordering guarantee, and
112
+ * out-of-order trace lines would corrupt the day-file as a timeline. Still fire-and-forget to callers. */
113
+ tail = Promise.resolve();
114
+ constructor(opts) {
115
+ this.opts = opts;
116
+ this.now = opts.now ?? (() => Date.now());
117
+ this.cap = opts.fileCapBytes ?? DEFAULT_TRACE_FILE_CAP_BYTES;
118
+ this.log = opts.logger ?? console;
119
+ try {
120
+ mkdirSync(opts.dir, { recursive: true });
121
+ }
122
+ catch {
123
+ /* surfaced on first write instead */
124
+ }
125
+ this.backfillExistingTraceUploads();
126
+ }
127
+ filePath() {
128
+ return join(this.opts.dir, `llm-trace-${dayStamp(this.now())}.jsonl`);
129
+ }
130
+ /**
131
+ * Await the appends queued so far. write() is fire-and-forget (it chains the fs append onto `tail` and returns),
132
+ * so a caller that needs the trace durable on disk — a graceful shutdown, or a test asserting file contents —
133
+ * must await this rather than guess a wall-clock delay. Never rejects: write() already swallows append errors
134
+ * into `tail`.
135
+ */
136
+ flush() {
137
+ return this.tail;
138
+ }
139
+ write = (record) => {
140
+ try {
141
+ const env = this.opts.env ?? process.env;
142
+ if (!traceCollectionEnabled(env, this.opts.mailboxStore))
143
+ return;
144
+ const day = dayStamp(this.now());
145
+ if (this.cappedDay === day)
146
+ return;
147
+ const file = this.filePath();
148
+ try {
149
+ if (statSync(file).size >= this.cap) {
150
+ this.cappedDay = day;
151
+ this.log.warn?.(JSON.stringify({ event: 'llm_trace_capped', file, cap_bytes: this.cap }));
152
+ return;
153
+ }
154
+ }
155
+ catch {
156
+ /* file does not exist yet → first write of the day */
157
+ }
158
+ const profileAnalysisEnabled = traceProfileAnalysisEnabled(env, this.opts.mailboxStore);
159
+ const traceSecret = resolveTraceNodeSecretMaterial(env, this.opts.mailboxStore, this.opts.nodeSecretVersion);
160
+ const materialized = materializeTraceForStorage(record, env, {
161
+ nodeSecretVersion: traceSecret.nodeSecretVersion,
162
+ nodeSecret: traceSecret.nodeSecret,
163
+ hubPublicKey: traceHubPublicKey(env, this.opts.mailboxStore),
164
+ profileAnalysisEnabled,
165
+ producerGeneration: 'v2',
166
+ producerVersion: this.opts.producerVersion,
167
+ producerComponent: 'proxy',
168
+ });
169
+ let storedRecord;
170
+ if (materialized.ok) {
171
+ storedRecord = materialized.record;
172
+ this.enqueueOutboundTrace(materialized.record);
173
+ }
174
+ else if (traceEncryptionExplicitlyDisabled(env)) {
175
+ // Escape hatch: body capture is on but no encryption key is available AND trace
176
+ // encryption is explicitly disabled, so redacted-but-plaintext request/response bodies
177
+ // are written to the local trace file. Warn once so this never happens silently
178
+ // (see docs/trace-body-capture.md).
179
+ if (!this.plaintextWarned) {
180
+ this.plaintextWarned = true;
181
+ this.log.warn?.(JSON.stringify({ event: 'llm_trace_plaintext_bodies', reason: 'trace_encryption_disabled' }));
182
+ }
183
+ storedRecord = record;
184
+ }
185
+ else {
186
+ if (!this.envelopeWarned) {
187
+ this.envelopeWarned = true;
188
+ this.log.warn?.(JSON.stringify({ event: 'llm_trace_hub_undecryptable', reason: materialized.reason }));
189
+ }
190
+ if (!metadataOnlyFallbackAllowed(env, profileAnalysisEnabled))
191
+ return;
192
+ storedRecord = metadataOnlyTraceRecord(record);
193
+ }
194
+ const line = `${JSON.stringify(storedRecord)}\n`;
195
+ this.tail = this.tail.then(async () => {
196
+ if (!this.securedFiles.has(file)) {
197
+ try {
198
+ statSync(file);
199
+ await this.secureTraceFile(file);
200
+ }
201
+ catch {
202
+ /* new file: appendFile mode below controls initial permissions */
203
+ }
204
+ }
205
+ await appendFile(file, line, { encoding: 'utf8', mode: 0o600 });
206
+ await this.secureTraceFile(file);
207
+ }).catch((err) => {
208
+ if (!this.warned) {
209
+ this.warned = true;
210
+ this.log.warn?.(JSON.stringify({ event: 'llm_trace_write_failed', error: err instanceof Error ? err.message : String(err) }));
211
+ }
212
+ });
213
+ }
214
+ catch (err) {
215
+ if (!this.warned) {
216
+ this.warned = true;
217
+ this.log.warn?.(JSON.stringify({ event: 'llm_trace_write_failed', error: err instanceof Error ? err.message : String(err) }));
218
+ }
219
+ }
220
+ };
221
+ async secureTraceFile(file) {
222
+ if (this.securedFiles.has(file))
223
+ return true;
224
+ try {
225
+ await chmod(file, 0o600);
226
+ this.securedFiles.add(file);
227
+ return true;
228
+ }
229
+ catch (err) {
230
+ if (!this.chmodWarned) {
231
+ this.chmodWarned = true;
232
+ this.log.warn?.(JSON.stringify({ event: 'llm_trace_chmod_failed', error: err instanceof Error ? err.message : String(err) }));
233
+ }
234
+ return false;
235
+ }
236
+ }
237
+ enqueueOutboundTrace(storedRecord) {
238
+ if (!this.opts.mailboxStore || !isHubDecryptableTraceEnvelope(storedRecord))
239
+ return;
240
+ try {
241
+ enqueueTraceEnvelope(this.opts.mailboxStore, storedRecord, {
242
+ now: this.now(),
243
+ env: this.opts.env ?? process.env,
244
+ ...(this.opts.runtimeNamespace ? { runtimeNamespace: this.opts.runtimeNamespace } : {}),
245
+ ...(this.opts.sourceAgent ? { sourceAgent: this.opts.sourceAgent } : {}),
246
+ ...(this.opts.targetAgent ? { targetAgent: this.opts.targetAgent } : {}),
247
+ });
248
+ }
249
+ catch (err) {
250
+ if (!this.mailboxWarned) {
251
+ this.mailboxWarned = true;
252
+ this.log.warn?.(JSON.stringify({ event: 'llm_trace_enqueue_failed', error: err instanceof Error ? err.message : String(err) }));
253
+ }
254
+ }
255
+ }
256
+ backfillExistingTraceUploads() {
257
+ if (!this.opts.mailboxStore)
258
+ return null;
259
+ try {
260
+ return backfillProxyTraceUploads({
261
+ dir: this.opts.dir,
262
+ store: this.opts.mailboxStore,
263
+ env: this.opts.env ?? process.env,
264
+ now: this.now,
265
+ ...(this.opts.runtimeNamespace ? { runtimeNamespace: this.opts.runtimeNamespace } : {}),
266
+ ...(this.opts.sourceAgent ? { sourceAgent: this.opts.sourceAgent } : {}),
267
+ ...(this.opts.targetAgent ? { targetAgent: this.opts.targetAgent } : {}),
268
+ });
269
+ }
270
+ catch (err) {
271
+ if (!this.mailboxWarned) {
272
+ this.mailboxWarned = true;
273
+ this.log.warn?.(JSON.stringify({ event: 'llm_trace_backfill_failed', error: err instanceof Error ? err.message : String(err) }));
274
+ }
275
+ return null;
276
+ }
277
+ }
278
+ }
@@ -0,0 +1,14 @@
1
+ import type { HubDecryptableTraceEnvelope } from './traceEnvelope.js';
2
+ export declare const PROXY_TRACE_UPLOAD_SCHEMA = "prism_trace_row.v1";
3
+ export interface ProxyTraceUploadPayload {
4
+ schema: typeof PROXY_TRACE_UPLOAD_SCHEMA;
5
+ encrypted: true;
6
+ trace: HubDecryptableTraceEnvelope;
7
+ node_secret_version?: number;
8
+ secret_version?: number;
9
+ producer_generation?: string;
10
+ producer_version?: string;
11
+ producer_component?: string;
12
+ }
13
+ export declare function buildProxyTraceUploadPayload(record: HubDecryptableTraceEnvelope): ProxyTraceUploadPayload;
14
+ export declare function proxyTraceUploadPayloadSizeBytes(record: HubDecryptableTraceEnvelope): number;
@@ -0,0 +1,27 @@
1
+ export const PROXY_TRACE_UPLOAD_SCHEMA = 'prism_trace_row.v1';
2
+ function parseNodeSecretVersion(value) {
3
+ if (typeof value === 'number' && Number.isInteger(value) && value > 0)
4
+ return value;
5
+ if (typeof value !== 'string')
6
+ return undefined;
7
+ const trimmed = value.trim();
8
+ if (!/^[1-9]\d*$/.test(trimmed))
9
+ return undefined;
10
+ const parsed = Number(trimmed);
11
+ return Number.isSafeInteger(parsed) ? parsed : undefined;
12
+ }
13
+ export function buildProxyTraceUploadPayload(record) {
14
+ const secretVersion = parseNodeSecretVersion(record.secret_version);
15
+ return {
16
+ schema: PROXY_TRACE_UPLOAD_SCHEMA,
17
+ encrypted: true,
18
+ trace: record,
19
+ ...(secretVersion !== undefined ? { node_secret_version: secretVersion } : {}),
20
+ ...(record.producer_generation ? { producer_generation: record.producer_generation } : {}),
21
+ ...(record.producer_version ? { producer_version: record.producer_version } : {}),
22
+ ...(record.producer_component ? { producer_component: record.producer_component } : {}),
23
+ };
24
+ }
25
+ export function proxyTraceUploadPayloadSizeBytes(record) {
26
+ return Buffer.byteLength(JSON.stringify(buildProxyTraceUploadPayload(record)), 'utf8');
27
+ }
@@ -0,0 +1,68 @@
1
+ import type { AnthropicProxy } from '../router/messagesRoute.js';
2
+ export declare const DEFAULT_UPSTREAM_URL = "https://api.anthropic.com";
3
+ export declare const DEFAULT_OPENAI_UPSTREAM_URL = "https://api.openai.com/v1";
4
+ export declare const DEFAULT_GEMINI_UPSTREAM_URL = "https://generativelanguage.googleapis.com";
5
+ export declare const DEFAULT_OLLAMA_UPSTREAM_URL = "http://127.0.0.1:11434";
6
+ /** Time allowed for upstream RESPONSE HEADERS to arrive. Never applied to the body: a healthy SSE stream
7
+ * routinely outlives any fixed deadline, so an AbortSignal.timeout-style cap on the whole fetch would kill
8
+ * long generations mid-stream (a real v1 hazard). Body lifetime is bounded by the client connection instead. */
9
+ export declare const DEFAULT_HEADERS_TIMEOUT_MS = 120000;
10
+ export type FetchLike = (url: string, init: {
11
+ method: string;
12
+ headers: Record<string, string>;
13
+ body?: string;
14
+ signal: AbortSignal;
15
+ }) => Promise<{
16
+ status: number;
17
+ headers: {
18
+ entries(): IterableIterator<[string, string]>;
19
+ };
20
+ body: unknown | null;
21
+ text(): Promise<string>;
22
+ }>;
23
+ export interface AnthropicUpstreamOptions {
24
+ /** Injected env (testability). Default process.env, read per request so creds/URL hot-swap without restart. */
25
+ env?: NodeJS.ProcessEnv;
26
+ /** Injected fetch (testability). Default globalThis.fetch. */
27
+ fetchImpl?: FetchLike;
28
+ /** Injected Bedrock runtime (testability). Default lazy-loads @aws-sdk/client-bedrock-runtime only in bedrock mode. */
29
+ bedrockRuntime?: BedrockRuntimeFactory;
30
+ headersTimeoutMs?: number;
31
+ }
32
+ export type ProviderUpstreamOptions = AnthropicUpstreamOptions;
33
+ export interface BedrockInvokeInput {
34
+ modelId: string;
35
+ contentType: string;
36
+ accept: string;
37
+ body: string;
38
+ }
39
+ export interface BedrockRuntimeClientLike {
40
+ send(command: unknown, options?: {
41
+ abortSignal?: AbortSignal;
42
+ }): Promise<unknown>;
43
+ }
44
+ export interface BedrockRuntimeFactory {
45
+ createClient(args: {
46
+ region: string;
47
+ endpoint?: string;
48
+ }): BedrockRuntimeClientLike;
49
+ createInvokeModelCommand(input: BedrockInvokeInput): unknown;
50
+ createInvokeModelWithResponseStreamCommand(input: BedrockInvokeInput): unknown;
51
+ }
52
+ export declare function resolveOpenAIUpstreamUrl(env?: NodeJS.ProcessEnv): string;
53
+ /** Resolve the upstream base URL. OpenAI-compatible routes never inherit the Anthropic-wide override. */
54
+ export declare function resolveUpstreamUrl(env?: NodeJS.ProcessEnv, upstreamMode?: string): string;
55
+ export declare function resolveGeminiUpstreamUrl(env?: NodeJS.ProcessEnv): string;
56
+ export declare function resolveOllamaUpstreamUrl(env?: NodeJS.ProcessEnv): string;
57
+ export declare function buildForwardHeaders(inbound: Record<string, string | undefined>, env: NodeJS.ProcessEnv, upstreamMode?: string): Record<string, string>;
58
+ export declare function buildOpenAIHeaders(inbound: Record<string, string | undefined>, env: NodeJS.ProcessEnv): Record<string, string>;
59
+ export declare function buildGeminiHeaders(inbound: Record<string, string | undefined>, env: NodeJS.ProcessEnv): Record<string, string>;
60
+ export declare function buildOllamaHeaders(env: NodeJS.ProcessEnv): Record<string, string>;
61
+ export declare function buildVertexHeaders(env: NodeJS.ProcessEnv): Record<string, string>;
62
+ /** Build the production AnthropicProxy. Streaming is detected from the upstream content-type
63
+ * (text/event-stream → expose the response body stream; anything else → buffered text()). */
64
+ export declare function makeAnthropicUpstream(opts?: AnthropicUpstreamOptions): AnthropicProxy;
65
+ export declare function makeOpenAIUpstream(opts?: ProviderUpstreamOptions): AnthropicProxy;
66
+ export declare function makeGeminiUpstream(opts?: ProviderUpstreamOptions): AnthropicProxy;
67
+ export declare function makeOllamaUpstream(opts?: ProviderUpstreamOptions): AnthropicProxy;
68
+ export declare function makeVertexUpstream(opts?: ProviderUpstreamOptions): AnthropicProxy;