@bbclaw/core 0.1.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 (85) hide show
  1. package/dist/index.d.ts +8 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +8 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/providers/anthropic/index.d.ts +44 -0
  6. package/dist/providers/anthropic/index.d.ts.map +1 -0
  7. package/dist/providers/anthropic/index.js +75 -0
  8. package/dist/providers/anthropic/index.js.map +1 -0
  9. package/dist/providers/index.d.ts +8 -0
  10. package/dist/providers/index.d.ts.map +1 -0
  11. package/dist/providers/index.js +8 -0
  12. package/dist/providers/index.js.map +1 -0
  13. package/dist/providers/openai-compat/index.d.ts +59 -0
  14. package/dist/providers/openai-compat/index.d.ts.map +1 -0
  15. package/dist/providers/openai-compat/index.js +175 -0
  16. package/dist/providers/openai-compat/index.js.map +1 -0
  17. package/dist/providers/openai-compat/presets.d.ts +22 -0
  18. package/dist/providers/openai-compat/presets.d.ts.map +1 -0
  19. package/dist/providers/openai-compat/presets.js +73 -0
  20. package/dist/providers/openai-compat/presets.js.map +1 -0
  21. package/dist/providers/openai-compat/requestTranslate.d.ts +39 -0
  22. package/dist/providers/openai-compat/requestTranslate.d.ts.map +1 -0
  23. package/dist/providers/openai-compat/requestTranslate.js +228 -0
  24. package/dist/providers/openai-compat/requestTranslate.js.map +1 -0
  25. package/dist/providers/openai-compat/sseParser.d.ts +29 -0
  26. package/dist/providers/openai-compat/sseParser.d.ts.map +1 -0
  27. package/dist/providers/openai-compat/sseParser.js +139 -0
  28. package/dist/providers/openai-compat/sseParser.js.map +1 -0
  29. package/dist/providers/openai-compat/streamAdapter.d.ts +45 -0
  30. package/dist/providers/openai-compat/streamAdapter.d.ts.map +1 -0
  31. package/dist/providers/openai-compat/streamAdapter.js +233 -0
  32. package/dist/providers/openai-compat/streamAdapter.js.map +1 -0
  33. package/dist/providers/openai-compat/types.d.ts +126 -0
  34. package/dist/providers/openai-compat/types.d.ts.map +1 -0
  35. package/dist/providers/openai-compat/types.js +11 -0
  36. package/dist/providers/openai-compat/types.js.map +1 -0
  37. package/dist/providers/selector.d.ts +52 -0
  38. package/dist/providers/selector.d.ts.map +1 -0
  39. package/dist/providers/selector.js +101 -0
  40. package/dist/providers/selector.js.map +1 -0
  41. package/dist/providers/types.d.ts +114 -0
  42. package/dist/providers/types.d.ts.map +1 -0
  43. package/dist/providers/types.js +152 -0
  44. package/dist/providers/types.js.map +1 -0
  45. package/dist/providers/web-bridge/deepseek/spec.d.ts +22 -0
  46. package/dist/providers/web-bridge/deepseek/spec.d.ts.map +1 -0
  47. package/dist/providers/web-bridge/deepseek/spec.js +70 -0
  48. package/dist/providers/web-bridge/deepseek/spec.js.map +1 -0
  49. package/dist/providers/web-bridge/historySerializer.d.ts +49 -0
  50. package/dist/providers/web-bridge/historySerializer.d.ts.map +1 -0
  51. package/dist/providers/web-bridge/historySerializer.js +152 -0
  52. package/dist/providers/web-bridge/historySerializer.js.map +1 -0
  53. package/dist/providers/web-bridge/index.d.ts +10 -0
  54. package/dist/providers/web-bridge/index.d.ts.map +1 -0
  55. package/dist/providers/web-bridge/index.js +10 -0
  56. package/dist/providers/web-bridge/index.js.map +1 -0
  57. package/dist/providers/web-bridge/promptInjector.d.ts +63 -0
  58. package/dist/providers/web-bridge/promptInjector.d.ts.map +1 -0
  59. package/dist/providers/web-bridge/promptInjector.js +189 -0
  60. package/dist/providers/web-bridge/promptInjector.js.map +1 -0
  61. package/dist/providers/web-bridge/provider.d.ts +59 -0
  62. package/dist/providers/web-bridge/provider.d.ts.map +1 -0
  63. package/dist/providers/web-bridge/provider.js +176 -0
  64. package/dist/providers/web-bridge/provider.js.map +1 -0
  65. package/dist/providers/web-bridge/shared/BrowserSession.d.ts +51 -0
  66. package/dist/providers/web-bridge/shared/BrowserSession.d.ts.map +1 -0
  67. package/dist/providers/web-bridge/shared/BrowserSession.js +88 -0
  68. package/dist/providers/web-bridge/shared/BrowserSession.js.map +1 -0
  69. package/dist/providers/web-bridge/shared/WebBridgeAdapter.d.ts +97 -0
  70. package/dist/providers/web-bridge/shared/WebBridgeAdapter.d.ts.map +1 -0
  71. package/dist/providers/web-bridge/shared/WebBridgeAdapter.js +359 -0
  72. package/dist/providers/web-bridge/shared/WebBridgeAdapter.js.map +1 -0
  73. package/dist/providers/web-bridge/shared/observerScript.d.ts +41 -0
  74. package/dist/providers/web-bridge/shared/observerScript.d.ts.map +1 -0
  75. package/dist/providers/web-bridge/shared/observerScript.js +138 -0
  76. package/dist/providers/web-bridge/shared/observerScript.js.map +1 -0
  77. package/dist/providers/web-bridge/shared/types.d.ts +94 -0
  78. package/dist/providers/web-bridge/shared/types.d.ts.map +1 -0
  79. package/dist/providers/web-bridge/shared/types.js +25 -0
  80. package/dist/providers/web-bridge/shared/types.js.map +1 -0
  81. package/dist/providers/web-bridge/toolUseParser.d.ts +70 -0
  82. package/dist/providers/web-bridge/toolUseParser.d.ts.map +1 -0
  83. package/dist/providers/web-bridge/toolUseParser.js +360 -0
  84. package/dist/providers/web-bridge/toolUseParser.js.map +1 -0
  85. package/package.json +36 -0
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Stream adapter: OpenAI chat/completions SSE → Anthropic RawMessageStreamEvent.
3
+ *
4
+ * This is the trickiest piece in the openai-compat provider. The two protocols
5
+ * model the world differently:
6
+ *
7
+ * - OpenAI streams a single "assistant message" whose `content` and
8
+ * `tool_calls` are filled in incrementally via deltas. Tool call deltas
9
+ * carry an `index` that identifies WHICH tool call in the parallel array
10
+ * they belong to.
11
+ *
12
+ * - Anthropic models the same response as a sequence of typed CONTENT BLOCKS
13
+ * (text / tool_use / thinking), each with its own index and lifecycle:
14
+ * content_block_start → content_block_delta* → content_block_stop.
15
+ *
16
+ * The mapping rules we use:
17
+ * • `delta.content` → text block, opened lazily, closed when something else starts
18
+ * • `delta.reasoning_content` (DeepSeek-R1 dialect) → thinking block, same lifecycle
19
+ * • `delta.tool_calls[i]` → one tool_use block per OpenAI index `i`
20
+ * • final `usage` → message_delta.usage
21
+ * • `finish_reason` → message_delta.stop_reason via mapStopReason()
22
+ *
23
+ * Block index allocation: we increment a single counter as we open blocks.
24
+ * The OpenAI-side `tool_calls.index` is REMAPPED to an Anthropic block index
25
+ * (they're not the same number — Anthropic counts ALL blocks including text).
26
+ *
27
+ * Concurrency: in practice OpenAI streams tool calls sequentially (one finishes
28
+ * before the next starts), but the spec allows parallel. We handle both cases
29
+ * by keeping per-OpenAI-index state and only closing when we see clear evidence
30
+ * the block is done (finish_reason or end of stream).
31
+ */
32
+ import { randomUUID } from 'node:crypto';
33
+ /**
34
+ * Adapt an OpenAI SSE chunk iterable into Anthropic stream events.
35
+ * Yields events; on upstream error, the error propagates (caller decides).
36
+ */
37
+ export async function* adaptOpenAIStream(upstream, opts) {
38
+ const state = {
39
+ messageId: opts.messageId ?? `msg_${randomUUID()}`,
40
+ model: opts.model,
41
+ nextBlockIndex: 0,
42
+ textBlock: null,
43
+ thinkingBlock: null,
44
+ toolCalls: new Map(),
45
+ usage: {
46
+ input_tokens: 0,
47
+ output_tokens: 0,
48
+ cache_creation_input_tokens: null,
49
+ cache_read_input_tokens: null,
50
+ },
51
+ stopReason: null,
52
+ stopSequence: null,
53
+ };
54
+ yield buildMessageStart(state);
55
+ for await (const chunk of upstream) {
56
+ yield* handleChunk(chunk, state);
57
+ }
58
+ // Close any blocks that are still open. Order: thinking → text → tool_use
59
+ // (so consumers see a tidy LIFO close sequence).
60
+ if (state.thinkingBlock) {
61
+ yield { type: 'content_block_stop', index: state.thinkingBlock.index };
62
+ state.thinkingBlock = null;
63
+ }
64
+ if (state.textBlock) {
65
+ yield { type: 'content_block_stop', index: state.textBlock.index };
66
+ state.textBlock = null;
67
+ }
68
+ for (const tc of state.toolCalls.values()) {
69
+ yield { type: 'content_block_stop', index: tc.anthropicIndex };
70
+ }
71
+ state.toolCalls.clear();
72
+ yield {
73
+ type: 'message_delta',
74
+ delta: {
75
+ stop_reason: state.stopReason ?? 'end_turn',
76
+ stop_sequence: state.stopSequence,
77
+ },
78
+ usage: { output_tokens: state.usage.output_tokens },
79
+ };
80
+ yield { type: 'message_stop' };
81
+ }
82
+ function buildMessageStart(state) {
83
+ const message = {
84
+ id: state.messageId,
85
+ type: 'message',
86
+ role: 'assistant',
87
+ model: state.model,
88
+ content: [],
89
+ stop_reason: null,
90
+ stop_sequence: null,
91
+ usage: state.usage,
92
+ };
93
+ return { type: 'message_start', message };
94
+ }
95
+ function* handleChunk(chunk, state) {
96
+ const choice = chunk.choices?.[0];
97
+ if (choice) {
98
+ yield* handleDelta(choice.delta, state);
99
+ if (choice.finish_reason) {
100
+ state.stopReason = mapFinishReason(choice.finish_reason);
101
+ }
102
+ }
103
+ if (chunk.usage)
104
+ mergeUsage(state.usage, chunk.usage);
105
+ }
106
+ function* handleDelta(delta, state) {
107
+ if (!delta)
108
+ return;
109
+ // Order: reasoning_content first (it always precedes content in DeepSeek-R1),
110
+ // then content, then tool_calls. Within a single chunk all three could be
111
+ // present in theory; we handle them in that natural reading order.
112
+ if (typeof delta.reasoning_content === 'string' && delta.reasoning_content.length > 0) {
113
+ // Closing text is wrong here — DeepSeek-R1 sends ALL reasoning_content
114
+ // BEFORE any content. So a thinking block is opened first and stays open
115
+ // until content arrives. If text was somehow already open, close it.
116
+ if (state.textBlock) {
117
+ yield { type: 'content_block_stop', index: state.textBlock.index };
118
+ state.textBlock = null;
119
+ }
120
+ if (!state.thinkingBlock) {
121
+ const index = state.nextBlockIndex++;
122
+ state.thinkingBlock = { index };
123
+ yield {
124
+ type: 'content_block_start',
125
+ index,
126
+ content_block: { type: 'thinking', thinking: '', signature: '' },
127
+ };
128
+ }
129
+ yield {
130
+ type: 'content_block_delta',
131
+ index: state.thinkingBlock.index,
132
+ delta: { type: 'thinking_delta', thinking: delta.reasoning_content },
133
+ };
134
+ }
135
+ if (typeof delta.content === 'string' && delta.content.length > 0) {
136
+ // First real text → close any thinking block (it's done by definition).
137
+ if (state.thinkingBlock) {
138
+ yield { type: 'content_block_stop', index: state.thinkingBlock.index };
139
+ state.thinkingBlock = null;
140
+ }
141
+ if (!state.textBlock) {
142
+ const index = state.nextBlockIndex++;
143
+ state.textBlock = { index };
144
+ yield {
145
+ type: 'content_block_start',
146
+ index,
147
+ content_block: { type: 'text', text: '', citations: null },
148
+ };
149
+ }
150
+ yield {
151
+ type: 'content_block_delta',
152
+ index: state.textBlock.index,
153
+ delta: { type: 'text_delta', text: delta.content },
154
+ };
155
+ }
156
+ if (delta.tool_calls && delta.tool_calls.length > 0) {
157
+ // Tool calls always come AFTER text/thinking in practice. Close those first.
158
+ if (state.thinkingBlock) {
159
+ yield { type: 'content_block_stop', index: state.thinkingBlock.index };
160
+ state.thinkingBlock = null;
161
+ }
162
+ if (state.textBlock) {
163
+ yield { type: 'content_block_stop', index: state.textBlock.index };
164
+ state.textBlock = null;
165
+ }
166
+ for (const tc of delta.tool_calls) {
167
+ const openaiIndex = tc.index;
168
+ let entry = state.toolCalls.get(openaiIndex);
169
+ if (!entry) {
170
+ // First time we're seeing this tool call. Allocate an Anthropic block.
171
+ const anthropicIndex = state.nextBlockIndex++;
172
+ entry = {
173
+ anthropicIndex,
174
+ id: tc.id ?? `toolu_${randomUUID().replace(/-/g, '').slice(0, 22)}`,
175
+ nameEmitted: false,
176
+ };
177
+ state.toolCalls.set(openaiIndex, entry);
178
+ // We may not have a name yet on the very first delta; if not, defer
179
+ // emitting content_block_start until we do. (Anthropic's content_block
180
+ // requires `name` to be set at start time.)
181
+ }
182
+ // If we know the name now and haven't emitted start yet, do so.
183
+ const name = tc.function?.name;
184
+ if (!entry.nameEmitted && name) {
185
+ entry.nameEmitted = true;
186
+ yield {
187
+ type: 'content_block_start',
188
+ index: entry.anthropicIndex,
189
+ content_block: {
190
+ type: 'tool_use',
191
+ id: entry.id,
192
+ name,
193
+ input: {},
194
+ },
195
+ };
196
+ }
197
+ const args = tc.function?.arguments;
198
+ if (entry.nameEmitted && typeof args === 'string' && args.length > 0) {
199
+ yield {
200
+ type: 'content_block_delta',
201
+ index: entry.anthropicIndex,
202
+ delta: { type: 'input_json_delta', partial_json: args },
203
+ };
204
+ }
205
+ }
206
+ }
207
+ }
208
+ function mapFinishReason(reason) {
209
+ switch (reason) {
210
+ case 'stop':
211
+ return 'end_turn';
212
+ case 'length':
213
+ return 'max_tokens';
214
+ case 'tool_calls':
215
+ case 'function_call':
216
+ return 'tool_use';
217
+ case 'content_filter':
218
+ // No exact Anthropic equivalent. 'stop_sequence' is the closest semantic
219
+ // ("model was stopped externally") but it's a stretch. We use 'end_turn'
220
+ // and rely on telemetry to flag filtered outputs upstream.
221
+ return 'end_turn';
222
+ default:
223
+ return 'end_turn';
224
+ }
225
+ }
226
+ function mergeUsage(target, src) {
227
+ target.input_tokens = src.prompt_tokens;
228
+ target.output_tokens = src.completion_tokens;
229
+ if (src.prompt_tokens_details?.cached_tokens !== undefined) {
230
+ target.cache_read_input_tokens = src.prompt_tokens_details.cached_tokens;
231
+ }
232
+ }
233
+ //# sourceMappingURL=streamAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamAdapter.js","sourceRoot":"","sources":["../../../src/providers/openai-compat/streamAdapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * OpenAI chat/completions wire types — a small subset of the v1 schema, just
3
+ * enough to send a streaming request and decode the SSE responses. We don't
4
+ * pull in `openai` as a dependency because we want to support arbitrary
5
+ * compatible servers (Ollama, Groq, OpenRouter, LM Studio, self-hosted),
6
+ * not all of which match the official SDK's strict shape.
7
+ *
8
+ * Reference: https://platform.openai.com/docs/api-reference/chat/streaming
9
+ */
10
+ export interface OpenAIToolFunction {
11
+ name: string;
12
+ description?: string;
13
+ parameters?: Record<string, unknown>;
14
+ }
15
+ export interface OpenAIToolDef {
16
+ type: 'function';
17
+ function: OpenAIToolFunction;
18
+ }
19
+ export type OpenAIToolChoice = 'auto' | 'none' | 'required' | {
20
+ type: 'function';
21
+ function: {
22
+ name: string;
23
+ };
24
+ };
25
+ export interface OpenAIContentPartText {
26
+ type: 'text';
27
+ text: string;
28
+ }
29
+ export interface OpenAIContentPartImage {
30
+ type: 'image_url';
31
+ image_url: {
32
+ url: string;
33
+ detail?: 'auto' | 'low' | 'high';
34
+ };
35
+ }
36
+ export type OpenAIContentPart = OpenAIContentPartText | OpenAIContentPartImage;
37
+ export interface OpenAIToolCall {
38
+ /** Stable identifier set on first delta, used to match `tool` role results. */
39
+ id: string;
40
+ type: 'function';
41
+ function: {
42
+ name: string;
43
+ arguments: string;
44
+ };
45
+ }
46
+ export interface OpenAIMessageSystem {
47
+ role: 'system';
48
+ content: string;
49
+ }
50
+ export interface OpenAIMessageUser {
51
+ role: 'user';
52
+ content: string | OpenAIContentPart[];
53
+ }
54
+ export interface OpenAIMessageAssistant {
55
+ role: 'assistant';
56
+ content?: string | null;
57
+ tool_calls?: OpenAIToolCall[];
58
+ }
59
+ export interface OpenAIMessageTool {
60
+ role: 'tool';
61
+ tool_call_id: string;
62
+ content: string;
63
+ }
64
+ export type OpenAIMessage = OpenAIMessageSystem | OpenAIMessageUser | OpenAIMessageAssistant | OpenAIMessageTool;
65
+ export interface OpenAIRequest {
66
+ model: string;
67
+ messages: OpenAIMessage[];
68
+ tools?: OpenAIToolDef[];
69
+ tool_choice?: OpenAIToolChoice;
70
+ stream: true;
71
+ stream_options?: {
72
+ include_usage?: boolean;
73
+ };
74
+ max_tokens?: number;
75
+ temperature?: number;
76
+ top_p?: number;
77
+ stop?: string | string[];
78
+ user?: string;
79
+ /**
80
+ * Some providers (DeepSeek, Together) accept extra fields here without
81
+ * complaining; we pass them through as an escape hatch.
82
+ */
83
+ [key: string]: unknown;
84
+ }
85
+ export interface OpenAIDeltaToolCall {
86
+ /** Index in the streamed assistant message's tool_calls array. */
87
+ index: number;
88
+ /** Set on the first chunk that introduces this tool call. */
89
+ id?: string;
90
+ type?: 'function';
91
+ function?: {
92
+ name?: string;
93
+ arguments?: string;
94
+ };
95
+ }
96
+ export interface OpenAIStreamDelta {
97
+ role?: 'assistant';
98
+ content?: string | null;
99
+ tool_calls?: OpenAIDeltaToolCall[];
100
+ /** Some providers (DeepSeek-R1) emit reasoning as a sibling field. */
101
+ reasoning_content?: string | null;
102
+ }
103
+ export type OpenAIFinishReason = 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'function_call' | null;
104
+ export interface OpenAIStreamChoice {
105
+ index: number;
106
+ delta: OpenAIStreamDelta;
107
+ finish_reason: OpenAIFinishReason;
108
+ }
109
+ export interface OpenAIUsage {
110
+ prompt_tokens: number;
111
+ completion_tokens: number;
112
+ total_tokens: number;
113
+ prompt_tokens_details?: {
114
+ cached_tokens?: number;
115
+ };
116
+ }
117
+ export interface OpenAIStreamChunk {
118
+ id: string;
119
+ object: 'chat.completion.chunk';
120
+ created: number;
121
+ model: string;
122
+ choices: OpenAIStreamChoice[];
123
+ /** Only present when stream_options.include_usage = true and only on the final chunk. */
124
+ usage?: OpenAIUsage;
125
+ }
126
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/openai-compat/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * OpenAI chat/completions wire types — a small subset of the v1 schema, just
3
+ * enough to send a streaming request and decode the SSE responses. We don't
4
+ * pull in `openai` as a dependency because we want to support arbitrary
5
+ * compatible servers (Ollama, Groq, OpenRouter, LM Studio, self-hosted),
6
+ * not all of which match the official SDK's strict shape.
7
+ *
8
+ * Reference: https://platform.openai.com/docs/api-reference/chat/streaming
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/providers/openai-compat/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Provider registry / selector.
3
+ *
4
+ * The selector keeps a map of registered providers and picks one by id, by
5
+ * default rule, or by a fallback chain. It does NOT instantiate providers
6
+ * itself — callers register pre-built instances. This keeps the selector
7
+ * dependency-light and makes testing easy.
8
+ *
9
+ * Selection precedence at lookup time:
10
+ * 1. Explicit id passed to pick()
11
+ * 2. Per-process default (set via setDefault)
12
+ * 3. First provider in the registry that passes healthCheck
13
+ */
14
+ import type { Logger } from '@bbclaw/shared';
15
+ import type { Provider } from './types.js';
16
+ export interface ProviderRegistryOptions {
17
+ logger?: Logger;
18
+ }
19
+ export declare class ProviderRegistry {
20
+ private readonly providers;
21
+ private defaultId;
22
+ private readonly logger;
23
+ constructor(opts?: ProviderRegistryOptions);
24
+ register(provider: Provider): this;
25
+ unregister(id: string): boolean;
26
+ has(id: string): boolean;
27
+ get(id: string): Provider | undefined;
28
+ list(): Provider[];
29
+ setDefault(id: string): void;
30
+ getDefault(): Provider | undefined;
31
+ /**
32
+ * Pick a provider. Lookup order:
33
+ * - explicit id
34
+ * - default
35
+ * - first registered (deterministic — Map preserves insertion order)
36
+ * Throws if the registry is empty or the requested id doesn't exist.
37
+ */
38
+ pick(id?: string): Provider;
39
+ /**
40
+ * Probe every registered provider in parallel and return the results.
41
+ * Useful for the `/provider health` UX and for surfacing config issues at
42
+ * startup.
43
+ */
44
+ healthCheckAll(): Promise<Array<{
45
+ id: string;
46
+ ok: boolean;
47
+ latencyMs?: number;
48
+ reason?: string;
49
+ }>>;
50
+ closeAll(): Promise<void>;
51
+ }
52
+ //# sourceMappingURL=selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector.d.ts","sourceRoot":"","sources":["../../src/providers/selector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAE1C,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8B;IACxD,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;gBAEnB,IAAI,GAAE,uBAA4B;IAK9C,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IASlC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAM/B,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIrC,IAAI,IAAI,QAAQ,EAAE;IAIlB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAO5B,UAAU,IAAI,QAAQ,GAAG,SAAS;IAIlC;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,QAAQ;IAa3B;;;;OAIG;IACG,cAAc,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAclG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAWhC"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Provider registry / selector.
3
+ *
4
+ * The selector keeps a map of registered providers and picks one by id, by
5
+ * default rule, or by a fallback chain. It does NOT instantiate providers
6
+ * itself — callers register pre-built instances. This keeps the selector
7
+ * dependency-light and makes testing easy.
8
+ *
9
+ * Selection precedence at lookup time:
10
+ * 1. Explicit id passed to pick()
11
+ * 2. Per-process default (set via setDefault)
12
+ * 3. First provider in the registry that passes healthCheck
13
+ */
14
+ export class ProviderRegistry {
15
+ providers = new Map();
16
+ defaultId = null;
17
+ logger;
18
+ constructor(opts = {}) {
19
+ this.logger =
20
+ opts.logger ?? { debug: () => { }, info: () => { }, warn: () => { }, error: () => { } };
21
+ }
22
+ register(provider) {
23
+ if (this.providers.has(provider.id)) {
24
+ throw new Error(`Provider already registered with id "${provider.id}"`);
25
+ }
26
+ this.providers.set(provider.id, provider);
27
+ if (this.defaultId === null)
28
+ this.defaultId = provider.id;
29
+ return this;
30
+ }
31
+ unregister(id) {
32
+ const removed = this.providers.delete(id);
33
+ if (this.defaultId === id)
34
+ this.defaultId = this.providers.keys().next().value ?? null;
35
+ return removed;
36
+ }
37
+ has(id) {
38
+ return this.providers.has(id);
39
+ }
40
+ get(id) {
41
+ return this.providers.get(id);
42
+ }
43
+ list() {
44
+ return [...this.providers.values()];
45
+ }
46
+ setDefault(id) {
47
+ if (!this.providers.has(id)) {
48
+ throw new Error(`Cannot set default to unknown provider id "${id}"`);
49
+ }
50
+ this.defaultId = id;
51
+ }
52
+ getDefault() {
53
+ return this.defaultId ? this.providers.get(this.defaultId) : undefined;
54
+ }
55
+ /**
56
+ * Pick a provider. Lookup order:
57
+ * - explicit id
58
+ * - default
59
+ * - first registered (deterministic — Map preserves insertion order)
60
+ * Throws if the registry is empty or the requested id doesn't exist.
61
+ */
62
+ pick(id) {
63
+ if (id) {
64
+ const p = this.providers.get(id);
65
+ if (!p)
66
+ throw new Error(`No provider registered with id "${id}"`);
67
+ return p;
68
+ }
69
+ const def = this.getDefault();
70
+ if (def)
71
+ return def;
72
+ const first = this.providers.values().next().value;
73
+ if (!first)
74
+ throw new Error('ProviderRegistry is empty');
75
+ return first;
76
+ }
77
+ /**
78
+ * Probe every registered provider in parallel and return the results.
79
+ * Useful for the `/provider health` UX and for surfacing config issues at
80
+ * startup.
81
+ */
82
+ async healthCheckAll() {
83
+ const entries = [...this.providers.values()];
84
+ const results = await Promise.all(entries.map(async (p) => {
85
+ const r = await p.healthCheck().catch((e) => ({
86
+ ok: false,
87
+ reason: e instanceof Error ? e.message : String(e),
88
+ }));
89
+ return { id: p.id, ...r };
90
+ }));
91
+ return results;
92
+ }
93
+ async closeAll() {
94
+ await Promise.all(this.list().map((p) => p.close().catch((e) => {
95
+ this.logger.warn(`[registry] close failed for ${p.id}:`, e);
96
+ })));
97
+ this.providers.clear();
98
+ this.defaultId = null;
99
+ }
100
+ }
101
+ //# sourceMappingURL=selector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector.js","sourceRoot":"","sources":["../../src/providers/selector.ts"],"names":[],"mappings":"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"}