@yanlinglabs/winter-provider-runtime 0.0.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/LICENSE +21 -0
- package/NOTICE +41 -0
- package/README.md +109 -0
- package/dist/adapters/anthropic/console-oauth.d.ts +101 -0
- package/dist/adapters/anthropic/index.d.ts +4 -0
- package/dist/adapters/anthropic/messages.d.ts +76 -0
- package/dist/adapters/bedrock/converse.d.ts +143 -0
- package/dist/adapters/bedrock/crc32.d.ts +9 -0
- package/dist/adapters/bedrock/credentials.d.ts +32 -0
- package/dist/adapters/bedrock/eventstream.d.ts +65 -0
- package/dist/adapters/bedrock/index.d.ts +8 -0
- package/dist/adapters/bedrock/sigv4.d.ts +119 -0
- package/dist/adapters/bedrock/testing.d.ts +46 -0
- package/dist/adapters/content-blocks.d.ts +7 -0
- package/dist/adapters/google/adc.d.ts +35 -0
- package/dist/adapters/google/generate-content.d.ts +136 -0
- package/dist/adapters/google/index.d.ts +8 -0
- package/dist/adapters/google/jwt-rs256.d.ts +36 -0
- package/dist/adapters/google/vertex.d.ts +15 -0
- package/dist/adapters/index.d.ts +34 -0
- package/dist/adapters/oauth/device-code.d.ts +32 -0
- package/dist/adapters/oauth/refresh.d.ts +40 -0
- package/dist/adapters/openai/azure.d.ts +38 -0
- package/dist/adapters/openai/chat-completions.d.ts +86 -0
- package/dist/adapters/openai/codex-config.d.ts +42 -0
- package/dist/adapters/openai/codex-oauth.d.ts +47 -0
- package/dist/adapters/openai/index.d.ts +20 -0
- package/dist/adapters/openai/local.d.ts +16 -0
- package/dist/adapters/openai/pkce.d.ts +111 -0
- package/dist/adapters/openai/quota.d.ts +99 -0
- package/dist/adapters/openai/responses.d.ts +142 -0
- package/dist/adapters/openai/shared.d.ts +359 -0
- package/dist/adapters/openai/testing.d.ts +59 -0
- package/dist/adapters/openai/xai-derived-shapes.d.ts +67 -0
- package/dist/adapters/openai/xai-oauth.d.ts +102 -0
- package/dist/adapters/openai/xai-oauth.testing.d.ts +62 -0
- package/dist/adapters/privileged-headers.d.ts +51 -0
- package/dist/adapters/refusals.d.ts +10 -0
- package/dist/address-classifier.d.ts +17 -0
- package/dist/bun-required.d.ts +54 -0
- package/dist/continuity/decoration.d.ts +89 -0
- package/dist/continuity/domains.d.ts +92 -0
- package/dist/continuity/fixtures.d.ts +44 -0
- package/dist/continuity/handoff.d.ts +94 -0
- package/dist/continuity/index.d.ts +10 -0
- package/dist/continuity/renderer.d.ts +111 -0
- package/dist/continuity/warnings.d.ts +46 -0
- package/dist/credentials/env.d.ts +6 -0
- package/dist/credentials/file.d.ts +21 -0
- package/dist/credentials/memory.d.ts +8 -0
- package/dist/credentials/types.d.ts +38 -0
- package/dist/discovery.d.ts +15 -0
- package/dist/endpoint-policy.d.ts +127 -0
- package/dist/errors.d.ts +68 -0
- package/dist/http.d.ts +29 -0
- package/dist/identity.d.ts +62 -0
- package/dist/index-5z94gxhk.js +43790 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +3194 -0
- package/dist/registry.d.ts +136 -0
- package/dist/retry.d.ts +38 -0
- package/dist/sse.d.ts +12 -0
- package/dist/testing.d.ts +19 -0
- package/dist/testing.js +432 -0
- package/dist/types.d.ts +376 -0
- package/package.json +49 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CredentialStore } from "../types.js";
|
|
2
|
+
export interface FileCredentialStoreOptions {
|
|
3
|
+
env: Record<string, string | undefined>;
|
|
4
|
+
/** The home directory the default `~/.aws/credentials` location resolves under. Injected so a test never reads the real one. */
|
|
5
|
+
home: string;
|
|
6
|
+
/** Reads a file as UTF-8, or rejects. Injectable for tests that want to simulate an IO failure without creating one. */
|
|
7
|
+
readFile?: (path: string) => Promise<string>;
|
|
8
|
+
/**
|
|
9
|
+
* Returns a file's size in bytes, or rejects. Defaults to `node:fs/promises` `stat`.
|
|
10
|
+
*
|
|
11
|
+
* Its job is to make the size cap bound what is PULLED INTO MEMORY rather than only what is kept:
|
|
12
|
+
* checking the length after reading means a multi-gigabyte file addressed by a `{ kind: "file" }`
|
|
13
|
+
* ref is fully buffered first and rejected second. A custom `readFile` with no matching `stat`
|
|
14
|
+
* skips the pre-check — the post-read cap still applies — because a test double's "file" has no
|
|
15
|
+
* size to ask about.
|
|
16
|
+
*/
|
|
17
|
+
stat?: (path: string) => Promise<{
|
|
18
|
+
size: number;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
21
|
+
export declare function createFileCredentialStore(opts: FileCredentialStoreOptions): CredentialStore;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CredentialMaterial, CredentialRef, CredentialStore } from "../types.js";
|
|
2
|
+
export interface MemoryCredentialStore extends CredentialStore {
|
|
3
|
+
/** Test/diagnostic seam: how many records are held. Never exposes material. */
|
|
4
|
+
size(): number;
|
|
5
|
+
}
|
|
6
|
+
export declare function createMemoryCredentialStore(seed?: Iterable<readonly [Extract<CredentialRef, {
|
|
7
|
+
kind: "keychain";
|
|
8
|
+
}>, CredentialMaterial]>): MemoryCredentialStore;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { CredentialMaterial, CredentialRef, CredentialStore } from "../types.js";
|
|
2
|
+
export type CredentialResolutionCode = "unsupported" | "malformed" | "io";
|
|
3
|
+
/**
|
|
4
|
+
* A typed credential failure. **Its message never contains credential material** — construct it from
|
|
5
|
+
* a locator (`redactRef`) and a reason, never from a file's contents or a parsed value. The stores
|
|
6
|
+
* in this directory are tested for exactly that (`credentials.test.ts` asserts a malformed-file
|
|
7
|
+
* error's message does not contain the file's secret).
|
|
8
|
+
*/
|
|
9
|
+
export declare class CredentialResolutionError extends Error {
|
|
10
|
+
readonly code: CredentialResolutionCode;
|
|
11
|
+
constructor(code: CredentialResolutionCode, message: string);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Renders material for a log line or an error message: the KIND, and `***` where the material was.
|
|
15
|
+
* The one sanctioned way to put a `CredentialMaterial` into a string anywhere in Winter.
|
|
16
|
+
*/
|
|
17
|
+
export declare function redactMaterial(material: CredentialMaterial): string;
|
|
18
|
+
/**
|
|
19
|
+
* Renders a reference for a log line or an error message. A ref is a LOCATOR, so its addressing
|
|
20
|
+
* fields (variable name, keychain account/service, file path) are kept — they are what makes a
|
|
21
|
+
* "credential not found" message actionable. `inline` is the one arm that carries material, and its
|
|
22
|
+
* value is replaced.
|
|
23
|
+
*/
|
|
24
|
+
export declare function redactRef(ref: CredentialRef): string;
|
|
25
|
+
/** Every store answers `none` identically: null, meaning "send no credential". Shared so no store can drift on it. */
|
|
26
|
+
export declare function isNoCredential(ref: CredentialRef): boolean;
|
|
27
|
+
export declare function unsupported(storeName: string, ref: CredentialRef): CredentialResolutionError;
|
|
28
|
+
/** A store that cannot write: `set`/`delete` are Keychain-only, and only a Keychain-backed store implements them. */
|
|
29
|
+
export declare function readOnlyWriteRefusal(storeName: string): CredentialResolutionError;
|
|
30
|
+
/**
|
|
31
|
+
* Chains stores: the first one that HANDLES the ref kind answers, whether it found material or not.
|
|
32
|
+
*
|
|
33
|
+
* The subtlety worth stating (and tested): a handled-but-empty `null` STOPS the chain. Falling
|
|
34
|
+
* through on null would mean a configured-but-empty env var silently resolved out of some later
|
|
35
|
+
* store — a credential arriving from a source the host never named, which is exactly what R6-10's
|
|
36
|
+
* "ambient keys are NEVER scanned implicitly" forbids.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createCompositeCredentialStore(stores: readonly CredentialStore[]): CredentialStore;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DiscoveryContext, ModelCatalogResult, ProviderAdapter } from "./types.js";
|
|
2
|
+
export interface DiscoveryCache {
|
|
3
|
+
get(key: string): ModelCatalogResult | undefined;
|
|
4
|
+
set(key: string, value: ModelCatalogResult): void;
|
|
5
|
+
}
|
|
6
|
+
/** A plain in-memory cache. Process-lifetime, no expiry — the caller decides when a cache is stale by choosing whether to pass one. */
|
|
7
|
+
export declare function createDiscoveryCache(): DiscoveryCache;
|
|
8
|
+
/**
|
|
9
|
+
* Runs `adapter.listModels` under the context's own bounds, validates and dedupes what comes back,
|
|
10
|
+
* and falls back to a cached answer when the provider fails.
|
|
11
|
+
*
|
|
12
|
+
* A failure with NO cache entry PROPAGATES rather than returning an empty catalog: `{ models: [] }`
|
|
13
|
+
* reads as "this provider has no models", which a picker would render as fact.
|
|
14
|
+
*/
|
|
15
|
+
export declare function discoverModels(adapter: ProviderAdapter, ctx: DiscoveryContext, cache?: DiscoveryCache): Promise<ModelCatalogResult>;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
export type EndpointEvaluation = {
|
|
2
|
+
ok: true;
|
|
3
|
+
origin: string;
|
|
4
|
+
local: boolean;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
reason: string;
|
|
8
|
+
};
|
|
9
|
+
export interface EndpointEvaluationOptions {
|
|
10
|
+
/** True for a descriptor's own immutable endpoint; false for a user-supplied `baseUrl`. */
|
|
11
|
+
generated: boolean;
|
|
12
|
+
/** The host's explicit declaration that this endpoint is a local installation. Only meaningful for a LITERAL local address. */
|
|
13
|
+
local?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* P7a (WS-13b §10, the M-1 partial): HOW a `ConnectionProfile.baseUrl` is evaluated.
|
|
17
|
+
*
|
|
18
|
+
* THE PROBLEM THIS CLOSES. Two populations arrive in the same field as byte-identical strings:
|
|
19
|
+
* the catalog's own reviewed endpoint, COPIED into the profile by the runtime because a
|
|
20
|
+
* multi-provider adapter has no single vendor default to fall back on; and a host- or user-entered
|
|
21
|
+
* URL. Unable to tell them apart, every `resolveEndpoint` in this package read a present `baseUrl`
|
|
22
|
+
* as `generated: false` — so 156 of the catalog's rows silently left the privileged-header path in
|
|
23
|
+
* production, while adapter fixtures (which pass a generated base URL directly, never through a
|
|
24
|
+
* profile) went on passing. `endpointOrigin` is the profile's own answer, and this function is the
|
|
25
|
+
* one place it is read.
|
|
26
|
+
*
|
|
27
|
+
* ABSENT IS `"user"`, and that is the whole safety argument: a profile with no marker is one nobody
|
|
28
|
+
* has vouched for, and the conservative reading of "unknown provenance" is the one that attaches no
|
|
29
|
+
* organisation, project or account header. A producer that forgets the marker under-privileges a
|
|
30
|
+
* request; a default of `"reviewed"` would put the operator's account topology on an unreviewed
|
|
31
|
+
* host. Only the runtime's own copy-from-the-catalog path may stamp `"reviewed"` — a HOST writing
|
|
32
|
+
* it is asserting a provenance it does not have, which is why the runtime stamps `"user"`
|
|
33
|
+
* unconditionally over whatever a profile arrived with (`connectionFrom`, session-provider.ts).
|
|
34
|
+
*/
|
|
35
|
+
export declare function connectionEndpointOptions(connection: {
|
|
36
|
+
local?: boolean;
|
|
37
|
+
endpointOrigin?: "reviewed" | "user";
|
|
38
|
+
}): EndpointEvaluationOptions;
|
|
39
|
+
/**
|
|
40
|
+
* Headers that carry (or can carry) a credential and must never survive an origin change, and must
|
|
41
|
+
* never be attached to a user endpoint that inherited them from a generated one.
|
|
42
|
+
*
|
|
43
|
+
* Lowercase; `Headers` matching is case-insensitive but a raw record's is not, so callers compare
|
|
44
|
+
* against these exact strings.
|
|
45
|
+
*/
|
|
46
|
+
export declare const CREDENTIAL_HEADER_NAMES: readonly string[];
|
|
47
|
+
/** Returns a COPY with every credential-bearing header removed. Never mutates its argument — a caller that reuses the original for a same-origin hop must still have it intact. */
|
|
48
|
+
export declare function stripCredentialHeaders(headers: Headers): Headers;
|
|
49
|
+
/**
|
|
50
|
+
* RULING R6-L — the enforcement point for R6-11's "privileged headers only for generated endpoints".
|
|
51
|
+
*
|
|
52
|
+
* Identity when the policy's endpoint is GENERATED (a reviewed, immutable descriptor endpoint);
|
|
53
|
+
* `{}` otherwise. Adapters build their privileged header set and route it through here, so the rule
|
|
54
|
+
* is a call site rather than prose — before this existed, `EndpointPolicy.generated` was plumbed and
|
|
55
|
+
* read by nothing at all.
|
|
56
|
+
*
|
|
57
|
+
* WHICH headers belong here is documented on `EndpointPolicy` below and is the adapter's judgement,
|
|
58
|
+
* not this function's: it cannot see a header's meaning, only the endpoint's provenance. The rule of
|
|
59
|
+
* thumb is "would this value still be true, and still be the operator's business to disclose, at a
|
|
60
|
+
* URL the reviewed catalog never named?" — an organisation or project identifier fails that test; a
|
|
61
|
+
* `content-type` passes it.
|
|
62
|
+
*
|
|
63
|
+
* Auth is deliberately NOT governed here. It has its own, stricter rule (`stripCredentialHeaders` on
|
|
64
|
+
* an origin change), and a user endpoint legitimately needs a credential to be reachable at all —
|
|
65
|
+
* routing auth through this helper would break every custom endpoint rather than protect anything.
|
|
66
|
+
*/
|
|
67
|
+
export declare function applyPrivilegedHeaders(policy: EndpointPolicy, headers: Record<string, string>): Record<string, string>;
|
|
68
|
+
/**
|
|
69
|
+
* Evaluates a STORED endpoint — a descriptor's `defaultEndpoints` entry or a
|
|
70
|
+
* `ConnectionProfile.baseUrl`.
|
|
71
|
+
*
|
|
72
|
+
* Everything `evaluateUrlShape` checks, PLUS a refusal of any query string or fragment. That extra
|
|
73
|
+
* pair is specific to stored endpoints: a persisted `?key=…` reaches every log line, error message
|
|
74
|
+
* and telemetry record verbatim, and a fragment is meaningless to a request. Live request URLs and
|
|
75
|
+
* redirect targets go through `EndpointPolicy.evaluateRedirect` instead, which deliberately does
|
|
76
|
+
* NOT apply it — see `evaluateUrlShape`'s own header.
|
|
77
|
+
*/
|
|
78
|
+
export declare function evaluateEndpoint(baseUrl: string, opts: EndpointEvaluationOptions): EndpointEvaluation;
|
|
79
|
+
/**
|
|
80
|
+
* The policy object `boundedFetch` carries: the accepted origin plus the rule a redirect target must
|
|
81
|
+
* pass before the request follows it.
|
|
82
|
+
*
|
|
83
|
+
* PRIVILEGED HEADERS (R6-11, ruling R6-L). `generated` is not decoration — it is the input to
|
|
84
|
+
* `applyPrivilegedHeaders` below, which is how "privileged headers only for generated endpoints"
|
|
85
|
+
* stops being prose. The split, stated once so adapters classify consistently:
|
|
86
|
+
*
|
|
87
|
+
* PRIVILEGED — headers a GENERATED descriptor implies and a user endpoint must never inherit:
|
|
88
|
+
* organisation / project / account identifiers (`OpenAI-Organization`, `OpenAI-Project`,
|
|
89
|
+
* `x-goog-user-project`, an AWS account or role identifier), the codex adapter's `originator`,
|
|
90
|
+
* and any header whose value only means something at the reviewed endpoint it was minted for.
|
|
91
|
+
* Sending these to a user-supplied base URL discloses the operator's account topology to a host
|
|
92
|
+
* the reviewed catalog never named.
|
|
93
|
+
*
|
|
94
|
+
* PROTOCOL — headers EVERY endpoint needs to be spoken to at all, and which carry no
|
|
95
|
+
* cross-endpoint meaning: `content-type`, `accept`, `anthropic-version`, `anthropic-beta`,
|
|
96
|
+
* `x-goog-api-key`, `authorization` / `x-api-key` / `api-key`. These are NOT routed through
|
|
97
|
+
* `applyPrivilegedHeaders`; auth in particular is governed by the separate and stricter
|
|
98
|
+
* origin-change rule (`stripCredentialHeaders`), not by this one.
|
|
99
|
+
*/
|
|
100
|
+
export interface EndpointPolicy {
|
|
101
|
+
readonly origin: string;
|
|
102
|
+
readonly local: boolean;
|
|
103
|
+
readonly generated: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Revalidates a redirect target against this policy.
|
|
106
|
+
*
|
|
107
|
+
* `sameOrigin: false` is an INSTRUCTION, not a note: the caller MUST strip credential headers
|
|
108
|
+
* before following it (R6-11 — "no credential forwarding across an origin change"). A redirect
|
|
109
|
+
* chain is the standard way a compliant client is talked into replaying its bearer token to a
|
|
110
|
+
* host the user never named.
|
|
111
|
+
*/
|
|
112
|
+
evaluateRedirect(target: string): {
|
|
113
|
+
ok: true;
|
|
114
|
+
origin: string;
|
|
115
|
+
sameOrigin: boolean;
|
|
116
|
+
} | {
|
|
117
|
+
ok: false;
|
|
118
|
+
reason: string;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export declare function createEndpointPolicy(baseUrl: string, opts: EndpointEvaluationOptions): {
|
|
122
|
+
ok: true;
|
|
123
|
+
policy: EndpointPolicy;
|
|
124
|
+
} | {
|
|
125
|
+
ok: false;
|
|
126
|
+
reason: string;
|
|
127
|
+
};
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ProviderError, SdkAssistantMessageError } from "./types.js";
|
|
2
|
+
/** A stream that produced no bytes for `providerStallTimeoutMs`. Thrown by `parseSse`; NOT retryable (bytes may already have been consumed — R6-6 forbids replaying an effectful turn). */
|
|
3
|
+
export declare class ProviderStallError extends Error {
|
|
4
|
+
constructor(message: string);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Lifts the provider's STRUCTURED error code out of a raw HTTP error body, across the three
|
|
8
|
+
* dialects Winter speaks. Never throws and never guesses: a non-JSON body (an HTML 502 page), a
|
|
9
|
+
* body with no envelope, or a non-string value all yield `undefined`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseProviderErrorCode(body: string): string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Parses a `Retry-After` header in either RFC 7231 form: delta-seconds, or an HTTP-date.
|
|
14
|
+
*
|
|
15
|
+
* Returns `undefined` — never `0` — for anything unusable, including a past date and a
|
|
16
|
+
* non-positive delta. That distinction matters downstream: `0` reads as "retry immediately", a
|
|
17
|
+
* different instruction from "the header told us nothing", which must fall through to the computed
|
|
18
|
+
* backoff.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseRetryAfterMs(value: string | null | undefined, now?: number): number | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Removes EXACT occurrences of a request's OWN credential material from a provider error body.
|
|
23
|
+
*
|
|
24
|
+
* HOISTED HERE from the Bedrock adapter (T2 carry), because the gap it closes is not Bedrock's.
|
|
25
|
+
* `scrubbedSnippet` scrubs a body whose contents `scanForSecrets` RECOGNISES, and that scanner is
|
|
26
|
+
* pattern-based: it knows `sk-`, `AKIA…`, `AIza…`, a PEM block. What it cannot know is a credential
|
|
27
|
+
* with no recognisable shape — an AWS SECRET access key is forty base64-ish characters, and no
|
|
28
|
+
* pattern could match that without matching arbitrary prose of the same length. Such a value echoed
|
|
29
|
+
* back by an endpoint survives verbatim into `ProviderError.message`, one of the most
|
|
30
|
+
* reliably-logged strings in the system, and the next family's shapeless token will do the same.
|
|
31
|
+
*
|
|
32
|
+
* Exact matching against the material THIS request actually carried is the complement: precise (no
|
|
33
|
+
* false positives, unlike a "40 base64-ish characters" heuristic) and family-agnostic, because the
|
|
34
|
+
* caller names its own secrets rather than this file guessing their shape. Belt and braces — the
|
|
35
|
+
* pattern scan still runs, and either one alone leaves the other's blind spot reachable.
|
|
36
|
+
*/
|
|
37
|
+
export declare function redactCredentialMaterial(text: string, secrets: readonly string[]): string;
|
|
38
|
+
/**
|
|
39
|
+
* @param secrets Credential material THIS request carried, redacted from the body by exact match
|
|
40
|
+
* before the snippet is taken. Optional and empty by default: a family with nothing to declare
|
|
41
|
+
* passes nothing and gets exactly the previous behaviour.
|
|
42
|
+
*/
|
|
43
|
+
export declare function normalizeHttpError(status: number, headers: Headers, body: string, secrets?: readonly string[]): ProviderError;
|
|
44
|
+
/** True for anything already shaped as a normalized `ProviderError`. */
|
|
45
|
+
export declare function isProviderError(value: unknown): value is ProviderError;
|
|
46
|
+
/**
|
|
47
|
+
* Normalizes anything thrown by a transport into a `ProviderError`.
|
|
48
|
+
*
|
|
49
|
+
* The two NOT-retryable transport cases are the load-bearing ones: an abort is a deliberate
|
|
50
|
+
* cancellation (retrying it would resurrect a turn the caller stopped), and a stall means bytes
|
|
51
|
+
* already flowed — R6-6 forbids replaying an effectful turn once a response has begun.
|
|
52
|
+
*/
|
|
53
|
+
export declare function normalizeThrown(err: unknown): ProviderError;
|
|
54
|
+
/**
|
|
55
|
+
* Maps a normalized Winter error onto the pin's CLOSED 11-member `SDKAssistantMessageError`
|
|
56
|
+
* (`sdk.d.ts:3159`) — the value `api_retry.error` and `SDKAssistantMessage.error` carry.
|
|
57
|
+
*
|
|
58
|
+
* Two members have NO WINTER PRODUCER and that is recorded rather than faked:
|
|
59
|
+
* `oauth_org_not_allowed` and `account_on_hold` describe first-party subscription states that a
|
|
60
|
+
* provider-API session cannot be in. Nothing here ever returns them; if a codex-oauth quota state
|
|
61
|
+
* ever needs one, it comes from that adapter's own quota manager, not from an HTTP status.
|
|
62
|
+
*
|
|
63
|
+
* Transport failures (`network`/`timeout`/`stall`/`aborted`/`capability`) collapse to `unknown`.
|
|
64
|
+
* The pinned union has no transport member — the pin represents that case with
|
|
65
|
+
* `api_retry.error_status: null` while `error` still has to be one of the eleven — so `unknown` is
|
|
66
|
+
* the honest bucket rather than a stretched `server_error`.
|
|
67
|
+
*/
|
|
68
|
+
export declare function toSdkAssistantMessageError(err: ProviderError): SdkAssistantMessageError;
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ProviderError } from "./types.js";
|
|
2
|
+
import { type EndpointPolicy } from "./endpoint-policy.js";
|
|
3
|
+
/** Following more than this many hops is a loop, not a route. */
|
|
4
|
+
export declare const DEFAULT_MAX_REDIRECTS = 5;
|
|
5
|
+
/**
|
|
6
|
+
* A `ProviderError` that is also a real `Error` — so it carries a stack, and `normalizeThrown`
|
|
7
|
+
* passes it through untouched (it satisfies `isProviderError` structurally).
|
|
8
|
+
*/
|
|
9
|
+
export declare class ProviderRequestError extends Error implements ProviderError {
|
|
10
|
+
readonly code: ProviderError["code"];
|
|
11
|
+
readonly retryable: boolean;
|
|
12
|
+
readonly status?: number;
|
|
13
|
+
readonly providerCode?: string;
|
|
14
|
+
readonly retryAfterMs?: number;
|
|
15
|
+
constructor(fields: ProviderError);
|
|
16
|
+
}
|
|
17
|
+
/** Thrown while READING a response body that exceeded `maxBodyBytes`. Not retryable: the peer is oversized, and a retry gets the same oversized answer. */
|
|
18
|
+
export declare class ProviderBodyLimitError extends ProviderRequestError {
|
|
19
|
+
constructor(maxBodyBytes: number);
|
|
20
|
+
}
|
|
21
|
+
export interface BoundedFetchInit extends Omit<RequestInit, "redirect" | "signal"> {
|
|
22
|
+
/** Milliseconds allowed for RESPONSE HEADERS to arrive. Cleared once they do. */
|
|
23
|
+
timeoutMs: number;
|
|
24
|
+
maxBodyBytes: number;
|
|
25
|
+
policy: EndpointPolicy;
|
|
26
|
+
signal?: AbortSignal;
|
|
27
|
+
maxRedirects?: number;
|
|
28
|
+
}
|
|
29
|
+
export declare function boundedFetch(url: string, init: BoundedFetchInit): Promise<Response>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { WinterCatalog } from "@yanlinglabs/winter-provider-catalog";
|
|
2
|
+
/** The identity tokens a running product puts on the wire. */
|
|
3
|
+
export interface WinterIdentity {
|
|
4
|
+
/** The product token in `User-Agent` and in a row's `<product>` placeholder — `brand.packageName`. */
|
|
5
|
+
product: string;
|
|
6
|
+
/** The codex backend's `originator` — `brand.codexOriginator`, validated never to be first-party. */
|
|
7
|
+
codexOriginator: string;
|
|
8
|
+
/**
|
|
9
|
+
* P7a fix wave (item 7): WHERE TO REACH the running product — a row's `<contact>` placeholder,
|
|
10
|
+
* `brand.contactUrl`.
|
|
11
|
+
*
|
|
12
|
+
* A vendor identity field is a `<name>:<version>:<contact>` triple. `product` moved with the brand
|
|
13
|
+
* from the day the profile landed; the contact did not, so a rebranded product's honest-identity
|
|
14
|
+
* header still named Winter's repository — a false statement in the one field whose entire purpose
|
|
15
|
+
* is being true, and the only part of it a vendor would actually act on.
|
|
16
|
+
*/
|
|
17
|
+
contactUrl: string;
|
|
18
|
+
}
|
|
19
|
+
/** What this process is currently presenting as. Winter's own values until a branded session sets it. */
|
|
20
|
+
export declare function activeWinterIdentity(): Readonly<WinterIdentity>;
|
|
21
|
+
/**
|
|
22
|
+
* Install a session's identity; the returned disposer withdraws THIS session's frame.
|
|
23
|
+
*
|
|
24
|
+
* The value in force is the innermost frame still installed, so overlapping sessions unwind
|
|
25
|
+
* correctly in ANY order (see `IDENTITY_FRAMES`). Idempotent: a second call on the same disposer
|
|
26
|
+
* does nothing, so a host that disposes twice cannot pop somebody else's frame.
|
|
27
|
+
*/
|
|
28
|
+
export declare function setWinterIdentity(next: WinterIdentity): () => void;
|
|
29
|
+
/**
|
|
30
|
+
* `<product>/<version>` — the `User-Agent` every adapter family sends.
|
|
31
|
+
*
|
|
32
|
+
* Never an editor, a vendor CLI or a first-party product identity (WS-13 §5, D21). Where a vendor
|
|
33
|
+
* names a second identity field (aihorde's `Client-Agent`, the codex backend's `originator`), that
|
|
34
|
+
* field carries the running product's name too; it never carries somebody else's.
|
|
35
|
+
*/
|
|
36
|
+
export declare function winterUserAgent(): string;
|
|
37
|
+
/** A row id -> the Winter-authored identity headers that row's vendor names. Built once per adapter registration. */
|
|
38
|
+
export type IdentityHeaderLookup = (providerId: string) => Record<string, string> | undefined;
|
|
39
|
+
/** What a row's identity-header value is rendered against: this build's version, and this run's product and contact. */
|
|
40
|
+
export interface IdentityRenderContext {
|
|
41
|
+
version: string;
|
|
42
|
+
product: string;
|
|
43
|
+
contact: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Substitutes ALL THREE placeholders in one row's declared identity headers.
|
|
47
|
+
*
|
|
48
|
+
* The seam Lane A needs, extracted from `winterIdentityHeaders` so the brand can be threaded in one
|
|
49
|
+
* place: everything about WHICH headers a row declares stays in the lookup, and everything about
|
|
50
|
+
* WHAT the tokens resolve to arrives here as data. A caller with no brand still gets today's answer.
|
|
51
|
+
*/
|
|
52
|
+
export declare function renderIdentityHeaders(declared: Record<string, string>, ctx: IdentityRenderContext): Record<string, string>;
|
|
53
|
+
/** Indexes a catalog's `identityHeaders` by provider id. Rows without any are simply absent. */
|
|
54
|
+
export declare function identityHeaderLookup(catalog: WinterCatalog): IdentityHeaderLookup;
|
|
55
|
+
/**
|
|
56
|
+
* The identity headers for one row, with `<product>`, `<version>` and `<contact>` substituted — or `{}`.
|
|
57
|
+
*
|
|
58
|
+
* `{}` for a row with none, for an adapter constructed without a lookup (every unit fixture), and
|
|
59
|
+
* for an unknown id. An absent second identity field is the normal case: only a vendor that NAMES
|
|
60
|
+
* one gets one.
|
|
61
|
+
*/
|
|
62
|
+
export declare function winterIdentityHeaders(lookup: IdentityHeaderLookup | undefined, providerId: string): Record<string, string>;
|