@providerprotocol/ai 0.0.33 → 0.0.35
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 +542 -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-3GWM5GR3.js +153 -0
- package/dist/chunk-3GWM5GR3.js.map +1 -0
- package/dist/chunk-4OGB7JZA.js +157 -0
- package/dist/chunk-4OGB7JZA.js.map +1 -0
- package/dist/chunk-7DXVRILR.js +49 -0
- package/dist/chunk-7DXVRILR.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-ETBFOLQN.js +34 -0
- package/dist/chunk-ETBFOLQN.js.map +1 -0
- package/dist/chunk-HB4ZIH3T.js +31 -0
- package/dist/chunk-HB4ZIH3T.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-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-VOEWHQUB.js +31 -0
- package/dist/chunk-VOEWHQUB.js.map +1 -0
- package/dist/{chunk-KUPF5KHT.js → chunk-Y5H7C5J4.js} +2 -2
- package/dist/chunk-ZI67WIQS.js +30 -0
- package/dist/chunk-ZI67WIQS.js.map +1 -0
- package/dist/{embedding-D2BYIehX.d.ts → embedding-CW6SaOOz.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-C0ciACM2.d.ts +11 -0
- package/dist/index.d.ts +8 -118
- package/dist/index.js +518 -767
- package/dist/index.js.map +1 -1
- package/dist/{llm-BQJZj3cD.d.ts → llm-DwbUK7un.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 +104 -0
- package/dist/middleware/pubsub/index.js +230 -0
- package/dist/middleware/pubsub/index.js.map +1 -0
- package/dist/middleware/pubsub/server/express/index.d.ts +52 -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 +53 -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 +56 -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 +53 -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 +379 -383
- 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-YayV42GV.d.ts} +1 -1
- package/dist/stream-CecfVCPO.d.ts +1632 -0
- package/dist/types-C8Gciizr.d.ts +168 -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 +94 -4
- package/dist/chunk-4J6OFUKX.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,76 @@
|
|
|
1
|
+
import { M as Middleware } from '../../llm-DwbUK7un.js';
|
|
2
|
+
import '../../stream-CecfVCPO.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @fileoverview Logging middleware for request/response visibility.
|
|
6
|
+
*
|
|
7
|
+
* Provides configurable logging for LLM, embedding, and image operations,
|
|
8
|
+
* including timing, error tracking, and optional event logging.
|
|
9
|
+
*
|
|
10
|
+
* @module middleware/logging
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Log levels for filtering output.
|
|
15
|
+
*/
|
|
16
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
17
|
+
/**
|
|
18
|
+
* Options for logging middleware.
|
|
19
|
+
*/
|
|
20
|
+
interface LoggingOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Minimum log level to output.
|
|
23
|
+
* @default 'info'
|
|
24
|
+
*/
|
|
25
|
+
level?: LogLevel;
|
|
26
|
+
/**
|
|
27
|
+
* Log individual stream events.
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
logStreamEvents?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Log tool calls and results.
|
|
33
|
+
* @default true
|
|
34
|
+
*/
|
|
35
|
+
logToolCalls?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Custom logger function. If not provided, uses console.log.
|
|
38
|
+
* @param level - The log level
|
|
39
|
+
* @param message - The log message
|
|
40
|
+
* @param data - Optional additional data
|
|
41
|
+
*/
|
|
42
|
+
logger?(level: LogLevel, message: string, data?: Record<string, unknown>): void;
|
|
43
|
+
/**
|
|
44
|
+
* Prefix for all log messages.
|
|
45
|
+
* @default '[PP]'
|
|
46
|
+
*/
|
|
47
|
+
prefix?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Creates a logging middleware for visibility into request lifecycle.
|
|
51
|
+
*
|
|
52
|
+
* This middleware logs the start, end, and errors of requests,
|
|
53
|
+
* with optional logging of stream events and tool calls.
|
|
54
|
+
*
|
|
55
|
+
* @param options - Configuration options
|
|
56
|
+
* @returns A middleware that logs request lifecycle events
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* import { llm } from '@providerprotocol/ai';
|
|
61
|
+
* import { loggingMiddleware } from '@providerprotocol/ai/middleware/logging';
|
|
62
|
+
* import { anthropic } from '@providerprotocol/ai/anthropic';
|
|
63
|
+
*
|
|
64
|
+
* const model = llm({
|
|
65
|
+
* model: anthropic('claude-sonnet-4-20250514'),
|
|
66
|
+
* middleware: [loggingMiddleware({ level: 'debug' })],
|
|
67
|
+
* });
|
|
68
|
+
*
|
|
69
|
+
* // Logs: [PP] [anthropic] Starting llm request (streaming)
|
|
70
|
+
* // Logs: [PP] [anthropic] Completed in 1234ms
|
|
71
|
+
* const result = await model.generate('Hello');
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
declare function loggingMiddleware(options?: LoggingOptions): Middleware;
|
|
75
|
+
|
|
76
|
+
export { type LogLevel, type LoggingOptions, loggingMiddleware };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// src/middleware/logging.ts
|
|
2
|
+
var LOG_LEVELS = {
|
|
3
|
+
debug: 0,
|
|
4
|
+
info: 1,
|
|
5
|
+
warn: 2,
|
|
6
|
+
error: 3
|
|
7
|
+
};
|
|
8
|
+
function loggingMiddleware(options = {}) {
|
|
9
|
+
const {
|
|
10
|
+
level = "info",
|
|
11
|
+
logStreamEvents = false,
|
|
12
|
+
logToolCalls = true,
|
|
13
|
+
logger,
|
|
14
|
+
prefix = "[PP]"
|
|
15
|
+
} = options;
|
|
16
|
+
const minLevel = LOG_LEVELS[level];
|
|
17
|
+
const log = (logLevel, message, data) => {
|
|
18
|
+
if (LOG_LEVELS[logLevel] < minLevel) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const fullMessage = `${prefix} ${message}`;
|
|
22
|
+
if (logger) {
|
|
23
|
+
logger(logLevel, fullMessage, data);
|
|
24
|
+
} else {
|
|
25
|
+
const consoleMethod = logLevel === "error" ? console.error : logLevel === "warn" ? console.warn : console.log;
|
|
26
|
+
if (data) {
|
|
27
|
+
consoleMethod(fullMessage, data);
|
|
28
|
+
} else {
|
|
29
|
+
consoleMethod(fullMessage);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
name: "logging",
|
|
35
|
+
onStart(ctx) {
|
|
36
|
+
const streamingLabel = ctx.streaming ? "(streaming)" : "";
|
|
37
|
+
log("info", `[${ctx.provider}] Starting ${ctx.modality} request ${streamingLabel}`.trim());
|
|
38
|
+
log("debug", `[${ctx.provider}] Model: ${ctx.modelId}`);
|
|
39
|
+
},
|
|
40
|
+
onEnd(ctx) {
|
|
41
|
+
const duration = ctx.endTime ? ctx.endTime - ctx.startTime : 0;
|
|
42
|
+
log("info", `[${ctx.provider}] Completed in ${duration}ms`);
|
|
43
|
+
},
|
|
44
|
+
onError(error, ctx) {
|
|
45
|
+
const duration = Date.now() - ctx.startTime;
|
|
46
|
+
log("error", `[${ctx.provider}] Error after ${duration}ms: ${error.message}`);
|
|
47
|
+
},
|
|
48
|
+
onAbort(error, ctx) {
|
|
49
|
+
const duration = Date.now() - ctx.startTime;
|
|
50
|
+
log("warn", `[${ctx.provider}] Aborted after ${duration}ms: ${error.message}`);
|
|
51
|
+
},
|
|
52
|
+
onStreamEvent(event, ctx) {
|
|
53
|
+
if (logStreamEvents) {
|
|
54
|
+
log("debug", `Stream event: ${event.type}`, { index: event.index });
|
|
55
|
+
}
|
|
56
|
+
return event;
|
|
57
|
+
},
|
|
58
|
+
onToolCall(tool, params, ctx) {
|
|
59
|
+
if (logToolCalls) {
|
|
60
|
+
log("info", `[${ctx.provider}] Tool call: ${tool.name}`);
|
|
61
|
+
log("debug", `[${ctx.provider}] Tool params:`, { params });
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
onToolResult(tool, result, ctx) {
|
|
65
|
+
if (logToolCalls) {
|
|
66
|
+
log("debug", `[${ctx.provider}] Tool result: ${tool.name}`, { result });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
loggingMiddleware
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/middleware/logging.ts"],"sourcesContent":["/**\n * @fileoverview Logging middleware for request/response visibility.\n *\n * Provides configurable logging for LLM, embedding, and image operations,\n * including timing, error tracking, and optional event logging.\n *\n * @module middleware/logging\n */\n\nimport type { Middleware, MiddlewareContext, StreamContext } from '../types/middleware.ts';\nimport type { StreamEvent } from '../types/stream.ts';\n\n/**\n * Log levels for filtering output.\n */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n/**\n * Options for logging middleware.\n */\nexport interface LoggingOptions {\n /**\n * Minimum log level to output.\n * @default 'info'\n */\n level?: LogLevel;\n\n /**\n * Log individual stream events.\n * @default false\n */\n logStreamEvents?: boolean;\n\n /**\n * Log tool calls and results.\n * @default true\n */\n logToolCalls?: boolean;\n\n /**\n * Custom logger function. If not provided, uses console.log.\n * @param level - The log level\n * @param message - The log message\n * @param data - Optional additional data\n */\n logger?(level: LogLevel, message: string, data?: Record<string, unknown>): void;\n\n /**\n * Prefix for all log messages.\n * @default '[PP]'\n */\n prefix?: string;\n}\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\n/**\n * Creates a logging middleware for visibility into request lifecycle.\n *\n * This middleware logs the start, end, and errors of requests,\n * with optional logging of stream events and tool calls.\n *\n * @param options - Configuration options\n * @returns A middleware that logs request lifecycle events\n *\n * @example\n * ```typescript\n * import { llm } from '@providerprotocol/ai';\n * import { loggingMiddleware } from '@providerprotocol/ai/middleware/logging';\n * import { anthropic } from '@providerprotocol/ai/anthropic';\n *\n * const model = llm({\n * model: anthropic('claude-sonnet-4-20250514'),\n * middleware: [loggingMiddleware({ level: 'debug' })],\n * });\n *\n * // Logs: [PP] [anthropic] Starting llm request (streaming)\n * // Logs: [PP] [anthropic] Completed in 1234ms\n * const result = await model.generate('Hello');\n * ```\n */\nexport function loggingMiddleware(options: LoggingOptions = {}): Middleware {\n const {\n level = 'info',\n logStreamEvents = false,\n logToolCalls = true,\n logger,\n prefix = '[PP]',\n } = options;\n\n const minLevel = LOG_LEVELS[level];\n\n const log = (logLevel: LogLevel, message: string, data?: Record<string, unknown>) => {\n if (LOG_LEVELS[logLevel] < minLevel) {\n return;\n }\n\n const fullMessage = `${prefix} ${message}`;\n\n if (logger) {\n logger(logLevel, fullMessage, data);\n } else {\n const consoleMethod = logLevel === 'error' ? console.error : logLevel === 'warn' ? console.warn : console.log;\n if (data) {\n consoleMethod(fullMessage, data);\n } else {\n consoleMethod(fullMessage);\n }\n }\n };\n\n return {\n name: 'logging',\n\n onStart(ctx: MiddlewareContext): void {\n const streamingLabel = ctx.streaming ? '(streaming)' : '';\n log('info', `[${ctx.provider}] Starting ${ctx.modality} request ${streamingLabel}`.trim());\n log('debug', `[${ctx.provider}] Model: ${ctx.modelId}`);\n },\n\n onEnd(ctx: MiddlewareContext): void {\n const duration = ctx.endTime ? ctx.endTime - ctx.startTime : 0;\n log('info', `[${ctx.provider}] Completed in ${duration}ms`);\n },\n\n onError(error: Error, ctx: MiddlewareContext): void {\n const duration = Date.now() - ctx.startTime;\n log('error', `[${ctx.provider}] Error after ${duration}ms: ${error.message}`);\n },\n\n onAbort(error: Error, ctx: MiddlewareContext): void {\n const duration = Date.now() - ctx.startTime;\n log('warn', `[${ctx.provider}] Aborted after ${duration}ms: ${error.message}`);\n },\n\n onStreamEvent(event: StreamEvent, ctx: StreamContext): StreamEvent {\n if (logStreamEvents) {\n log('debug', `Stream event: ${event.type}`, { index: event.index });\n }\n return event;\n },\n\n onToolCall(tool, params, ctx: MiddlewareContext): void {\n if (logToolCalls) {\n log('info', `[${ctx.provider}] Tool call: ${tool.name}`);\n log('debug', `[${ctx.provider}] Tool params:`, { params });\n }\n },\n\n onToolResult(tool, result, ctx: MiddlewareContext): void {\n if (logToolCalls) {\n log('debug', `[${ctx.provider}] Tool result: ${tool.name}`, { result });\n }\n },\n };\n}\n"],"mappings":";AAsDA,IAAM,aAAuC;AAAA,EAC3C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AA2BO,SAAS,kBAAkB,UAA0B,CAAC,GAAe;AAC1E,QAAM;AAAA,IACJ,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf;AAAA,IACA,SAAS;AAAA,EACX,IAAI;AAEJ,QAAM,WAAW,WAAW,KAAK;AAEjC,QAAM,MAAM,CAAC,UAAoB,SAAiB,SAAmC;AACnF,QAAI,WAAW,QAAQ,IAAI,UAAU;AACnC;AAAA,IACF;AAEA,UAAM,cAAc,GAAG,MAAM,IAAI,OAAO;AAExC,QAAI,QAAQ;AACV,aAAO,UAAU,aAAa,IAAI;AAAA,IACpC,OAAO;AACL,YAAM,gBAAgB,aAAa,UAAU,QAAQ,QAAQ,aAAa,SAAS,QAAQ,OAAO,QAAQ;AAC1G,UAAI,MAAM;AACR,sBAAc,aAAa,IAAI;AAAA,MACjC,OAAO;AACL,sBAAc,WAAW;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,QAAQ,KAA8B;AACpC,YAAM,iBAAiB,IAAI,YAAY,gBAAgB;AACvD,UAAI,QAAQ,IAAI,IAAI,QAAQ,cAAc,IAAI,QAAQ,YAAY,cAAc,GAAG,KAAK,CAAC;AACzF,UAAI,SAAS,IAAI,IAAI,QAAQ,YAAY,IAAI,OAAO,EAAE;AAAA,IACxD;AAAA,IAEA,MAAM,KAA8B;AAClC,YAAM,WAAW,IAAI,UAAU,IAAI,UAAU,IAAI,YAAY;AAC7D,UAAI,QAAQ,IAAI,IAAI,QAAQ,kBAAkB,QAAQ,IAAI;AAAA,IAC5D;AAAA,IAEA,QAAQ,OAAc,KAA8B;AAClD,YAAM,WAAW,KAAK,IAAI,IAAI,IAAI;AAClC,UAAI,SAAS,IAAI,IAAI,QAAQ,iBAAiB,QAAQ,OAAO,MAAM,OAAO,EAAE;AAAA,IAC9E;AAAA,IAEA,QAAQ,OAAc,KAA8B;AAClD,YAAM,WAAW,KAAK,IAAI,IAAI,IAAI;AAClC,UAAI,QAAQ,IAAI,IAAI,QAAQ,mBAAmB,QAAQ,OAAO,MAAM,OAAO,EAAE;AAAA,IAC/E;AAAA,IAEA,cAAc,OAAoB,KAAiC;AACjE,UAAI,iBAAiB;AACnB,YAAI,SAAS,iBAAiB,MAAM,IAAI,IAAI,EAAE,OAAO,MAAM,MAAM,CAAC;AAAA,MACpE;AACA,aAAO;AAAA,IACT;AAAA,IAEA,WAAW,MAAM,QAAQ,KAA8B;AACrD,UAAI,cAAc;AAChB,YAAI,QAAQ,IAAI,IAAI,QAAQ,gBAAgB,KAAK,IAAI,EAAE;AACvD,YAAI,SAAS,IAAI,IAAI,QAAQ,kBAAkB,EAAE,OAAO,CAAC;AAAA,MAC3D;AAAA,IACF;AAAA,IAEA,aAAa,MAAM,QAAQ,KAA8B;AACvD,UAAI,cAAc;AAChB,YAAI,SAAS,IAAI,IAAI,QAAQ,kBAAkB,KAAK,IAAI,IAAI,EAAE,OAAO,CAAC;AAAA,MACxE;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { M as Middleware } from '../../llm-DwbUK7un.js';
|
|
2
|
+
import { E as EventDelta, S as StreamEvent } from '../../stream-CecfVCPO.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @fileoverview Parsed object middleware for incremental JSON parsing.
|
|
6
|
+
*
|
|
7
|
+
* This middleware parses partial JSON from ObjectDelta and ToolCallDelta
|
|
8
|
+
* stream events, providing incremental structured data during streaming.
|
|
9
|
+
*
|
|
10
|
+
* @module middleware/parsed-object
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Event delta with parsed JSON data.
|
|
15
|
+
* Extended by parsedObjectMiddleware when parsing is enabled.
|
|
16
|
+
*/
|
|
17
|
+
interface ParsedEventDelta extends EventDelta {
|
|
18
|
+
/** Incrementally parsed JSON value */
|
|
19
|
+
parsed?: unknown;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Stream event with parsed JSON data.
|
|
23
|
+
* Returned by parsedObjectMiddleware for ObjectDelta and ToolCallDelta events.
|
|
24
|
+
*/
|
|
25
|
+
interface ParsedStreamEvent extends Omit<StreamEvent, 'delta'> {
|
|
26
|
+
delta: ParsedEventDelta;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Options for parsed object middleware.
|
|
30
|
+
*/
|
|
31
|
+
interface ParsedObjectOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Parse ObjectDelta events (structured output responses).
|
|
34
|
+
* @default true
|
|
35
|
+
*/
|
|
36
|
+
parseObjects?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Parse ToolCallDelta events (tool call arguments).
|
|
39
|
+
* @default true
|
|
40
|
+
*/
|
|
41
|
+
parseToolCalls?: boolean;
|
|
42
|
+
}
|
|
43
|
+
declare function parsedObjectMiddleware(options?: ParsedObjectOptions): Middleware;
|
|
44
|
+
|
|
45
|
+
export { type ParsedEventDelta, type ParsedObjectOptions, type ParsedStreamEvent, parsedObjectMiddleware };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parsePartialJson
|
|
3
|
+
} from "../../chunk-I53CI6ZZ.js";
|
|
4
|
+
import {
|
|
5
|
+
StreamEventType
|
|
6
|
+
} from "../../chunk-6S222DHN.js";
|
|
7
|
+
|
|
8
|
+
// src/middleware/parsed-object.ts
|
|
9
|
+
var ACCUMULATED_TEXT_KEY = "parsedObject:text";
|
|
10
|
+
var ACCUMULATED_ARGS_KEY = "parsedObject:args";
|
|
11
|
+
function getAccumulatedText(state) {
|
|
12
|
+
let map = state.get(ACCUMULATED_TEXT_KEY);
|
|
13
|
+
if (!map) {
|
|
14
|
+
map = /* @__PURE__ */ new Map();
|
|
15
|
+
state.set(ACCUMULATED_TEXT_KEY, map);
|
|
16
|
+
}
|
|
17
|
+
return map;
|
|
18
|
+
}
|
|
19
|
+
function getAccumulatedArgs(state) {
|
|
20
|
+
let map = state.get(ACCUMULATED_ARGS_KEY);
|
|
21
|
+
if (!map) {
|
|
22
|
+
map = /* @__PURE__ */ new Map();
|
|
23
|
+
state.set(ACCUMULATED_ARGS_KEY, map);
|
|
24
|
+
}
|
|
25
|
+
return map;
|
|
26
|
+
}
|
|
27
|
+
function parsedObjectMiddleware(options = {}) {
|
|
28
|
+
const { parseObjects = true, parseToolCalls = true } = options;
|
|
29
|
+
return {
|
|
30
|
+
name: "parsed-object",
|
|
31
|
+
onStreamEvent(event, ctx) {
|
|
32
|
+
if (parseObjects && event.type === StreamEventType.ObjectDelta) {
|
|
33
|
+
const accumulatedText = getAccumulatedText(ctx.state);
|
|
34
|
+
const current = accumulatedText.get(event.index) ?? "";
|
|
35
|
+
const newText = current + (event.delta.text ?? "");
|
|
36
|
+
accumulatedText.set(event.index, newText);
|
|
37
|
+
const parseResult = parsePartialJson(newText);
|
|
38
|
+
const parsedEvent = {
|
|
39
|
+
...event,
|
|
40
|
+
delta: {
|
|
41
|
+
...event.delta,
|
|
42
|
+
parsed: parseResult.value
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
return parsedEvent;
|
|
46
|
+
}
|
|
47
|
+
if (parseToolCalls && event.type === StreamEventType.ToolCallDelta) {
|
|
48
|
+
const accumulatedArgs = getAccumulatedArgs(ctx.state);
|
|
49
|
+
const current = accumulatedArgs.get(event.index) ?? "";
|
|
50
|
+
const newJson = current + (event.delta.argumentsJson ?? "");
|
|
51
|
+
accumulatedArgs.set(event.index, newJson);
|
|
52
|
+
const parseResult = parsePartialJson(newJson);
|
|
53
|
+
const parsedEvent = {
|
|
54
|
+
...event,
|
|
55
|
+
delta: {
|
|
56
|
+
...event.delta,
|
|
57
|
+
parsed: parseResult.value
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
return parsedEvent;
|
|
61
|
+
}
|
|
62
|
+
return event;
|
|
63
|
+
},
|
|
64
|
+
onStreamEnd(ctx) {
|
|
65
|
+
ctx.state.delete(ACCUMULATED_TEXT_KEY);
|
|
66
|
+
ctx.state.delete(ACCUMULATED_ARGS_KEY);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
parsedObjectMiddleware
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/middleware/parsed-object.ts"],"sourcesContent":["/**\n * @fileoverview Parsed object middleware for incremental JSON parsing.\n *\n * This middleware parses partial JSON from ObjectDelta and ToolCallDelta\n * stream events, providing incremental structured data during streaming.\n *\n * @module middleware/parsed-object\n */\n\nimport type { Middleware, StreamContext } from '../types/middleware.ts';\nimport type { EventDelta, StreamEvent } from '../types/stream.ts';\nimport { StreamEventType } from '../types/stream.ts';\nimport { parsePartialJson } from '../utils/partial-json.ts';\n\n/**\n * Event delta with parsed JSON data.\n * Extended by parsedObjectMiddleware when parsing is enabled.\n */\nexport interface ParsedEventDelta extends EventDelta {\n /** Incrementally parsed JSON value */\n parsed?: unknown;\n}\n\n/**\n * Stream event with parsed JSON data.\n * Returned by parsedObjectMiddleware for ObjectDelta and ToolCallDelta events.\n */\nexport interface ParsedStreamEvent extends Omit<StreamEvent, 'delta'> {\n delta: ParsedEventDelta;\n}\n\n/**\n * Options for parsed object middleware.\n */\nexport interface ParsedObjectOptions {\n /**\n * Parse ObjectDelta events (structured output responses).\n * @default true\n */\n parseObjects?: boolean;\n\n /**\n * Parse ToolCallDelta events (tool call arguments).\n * @default true\n */\n parseToolCalls?: boolean;\n}\n\n/**\n * Creates a middleware that parses partial JSON from stream events.\n *\n * This middleware accumulates text from ObjectDelta events and tool\n * argument JSON from ToolCallDelta events, then parses them incrementally\n * using partial JSON parsing. The parsed result is added to the event's\n * `parsed` field.\n *\n * @param options - Configuration options\n * @returns A middleware that adds parsed JSON to stream events\n *\n * @example\n * ```typescript\n * import { llm } from '@providerprotocol/ai';\n * import { parsedObjectMiddleware } from '@providerprotocol/ai/middleware/parsed-object';\n * import { anthropic } from '@providerprotocol/ai/anthropic';\n *\n * const model = llm({\n * model: anthropic('claude-sonnet-4-20250514'),\n * structure: mySchema,\n * middleware: [parsedObjectMiddleware()],\n * });\n *\n * for await (const event of model.stream('Extract data from this text')) {\n * if (event.type === 'object_delta') {\n * // event.delta.parsed contains incrementally parsed object\n * console.log(event.delta.parsed);\n * }\n * }\n * ```\n */\n/** State key for accumulated object text */\nconst ACCUMULATED_TEXT_KEY = 'parsedObject:text';\n/** State key for accumulated tool arguments */\nconst ACCUMULATED_ARGS_KEY = 'parsedObject:args';\n\n/**\n * Gets or creates the accumulated text map from state.\n */\nfunction getAccumulatedText(state: Map<string, unknown>): Map<number, string> {\n let map = state.get(ACCUMULATED_TEXT_KEY) as Map<number, string> | undefined;\n if (!map) {\n map = new Map();\n state.set(ACCUMULATED_TEXT_KEY, map);\n }\n return map;\n}\n\n/**\n * Gets or creates the accumulated args map from state.\n */\nfunction getAccumulatedArgs(state: Map<string, unknown>): Map<number, string> {\n let map = state.get(ACCUMULATED_ARGS_KEY) as Map<number, string> | undefined;\n if (!map) {\n map = new Map();\n state.set(ACCUMULATED_ARGS_KEY, map);\n }\n return map;\n}\n\nexport function parsedObjectMiddleware(options: ParsedObjectOptions = {}): Middleware {\n const { parseObjects = true, parseToolCalls = true } = options;\n\n return {\n name: 'parsed-object',\n\n onStreamEvent(event: StreamEvent, ctx: StreamContext): StreamEvent | StreamEvent[] | null {\n if (parseObjects && event.type === StreamEventType.ObjectDelta) {\n const accumulatedText = getAccumulatedText(ctx.state);\n const current = accumulatedText.get(event.index) ?? '';\n const newText = current + (event.delta.text ?? '');\n accumulatedText.set(event.index, newText);\n\n const parseResult = parsePartialJson(newText);\n\n const parsedEvent: ParsedStreamEvent = {\n ...event,\n delta: {\n ...event.delta,\n parsed: parseResult.value,\n },\n };\n return parsedEvent as StreamEvent;\n }\n\n if (parseToolCalls && event.type === StreamEventType.ToolCallDelta) {\n const accumulatedArgs = getAccumulatedArgs(ctx.state);\n const current = accumulatedArgs.get(event.index) ?? '';\n const newJson = current + (event.delta.argumentsJson ?? '');\n accumulatedArgs.set(event.index, newJson);\n\n const parseResult = parsePartialJson(newJson);\n\n const parsedEvent: ParsedStreamEvent = {\n ...event,\n delta: {\n ...event.delta,\n parsed: parseResult.value,\n },\n };\n return parsedEvent as StreamEvent;\n }\n\n return event;\n },\n\n onStreamEnd(ctx: StreamContext): void {\n // Clean up accumulated state to prevent memory buildup in long sessions\n ctx.state.delete(ACCUMULATED_TEXT_KEY);\n ctx.state.delete(ACCUMULATED_ARGS_KEY);\n },\n };\n}\n"],"mappings":";;;;;;;;AAgFA,IAAM,uBAAuB;AAE7B,IAAM,uBAAuB;AAK7B,SAAS,mBAAmB,OAAkD;AAC5E,MAAI,MAAM,MAAM,IAAI,oBAAoB;AACxC,MAAI,CAAC,KAAK;AACR,UAAM,oBAAI,IAAI;AACd,UAAM,IAAI,sBAAsB,GAAG;AAAA,EACrC;AACA,SAAO;AACT;AAKA,SAAS,mBAAmB,OAAkD;AAC5E,MAAI,MAAM,MAAM,IAAI,oBAAoB;AACxC,MAAI,CAAC,KAAK;AACR,UAAM,oBAAI,IAAI;AACd,UAAM,IAAI,sBAAsB,GAAG;AAAA,EACrC;AACA,SAAO;AACT;AAEO,SAAS,uBAAuB,UAA+B,CAAC,GAAe;AACpF,QAAM,EAAE,eAAe,MAAM,iBAAiB,KAAK,IAAI;AAEvD,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,cAAc,OAAoB,KAAwD;AACxF,UAAI,gBAAgB,MAAM,SAAS,gBAAgB,aAAa;AAC9D,cAAM,kBAAkB,mBAAmB,IAAI,KAAK;AACpD,cAAM,UAAU,gBAAgB,IAAI,MAAM,KAAK,KAAK;AACpD,cAAM,UAAU,WAAW,MAAM,MAAM,QAAQ;AAC/C,wBAAgB,IAAI,MAAM,OAAO,OAAO;AAExC,cAAM,cAAc,iBAAiB,OAAO;AAE5C,cAAM,cAAiC;AAAA,UACrC,GAAG;AAAA,UACH,OAAO;AAAA,YACL,GAAG,MAAM;AAAA,YACT,QAAQ,YAAY;AAAA,UACtB;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAEA,UAAI,kBAAkB,MAAM,SAAS,gBAAgB,eAAe;AAClE,cAAM,kBAAkB,mBAAmB,IAAI,KAAK;AACpD,cAAM,UAAU,gBAAgB,IAAI,MAAM,KAAK,KAAK;AACpD,cAAM,UAAU,WAAW,MAAM,MAAM,iBAAiB;AACxD,wBAAgB,IAAI,MAAM,OAAO,OAAO;AAExC,cAAM,cAAc,iBAAiB,OAAO;AAE5C,cAAM,cAAiC;AAAA,UACrC,GAAG;AAAA,UACH,OAAO;AAAA,YACL,GAAG,MAAM;AAAA,YACT,QAAQ,YAAY;AAAA,UACtB;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT;AAAA,IAEA,YAAY,KAA0B;AAEpC,UAAI,MAAM,OAAO,oBAAoB;AACrC,UAAI,MAAM,OAAO,oBAAoB;AAAA,IACvC;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { M as Middleware } from '../../llm-DwbUK7un.js';
|
|
2
|
+
import { M as MemoryAdapterOptions, P as PubSubAdapter, a as PubSubOptions } from '../../types-C8Gciizr.js';
|
|
3
|
+
export { S as StoredStream, b as SubscriptionCallback, U as Unsubscribe } from '../../types-C8Gciizr.js';
|
|
4
|
+
import '../../stream-CecfVCPO.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @fileoverview In-memory storage adapter for pub-sub middleware.
|
|
8
|
+
*
|
|
9
|
+
* Provides a simple Map-based implementation with LRU eviction
|
|
10
|
+
* for temporary stream storage during active generation.
|
|
11
|
+
*
|
|
12
|
+
* @module middleware/pubsub/memory-adapter
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Creates an in-memory storage adapter for pub-sub middleware.
|
|
17
|
+
*
|
|
18
|
+
* Stores streams in a Map with LRU eviction when maxStreams is reached.
|
|
19
|
+
* All methods return promises for interface compatibility with async backends.
|
|
20
|
+
*
|
|
21
|
+
* @param options - Adapter configuration
|
|
22
|
+
* @returns A PubSubAdapter instance
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { pubsubMiddleware, memoryAdapter } from '@providerprotocol/ai/middleware/pubsub';
|
|
27
|
+
*
|
|
28
|
+
* const mw = pubsubMiddleware({
|
|
29
|
+
* adapter: memoryAdapter({ maxStreams: 500 }),
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
declare function memoryAdapter(options?: MemoryAdapterOptions): PubSubAdapter;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @fileoverview Pub-sub middleware for stream resumption.
|
|
37
|
+
*
|
|
38
|
+
* Enables reconnecting clients to catch up on missed events during
|
|
39
|
+
* active generation. The middleware buffers events and publishes them
|
|
40
|
+
* to subscribers. Server routes handle reconnection logic using the
|
|
41
|
+
* exported `createSubscriberStream` utility.
|
|
42
|
+
*
|
|
43
|
+
* @module middleware/pubsub
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Gets the stream ID from middleware state.
|
|
48
|
+
*
|
|
49
|
+
* @param state - Middleware state map
|
|
50
|
+
* @returns Stream ID or undefined if not set
|
|
51
|
+
*/
|
|
52
|
+
declare function getStreamId(state: Map<string, unknown>): string | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Gets the adapter from middleware state.
|
|
55
|
+
*
|
|
56
|
+
* @param state - Middleware state map
|
|
57
|
+
* @returns Adapter or undefined if not set
|
|
58
|
+
*/
|
|
59
|
+
declare function getAdapter(state: Map<string, unknown>): PubSubAdapter | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* Creates pub-sub middleware for stream buffering and publishing.
|
|
62
|
+
*
|
|
63
|
+
* The middleware:
|
|
64
|
+
* - Creates stream entries for new requests
|
|
65
|
+
* - Buffers all stream events
|
|
66
|
+
* - Publishes events to subscribers
|
|
67
|
+
* - Marks streams as completed
|
|
68
|
+
*
|
|
69
|
+
* Server routes handle reconnection logic using `createSubscriberStream`.
|
|
70
|
+
*
|
|
71
|
+
* @param options - Middleware configuration
|
|
72
|
+
* @returns Middleware instance
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* import { llm } from '@providerprotocol/ai';
|
|
77
|
+
* import { anthropic } from '@providerprotocol/ai/anthropic';
|
|
78
|
+
* import { pubsubMiddleware } from '@providerprotocol/ai/middleware/pubsub';
|
|
79
|
+
* import { createSubscriberStream } from '@providerprotocol/ai/middleware/pubsub/server/webapi';
|
|
80
|
+
*
|
|
81
|
+
* // Server route handling both new requests and reconnections
|
|
82
|
+
* export async function POST(req: Request) {
|
|
83
|
+
* const { messages, streamId } = await req.json();
|
|
84
|
+
* const exists = await adapter.exists(streamId);
|
|
85
|
+
*
|
|
86
|
+
* if (!exists) {
|
|
87
|
+
* // Start background generation (fire and forget)
|
|
88
|
+
* const model = llm({
|
|
89
|
+
* model: anthropic('claude-sonnet-4-20250514'),
|
|
90
|
+
* middleware: [pubsubMiddleware({ adapter, streamId })],
|
|
91
|
+
* });
|
|
92
|
+
* consumeInBackground(model.stream(messages));
|
|
93
|
+
* }
|
|
94
|
+
*
|
|
95
|
+
* // Both new and reconnect: subscribe to events
|
|
96
|
+
* return new Response(createSubscriberStream(streamId, adapter), {
|
|
97
|
+
* headers: { 'Content-Type': 'text/event-stream' },
|
|
98
|
+
* });
|
|
99
|
+
* }
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
declare function pubsubMiddleware(options?: PubSubOptions): Middleware;
|
|
103
|
+
|
|
104
|
+
export { MemoryAdapterOptions, PubSubAdapter, PubSubOptions, getAdapter, getStreamId, memoryAdapter, pubsubMiddleware };
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
// src/middleware/pubsub/memory-adapter.ts
|
|
2
|
+
function memoryAdapter(options = {}) {
|
|
3
|
+
const { maxStreams = 1e3 } = options;
|
|
4
|
+
const streams = /* @__PURE__ */ new Map();
|
|
5
|
+
const eventCursors = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
const evictOldest = () => {
|
|
7
|
+
if (streams.size >= maxStreams) {
|
|
8
|
+
let oldest = null;
|
|
9
|
+
let oldestTime = Infinity;
|
|
10
|
+
for (const [id, entry] of streams) {
|
|
11
|
+
if (entry.stream.updatedAt < oldestTime) {
|
|
12
|
+
oldestTime = entry.stream.updatedAt;
|
|
13
|
+
oldest = id;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (oldest) {
|
|
17
|
+
streams.delete(oldest);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
async exists(streamId) {
|
|
23
|
+
return streams.has(streamId);
|
|
24
|
+
},
|
|
25
|
+
async create(streamId, metadata) {
|
|
26
|
+
evictOldest();
|
|
27
|
+
const now = Date.now();
|
|
28
|
+
const stream = {
|
|
29
|
+
streamId,
|
|
30
|
+
modelId: metadata.modelId,
|
|
31
|
+
provider: metadata.provider,
|
|
32
|
+
createdAt: now,
|
|
33
|
+
updatedAt: now,
|
|
34
|
+
completed: false,
|
|
35
|
+
events: []
|
|
36
|
+
};
|
|
37
|
+
streams.set(streamId, {
|
|
38
|
+
stream,
|
|
39
|
+
subscribers: /* @__PURE__ */ new Set()
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
async append(streamId, event) {
|
|
43
|
+
const entry = streams.get(streamId);
|
|
44
|
+
if (!entry) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
entry.stream.events.push(event);
|
|
48
|
+
eventCursors.set(event, entry.stream.events.length - 1);
|
|
49
|
+
entry.stream.updatedAt = Date.now();
|
|
50
|
+
},
|
|
51
|
+
async markCompleted(streamId) {
|
|
52
|
+
const entry = streams.get(streamId);
|
|
53
|
+
if (!entry) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
entry.stream.completed = true;
|
|
57
|
+
entry.stream.updatedAt = Date.now();
|
|
58
|
+
},
|
|
59
|
+
async isCompleted(streamId) {
|
|
60
|
+
const entry = streams.get(streamId);
|
|
61
|
+
return entry?.stream.completed ?? false;
|
|
62
|
+
},
|
|
63
|
+
async getEvents(streamId) {
|
|
64
|
+
const entry = streams.get(streamId);
|
|
65
|
+
if (!entry) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return [...entry.stream.events];
|
|
69
|
+
},
|
|
70
|
+
async getStream(streamId) {
|
|
71
|
+
const entry = streams.get(streamId);
|
|
72
|
+
return entry?.stream ?? null;
|
|
73
|
+
},
|
|
74
|
+
subscribe(streamId, callback) {
|
|
75
|
+
const entry = streams.get(streamId);
|
|
76
|
+
if (!entry) {
|
|
77
|
+
return () => {
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
entry.subscribers.add(callback);
|
|
81
|
+
return () => {
|
|
82
|
+
entry.subscribers.delete(callback);
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
publish(streamId, event) {
|
|
86
|
+
const entry = streams.get(streamId);
|
|
87
|
+
if (!entry) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const cursor = eventCursors.get(event) ?? entry.stream.events.length - 1;
|
|
91
|
+
for (const callback of entry.subscribers) {
|
|
92
|
+
try {
|
|
93
|
+
callback(event, cursor);
|
|
94
|
+
} catch {
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
async remove(streamId) {
|
|
99
|
+
streams.delete(streamId);
|
|
100
|
+
},
|
|
101
|
+
async cleanup(maxAge) {
|
|
102
|
+
const now = Date.now();
|
|
103
|
+
const cutoff = now - maxAge;
|
|
104
|
+
for (const [id, entry] of streams) {
|
|
105
|
+
if (entry.stream.updatedAt < cutoff) {
|
|
106
|
+
streams.delete(id);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/middleware/pubsub/index.ts
|
|
114
|
+
var STATE_KEY_STREAM_ID = "pubsub:streamId";
|
|
115
|
+
var STATE_KEY_ADAPTER = "pubsub:adapter";
|
|
116
|
+
var DEFAULT_TTL = 6e5;
|
|
117
|
+
var CLEANUP_INTERVAL = 6e4;
|
|
118
|
+
var adapterCleanupTimes = /* @__PURE__ */ new WeakMap();
|
|
119
|
+
function getStreamId(state) {
|
|
120
|
+
return state.get(STATE_KEY_STREAM_ID);
|
|
121
|
+
}
|
|
122
|
+
function getAdapter(state) {
|
|
123
|
+
return state.get(STATE_KEY_ADAPTER);
|
|
124
|
+
}
|
|
125
|
+
function pubsubMiddleware(options = {}) {
|
|
126
|
+
const {
|
|
127
|
+
adapter = memoryAdapter(),
|
|
128
|
+
streamId,
|
|
129
|
+
ttl = DEFAULT_TTL
|
|
130
|
+
} = options;
|
|
131
|
+
const appendChains = /* @__PURE__ */ new Map();
|
|
132
|
+
const enqueueAppend = (id, event) => {
|
|
133
|
+
const state = appendChains.get(id) ?? { chain: Promise.resolve() };
|
|
134
|
+
const task = state.chain.catch(() => {
|
|
135
|
+
}).then(async () => {
|
|
136
|
+
await adapter.append(id, event);
|
|
137
|
+
adapter.publish(id, event);
|
|
138
|
+
});
|
|
139
|
+
state.chain = task.catch(() => {
|
|
140
|
+
});
|
|
141
|
+
appendChains.set(id, state);
|
|
142
|
+
};
|
|
143
|
+
const waitForAppends = async (id) => {
|
|
144
|
+
const state = appendChains.get(id);
|
|
145
|
+
if (!state) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
await state.chain.catch(() => {
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
const clearAppendState = (id) => {
|
|
152
|
+
appendChains.delete(id);
|
|
153
|
+
};
|
|
154
|
+
const maybeCleanup = () => {
|
|
155
|
+
const now = Date.now();
|
|
156
|
+
const lastCleanup = adapterCleanupTimes.get(adapter) ?? 0;
|
|
157
|
+
if (now - lastCleanup > CLEANUP_INTERVAL) {
|
|
158
|
+
adapterCleanupTimes.set(adapter, now);
|
|
159
|
+
adapter.cleanup(ttl).catch(() => {
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const finalizeStream = async (ctx) => {
|
|
164
|
+
const id = ctx.state.get(STATE_KEY_STREAM_ID);
|
|
165
|
+
if (!id) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
await waitForAppends(id);
|
|
169
|
+
await adapter.markCompleted(id).catch(() => {
|
|
170
|
+
});
|
|
171
|
+
clearAppendState(id);
|
|
172
|
+
maybeCleanup();
|
|
173
|
+
};
|
|
174
|
+
return {
|
|
175
|
+
name: "pubsub",
|
|
176
|
+
onStart(ctx) {
|
|
177
|
+
ctx.state.set(STATE_KEY_ADAPTER, adapter);
|
|
178
|
+
if (streamId) {
|
|
179
|
+
ctx.state.set(STATE_KEY_STREAM_ID, streamId);
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
async onRequest(ctx) {
|
|
183
|
+
if (!streamId) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (!ctx.streaming) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const exists = await adapter.exists(streamId);
|
|
190
|
+
if (!exists) {
|
|
191
|
+
await adapter.create(streamId, {
|
|
192
|
+
modelId: ctx.modelId,
|
|
193
|
+
provider: ctx.provider
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
onStreamEvent(event, ctx) {
|
|
198
|
+
const id = ctx.state.get(STATE_KEY_STREAM_ID);
|
|
199
|
+
if (!id) {
|
|
200
|
+
return event;
|
|
201
|
+
}
|
|
202
|
+
enqueueAppend(id, event);
|
|
203
|
+
return event;
|
|
204
|
+
},
|
|
205
|
+
async onStreamEnd(ctx) {
|
|
206
|
+
const id = ctx.state.get(STATE_KEY_STREAM_ID);
|
|
207
|
+
if (!id) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
await waitForAppends(id);
|
|
211
|
+
await adapter.markCompleted(id).catch(() => {
|
|
212
|
+
});
|
|
213
|
+
clearAppendState(id);
|
|
214
|
+
maybeCleanup();
|
|
215
|
+
},
|
|
216
|
+
async onError(_error, ctx) {
|
|
217
|
+
await finalizeStream(ctx);
|
|
218
|
+
},
|
|
219
|
+
async onAbort(_error, ctx) {
|
|
220
|
+
await finalizeStream(ctx);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
export {
|
|
225
|
+
getAdapter,
|
|
226
|
+
getStreamId,
|
|
227
|
+
memoryAdapter,
|
|
228
|
+
pubsubMiddleware
|
|
229
|
+
};
|
|
230
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/middleware/pubsub/memory-adapter.ts","../../../src/middleware/pubsub/index.ts"],"sourcesContent":["/**\n * @fileoverview In-memory storage adapter for pub-sub middleware.\n *\n * Provides a simple Map-based implementation with LRU eviction\n * for temporary stream storage during active generation.\n *\n * @module middleware/pubsub/memory-adapter\n */\n\nimport type { StreamEvent } from '../../types/stream.ts';\nimport type {\n PubSubAdapter,\n StoredStream,\n SubscriptionCallback,\n Unsubscribe,\n MemoryAdapterOptions,\n} from './types.ts';\n\n/**\n * Internal mutable version of StoredStream for adapter operations.\n * Public API exposes readonly StoredStream.\n */\ninterface MutableStoredStream {\n streamId: string;\n modelId: string;\n provider: string;\n createdAt: number;\n updatedAt: number;\n completed: boolean;\n events: StreamEvent[];\n}\n\ninterface StreamEntry {\n stream: MutableStoredStream;\n subscribers: Set<SubscriptionCallback>;\n}\n\n/**\n * Creates an in-memory storage adapter for pub-sub middleware.\n *\n * Stores streams in a Map with LRU eviction when maxStreams is reached.\n * All methods return promises for interface compatibility with async backends.\n *\n * @param options - Adapter configuration\n * @returns A PubSubAdapter instance\n *\n * @example\n * ```typescript\n * import { pubsubMiddleware, memoryAdapter } from '@providerprotocol/ai/middleware/pubsub';\n *\n * const mw = pubsubMiddleware({\n * adapter: memoryAdapter({ maxStreams: 500 }),\n * });\n * ```\n */\nexport function memoryAdapter(options: MemoryAdapterOptions = {}): PubSubAdapter {\n const { maxStreams = 1000 } = options;\n\n const streams = new Map<string, StreamEntry>();\n const eventCursors = new WeakMap<StreamEvent, number>();\n\n const evictOldest = (): void => {\n if (streams.size >= maxStreams) {\n let oldest: string | null = null;\n let oldestTime = Infinity;\n\n for (const [id, entry] of streams) {\n if (entry.stream.updatedAt < oldestTime) {\n oldestTime = entry.stream.updatedAt;\n oldest = id;\n }\n }\n\n if (oldest) {\n streams.delete(oldest);\n }\n }\n };\n\n return {\n async exists(streamId): Promise<boolean> {\n return streams.has(streamId);\n },\n\n async create(streamId, metadata): Promise<void> {\n evictOldest();\n\n const now = Date.now();\n const stream: MutableStoredStream = {\n streamId,\n modelId: metadata.modelId,\n provider: metadata.provider,\n createdAt: now,\n updatedAt: now,\n completed: false,\n events: [],\n };\n\n streams.set(streamId, {\n stream,\n subscribers: new Set(),\n });\n },\n\n async append(streamId, event): Promise<void> {\n const entry = streams.get(streamId);\n if (!entry) {\n return;\n }\n\n entry.stream.events.push(event);\n eventCursors.set(event, entry.stream.events.length - 1);\n entry.stream.updatedAt = Date.now();\n },\n\n async markCompleted(streamId): Promise<void> {\n const entry = streams.get(streamId);\n if (!entry) {\n return;\n }\n\n entry.stream.completed = true;\n entry.stream.updatedAt = Date.now();\n },\n\n async isCompleted(streamId): Promise<boolean> {\n const entry = streams.get(streamId);\n return entry?.stream.completed ?? false;\n },\n\n async getEvents(streamId): Promise<StreamEvent[] | null> {\n const entry = streams.get(streamId);\n if (!entry) {\n return null;\n }\n\n return [...entry.stream.events];\n },\n\n async getStream(streamId): Promise<StoredStream | null> {\n const entry = streams.get(streamId);\n return entry?.stream ?? null;\n },\n\n subscribe(streamId, callback): Unsubscribe {\n const entry = streams.get(streamId);\n if (!entry) {\n return () => {};\n }\n\n entry.subscribers.add(callback);\n\n return () => {\n entry.subscribers.delete(callback);\n };\n },\n\n publish(streamId, event): void {\n const entry = streams.get(streamId);\n if (!entry) {\n return;\n }\n\n const cursor = eventCursors.get(event) ?? entry.stream.events.length - 1;\n for (const callback of entry.subscribers) {\n try {\n callback(event, cursor);\n } catch {\n // Subscriber errors should not affect other subscribers\n }\n }\n },\n\n async remove(streamId): Promise<void> {\n streams.delete(streamId);\n },\n\n async cleanup(maxAge): Promise<void> {\n const now = Date.now();\n const cutoff = now - maxAge;\n\n for (const [id, entry] of streams) {\n if (entry.stream.updatedAt < cutoff) {\n streams.delete(id);\n }\n }\n },\n };\n}\n","/**\n * @fileoverview Pub-sub middleware for stream resumption.\n *\n * Enables reconnecting clients to catch up on missed events during\n * active generation. The middleware buffers events and publishes them\n * to subscribers. Server routes handle reconnection logic using the\n * exported `createSubscriberStream` utility.\n *\n * @module middleware/pubsub\n */\n\nimport type {\n Middleware,\n MiddlewareContext,\n StreamContext,\n} from '../../types/middleware.ts';\nimport type { StreamEvent } from '../../types/stream.ts';\nimport type { PubSubAdapter, PubSubOptions } from './types.ts';\nimport { memoryAdapter } from './memory-adapter.ts';\n\nexport type {\n PubSubAdapter,\n PubSubOptions,\n StoredStream,\n SubscriptionCallback,\n Unsubscribe,\n MemoryAdapterOptions,\n} from './types.ts';\nexport { memoryAdapter } from './memory-adapter.ts';\n\nconst STATE_KEY_STREAM_ID = 'pubsub:streamId';\nconst STATE_KEY_ADAPTER = 'pubsub:adapter';\n\nconst DEFAULT_TTL = 600_000; // 10 minutes\nconst CLEANUP_INTERVAL = 60_000; // 1 minute\n\n/** Track last cleanup time per adapter to avoid shared state issues */\nconst adapterCleanupTimes = new WeakMap<PubSubAdapter, number>();\n\ninterface AppendChainState {\n chain: Promise<void>;\n}\n\n/**\n * Gets the stream ID from middleware state.\n *\n * @param state - Middleware state map\n * @returns Stream ID or undefined if not set\n */\nexport function getStreamId(state: Map<string, unknown>): string | undefined {\n return state.get(STATE_KEY_STREAM_ID) as string | undefined;\n}\n\n/**\n * Gets the adapter from middleware state.\n *\n * @param state - Middleware state map\n * @returns Adapter or undefined if not set\n */\nexport function getAdapter(state: Map<string, unknown>): PubSubAdapter | undefined {\n return state.get(STATE_KEY_ADAPTER) as PubSubAdapter | undefined;\n}\n\n/**\n * Creates pub-sub middleware for stream buffering and publishing.\n *\n * The middleware:\n * - Creates stream entries for new requests\n * - Buffers all stream events\n * - Publishes events to subscribers\n * - Marks streams as completed\n *\n * Server routes handle reconnection logic using `createSubscriberStream`.\n *\n * @param options - Middleware configuration\n * @returns Middleware instance\n *\n * @example\n * ```typescript\n * import { llm } from '@providerprotocol/ai';\n * import { anthropic } from '@providerprotocol/ai/anthropic';\n * import { pubsubMiddleware } from '@providerprotocol/ai/middleware/pubsub';\n * import { createSubscriberStream } from '@providerprotocol/ai/middleware/pubsub/server/webapi';\n *\n * // Server route handling both new requests and reconnections\n * export async function POST(req: Request) {\n * const { messages, streamId } = await req.json();\n * const exists = await adapter.exists(streamId);\n *\n * if (!exists) {\n * // Start background generation (fire and forget)\n * const model = llm({\n * model: anthropic('claude-sonnet-4-20250514'),\n * middleware: [pubsubMiddleware({ adapter, streamId })],\n * });\n * consumeInBackground(model.stream(messages));\n * }\n *\n * // Both new and reconnect: subscribe to events\n * return new Response(createSubscriberStream(streamId, adapter), {\n * headers: { 'Content-Type': 'text/event-stream' },\n * });\n * }\n * ```\n */\nexport function pubsubMiddleware(options: PubSubOptions = {}): Middleware {\n const {\n adapter = memoryAdapter(),\n streamId,\n ttl = DEFAULT_TTL,\n } = options;\n\n const appendChains = new Map<string, AppendChainState>();\n\n const enqueueAppend = (id: string, event: StreamEvent): void => {\n const state = appendChains.get(id) ?? { chain: Promise.resolve() };\n\n const task = state.chain\n .catch(() => {})\n .then(async () => {\n await adapter.append(id, event);\n adapter.publish(id, event);\n });\n\n state.chain = task.catch(() => {});\n appendChains.set(id, state);\n };\n\n const waitForAppends = async (id: string): Promise<void> => {\n const state = appendChains.get(id);\n if (!state) {\n return;\n }\n\n await state.chain.catch(() => {});\n };\n\n const clearAppendState = (id: string): void => {\n appendChains.delete(id);\n };\n\n const maybeCleanup = (): void => {\n const now = Date.now();\n const lastCleanup = adapterCleanupTimes.get(adapter) ?? 0;\n if (now - lastCleanup > CLEANUP_INTERVAL) {\n adapterCleanupTimes.set(adapter, now);\n adapter.cleanup(ttl).catch(() => {\n // Cleanup errors are non-fatal\n });\n }\n };\n\n const finalizeStream = async (ctx: MiddlewareContext): Promise<void> => {\n const id = ctx.state.get(STATE_KEY_STREAM_ID) as string | undefined;\n if (!id) {\n return;\n }\n\n await waitForAppends(id);\n\n await adapter.markCompleted(id).catch(() => {\n // Completion errors are non-fatal\n });\n\n clearAppendState(id);\n\n maybeCleanup();\n };\n\n return {\n name: 'pubsub',\n\n onStart(ctx: MiddlewareContext): void {\n ctx.state.set(STATE_KEY_ADAPTER, adapter);\n\n if (streamId) {\n ctx.state.set(STATE_KEY_STREAM_ID, streamId);\n }\n },\n\n async onRequest(ctx: MiddlewareContext): Promise<void> {\n if (!streamId) {\n return;\n }\n if (!ctx.streaming) {\n return;\n }\n\n // Create stream entry if it doesn't exist\n const exists = await adapter.exists(streamId);\n if (!exists) {\n await adapter.create(streamId, {\n modelId: ctx.modelId,\n provider: ctx.provider,\n });\n }\n },\n\n onStreamEvent(event: StreamEvent, ctx: StreamContext): StreamEvent {\n const id = ctx.state.get(STATE_KEY_STREAM_ID) as string | undefined;\n if (!id) {\n return event;\n }\n\n // Buffer first, then broadcast - ensures event is persisted before\n // subscribers are notified, preventing replay gaps with async adapters\n enqueueAppend(id, event);\n\n return event;\n },\n\n async onStreamEnd(ctx: StreamContext): Promise<void> {\n const id = ctx.state.get(STATE_KEY_STREAM_ID) as string | undefined;\n if (!id) {\n return;\n }\n\n await waitForAppends(id);\n\n await adapter.markCompleted(id).catch(() => {\n // Completion errors are non-fatal\n });\n\n clearAppendState(id);\n\n maybeCleanup();\n },\n\n async onError(_error: Error, ctx: MiddlewareContext): Promise<void> {\n await finalizeStream(ctx);\n },\n\n async onAbort(_error: Error, ctx: MiddlewareContext): Promise<void> {\n await finalizeStream(ctx);\n },\n };\n}\n"],"mappings":"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","names":[]}
|