@providerprotocol/ai 0.0.34 → 0.0.36
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/README.md +546 -3
- package/dist/anthropic/index.d.ts +2 -1
- package/dist/anthropic/index.js +151 -145
- package/dist/anthropic/index.js.map +1 -1
- package/dist/cerebras/index.d.ts +392 -0
- package/dist/cerebras/index.js +648 -0
- package/dist/cerebras/index.js.map +1 -0
- package/dist/chunk-2YXFLRQ6.js +49 -0
- package/dist/chunk-2YXFLRQ6.js.map +1 -0
- package/dist/chunk-4OGB7JZA.js +157 -0
- package/dist/chunk-4OGB7JZA.js.map +1 -0
- package/dist/chunk-4RX4VQCB.js +31 -0
- package/dist/chunk-4RX4VQCB.js.map +1 -0
- package/dist/chunk-5IWHCXKN.js +30 -0
- package/dist/chunk-5IWHCXKN.js.map +1 -0
- package/dist/{chunk-3C7O2RNO.js → chunk-A2IM7PGT.js} +6 -4
- package/dist/{chunk-3C7O2RNO.js.map → chunk-A2IM7PGT.js.map} +1 -1
- package/dist/{chunk-3D6XGGVG.js → chunk-ARVM24K2.js} +2 -2
- package/dist/{chunk-4J6OFUKX.js → chunk-AY55T37A.js} +70 -162
- package/dist/chunk-AY55T37A.js.map +1 -0
- package/dist/{chunk-ILR2D5PN.js → chunk-BRP5XJ6Q.js} +2 -86
- package/dist/chunk-BRP5XJ6Q.js.map +1 -0
- package/dist/chunk-C4JP64VW.js +298 -0
- package/dist/chunk-C4JP64VW.js.map +1 -0
- package/dist/chunk-COS4ON4G.js +111 -0
- package/dist/chunk-COS4ON4G.js.map +1 -0
- package/dist/chunk-CRP6Y7NF.js +31 -0
- package/dist/chunk-CRP6Y7NF.js.map +1 -0
- package/dist/chunk-EPB3GQNL.js +118 -0
- package/dist/chunk-EPB3GQNL.js.map +1 -0
- package/dist/chunk-ETBFOLQN.js +34 -0
- package/dist/chunk-ETBFOLQN.js.map +1 -0
- package/dist/chunk-I53CI6ZZ.js +142 -0
- package/dist/chunk-I53CI6ZZ.js.map +1 -0
- package/dist/chunk-IDZOVWP3.js +29 -0
- package/dist/chunk-IDZOVWP3.js.map +1 -0
- package/dist/chunk-JA3UZALR.js +88 -0
- package/dist/chunk-JA3UZALR.js.map +1 -0
- package/dist/{chunk-WAKD3OO5.js → chunk-N5DX5JW3.js} +31 -31
- package/dist/chunk-N5DX5JW3.js.map +1 -0
- package/dist/chunk-OIEWDFQU.js +97 -0
- package/dist/chunk-OIEWDFQU.js.map +1 -0
- package/dist/{chunk-TOJCZMVU.js → chunk-PMK5LZ5Z.js} +40 -40
- package/dist/chunk-PMK5LZ5Z.js.map +1 -0
- package/dist/{chunk-6S222DHN.js → chunk-RJGTRQ47.js} +20 -1
- package/dist/chunk-RJGTRQ47.js.map +1 -0
- package/dist/chunk-UFFJDYCE.js +94 -0
- package/dist/chunk-UFFJDYCE.js.map +1 -0
- package/dist/chunk-VGKZIGVI.js +222 -0
- package/dist/chunk-VGKZIGVI.js.map +1 -0
- package/dist/{chunk-KUPF5KHT.js → chunk-Y5H7C5J4.js} +2 -2
- package/dist/{embedding-D2BYIehX.d.ts → embedding-BXA72PlJ.d.ts} +1 -1
- package/dist/google/index.d.ts +2 -1
- package/dist/google/index.js +202 -199
- package/dist/google/index.js.map +1 -1
- package/dist/groq/index.d.ts +410 -0
- package/dist/groq/index.js +649 -0
- package/dist/groq/index.js.map +1 -0
- package/dist/http/index.d.ts +3 -2
- package/dist/http/index.js +5 -4
- package/dist/image-stream-CCgwB7ve.d.ts +11 -0
- package/dist/index.d.ts +8 -118
- package/dist/index.js +520 -769
- package/dist/index.js.map +1 -1
- package/dist/{llm-BQJZj3cD.d.ts → llm-ByUFPcFH.d.ts} +12 -1632
- package/dist/middleware/logging/index.d.ts +76 -0
- package/dist/middleware/logging/index.js +74 -0
- package/dist/middleware/logging/index.js.map +1 -0
- package/dist/middleware/parsed-object/index.d.ts +45 -0
- package/dist/middleware/parsed-object/index.js +73 -0
- package/dist/middleware/parsed-object/index.js.map +1 -0
- package/dist/middleware/pubsub/index.d.ts +97 -0
- package/dist/middleware/pubsub/index.js +160 -0
- package/dist/middleware/pubsub/index.js.map +1 -0
- package/dist/middleware/pubsub/server/express/index.d.ts +66 -0
- package/dist/middleware/pubsub/server/express/index.js +11 -0
- package/dist/middleware/pubsub/server/express/index.js.map +1 -0
- package/dist/middleware/pubsub/server/fastify/index.d.ts +67 -0
- package/dist/middleware/pubsub/server/fastify/index.js +11 -0
- package/dist/middleware/pubsub/server/fastify/index.js.map +1 -0
- package/dist/middleware/pubsub/server/h3/index.d.ts +70 -0
- package/dist/middleware/pubsub/server/h3/index.js +11 -0
- package/dist/middleware/pubsub/server/h3/index.js.map +1 -0
- package/dist/middleware/pubsub/server/index.d.ts +78 -0
- package/dist/middleware/pubsub/server/index.js +34 -0
- package/dist/middleware/pubsub/server/index.js.map +1 -0
- package/dist/middleware/pubsub/server/webapi/index.d.ts +63 -0
- package/dist/middleware/pubsub/server/webapi/index.js +11 -0
- package/dist/middleware/pubsub/server/webapi/index.js.map +1 -0
- package/dist/ollama/index.d.ts +2 -1
- package/dist/ollama/index.js +48 -45
- package/dist/ollama/index.js.map +1 -1
- package/dist/openai/index.d.ts +2 -1
- package/dist/openai/index.js +319 -313
- package/dist/openai/index.js.map +1 -1
- package/dist/openrouter/index.d.ts +2 -1
- package/dist/openrouter/index.js +381 -385
- package/dist/openrouter/index.js.map +1 -1
- package/dist/proxy/index.d.ts +10 -914
- package/dist/proxy/index.js +275 -1007
- package/dist/proxy/index.js.map +1 -1
- package/dist/proxy/server/express/index.d.ts +161 -0
- package/dist/proxy/server/express/index.js +24 -0
- package/dist/proxy/server/express/index.js.map +1 -0
- package/dist/proxy/server/fastify/index.d.ts +162 -0
- package/dist/proxy/server/fastify/index.js +24 -0
- package/dist/proxy/server/fastify/index.js.map +1 -0
- package/dist/proxy/server/h3/index.d.ts +189 -0
- package/dist/proxy/server/h3/index.js +28 -0
- package/dist/proxy/server/h3/index.js.map +1 -0
- package/dist/proxy/server/index.d.ts +151 -0
- package/dist/proxy/server/index.js +48 -0
- package/dist/proxy/server/index.js.map +1 -0
- package/dist/proxy/server/webapi/index.d.ts +278 -0
- package/dist/proxy/server/webapi/index.js +32 -0
- package/dist/proxy/server/webapi/index.js.map +1 -0
- package/dist/responses/index.d.ts +650 -0
- package/dist/responses/index.js +930 -0
- package/dist/responses/index.js.map +1 -0
- package/dist/{retry-8Ch-WWgX.d.ts → retry-BDMo4AVu.d.ts} +1 -1
- package/dist/stream-S7nwQRqM.d.ts +1643 -0
- package/dist/types-CE4B7pno.d.ts +96 -0
- package/dist/utils/index.d.ts +53 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/xai/index.d.ts +2 -1
- package/dist/xai/index.js +310 -310
- package/dist/xai/index.js.map +1 -1
- package/package.json +82 -4
- package/dist/chunk-4J6OFUKX.js.map +0 -1
- package/dist/chunk-6S222DHN.js.map +0 -1
- package/dist/chunk-ILR2D5PN.js.map +0 -1
- package/dist/chunk-TOJCZMVU.js.map +0 -1
- package/dist/chunk-WAKD3OO5.js.map +0 -1
- /package/dist/{chunk-3D6XGGVG.js.map → chunk-ARVM24K2.js.map} +0 -0
- /package/dist/{chunk-KUPF5KHT.js.map → chunk-Y5H7C5J4.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/http/sse.ts"],"sourcesContent":["/**\n * Server-Sent Events (SSE) stream parsing utilities.\n * @module http/sse\n */\n\n/**\n * Parses a single SSE event block into a JSON object.\n *\n * Handles the following line prefixes:\n * - \"data:\" - Event data (multiple data lines are concatenated)\n * - \"event:\" - Event type (added to result as _eventType)\n * - \":\" - Comment (ignored, often used for keep-alive)\n * - Raw JSON starting with { or [ (provider-specific fallback)\n *\n * @param eventText - Raw text of a single SSE event block\n * @returns Parsed JSON object, 'DONE' for termination signal, or null for invalid/empty events\n */\nfunction parseSSEEvent(eventText: string): unknown | 'DONE' | null {\n const lines = eventText.split('\\n');\n let data = '';\n let eventType = '';\n\n for (const line of lines) {\n const normalizedLine = line.endsWith('\\r') ? line.slice(0, -1) : line;\n if (normalizedLine.startsWith('event:')) {\n let value = normalizedLine.slice(6);\n if (value.startsWith(' ')) value = value.slice(1);\n eventType = value;\n } else if (normalizedLine.startsWith('data:')) {\n let value = normalizedLine.slice(5);\n if (value.startsWith(' ')) value = value.slice(1);\n data += (data ? '\\n' : '') + value;\n } else if (normalizedLine.startsWith(':')) {\n continue;\n } else {\n const trimmedStart = normalizedLine.trimStart();\n if (trimmedStart.startsWith('{') || trimmedStart.startsWith('[')) {\n data += (data ? '\\n' : '') + trimmedStart;\n }\n }\n }\n\n if (!data) {\n return null;\n }\n\n if (data === '[DONE]') {\n return 'DONE';\n }\n\n try {\n const parsed = JSON.parse(data);\n\n if (eventType) {\n return { _eventType: eventType, ...parsed };\n }\n\n return parsed;\n } catch {\n return null;\n }\n}\n\n/**\n * Parses a Server-Sent Events stream into JSON objects.\n *\n * This async generator handles the standard SSE wire format:\n * - Lines prefixed with \"data:\" contain event data\n * - Lines prefixed with \"event:\" specify event types\n * - Lines prefixed with \":\" are comments (used for keep-alive)\n * - Events are separated by double newlines\n * - Stream terminates on \"[DONE]\" message (OpenAI convention)\n *\n * Also handles non-standard formats used by some providers:\n * - Raw JSON without \"data:\" prefix (Google)\n * - Multi-line data fields\n *\n * @param body - ReadableStream from fetch response body\n * @yields Parsed JSON objects from each SSE event\n *\n * @example\n * ```typescript\n * const response = await doStreamFetch(url, init, config, 'openai', 'llm');\n *\n * for await (const event of parseSSEStream(response.body!)) {\n * // event is parsed JSON from each SSE data field\n * const chunk = event as OpenAIStreamChunk;\n * const delta = chunk.choices[0]?.delta?.content;\n * if (delta) {\n * process.stdout.write(delta);\n * }\n * }\n * ```\n */\nexport async function* parseSSEStream(\n body: ReadableStream<Uint8Array>\n): AsyncGenerator<unknown, void, unknown> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n const tail = decoder.decode();\n if (tail) {\n buffer += tail;\n }\n // Process any remaining data in buffer\n if (buffer.trim()) {\n const event = parseSSEEvent(buffer);\n if (event !== null && event !== undefined) {\n yield event;\n }\n }\n break;\n }\n\n const chunk = decoder.decode(value, { stream: true });\n if (chunk) {\n buffer += chunk;\n }\n\n // Process complete events (separated by double newlines or \\r\\n\\r\\n)\n const events = buffer.split(/\\r?\\n\\r?\\n/);\n\n // Keep the last partial event in the buffer\n buffer = events.pop() ?? '';\n\n for (const eventText of events) {\n if (!eventText.trim()) continue;\n\n const event = parseSSEEvent(eventText);\n if (event === 'DONE') {\n return;\n }\n if (event !== null && event !== undefined) {\n yield event;\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Parses a simple text stream without SSE formatting.\n *\n * This is a simpler alternative to {@link parseSSEStream} for providers\n * that stream raw text deltas without SSE event wrappers. Each chunk\n * from the response body is decoded and yielded as-is.\n *\n * Use this for:\n * - Plain text streaming responses\n * - Providers with custom streaming formats\n * - Testing and debugging stream handling\n *\n * @param body - ReadableStream from fetch response body\n * @yields Decoded text strings from each stream chunk\n *\n * @example\n * ```typescript\n * const response = await doStreamFetch(url, init, config, 'custom', 'llm');\n *\n * for await (const text of parseSimpleTextStream(response.body!)) {\n * process.stdout.write(text);\n * }\n * ```\n */\nexport async function* parseSimpleTextStream(\n body: ReadableStream<Uint8Array>\n): AsyncGenerator<string, void, unknown> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) break;\n\n const text = decoder.decode(value, { stream: true });\n if (text) {\n yield text;\n }\n }\n const remaining = decoder.decode();\n if (remaining) {\n yield remaining;\n }\n } finally {\n reader.releaseLock();\n }\n}\n"],"mappings":";AAiBA,SAAS,cAAc,WAA4C;AACjE,QAAM,QAAQ,UAAU,MAAM,IAAI;AAClC,MAAI,OAAO;AACX,MAAI,YAAY;AAEhB,aAAW,QAAQ,OAAO;AACxB,UAAM,iBAAiB,KAAK,SAAS,IAAI,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;AACjE,QAAI,eAAe,WAAW,QAAQ,GAAG;AACvC,UAAI,QAAQ,eAAe,MAAM,CAAC;AAClC,UAAI,MAAM,WAAW,GAAG,EAAG,SAAQ,MAAM,MAAM,CAAC;AAChD,kBAAY;AAAA,IACd,WAAW,eAAe,WAAW,OAAO,GAAG;AAC7C,UAAI,QAAQ,eAAe,MAAM,CAAC;AAClC,UAAI,MAAM,WAAW,GAAG,EAAG,SAAQ,MAAM,MAAM,CAAC;AAChD,eAAS,OAAO,OAAO,MAAM;AAAA,IAC/B,WAAW,eAAe,WAAW,GAAG,GAAG;AACzC;AAAA,IACF,OAAO;AACL,YAAM,eAAe,eAAe,UAAU;AAC9C,UAAI,aAAa,WAAW,GAAG,KAAK,aAAa,WAAW,GAAG,GAAG;AAChE,iBAAS,OAAO,OAAO,MAAM;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,UAAU;AACrB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,IAAI;AAE9B,QAAI,WAAW;AACb,aAAO,EAAE,YAAY,WAAW,GAAG,OAAO;AAAA,IAC5C;AAEA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAiCA,gBAAuB,eACrB,MACwC;AACxC,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AAEb,MAAI;AACF,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAE1C,UAAI,MAAM;AACR,cAAM,OAAO,QAAQ,OAAO;AAC5B,YAAI,MAAM;AACR,oBAAU;AAAA,QACZ;AAEA,YAAI,OAAO,KAAK,GAAG;AACjB,gBAAM,QAAQ,cAAc,MAAM;AAClC,cAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,kBAAM;AAAA,UACR;AAAA,QACF;AACA;AAAA,MACF;AAEA,YAAM,QAAQ,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AACpD,UAAI,OAAO;AACT,kBAAU;AAAA,MACZ;AAGA,YAAM,SAAS,OAAO,MAAM,YAAY;AAGxC,eAAS,OAAO,IAAI,KAAK;AAEzB,iBAAW,aAAa,QAAQ;AAC9B,YAAI,CAAC,UAAU,KAAK,EAAG;AAEvB,cAAM,QAAQ,cAAc,SAAS;AACrC,YAAI,UAAU,QAAQ;AACpB;AAAA,QACF;AACA,YAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACF;AA0BA,gBAAuB,sBACrB,MACuC;AACvC,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAU,IAAI,YAAY;AAEhC,MAAI;AACF,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAE1C,UAAI,KAAM;AAEV,YAAM,OAAO,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AACnD,UAAI,MAAM;AACR,cAAM;AAAA,MACR;AAAA,IACF;AACA,UAAM,YAAY,QAAQ,OAAO;AACjC,QAAI,WAAW;AACb,YAAM;AAAA,IACR;AAAA,EACF,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACF;","names":[]}
|
|
@@ -29,6 +29,7 @@ var StreamEventType = {
|
|
|
29
29
|
};
|
|
30
30
|
function createStreamResult(generator, turnPromiseOrFactory, abortController) {
|
|
31
31
|
let cachedTurn = null;
|
|
32
|
+
let drainStarted = false;
|
|
32
33
|
const getTurn = () => {
|
|
33
34
|
if (typeof turnPromiseOrFactory === "function") {
|
|
34
35
|
if (!cachedTurn) {
|
|
@@ -38,6 +39,20 @@ function createStreamResult(generator, turnPromiseOrFactory, abortController) {
|
|
|
38
39
|
}
|
|
39
40
|
return turnPromiseOrFactory;
|
|
40
41
|
};
|
|
42
|
+
const drain = () => {
|
|
43
|
+
if (drainStarted) return;
|
|
44
|
+
drainStarted = true;
|
|
45
|
+
void (async () => {
|
|
46
|
+
try {
|
|
47
|
+
let done = false;
|
|
48
|
+
while (!done) {
|
|
49
|
+
const result = await generator.next();
|
|
50
|
+
done = result.done ?? false;
|
|
51
|
+
}
|
|
52
|
+
} catch {
|
|
53
|
+
}
|
|
54
|
+
})();
|
|
55
|
+
};
|
|
41
56
|
return {
|
|
42
57
|
[Symbol.asyncIterator]() {
|
|
43
58
|
return generator;
|
|
@@ -47,6 +62,10 @@ function createStreamResult(generator, turnPromiseOrFactory, abortController) {
|
|
|
47
62
|
},
|
|
48
63
|
abort() {
|
|
49
64
|
abortController.abort();
|
|
65
|
+
},
|
|
66
|
+
then(onfulfilled, onrejected) {
|
|
67
|
+
drain();
|
|
68
|
+
return getTurn().then(onfulfilled, onrejected);
|
|
50
69
|
}
|
|
51
70
|
};
|
|
52
71
|
}
|
|
@@ -127,4 +146,4 @@ export {
|
|
|
127
146
|
toolExecutionStart,
|
|
128
147
|
toolExecutionEnd
|
|
129
148
|
};
|
|
130
|
-
//# sourceMappingURL=chunk-
|
|
149
|
+
//# sourceMappingURL=chunk-RJGTRQ47.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types/stream.ts"],"sourcesContent":["/**\n * @fileoverview Streaming types for real-time LLM responses.\n *\n * Defines the event types and interfaces for streaming LLM inference,\n * including text deltas, tool call deltas, and control events.\n *\n * @module types/stream\n */\n\nimport type { Turn } from './turn.ts';\n\n/**\n * Stream event type constants.\n *\n * Use these constants instead of raw strings for type-safe event handling:\n *\n * @example\n * ```typescript\n * import { StreamEventType } from 'upp';\n *\n * for await (const event of stream) {\n * if (event.type === StreamEventType.TextDelta) {\n * process.stdout.write(event.delta.text ?? '');\n * }\n * }\n * ```\n */\nexport const StreamEventType = {\n /** Incremental text output */\n TextDelta: 'text_delta',\n /** Incremental reasoning/thinking output */\n ReasoningDelta: 'reasoning_delta',\n /** Incremental image data */\n ImageDelta: 'image_delta',\n /** Incremental audio data */\n AudioDelta: 'audio_delta',\n /** Incremental video data */\n VideoDelta: 'video_delta',\n /** Incremental tool call data (arguments being streamed) */\n ToolCallDelta: 'tool_call_delta',\n /** Incremental structured object data (for structured output responses) */\n ObjectDelta: 'object_delta',\n /** Tool execution has started (may be emitted after completion in some implementations) */\n ToolExecutionStart: 'tool_execution_start',\n /** Tool execution has completed */\n ToolExecutionEnd: 'tool_execution_end',\n /** Beginning of a message */\n MessageStart: 'message_start',\n /** End of a message */\n MessageStop: 'message_stop',\n /** Beginning of a content block */\n ContentBlockStart: 'content_block_start',\n /** End of a content block */\n ContentBlockStop: 'content_block_stop',\n} as const;\n\n/**\n * Stream event type discriminator union.\n *\n * This type is derived from {@link StreamEventType} constants. Use `StreamEventType.TextDelta`\n * for constants or `type MyType = StreamEventType` for type annotations.\n */\nexport type StreamEventType = (typeof StreamEventType)[keyof typeof StreamEventType];\n\n/**\n * Event delta data payload.\n *\n * Contains the type-specific data for a streaming event.\n * Different fields are populated depending on the event type:\n *\n * | Event Type | Fields |\n * |------------|--------|\n * | `text_delta` | `text` |\n * | `reasoning_delta` | `text` |\n * | `object_delta` | `text` |\n * | `image_delta` | `data` |\n * | `audio_delta` | `data` |\n * | `video_delta` | `data` |\n * | `tool_call_delta` | `toolCallId`, `toolName`, `argumentsJson` |\n * | `tool_execution_start` | `toolCallId`, `toolName`, `timestamp` |\n * | `tool_execution_end` | `toolCallId`, `toolName`, `result`, `isError`, `timestamp` |\n * | `message_start` | (none) |\n * | `message_stop` | (none) |\n * | `content_block_start` | (none) |\n * | `content_block_stop` | (none) |\n */\nexport interface EventDelta {\n /** Incremental text content (text_delta, reasoning_delta, object_delta) */\n text?: string;\n\n /** Incremental binary data (image_delta, audio_delta, video_delta) */\n data?: Uint8Array;\n\n /** Tool call identifier (tool_call_delta, tool_execution_start/end) */\n toolCallId?: string;\n\n /** Tool name (tool_call_delta, tool_execution_start/end) */\n toolName?: string;\n\n /** Incremental JSON arguments string (tool_call_delta) */\n argumentsJson?: string;\n\n /** Tool execution result (tool_execution_end) */\n result?: unknown;\n\n /** Whether tool execution resulted in an error (tool_execution_end) */\n isError?: boolean;\n\n /** Timestamp in milliseconds (tool_execution_start/end) */\n timestamp?: number;\n}\n\n/**\n * A single streaming event from the LLM.\n *\n * Events are emitted in order as the model generates output,\n * allowing for real-time display of responses.\n *\n * @example\n * ```typescript\n * import { StreamEventType } from 'upp';\n *\n * for await (const event of stream) {\n * if (event.type === StreamEventType.TextDelta) {\n * process.stdout.write(event.delta.text ?? '');\n * } else if (event.type === StreamEventType.ToolCallDelta) {\n * console.log('Tool:', event.delta.toolName);\n * }\n * }\n * ```\n */\nexport interface StreamEvent {\n /** Event type discriminator */\n type: StreamEventType;\n\n /** Index of the content block this event belongs to */\n index: number;\n\n /** Event-specific data payload */\n delta: EventDelta;\n}\n\n/**\n * Stream result - an async iterable that also provides the final turn.\n *\n * Allows consuming streaming events while also awaiting the complete\n * Turn result after streaming finishes. Implements `PromiseLike<Turn>`\n * for direct awaiting with automatic stream consumption.\n *\n * @typeParam TData - Type of the structured output data\n *\n * @example\n * ```typescript\n * import { StreamEventType } from 'upp';\n *\n * const stream = instance.stream('Tell me a story');\n *\n * // Option 1: Consume streaming events manually\n * for await (const event of stream) {\n * if (event.type === StreamEventType.TextDelta) {\n * process.stdout.write(event.delta.text ?? '');\n * }\n * }\n * const turn = await stream.turn;\n *\n * // Option 2: Just await the turn (auto-drains the stream)\n * const turn = await instance.stream('Tell me a story');\n *\n * // Option 3: Fire-and-forget with callback\n * instance.stream('Tell me a story').then(turn => saveToDB(turn));\n * ```\n */\nexport interface StreamResult<TData = unknown>\n extends AsyncIterable<StreamEvent>, PromiseLike<Turn<TData>> {\n /**\n * Promise that resolves to the complete Turn after streaming finishes.\n * Rejects if the stream is aborted or terminated early.\n */\n readonly turn: Promise<Turn<TData>>;\n\n /**\n * Aborts the stream, stopping further events and cancelling the request.\n * This will cause {@link StreamResult.turn} to reject.\n */\n abort(): void;\n}\n\n/**\n * Creates a StreamResult from an async generator and completion promise.\n *\n * @typeParam TData - Type of the structured output data\n * @param generator - Async generator that yields stream events\n * @param turnPromiseOrFactory - Promise or factory that resolves to the complete Turn\n * @param abortController - Controller for aborting the stream\n * @returns A StreamResult that can be iterated and awaited\n *\n * @example\n * ```typescript\n * const abortController = new AbortController();\n * const stream = createStreamResult(\n * eventGenerator(),\n * turnPromise,\n * abortController\n * );\n *\n * // Can be awaited directly (auto-drains)\n * const turn = await stream;\n *\n * // Or iterated manually\n * for await (const event of stream) { ... }\n * const turn = await stream.turn;\n * ```\n */\nexport function createStreamResult<TData = unknown>(\n generator: AsyncGenerator<StreamEvent, void, unknown>,\n turnPromiseOrFactory: Promise<Turn<TData>> | (() => Promise<Turn<TData>>),\n abortController: AbortController\n): StreamResult<TData> {\n let cachedTurn: Promise<Turn<TData>> | null = null;\n let drainStarted = false;\n\n const getTurn = (): Promise<Turn<TData>> => {\n if (typeof turnPromiseOrFactory === 'function') {\n if (!cachedTurn) {\n cachedTurn = turnPromiseOrFactory();\n }\n return cachedTurn;\n }\n return turnPromiseOrFactory;\n };\n\n const drain = (): void => {\n if (drainStarted) return;\n drainStarted = true;\n void (async () => {\n try {\n let done = false;\n while (!done) {\n const result = await generator.next();\n done = result.done ?? false;\n }\n } catch {\n // Errors are surfaced via turn promise\n }\n })();\n };\n\n return {\n [Symbol.asyncIterator]() {\n return generator;\n },\n get turn() {\n return getTurn();\n },\n abort() {\n abortController.abort();\n },\n then<TResult1 = Turn<TData>, TResult2 = never>(\n onfulfilled?: ((value: Turn<TData>) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): Promise<TResult1 | TResult2> {\n drain();\n return getTurn().then(onfulfilled, onrejected);\n },\n };\n}\n\n/**\n * Creates a text delta stream event.\n *\n * @param text - The incremental text content\n * @param index - Content block index (default: 0)\n * @returns A text_delta StreamEvent\n */\nexport function textDelta(text: string, index = 0): StreamEvent {\n return {\n type: StreamEventType.TextDelta,\n index,\n delta: { text },\n };\n}\n\n/**\n * Creates a tool call delta stream event.\n *\n * @param toolCallId - Unique identifier for the tool call\n * @param toolName - Name of the tool being called\n * @param argumentsJson - Incremental JSON arguments string\n * @param index - Content block index (default: 0)\n * @returns A tool_call_delta StreamEvent\n */\nexport function toolCallDelta(\n toolCallId: string,\n toolName: string,\n argumentsJson: string,\n index = 0\n): StreamEvent {\n return {\n type: StreamEventType.ToolCallDelta,\n index,\n delta: { toolCallId, toolName, argumentsJson },\n };\n}\n\n/**\n * Creates an object delta stream event for structured output responses.\n *\n * @param text - The incremental text content\n * @param index - Content block index (default: 0)\n * @returns An object_delta StreamEvent\n */\nexport function objectDelta(text: string, index = 0): StreamEvent {\n return {\n type: StreamEventType.ObjectDelta,\n index,\n delta: { text },\n };\n}\n\n/**\n * Creates a message start stream event.\n *\n * @returns A message_start StreamEvent\n */\nexport function messageStart(): StreamEvent {\n return {\n type: StreamEventType.MessageStart,\n index: 0,\n delta: {},\n };\n}\n\n/**\n * Creates a message stop stream event.\n *\n * @returns A message_stop StreamEvent\n */\nexport function messageStop(): StreamEvent {\n return {\n type: StreamEventType.MessageStop,\n index: 0,\n delta: {},\n };\n}\n\n/**\n * Creates a content block start stream event.\n *\n * @param index - The content block index starting\n * @returns A content_block_start StreamEvent\n */\nexport function contentBlockStart(index: number): StreamEvent {\n return {\n type: StreamEventType.ContentBlockStart,\n index,\n delta: {},\n };\n}\n\n/**\n * Creates a content block stop stream event.\n *\n * @param index - The content block index stopping\n * @returns A content_block_stop StreamEvent\n */\nexport function contentBlockStop(index: number): StreamEvent {\n return {\n type: StreamEventType.ContentBlockStop,\n index,\n delta: {},\n };\n}\n\n/**\n * Creates a tool execution start stream event.\n *\n * @param toolCallId - Unique identifier for the tool call\n * @param toolName - Name of the tool being executed\n * @param timestamp - Start timestamp in milliseconds\n * @param index - Content block index (default: 0)\n * @returns A tool_execution_start StreamEvent\n */\nexport function toolExecutionStart(\n toolCallId: string,\n toolName: string,\n timestamp: number,\n index = 0\n): StreamEvent {\n return {\n type: StreamEventType.ToolExecutionStart,\n index,\n delta: { toolCallId, toolName, timestamp },\n };\n}\n\n/**\n * Creates a tool execution end stream event.\n *\n * @param toolCallId - Unique identifier for the tool call\n * @param toolName - Name of the tool that was executed\n * @param result - The result from the tool execution\n * @param isError - Whether the execution resulted in an error\n * @param timestamp - End timestamp in milliseconds\n * @param index - Content block index (default: 0)\n * @returns A tool_execution_end StreamEvent\n */\nexport function toolExecutionEnd(\n toolCallId: string,\n toolName: string,\n result: unknown,\n isError: boolean,\n timestamp: number,\n index = 0\n): StreamEvent {\n return {\n type: StreamEventType.ToolExecutionEnd,\n index,\n delta: { toolCallId, toolName, result, isError, timestamp },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveImageResult,
|
|
3
|
+
serializeImageResult,
|
|
4
|
+
serializeImageStreamEvent,
|
|
5
|
+
serializeStreamEvent,
|
|
6
|
+
serializeTurn
|
|
7
|
+
} from "./chunk-C4JP64VW.js";
|
|
8
|
+
|
|
9
|
+
// src/providers/proxy/server/fastify.ts
|
|
10
|
+
function sendJSON(turn, reply) {
|
|
11
|
+
return reply.header("Content-Type", "application/json").send(serializeTurn(turn));
|
|
12
|
+
}
|
|
13
|
+
function sendEmbeddingJSON(result, reply) {
|
|
14
|
+
return reply.header("Content-Type", "application/json").send(result);
|
|
15
|
+
}
|
|
16
|
+
function sendImageJSON(result, reply) {
|
|
17
|
+
return reply.header("Content-Type", "application/json").send(serializeImageResult(result));
|
|
18
|
+
}
|
|
19
|
+
function streamSSE(stream, reply) {
|
|
20
|
+
reply.header("Content-Type", "text/event-stream").header("Cache-Control", "no-cache").header("Connection", "keep-alive");
|
|
21
|
+
const raw = reply.raw;
|
|
22
|
+
(async () => {
|
|
23
|
+
try {
|
|
24
|
+
for await (const event of stream) {
|
|
25
|
+
const serialized = serializeStreamEvent(event);
|
|
26
|
+
raw.write(`data: ${JSON.stringify(serialized)}
|
|
27
|
+
|
|
28
|
+
`);
|
|
29
|
+
}
|
|
30
|
+
const turn = await stream.turn;
|
|
31
|
+
raw.write(`data: ${JSON.stringify(serializeTurn(turn))}
|
|
32
|
+
|
|
33
|
+
`);
|
|
34
|
+
raw.write("data: [DONE]\n\n");
|
|
35
|
+
} catch (error) {
|
|
36
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
37
|
+
raw.write(`data: ${JSON.stringify({ error: message })}
|
|
38
|
+
|
|
39
|
+
`);
|
|
40
|
+
} finally {
|
|
41
|
+
raw.end();
|
|
42
|
+
}
|
|
43
|
+
})();
|
|
44
|
+
return reply;
|
|
45
|
+
}
|
|
46
|
+
function streamImageSSE(stream, reply) {
|
|
47
|
+
reply.header("Content-Type", "text/event-stream").header("Cache-Control", "no-cache").header("Connection", "keep-alive");
|
|
48
|
+
const raw = reply.raw;
|
|
49
|
+
(async () => {
|
|
50
|
+
try {
|
|
51
|
+
for await (const event of stream) {
|
|
52
|
+
const serialized = serializeImageStreamEvent(event);
|
|
53
|
+
raw.write(`data: ${JSON.stringify(serialized)}
|
|
54
|
+
|
|
55
|
+
`);
|
|
56
|
+
}
|
|
57
|
+
const result = await resolveImageResult(stream);
|
|
58
|
+
raw.write(`data: ${JSON.stringify(serializeImageResult(result))}
|
|
59
|
+
|
|
60
|
+
`);
|
|
61
|
+
raw.write("data: [DONE]\n\n");
|
|
62
|
+
} catch (error) {
|
|
63
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
64
|
+
raw.write(`data: ${JSON.stringify({ error: message })}
|
|
65
|
+
|
|
66
|
+
`);
|
|
67
|
+
} finally {
|
|
68
|
+
raw.end();
|
|
69
|
+
}
|
|
70
|
+
})();
|
|
71
|
+
return reply;
|
|
72
|
+
}
|
|
73
|
+
function sendError(message, status, reply) {
|
|
74
|
+
return reply.status(status).send({ error: message });
|
|
75
|
+
}
|
|
76
|
+
var fastify = {
|
|
77
|
+
sendJSON,
|
|
78
|
+
sendEmbeddingJSON,
|
|
79
|
+
sendImageJSON,
|
|
80
|
+
streamSSE,
|
|
81
|
+
streamImageSSE,
|
|
82
|
+
sendError
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export {
|
|
86
|
+
sendJSON,
|
|
87
|
+
sendEmbeddingJSON,
|
|
88
|
+
sendImageJSON,
|
|
89
|
+
streamSSE,
|
|
90
|
+
streamImageSSE,
|
|
91
|
+
sendError,
|
|
92
|
+
fastify
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=chunk-UFFJDYCE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/proxy/server/fastify.ts"],"sourcesContent":["/**\n * @fileoverview Fastify adapter for proxy server.\n *\n * Provides utilities for using PP proxy with Fastify servers.\n * These adapters convert PP types to Fastify-compatible responses.\n *\n * @module providers/proxy/server/fastify\n */\n\nimport type { Turn } from '../../../types/turn.ts';\nimport type { StreamResult } from '../../../types/stream.ts';\nimport type { EmbeddingResult } from '../../../types/embedding.ts';\nimport type { ImageResult } from '../../../types/image.ts';\nimport { serializeTurn, serializeStreamEvent } from '../serialization.ts';\nimport { serializeImageResult, serializeImageStreamEvent } from '../serialization.media.ts';\nimport { resolveImageResult, type ImageStreamLike } from './image-stream.ts';\n\n/**\n * Fastify Reply interface (minimal type to avoid dependency).\n */\ninterface FastifyReply {\n header(name: string, value: string): FastifyReply;\n status(code: number): FastifyReply;\n send(payload: unknown): FastifyReply;\n raw: {\n write(chunk: string): boolean;\n end(): void;\n };\n}\n\n/**\n * Send a Turn as JSON response.\n *\n * @param turn - The completed inference turn\n * @param reply - Fastify reply object\n *\n * @example\n * ```typescript\n * const turn = await instance.generate(messages);\n * return fastifyAdapter.sendJSON(turn, reply);\n * ```\n */\nexport function sendJSON(turn: Turn, reply: FastifyReply): FastifyReply {\n return reply\n .header('Content-Type', 'application/json')\n .send(serializeTurn(turn));\n}\n\n/**\n * Send an EmbeddingResult as JSON response.\n *\n * @param result - The embedding result\n * @param reply - Fastify reply object\n */\nexport function sendEmbeddingJSON(result: EmbeddingResult, reply: FastifyReply): FastifyReply {\n return reply\n .header('Content-Type', 'application/json')\n .send(result);\n}\n\n/**\n * Send an ImageResult as JSON response.\n *\n * @param result - The image result\n * @param reply - Fastify reply object\n */\nexport function sendImageJSON(result: ImageResult, reply: FastifyReply): FastifyReply {\n return reply\n .header('Content-Type', 'application/json')\n .send(serializeImageResult(result));\n}\n\n/**\n * Stream a StreamResult as Server-Sent Events.\n *\n * @param stream - The StreamResult from instance.stream()\n * @param reply - Fastify reply object\n *\n * @example\n * ```typescript\n * const stream = instance.stream(messages);\n * return fastifyAdapter.streamSSE(stream, reply);\n * ```\n */\nexport function streamSSE(stream: StreamResult, reply: FastifyReply): FastifyReply {\n reply\n .header('Content-Type', 'text/event-stream')\n .header('Cache-Control', 'no-cache')\n .header('Connection', 'keep-alive');\n\n const raw = reply.raw;\n\n (async () => {\n try {\n for await (const event of stream) {\n const serialized = serializeStreamEvent(event);\n raw.write(`data: ${JSON.stringify(serialized)}\\n\\n`);\n }\n\n const turn = await stream.turn;\n raw.write(`data: ${JSON.stringify(serializeTurn(turn))}\\n\\n`);\n raw.write('data: [DONE]\\n\\n');\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n raw.write(`data: ${JSON.stringify({ error: message })}\\n\\n`);\n } finally {\n raw.end();\n }\n })();\n\n return reply;\n}\n\n/**\n * Stream an ImageStreamResult as Server-Sent Events.\n *\n * @param stream - The ImageStreamResult or ImageProviderStreamResult from image().stream()\n * @param reply - Fastify reply object\n */\nexport function streamImageSSE(stream: ImageStreamLike, reply: FastifyReply): FastifyReply {\n reply\n .header('Content-Type', 'text/event-stream')\n .header('Cache-Control', 'no-cache')\n .header('Connection', 'keep-alive');\n\n const raw = reply.raw;\n\n (async () => {\n try {\n for await (const event of stream) {\n const serialized = serializeImageStreamEvent(event);\n raw.write(`data: ${JSON.stringify(serialized)}\\n\\n`);\n }\n\n const result = await resolveImageResult(stream);\n raw.write(`data: ${JSON.stringify(serializeImageResult(result))}\\n\\n`);\n raw.write('data: [DONE]\\n\\n');\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n raw.write(`data: ${JSON.stringify({ error: message })}\\n\\n`);\n } finally {\n raw.end();\n }\n })();\n\n return reply;\n}\n\n/**\n * Send an error response.\n *\n * @param message - Error message\n * @param status - HTTP status code\n * @param reply - Fastify reply object\n */\nexport function sendError(message: string, status: number, reply: FastifyReply): FastifyReply {\n return reply.status(status).send({ error: message });\n}\n\n/**\n * Fastify adapter utilities.\n *\n * @example Basic usage\n * ```typescript\n * import Fastify from 'fastify';\n * import { llm } from '@providerprotocol/ai';\n * import { anthropic } from '@providerprotocol/ai/anthropic';\n * import { parseBody } from '@providerprotocol/ai/proxy';\n * import { fastify as fastifyAdapter } from '@providerprotocol/ai/proxy/server';\n *\n * const app = Fastify();\n *\n * app.post('/api/ai', async (request, reply) => {\n * const { messages, system, params } = parseBody(request.body);\n * const instance = llm({ model: anthropic('claude-sonnet-4-20250514'), system });\n *\n * if (request.headers.accept?.includes('text/event-stream')) {\n * return fastifyAdapter.streamSSE(instance.stream(messages), reply);\n * } else {\n * const turn = await instance.generate(messages);\n * return fastifyAdapter.sendJSON(turn, reply);\n * }\n * });\n * ```\n *\n * @example API Gateway with authentication\n * ```typescript\n * import Fastify from 'fastify';\n * import { llm } from '@providerprotocol/ai';\n * import { anthropic } from '@providerprotocol/ai/anthropic';\n * import { ExponentialBackoff, RoundRobinKeys } from '@providerprotocol/ai/http';\n * import { parseBody } from '@providerprotocol/ai/proxy';\n * import { fastify as fastifyAdapter } from '@providerprotocol/ai/proxy/server';\n *\n * const app = Fastify();\n *\n * // Server manages AI provider keys - users never see them\n * const claude = llm({\n * model: anthropic('claude-sonnet-4-20250514'),\n * config: {\n * apiKey: new RoundRobinKeys([process.env.ANTHROPIC_KEY_1!, process.env.ANTHROPIC_KEY_2!]),\n * retryStrategy: new ExponentialBackoff({ maxAttempts: 3 }),\n * },\n * });\n *\n * // Auth hook for your platform\n * app.addHook('preHandler', async (request, reply) => {\n * const token = request.headers.authorization?.replace('Bearer ', '');\n * const user = await validatePlatformToken(token);\n * if (!user) {\n * reply.status(401).send({ error: 'Unauthorized' });\n * return;\n * }\n * request.user = user;\n * });\n *\n * app.post('/api/ai', async (request, reply) => {\n * // Track usage per user\n * // await trackUsage(request.user.id);\n *\n * const { messages, system, params } = parseBody(request.body);\n *\n * if (params?.stream) {\n * return fastifyAdapter.streamSSE(claude.stream(messages, { system }), reply);\n * }\n * const turn = await claude.generate(messages, { system });\n * return fastifyAdapter.sendJSON(turn, reply);\n * });\n * ```\n */\nexport const fastify = {\n sendJSON,\n sendEmbeddingJSON,\n sendImageJSON,\n streamSSE,\n streamImageSSE,\n sendError,\n};\n"],"mappings":";;;;;;;;;AA0CO,SAAS,SAAS,MAAY,OAAmC;AACtE,SAAO,MACJ,OAAO,gBAAgB,kBAAkB,EACzC,KAAK,cAAc,IAAI,CAAC;AAC7B;AAQO,SAAS,kBAAkB,QAAyB,OAAmC;AAC5F,SAAO,MACJ,OAAO,gBAAgB,kBAAkB,EACzC,KAAK,MAAM;AAChB;AAQO,SAAS,cAAc,QAAqB,OAAmC;AACpF,SAAO,MACJ,OAAO,gBAAgB,kBAAkB,EACzC,KAAK,qBAAqB,MAAM,CAAC;AACtC;AAcO,SAAS,UAAU,QAAsB,OAAmC;AACjF,QACG,OAAO,gBAAgB,mBAAmB,EAC1C,OAAO,iBAAiB,UAAU,EAClC,OAAO,cAAc,YAAY;AAEpC,QAAM,MAAM,MAAM;AAElB,GAAC,YAAY;AACX,QAAI;AACF,uBAAiB,SAAS,QAAQ;AAChC,cAAM,aAAa,qBAAqB,KAAK;AAC7C,YAAI,MAAM,SAAS,KAAK,UAAU,UAAU,CAAC;AAAA;AAAA,CAAM;AAAA,MACrD;AAEA,YAAM,OAAO,MAAM,OAAO;AAC1B,UAAI,MAAM,SAAS,KAAK,UAAU,cAAc,IAAI,CAAC,CAAC;AAAA;AAAA,CAAM;AAC5D,UAAI,MAAM,kBAAkB;AAAA,IAC9B,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAI,MAAM,SAAS,KAAK,UAAU,EAAE,OAAO,QAAQ,CAAC,CAAC;AAAA;AAAA,CAAM;AAAA,IAC7D,UAAE;AACA,UAAI,IAAI;AAAA,IACV;AAAA,EACF,GAAG;AAEH,SAAO;AACT;AAQO,SAAS,eAAe,QAAyB,OAAmC;AACzF,QACG,OAAO,gBAAgB,mBAAmB,EAC1C,OAAO,iBAAiB,UAAU,EAClC,OAAO,cAAc,YAAY;AAEpC,QAAM,MAAM,MAAM;AAElB,GAAC,YAAY;AACX,QAAI;AACF,uBAAiB,SAAS,QAAQ;AAChC,cAAM,aAAa,0BAA0B,KAAK;AAClD,YAAI,MAAM,SAAS,KAAK,UAAU,UAAU,CAAC;AAAA;AAAA,CAAM;AAAA,MACrD;AAEA,YAAM,SAAS,MAAM,mBAAmB,MAAM;AAC9C,UAAI,MAAM,SAAS,KAAK,UAAU,qBAAqB,MAAM,CAAC,CAAC;AAAA;AAAA,CAAM;AACrE,UAAI,MAAM,kBAAkB;AAAA,IAC9B,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAI,MAAM,SAAS,KAAK,UAAU,EAAE,OAAO,QAAQ,CAAC,CAAC;AAAA;AAAA,CAAM;AAAA,IAC7D,UAAE;AACA,UAAI,IAAI;AAAA,IACV;AAAA,EACF,GAAG;AAEH,SAAO;AACT;AASO,SAAS,UAAU,SAAiB,QAAgB,OAAmC;AAC5F,SAAO,MAAM,OAAO,MAAM,EAAE,KAAK,EAAE,OAAO,QAAQ,CAAC;AACrD;AAyEO,IAAM,UAAU;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;","names":[]}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deserializeEmbeddingInput,
|
|
3
|
+
deserializeImage,
|
|
4
|
+
deserializeMessage,
|
|
5
|
+
resolveImageResult,
|
|
6
|
+
serializeImageResult,
|
|
7
|
+
serializeImageStreamEvent,
|
|
8
|
+
serializeStreamEvent,
|
|
9
|
+
serializeTurn
|
|
10
|
+
} from "./chunk-C4JP64VW.js";
|
|
11
|
+
|
|
12
|
+
// src/providers/proxy/server/webapi.ts
|
|
13
|
+
function parseBody(body) {
|
|
14
|
+
if (!body || typeof body !== "object") {
|
|
15
|
+
throw new Error("Request body must be an object");
|
|
16
|
+
}
|
|
17
|
+
const data = body;
|
|
18
|
+
if (!Array.isArray(data.messages)) {
|
|
19
|
+
throw new Error("Request body must have a messages array");
|
|
20
|
+
}
|
|
21
|
+
for (const message of data.messages) {
|
|
22
|
+
if (!message || typeof message !== "object") {
|
|
23
|
+
throw new Error("Each message must be an object");
|
|
24
|
+
}
|
|
25
|
+
const msg = message;
|
|
26
|
+
if (typeof msg.id !== "string") {
|
|
27
|
+
throw new Error("Each message must have a string id");
|
|
28
|
+
}
|
|
29
|
+
if (typeof msg.type !== "string") {
|
|
30
|
+
throw new Error("Each message must have a string type");
|
|
31
|
+
}
|
|
32
|
+
if (typeof msg.timestamp !== "string") {
|
|
33
|
+
throw new Error("Each message must have a string timestamp");
|
|
34
|
+
}
|
|
35
|
+
if ((msg.type === "user" || msg.type === "assistant") && !Array.isArray(msg.content)) {
|
|
36
|
+
throw new Error("User and assistant messages must have a content array");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
messages: data.messages.map(deserializeMessage),
|
|
41
|
+
system: data.system,
|
|
42
|
+
params: data.params,
|
|
43
|
+
model: typeof data.model === "string" ? data.model : void 0,
|
|
44
|
+
tools: data.tools,
|
|
45
|
+
structure: data.structure
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function parseEmbeddingBody(body) {
|
|
49
|
+
if (!body || typeof body !== "object") {
|
|
50
|
+
throw new Error("Request body must be an object");
|
|
51
|
+
}
|
|
52
|
+
const data = body;
|
|
53
|
+
if (!Array.isArray(data.inputs)) {
|
|
54
|
+
throw new Error("Request body must have an inputs array");
|
|
55
|
+
}
|
|
56
|
+
const inputs = data.inputs.map(
|
|
57
|
+
(input) => deserializeEmbeddingInput(input)
|
|
58
|
+
);
|
|
59
|
+
return {
|
|
60
|
+
inputs,
|
|
61
|
+
params: data.params,
|
|
62
|
+
model: typeof data.model === "string" ? data.model : void 0
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function parseImageBody(body) {
|
|
66
|
+
if (!body || typeof body !== "object") {
|
|
67
|
+
throw new Error("Request body must be an object");
|
|
68
|
+
}
|
|
69
|
+
const data = body;
|
|
70
|
+
const promptValue = data.prompt;
|
|
71
|
+
let prompt;
|
|
72
|
+
if (typeof promptValue === "string") {
|
|
73
|
+
prompt = promptValue;
|
|
74
|
+
} else if (promptValue && typeof promptValue === "object") {
|
|
75
|
+
const promptObj = promptValue;
|
|
76
|
+
if (typeof promptObj.prompt === "string") {
|
|
77
|
+
prompt = promptObj.prompt;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (!prompt) {
|
|
81
|
+
throw new Error("Request body must have a prompt string");
|
|
82
|
+
}
|
|
83
|
+
const image = data.image ? deserializeImage(data.image) : void 0;
|
|
84
|
+
const mask = data.mask ? deserializeImage(data.mask) : void 0;
|
|
85
|
+
return {
|
|
86
|
+
prompt,
|
|
87
|
+
params: data.params,
|
|
88
|
+
model: typeof data.model === "string" ? data.model : void 0,
|
|
89
|
+
image,
|
|
90
|
+
mask
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function toJSON(turn) {
|
|
94
|
+
return new Response(JSON.stringify(serializeTurn(turn)), {
|
|
95
|
+
headers: { "Content-Type": "application/json" }
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function toEmbeddingJSON(result) {
|
|
99
|
+
return new Response(JSON.stringify(result), {
|
|
100
|
+
headers: { "Content-Type": "application/json" }
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function toImageJSON(result) {
|
|
104
|
+
return new Response(JSON.stringify(serializeImageResult(result)), {
|
|
105
|
+
headers: { "Content-Type": "application/json" }
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
function toSSE(stream) {
|
|
109
|
+
const encoder = new TextEncoder();
|
|
110
|
+
const readable = new ReadableStream({
|
|
111
|
+
async start(controller) {
|
|
112
|
+
try {
|
|
113
|
+
for await (const event of stream) {
|
|
114
|
+
const serialized = serializeStreamEvent(event);
|
|
115
|
+
const data = `data: ${JSON.stringify(serialized)}
|
|
116
|
+
|
|
117
|
+
`;
|
|
118
|
+
controller.enqueue(encoder.encode(data));
|
|
119
|
+
}
|
|
120
|
+
const turn = await stream.turn;
|
|
121
|
+
const turnData = serializeTurn(turn);
|
|
122
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(turnData)}
|
|
123
|
+
|
|
124
|
+
`));
|
|
125
|
+
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
|
|
126
|
+
controller.close();
|
|
127
|
+
} catch (error) {
|
|
128
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
129
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ error: errorMsg })}
|
|
130
|
+
|
|
131
|
+
`));
|
|
132
|
+
controller.close();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
return new Response(readable, {
|
|
137
|
+
headers: {
|
|
138
|
+
"Content-Type": "text/event-stream",
|
|
139
|
+
"Cache-Control": "no-cache",
|
|
140
|
+
Connection: "keep-alive"
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function toImageSSE(stream) {
|
|
145
|
+
const encoder = new TextEncoder();
|
|
146
|
+
const readable = new ReadableStream({
|
|
147
|
+
async start(controller) {
|
|
148
|
+
try {
|
|
149
|
+
for await (const event of stream) {
|
|
150
|
+
const serialized = serializeImageStreamEvent(event);
|
|
151
|
+
const data = `data: ${JSON.stringify(serialized)}
|
|
152
|
+
|
|
153
|
+
`;
|
|
154
|
+
controller.enqueue(encoder.encode(data));
|
|
155
|
+
}
|
|
156
|
+
const result = await resolveImageResult(stream);
|
|
157
|
+
const resultData = serializeImageResult(result);
|
|
158
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(resultData)}
|
|
159
|
+
|
|
160
|
+
`));
|
|
161
|
+
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
|
|
162
|
+
controller.close();
|
|
163
|
+
} catch (error) {
|
|
164
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
165
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ error: errorMsg })}
|
|
166
|
+
|
|
167
|
+
`));
|
|
168
|
+
controller.close();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
return new Response(readable, {
|
|
173
|
+
headers: {
|
|
174
|
+
"Content-Type": "text/event-stream",
|
|
175
|
+
"Cache-Control": "no-cache",
|
|
176
|
+
Connection: "keep-alive"
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function toError(message, status = 500) {
|
|
181
|
+
return new Response(JSON.stringify({ error: message }), {
|
|
182
|
+
status,
|
|
183
|
+
headers: { "Content-Type": "application/json" }
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
function bindTools(schemas, implementations) {
|
|
187
|
+
if (!schemas) return [];
|
|
188
|
+
return schemas.map((schema) => {
|
|
189
|
+
const run = implementations[schema.name];
|
|
190
|
+
if (!run) {
|
|
191
|
+
throw new Error(`No implementation for tool: ${schema.name}`);
|
|
192
|
+
}
|
|
193
|
+
return { ...schema, run };
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
var webapi = {
|
|
197
|
+
parseBody,
|
|
198
|
+
parseEmbeddingBody,
|
|
199
|
+
parseImageBody,
|
|
200
|
+
toJSON,
|
|
201
|
+
toEmbeddingJSON,
|
|
202
|
+
toImageJSON,
|
|
203
|
+
toSSE,
|
|
204
|
+
toImageSSE,
|
|
205
|
+
toError,
|
|
206
|
+
bindTools
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export {
|
|
210
|
+
parseBody,
|
|
211
|
+
parseEmbeddingBody,
|
|
212
|
+
parseImageBody,
|
|
213
|
+
toJSON,
|
|
214
|
+
toEmbeddingJSON,
|
|
215
|
+
toImageJSON,
|
|
216
|
+
toSSE,
|
|
217
|
+
toImageSSE,
|
|
218
|
+
toError,
|
|
219
|
+
bindTools,
|
|
220
|
+
webapi
|
|
221
|
+
};
|
|
222
|
+
//# sourceMappingURL=chunk-VGKZIGVI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/proxy/server/webapi.ts"],"sourcesContent":["/**\n * @fileoverview Web API adapter for proxy server.\n *\n * Provides utilities for using PP proxy with Web API native frameworks\n * (Bun, Deno, Next.js App Router, Cloudflare Workers).\n *\n * These utilities return standard Web API Response objects that work\n * directly with modern runtimes.\n *\n * @module providers/proxy/server/webapi\n */\n\nimport type { Message } from '../../../types/messages.ts';\nimport type { EmbeddingInput } from '../../../types/provider.ts';\nimport type { Turn } from '../../../types/turn.ts';\nimport type { StreamResult } from '../../../types/stream.ts';\nimport type { MessageJSON } from '../../../types/messages.ts';\nimport type { JSONSchema } from '../../../types/schema.ts';\nimport type { Tool, ToolMetadata } from '../../../types/tool.ts';\nimport type { EmbeddingResult } from '../../../types/embedding.ts';\nimport type { ImageResult } from '../../../types/image.ts';\nimport {\n deserializeMessage,\n serializeTurn,\n serializeStreamEvent,\n} from '../serialization.ts';\nimport {\n deserializeEmbeddingInput,\n deserializeImage,\n serializeImageResult,\n serializeImageStreamEvent,\n type SerializedEmbeddingInput,\n type SerializedImage,\n} from '../serialization.media.ts';\nimport { resolveImageResult, type ImageStreamLike } from './image-stream.ts';\n\n/**\n * Parsed request body from a proxy HTTP request.\n * This is just the deserialized PP data from the request body.\n */\nexport interface ParsedRequest {\n messages: Message[];\n system?: string | unknown[];\n params?: Record<string, unknown>;\n model?: string;\n tools?: Array<{\n name: string;\n description: string;\n parameters: JSONSchema;\n metadata?: ToolMetadata;\n }>;\n structure?: JSONSchema;\n}\n\n/**\n * Parsed request body for embedding endpoints.\n */\nexport interface ParsedEmbeddingRequest {\n inputs: EmbeddingInput[];\n params?: Record<string, unknown>;\n model?: string;\n}\n\n/**\n * Parsed request body for image endpoints.\n */\nexport interface ParsedImageRequest {\n prompt: string;\n params?: Record<string, unknown>;\n model?: string;\n image?: ReturnType<typeof deserializeImage>;\n mask?: ReturnType<typeof deserializeImage>;\n}\n\n/**\n * Parse an HTTP request body into PP types.\n *\n * @param body - The JSON-parsed request body\n * @returns Deserialized PP data\n *\n * @example\n * ```typescript\n * const body = await req.json();\n * const { messages, system, params } = parseBody(body);\n *\n * const instance = llm({ model: anthropic('...'), system, params });\n * const turn = await instance.generate(messages);\n * ```\n */\nexport function parseBody(body: unknown): ParsedRequest {\n if (!body || typeof body !== 'object') {\n throw new Error('Request body must be an object');\n }\n\n const data = body as Record<string, unknown>;\n\n if (!Array.isArray(data.messages)) {\n throw new Error('Request body must have a messages array');\n }\n\n for (const message of data.messages) {\n if (!message || typeof message !== 'object') {\n throw new Error('Each message must be an object');\n }\n const msg = message as Record<string, unknown>;\n if (typeof msg.id !== 'string') {\n throw new Error('Each message must have a string id');\n }\n if (typeof msg.type !== 'string') {\n throw new Error('Each message must have a string type');\n }\n if (typeof msg.timestamp !== 'string') {\n throw new Error('Each message must have a string timestamp');\n }\n if ((msg.type === 'user' || msg.type === 'assistant') && !Array.isArray(msg.content)) {\n throw new Error('User and assistant messages must have a content array');\n }\n }\n\n return {\n messages: (data.messages as MessageJSON[]).map(deserializeMessage),\n system: data.system as string | unknown[] | undefined,\n params: data.params as Record<string, unknown> | undefined,\n model: typeof data.model === 'string' ? data.model : undefined,\n tools: data.tools as ParsedRequest['tools'],\n structure: data.structure as JSONSchema | undefined,\n };\n}\n\n/**\n * Parse an HTTP request body into embedding inputs.\n *\n * @param body - The JSON-parsed request body\n * @returns Parsed embedding request data\n */\nexport function parseEmbeddingBody(body: unknown): ParsedEmbeddingRequest {\n if (!body || typeof body !== 'object') {\n throw new Error('Request body must be an object');\n }\n\n const data = body as Record<string, unknown>;\n\n if (!Array.isArray(data.inputs)) {\n throw new Error('Request body must have an inputs array');\n }\n\n const inputs = data.inputs.map((input) =>\n deserializeEmbeddingInput(input as SerializedEmbeddingInput)\n );\n\n return {\n inputs,\n params: data.params as Record<string, unknown> | undefined,\n model: typeof data.model === 'string' ? data.model : undefined,\n };\n}\n\n/**\n * Parse an HTTP request body into image request data.\n *\n * @param body - The JSON-parsed request body\n * @returns Parsed image request data\n */\nexport function parseImageBody(body: unknown): ParsedImageRequest {\n if (!body || typeof body !== 'object') {\n throw new Error('Request body must be an object');\n }\n\n const data = body as Record<string, unknown>;\n const promptValue = data.prompt;\n\n let prompt: string | undefined;\n if (typeof promptValue === 'string') {\n prompt = promptValue;\n } else if (promptValue && typeof promptValue === 'object') {\n const promptObj = promptValue as Record<string, unknown>;\n if (typeof promptObj.prompt === 'string') {\n prompt = promptObj.prompt;\n }\n }\n\n if (!prompt) {\n throw new Error('Request body must have a prompt string');\n }\n\n const image = data.image ? deserializeImage(data.image as SerializedImage) : undefined;\n const mask = data.mask ? deserializeImage(data.mask as SerializedImage) : undefined;\n\n return {\n prompt,\n params: data.params as Record<string, unknown> | undefined,\n model: typeof data.model === 'string' ? data.model : undefined,\n image,\n mask,\n };\n}\n\n/**\n * Create a JSON Response from a Turn.\n *\n * @param turn - The completed inference turn\n * @returns HTTP Response with JSON body\n *\n * @example\n * ```typescript\n * const turn = await instance.generate(messages);\n * return toJSON(turn);\n * ```\n */\nexport function toJSON(turn: Turn): Response {\n return new Response(JSON.stringify(serializeTurn(turn)), {\n headers: { 'Content-Type': 'application/json' },\n });\n}\n\n/**\n * Create a JSON Response from an embedding result.\n *\n * @param result - The embedding result\n * @returns HTTP Response with JSON body\n */\nexport function toEmbeddingJSON(result: EmbeddingResult): Response {\n return new Response(JSON.stringify(result), {\n headers: { 'Content-Type': 'application/json' },\n });\n}\n\n/**\n * Create a JSON Response from an image result.\n *\n * @param result - The image result\n * @returns HTTP Response with JSON body\n */\nexport function toImageJSON(result: ImageResult): Response {\n return new Response(JSON.stringify(serializeImageResult(result)), {\n headers: { 'Content-Type': 'application/json' },\n });\n}\n\n/**\n * Create an SSE Response from a StreamResult.\n *\n * Streams PP StreamEvents as SSE, then sends the final Turn data.\n *\n * @param stream - The StreamResult from instance.stream()\n * @returns HTTP Response with SSE body\n *\n * @example\n * ```typescript\n * const stream = instance.stream(messages);\n * return toSSE(stream);\n * ```\n */\nexport function toSSE(stream: StreamResult): Response {\n const encoder = new TextEncoder();\n\n const readable = new ReadableStream({\n async start(controller) {\n try {\n for await (const event of stream) {\n const serialized = serializeStreamEvent(event);\n const data = `data: ${JSON.stringify(serialized)}\\n\\n`;\n controller.enqueue(encoder.encode(data));\n }\n\n // Send the final turn data\n const turn = await stream.turn;\n const turnData = serializeTurn(turn);\n controller.enqueue(encoder.encode(`data: ${JSON.stringify(turnData)}\\n\\n`));\n controller.enqueue(encoder.encode('data: [DONE]\\n\\n'));\n controller.close();\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n controller.enqueue(encoder.encode(`data: ${JSON.stringify({ error: errorMsg })}\\n\\n`));\n controller.close();\n }\n },\n });\n\n return new Response(readable, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n },\n });\n}\n\n/**\n * Create an SSE Response from an ImageStreamResult.\n *\n * Streams image events as SSE, then sends the final image result.\n *\n * @param stream - The ImageStreamResult or ImageProviderStreamResult from image().stream()\n * @returns HTTP Response with SSE body\n */\nexport function toImageSSE(stream: ImageStreamLike): Response {\n const encoder = new TextEncoder();\n\n const readable = new ReadableStream({\n async start(controller) {\n try {\n for await (const event of stream) {\n const serialized = serializeImageStreamEvent(event);\n const data = `data: ${JSON.stringify(serialized)}\\n\\n`;\n controller.enqueue(encoder.encode(data));\n }\n\n const result = await resolveImageResult(stream);\n const resultData = serializeImageResult(result);\n controller.enqueue(encoder.encode(`data: ${JSON.stringify(resultData)}\\n\\n`));\n controller.enqueue(encoder.encode('data: [DONE]\\n\\n'));\n controller.close();\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n controller.enqueue(encoder.encode(`data: ${JSON.stringify({ error: errorMsg })}\\n\\n`));\n controller.close();\n }\n },\n });\n\n return new Response(readable, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n },\n });\n}\n\n/**\n * Create an error Response.\n *\n * @param message - Error message\n * @param status - HTTP status code (default: 500)\n * @returns HTTP Response with error body\n */\nexport function toError(message: string, status = 500): Response {\n return new Response(JSON.stringify({ error: message }), {\n status,\n headers: { 'Content-Type': 'application/json' },\n });\n}\n\n/**\n * Bind tool schemas to implementation functions.\n *\n * Takes tool schemas from the request and binds them to your\n * server-side implementations.\n *\n * @param schemas - Tool schemas from the request\n * @param implementations - Map of tool name to implementation\n * @returns Array of complete Tool objects\n *\n * @example\n * ```typescript\n * const { tools: schemas } = parseBody(body);\n *\n * const tools = bindTools(schemas, {\n * get_weather: async ({ location }) => fetchWeather(location),\n * search: async ({ query }) => searchDB(query),\n * });\n *\n * const instance = llm({ model, tools });\n * ```\n */\nexport function bindTools(\n schemas: ParsedRequest['tools'],\n implementations: Record<string, (params: unknown) => unknown | Promise<unknown>>\n): Tool[] {\n if (!schemas) return [];\n\n return schemas.map((schema) => {\n const run = implementations[schema.name];\n if (!run) {\n throw new Error(`No implementation for tool: ${schema.name}`);\n }\n return { ...schema, run };\n });\n}\n\n/**\n * Web API adapter utilities.\n *\n * For use with Bun, Deno, Next.js App Router, Cloudflare Workers,\n * and other frameworks that support Web API Response.\n *\n * **Security Note:** The proxy works without configuration, meaning no\n * authentication by default. Always add your own auth layer in production.\n *\n * @example Basic usage\n * ```typescript\n * import { llm } from '@providerprotocol/ai';\n * import { anthropic } from '@providerprotocol/ai/anthropic';\n * import { parseBody, toJSON, toSSE } from '@providerprotocol/ai/proxy';\n *\n * // Bun.serve / Deno.serve / Next.js App Router\n * export async function POST(req: Request) {\n * const { messages, system } = parseBody(await req.json());\n * const instance = llm({ model: anthropic('claude-sonnet-4-20250514'), system });\n *\n * if (req.headers.get('accept')?.includes('text/event-stream')) {\n * return toSSE(instance.stream(messages));\n * }\n * return toJSON(await instance.generate(messages));\n * }\n * ```\n *\n * @example API Gateway with authentication\n * ```typescript\n * import { llm } from '@providerprotocol/ai';\n * import { anthropic } from '@providerprotocol/ai/anthropic';\n * import { ExponentialBackoff, RoundRobinKeys } from '@providerprotocol/ai/http';\n * import { parseBody, toJSON, toSSE, toError } from '@providerprotocol/ai/proxy';\n *\n * // Your platform's user validation\n * async function validateToken(token: string): Promise<{ id: string } | null> {\n * // Verify JWT, check database, etc.\n * return token ? { id: 'user-123' } : null;\n * }\n *\n * // Server manages AI provider keys - users never see them\n * const claude = llm({\n * model: anthropic('claude-sonnet-4-20250514'),\n * config: {\n * apiKey: new RoundRobinKeys([process.env.ANTHROPIC_KEY_1!, process.env.ANTHROPIC_KEY_2!]),\n * retryStrategy: new ExponentialBackoff({ maxAttempts: 3 }),\n * },\n * });\n *\n * Bun.serve({\n * port: 3000,\n * async fetch(req) {\n * // Authenticate with YOUR platform credentials\n * const token = req.headers.get('Authorization')?.replace('Bearer ', '');\n * const user = await validateToken(token ?? '');\n * if (!user) return toError('Unauthorized', 401);\n *\n * // Rate limit, track usage, bill user, etc.\n * // await trackUsage(user.id);\n *\n * const { messages, system, params } = parseBody(await req.json());\n *\n * if (params?.stream) {\n * return toSSE(claude.stream(messages, { system }));\n * }\n * return toJSON(await claude.generate(messages, { system }));\n * },\n * });\n * ```\n */\nexport const webapi = {\n parseBody,\n parseEmbeddingBody,\n parseImageBody,\n toJSON,\n toEmbeddingJSON,\n toImageJSON,\n toSSE,\n toImageSSE,\n toError,\n bindTools,\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ErrorCode
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-COS4ON4G.js";
|
|
4
4
|
|
|
5
5
|
// src/http/retry.ts
|
|
6
6
|
var ExponentialBackoff = class {
|
|
@@ -260,4 +260,4 @@ export {
|
|
|
260
260
|
TokenBucket,
|
|
261
261
|
RetryAfterStrategy
|
|
262
262
|
};
|
|
263
|
-
//# sourceMappingURL=chunk-
|
|
263
|
+
//# sourceMappingURL=chunk-Y5H7C5J4.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { P as ProviderIdentity, b as ProviderConfig, M as Middleware, E as EmbeddingInput, c as EmbeddingUsage, B as BoundEmbeddingModel } from './llm-ByUFPcFH.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @fileoverview Embedding types for vector embedding generation.
|
package/dist/google/index.d.ts
CHANGED