@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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +41 -0
  3. package/README.md +109 -0
  4. package/dist/adapters/anthropic/console-oauth.d.ts +101 -0
  5. package/dist/adapters/anthropic/index.d.ts +4 -0
  6. package/dist/adapters/anthropic/messages.d.ts +76 -0
  7. package/dist/adapters/bedrock/converse.d.ts +143 -0
  8. package/dist/adapters/bedrock/crc32.d.ts +9 -0
  9. package/dist/adapters/bedrock/credentials.d.ts +32 -0
  10. package/dist/adapters/bedrock/eventstream.d.ts +65 -0
  11. package/dist/adapters/bedrock/index.d.ts +8 -0
  12. package/dist/adapters/bedrock/sigv4.d.ts +119 -0
  13. package/dist/adapters/bedrock/testing.d.ts +46 -0
  14. package/dist/adapters/content-blocks.d.ts +7 -0
  15. package/dist/adapters/google/adc.d.ts +35 -0
  16. package/dist/adapters/google/generate-content.d.ts +136 -0
  17. package/dist/adapters/google/index.d.ts +8 -0
  18. package/dist/adapters/google/jwt-rs256.d.ts +36 -0
  19. package/dist/adapters/google/vertex.d.ts +15 -0
  20. package/dist/adapters/index.d.ts +34 -0
  21. package/dist/adapters/oauth/device-code.d.ts +32 -0
  22. package/dist/adapters/oauth/refresh.d.ts +40 -0
  23. package/dist/adapters/openai/azure.d.ts +38 -0
  24. package/dist/adapters/openai/chat-completions.d.ts +86 -0
  25. package/dist/adapters/openai/codex-config.d.ts +42 -0
  26. package/dist/adapters/openai/codex-oauth.d.ts +47 -0
  27. package/dist/adapters/openai/index.d.ts +20 -0
  28. package/dist/adapters/openai/local.d.ts +16 -0
  29. package/dist/adapters/openai/pkce.d.ts +111 -0
  30. package/dist/adapters/openai/quota.d.ts +99 -0
  31. package/dist/adapters/openai/responses.d.ts +142 -0
  32. package/dist/adapters/openai/shared.d.ts +359 -0
  33. package/dist/adapters/openai/testing.d.ts +59 -0
  34. package/dist/adapters/openai/xai-derived-shapes.d.ts +67 -0
  35. package/dist/adapters/openai/xai-oauth.d.ts +102 -0
  36. package/dist/adapters/openai/xai-oauth.testing.d.ts +62 -0
  37. package/dist/adapters/privileged-headers.d.ts +51 -0
  38. package/dist/adapters/refusals.d.ts +10 -0
  39. package/dist/address-classifier.d.ts +17 -0
  40. package/dist/bun-required.d.ts +54 -0
  41. package/dist/continuity/decoration.d.ts +89 -0
  42. package/dist/continuity/domains.d.ts +92 -0
  43. package/dist/continuity/fixtures.d.ts +44 -0
  44. package/dist/continuity/handoff.d.ts +94 -0
  45. package/dist/continuity/index.d.ts +10 -0
  46. package/dist/continuity/renderer.d.ts +111 -0
  47. package/dist/continuity/warnings.d.ts +46 -0
  48. package/dist/credentials/env.d.ts +6 -0
  49. package/dist/credentials/file.d.ts +21 -0
  50. package/dist/credentials/memory.d.ts +8 -0
  51. package/dist/credentials/types.d.ts +38 -0
  52. package/dist/discovery.d.ts +15 -0
  53. package/dist/endpoint-policy.d.ts +127 -0
  54. package/dist/errors.d.ts +68 -0
  55. package/dist/http.d.ts +29 -0
  56. package/dist/identity.d.ts +62 -0
  57. package/dist/index-5z94gxhk.js +43790 -0
  58. package/dist/index.d.ts +39 -0
  59. package/dist/index.js +3194 -0
  60. package/dist/registry.d.ts +136 -0
  61. package/dist/retry.d.ts +38 -0
  62. package/dist/sse.d.ts +12 -0
  63. package/dist/testing.d.ts +19 -0
  64. package/dist/testing.js +432 -0
  65. package/dist/types.d.ts +376 -0
  66. package/package.json +49 -0
@@ -0,0 +1,376 @@
1
+ import type { ProviderProtocol, ToolCalling, WinterModelDescriptor } from "@yanlinglabs/winter-provider-catalog";
2
+ export type { CredentialRef } from "@yanlinglabs/winter-agent-sdk";
3
+ import type { CredentialRef } from "@yanlinglabs/winter-agent-sdk";
4
+ /** The wire-mapping family an adapter belongs to. Coarser than `ProviderProtocol`: Azure and OpenRouter are both `openai`, Vertex and the Gemini API are both `google`. */
5
+ export type ProviderFamily = "openai" | "anthropic" | "google" | "bedrock" | "local-openai" | "custom";
6
+ /**
7
+ * Non-secret connection metadata for one provider (WS-13 §6). `baseUrl` is a USER endpoint and goes
8
+ * through `evaluateEndpoint`; a generated descriptor endpoint is immutable and never arrives here.
9
+ *
10
+ * `local: true` is a DECLARATION by the host, not a discovery: it is what lets `evaluateEndpoint`
11
+ * accept a loopback/RFC-1918 `http://` target. An undeclared private address is still refused.
12
+ */
13
+ export interface ConnectionProfile {
14
+ providerId: string;
15
+ baseUrl?: string;
16
+ headers?: Record<string, string>;
17
+ region?: string;
18
+ project?: string;
19
+ location?: string;
20
+ deployment?: string;
21
+ apiVersion?: string;
22
+ local?: boolean;
23
+ /**
24
+ * P7a: WHERE `baseUrl` came from — the sdk's `ProviderConnectionConfig.endpointOrigin`, carried
25
+ * across the wire and into every adapter through `createProviderContext`.
26
+ *
27
+ * `"reviewed"` the catalog's own endpoint, copied into the profile by the runtime for an adapter
28
+ * that serves several providers and so has no vendor default to fall back on.
29
+ * `"user"` a host- or user-entered endpoint. ABSENT means the same thing (see
30
+ * `connectionEndpointOptions` in endpoint-policy.ts for why unknown must read as
31
+ * user, and why only the runtime's copy path may stamp `"reviewed"`).
32
+ *
33
+ * Read in exactly one place — `connectionEndpointOptions` — so no adapter re-derives the rule.
34
+ */
35
+ endpointOrigin?: "reviewed" | "user";
36
+ }
37
+ /**
38
+ * The material a `CredentialRef` resolves to, at the last responsible moment. NEVER persisted by
39
+ * this package, never logged, never placed in an error message — `redactMaterial()` (credentials/
40
+ * types.ts) is the only sanctioned way to render one.
41
+ */
42
+ export type CredentialMaterial = {
43
+ kind: "api-key";
44
+ key: string;
45
+ } | {
46
+ kind: "bearer";
47
+ token: string;
48
+ } | {
49
+ kind: "oauth";
50
+ accessToken: string;
51
+ refreshToken?: string;
52
+ expiresAt?: number;
53
+ accountId?: string;
54
+ idToken?: string;
55
+ } | {
56
+ kind: "aws";
57
+ accessKeyId: string;
58
+ secretAccessKey: string;
59
+ sessionToken?: string;
60
+ } | {
61
+ kind: "gcp-service-account";
62
+ clientEmail: string;
63
+ privateKeyPem: string;
64
+ tokenUri: string;
65
+ } | {
66
+ kind: "gcp-access-token";
67
+ token: string;
68
+ };
69
+ /**
70
+ * Resolves credential references. `set`/`delete` are Keychain-only BY TYPE, not by convention: the
71
+ * SDK never persists an `inline` value (a host responsibility), never writes an env var, and never
72
+ * writes a credentials file. Making those unrepresentable is cheaper than documenting them.
73
+ */
74
+ export interface CredentialStore {
75
+ get(ref: CredentialRef): Promise<CredentialMaterial | null>;
76
+ set(ref: Extract<CredentialRef, {
77
+ kind: "keychain";
78
+ }>, material: CredentialMaterial): Promise<void>;
79
+ delete(ref: Extract<CredentialRef, {
80
+ kind: "keychain";
81
+ }>): Promise<void>;
82
+ }
83
+ /** The verdict of `ProviderAdapter.validateCredential`. `unsupported` means the adapter cannot check this ref KIND — not that the credential is bad. */
84
+ export type CredentialStatus = {
85
+ ok: true;
86
+ accountId?: string;
87
+ scopes?: string[];
88
+ } | {
89
+ ok: false;
90
+ code: "missing" | "invalid" | "expired" | "network" | "unsupported";
91
+ message: string;
92
+ };
93
+ /** Which provider/model produced a message — the input to R6-9's continuation-domain check on resume, fallback and handoff. */
94
+ export interface MessageOrigin {
95
+ providerId: string;
96
+ modelKey: string;
97
+ family: ProviderFamily | string;
98
+ continuationDomain?: string;
99
+ }
100
+ /**
101
+ * OPAQUE, adapter-owned provider state (OpenAI `encrypted_content`, Gemini `thoughtSignature`, xAI
102
+ * opaque items). **Never logged, never model-readable, never in an error message or frame.** Its
103
+ * only sink is the provider-state sidecar (R6-7); `items` is `unknown[]` precisely so nothing is
104
+ * tempted to inspect it.
105
+ */
106
+ export interface ProviderNativeState {
107
+ family: string;
108
+ continuationDomain: string;
109
+ items: unknown[];
110
+ }
111
+ /**
112
+ * The structural mirror of the captured wire content blocks (R6-D). Deliberately declared here
113
+ * rather than imported from a floating `@anthropic-ai/sdk` peer: the pin declares NO wire block
114
+ * shape at all (derived-shapes-p6.md item (f) — `redacted_thinking`, a `type: 'thinking'` literal
115
+ * and `signature`-as-a-block-field have ZERO occurrences in the pinned artifact), so these shapes
116
+ * come from the runtime's observed behaviour, and a dependency would buy nothing but drift.
117
+ *
118
+ * `thinking.signature` is a plain `string` that MAY be `""`: capture (F) shows the runtime
119
+ * normalising a signatureless thinking block to exactly that and REPLAYING it. Typing it optional
120
+ * would let a producer omit it and break the signature chain silently.
121
+ */
122
+ export type ContentBlockLike = {
123
+ type: "text";
124
+ text: string;
125
+ } | {
126
+ type: "tool_use";
127
+ id: string;
128
+ name: string;
129
+ input: unknown;
130
+ } | {
131
+ type: "tool_result";
132
+ tool_use_id: string;
133
+ content: string | ContentBlockLike[];
134
+ [k: string]: unknown;
135
+ } | {
136
+ type: "thinking";
137
+ thinking: string;
138
+ signature: string;
139
+ } | {
140
+ type: "redacted_thinking";
141
+ data: string;
142
+ } | {
143
+ type: "image";
144
+ source: {
145
+ type: "base64";
146
+ media_type: string;
147
+ data: string;
148
+ };
149
+ } | {
150
+ type: "tool_reference";
151
+ tool_names: string[];
152
+ };
153
+ export interface ProviderMessageLike {
154
+ role: "user" | "assistant" | "tool";
155
+ content: string | ContentBlockLike[];
156
+ uuid?: string;
157
+ origin?: MessageOrigin;
158
+ nativeState?: ProviderNativeState;
159
+ /** A Winter-authored annotation shown to the model (a handoff note, a foreign-reasoning summary) — carried plainly, never dressed as signed thinking (R6-8). */
160
+ decoration?: {
161
+ text: string;
162
+ door: "tag" | "thinking-channel";
163
+ };
164
+ }
165
+ export interface TurnRequest {
166
+ model: string;
167
+ system?: string;
168
+ messages: ProviderMessageLike[];
169
+ tools?: Array<{
170
+ name: string;
171
+ description: string;
172
+ inputSchema: Record<string, unknown>;
173
+ }>;
174
+ toolChoice?: {
175
+ type: "auto";
176
+ } | {
177
+ type: "any";
178
+ } | {
179
+ type: "tool";
180
+ name: string;
181
+ };
182
+ /**
183
+ * KEEPS `number`, unlike `Options.effort` (R6-E): a child carries numeric effort
184
+ * (`AgentDefinition.effort` is the pin's only numeric-admitting effort surface), and it reaches an
185
+ * adapter through here. `mapEffort` maps a number to the nearest verified tier of the model's own
186
+ * `reasoning.efforts` — the pin states no unit, range or mapping (a documented absence, OQ-P6-2),
187
+ * so that is gap-filling rather than divergence, and it is disclosed.
188
+ */
189
+ effort?: "low" | "medium" | "high" | "xhigh" | "max" | number;
190
+ thinking?: {
191
+ type: "disabled";
192
+ } | {
193
+ type: "enabled";
194
+ budgetTokens?: number;
195
+ } | {
196
+ type: "adaptive";
197
+ };
198
+ maxOutputTokens?: number;
199
+ signal?: AbortSignal;
200
+ /** Ask the provider for a readable reasoning SUMMARY where its descriptor's `reasoning.summaryRequest` says how. Never a request for raw reasoning. */
201
+ requestSummary?: boolean;
202
+ }
203
+ /**
204
+ * The normalized stream every adapter produces. R6-5: the runtime-side bridge folds this into one
205
+ * `ProviderTurn`, and only under `includePartialMessages` does any of it become `stream_event`s.
206
+ */
207
+ export type ProviderEvent = {
208
+ type: "message_start";
209
+ id?: string;
210
+ model?: string;
211
+ } | {
212
+ type: "text_delta";
213
+ text: string;
214
+ }
215
+ /** A provider-produced SUMMARY of reasoning. Never written into `assistant.message.content` (R6-8) — it rides the sidecar and the Winter-only `system/reasoning_summary` frame. */
216
+ | {
217
+ type: "thinking_summary_delta";
218
+ text: string;
219
+ }
220
+ /** Raw exposed reasoning, for the models whose `readableState` is `full-exposed`. Same destination rule as the summary. */
221
+ | {
222
+ type: "thinking_exposed_delta";
223
+ text: string;
224
+ }
225
+ /** A COMPLETE Anthropic-family in-dialect thinking/redacted block, carried verbatim with its real signature so it can be replayed in-dialect. */
226
+ | {
227
+ type: "native_thinking_block";
228
+ block: unknown;
229
+ } | {
230
+ type: "tool_call_start";
231
+ id: string;
232
+ name: string;
233
+ } | {
234
+ type: "tool_call_delta";
235
+ id: string;
236
+ argumentsJsonDelta: string;
237
+ } | {
238
+ type: "tool_call_end";
239
+ id: string;
240
+ }
241
+ /** Opaque continuation state, COMPLETE, captured from the completion event — never an earlier partial copy (the descriptor's `reasoning.completionEvent` names which). */
242
+ | {
243
+ type: "native_state";
244
+ items: unknown[];
245
+ } | {
246
+ type: "usage";
247
+ inputTokens: number;
248
+ outputTokens: number;
249
+ cacheReadTokens?: number;
250
+ cacheWriteTokens?: number;
251
+ }
252
+ /**
253
+ * R6-B: SUBSCRIPTION-QUOTA states ONLY, and the `kind` discriminant is what says so at the type
254
+ * level. An HTTP 429 is NOT this event — capture (G) proved the pinned runtime emits zero
255
+ * `rate_limit_event` frames for a 429 carrying a full `anthropic-ratelimit-*` header set with a
256
+ * `rejected` unified status; the pinned 429 path is `api_retry` with `error_status: 429` and
257
+ * `error: "rate_limit"`. So a 429 here is a `retry` event plus a normalized `rate_limit` error
258
+ * code, and HEADER-DERIVED limits never become events at all.
259
+ */
260
+ | {
261
+ type: "rate_limit";
262
+ kind: "subscription-quota";
263
+ info: Record<string, unknown>;
264
+ }
265
+ /**
266
+ * R6-C: mirrors the pinned `api_retry` payload minus its frame envelope (`uuid`/`session_id`,
267
+ * which the runtime stamps). `error` is the CLOSED 11-member union, not a free string — the pin
268
+ * types it that way (`sdk.d.ts:3092`) and `withRetry`'s producer already returns exactly that, so
269
+ * a bare `string` here only made a consumer's exhaustive switch impossible to write.
270
+ */
271
+ | {
272
+ type: "retry";
273
+ attempt: number;
274
+ maxRetries: number;
275
+ retryDelayMs: number;
276
+ errorStatus?: number;
277
+ error: SdkAssistantMessageError;
278
+ }
279
+ /** A LOGIN-FLOW progress channel (codex-oauth login/refresh only), never the credential-failure frame — a bad key is a `ProviderError` with `code: "auth"`. */
280
+ | {
281
+ type: "auth_status";
282
+ isAuthenticating: boolean;
283
+ output?: string[];
284
+ error?: string;
285
+ } | {
286
+ type: "done";
287
+ stopReason: "end_turn" | "tool_use" | "max_tokens" | "aborted" | "refusal";
288
+ } | {
289
+ type: "error";
290
+ error: ProviderError;
291
+ };
292
+ /**
293
+ * The normalized provider failure. `code` is Winter's own coarse taxonomy; `providerCode` is the
294
+ * provider's VERBATIM structured code, parsed off the FULL body before any truncation (the OpenAI
295
+ * envelope puts `code` after an unbounded human message, so a truncated body loses exactly the field
296
+ * a consumer wants).
297
+ *
298
+ * `status` is carried so the engine can set the pinned `result.api_error_status` (R6-F). It is
299
+ * ABSENT — not `null` — for a connection error with no HTTP response, which is the case the pinned
300
+ * `api_retry.error_status: number | null` describes and which capture (G) could not reach.
301
+ */
302
+ export interface ProviderError {
303
+ code: "auth" | "rate_limit" | "server" | "network" | "bad_request" | "timeout" | "stall" | "aborted" | "capability";
304
+ message: string;
305
+ status?: number;
306
+ providerCode?: string;
307
+ retryAfterMs?: number;
308
+ retryable: boolean;
309
+ }
310
+ /**
311
+ * The pinned provider-error taxonomy, `sdk.d.ts:3159` — the closed 11-member `SDKAssistantMessageError`
312
+ * carried on `api_retry.error`, `SDKAssistantMessage.error?` and `StopFailureHookInput.error`.
313
+ *
314
+ * These eleven buckets are all a Winter adapter has to map into for parity; anything finer is a
315
+ * Winter extension to disclose (which is exactly what `ProviderError.providerCode` is).
316
+ */
317
+ export type SdkAssistantMessageError = "authentication_failed" | "oauth_org_not_allowed" | "account_on_hold" | "billing_error" | "rate_limit" | "overloaded" | "invalid_request" | "model_not_found" | "server_error" | "unknown" | "max_output_tokens";
318
+ export interface ProviderContext {
319
+ connection: ConnectionProfile;
320
+ credentials: CredentialStore;
321
+ authRef: CredentialRef;
322
+ stallTimeoutMs: number;
323
+ /** Telemetry: provider/model identifiers and byte COUNTS only. Never content, never credential material, never opaque state (Global Constraints). */
324
+ log: (event: {
325
+ kind: string;
326
+ providerId: string;
327
+ model?: string;
328
+ bytes?: number;
329
+ }) => void;
330
+ }
331
+ export interface DiscoveryContext extends ProviderContext {
332
+ signal?: AbortSignal;
333
+ /** WS-13 §7: discovery responses MUST be size-, time- and item-bounded. These are not advisory. */
334
+ limits: {
335
+ maxBytes: number;
336
+ maxItems: number;
337
+ timeoutMs: number;
338
+ };
339
+ }
340
+ export interface ModelCatalogResult {
341
+ /** Model ids and names are UNTRUSTED display/input data (WS-13 §7) — never interpolated into a path, a command, or a log line unescaped. */
342
+ models: Array<{
343
+ id: string;
344
+ displayName?: string;
345
+ contextWindow?: number;
346
+ inputModalities?: string[];
347
+ }>;
348
+ /** True when the provider returned a page/subset rather than its whole catalog: the caller must NOT treat absence as removal. */
349
+ partial: boolean;
350
+ cached: boolean;
351
+ warnings: string[];
352
+ }
353
+ export interface ProviderAdapter {
354
+ readonly id: string;
355
+ readonly version: string;
356
+ readonly family: ProviderFamily;
357
+ readonly protocol: ProviderProtocol;
358
+ validateCredential(ref: CredentialRef, ctx: ProviderContext): Promise<CredentialStatus>;
359
+ listModels(ctx: DiscoveryContext): Promise<ModelCatalogResult>;
360
+ streamTurn(req: TurnRequest, ctx: ProviderContext): AsyncIterable<ProviderEvent>;
361
+ /** R6-15: optional. `compact_metadata.post_tokens` is set from a REAL count when an adapter offers one, and omitted otherwise — never estimated. */
362
+ countTokens?(req: TurnRequest, ctx: ProviderContext): Promise<number>;
363
+ /** WS-13 §8.2: map onto the model's VERIFIED vocabulary or reject BEFORE sending a request. A silent downgrade to the provider's default is prohibited. */
364
+ mapEffort(effort: TurnRequest["effort"], model: WinterModelDescriptor): {
365
+ ok: true;
366
+ value: unknown;
367
+ } | {
368
+ ok: false;
369
+ reason: string;
370
+ };
371
+ capabilities(model: WinterModelDescriptor): {
372
+ toolCalling: ToolCalling;
373
+ continuationDomain?: string;
374
+ readableState: "none" | "summary" | "full-exposed";
375
+ };
376
+ }
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@yanlinglabs/winter-provider-runtime",
3
+ "version": "0.0.2",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=18"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/yanlingLabs/winter-agent-sdk.git",
12
+ "directory": "packages/provider-runtime"
13
+ },
14
+ "homepage": "https://github.com/yanlingLabs/winter-agent-sdk",
15
+ "bugs": {
16
+ "url": "https://github.com/yanlingLabs/winter-agent-sdk/issues"
17
+ },
18
+ "main": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "default": "./dist/index.js"
24
+ },
25
+ "./testing": {
26
+ "types": "./dist/testing.d.ts",
27
+ "default": "./dist/testing.js"
28
+ }
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "NOTICE",
33
+ "README.md",
34
+ "LICENSE"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "restricted"
38
+ },
39
+ "winter": {
40
+ "publish": {
41
+ "npm": true
42
+ }
43
+ },
44
+ "dependencies": {
45
+ "@yanlinglabs/winter-agent-sdk": "0.0.2",
46
+ "@yanlinglabs/winter-provider-catalog": "0.0.2"
47
+ },
48
+ "scripts": {}
49
+ }