@providerprotocol/ai 0.0.36 → 0.0.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +28 -0
  2. package/dist/anthropic/index.d.ts +2 -2
  3. package/dist/anthropic/index.js +12 -10
  4. package/dist/anthropic/index.js.map +1 -1
  5. package/dist/cerebras/index.d.ts +2 -2
  6. package/dist/cerebras/index.js +12 -10
  7. package/dist/cerebras/index.js.map +1 -1
  8. package/dist/{chunk-UFFJDYCE.js → chunk-7GTWHZY2.js} +2 -2
  9. package/dist/{chunk-OIEWDFQU.js → chunk-FYSZFIZS.js} +2 -2
  10. package/dist/chunk-GIDT7C6I.js +37 -0
  11. package/dist/chunk-GIDT7C6I.js.map +1 -0
  12. package/dist/{chunk-IDZOVWP3.js → chunk-IK6NRCW5.js} +7 -7
  13. package/dist/{chunk-VGKZIGVI.js → chunk-LTEMH3CI.js} +2 -2
  14. package/dist/{chunk-RJGTRQ47.js → chunk-MJI74VEJ.js} +6 -1
  15. package/dist/chunk-MJI74VEJ.js.map +1 -0
  16. package/dist/{chunk-AY55T37A.js → chunk-SBGZJVTJ.js} +4 -30
  17. package/dist/chunk-SBGZJVTJ.js.map +1 -0
  18. package/dist/{chunk-A2IM7PGT.js → chunk-TUTYMOBL.js} +2 -2
  19. package/dist/{chunk-BRP5XJ6Q.js → chunk-WU4U6IHF.js} +2 -2
  20. package/dist/chunk-WU4U6IHF.js.map +1 -0
  21. package/dist/{chunk-C4JP64VW.js → chunk-YQLR3XOA.js} +2 -2
  22. package/dist/chunk-ZKNPQBIE.js +265 -0
  23. package/dist/chunk-ZKNPQBIE.js.map +1 -0
  24. package/dist/{chunk-4OGB7JZA.js → chunk-ZRVNAET3.js} +2 -2
  25. package/dist/{embedding-BXA72PlJ.d.ts → embedding-CwZ1ZNWv.d.ts} +1 -1
  26. package/dist/google/index.d.ts +2 -2
  27. package/dist/google/index.js +12 -10
  28. package/dist/google/index.js.map +1 -1
  29. package/dist/groq/index.d.ts +2 -2
  30. package/dist/groq/index.js +12 -10
  31. package/dist/groq/index.js.map +1 -1
  32. package/dist/http/index.d.ts +3 -3
  33. package/dist/http/index.js +2 -1
  34. package/dist/{image-stream-CCgwB7ve.d.ts → image-stream-CeQHtjxS.d.ts} +1 -1
  35. package/dist/index.d.ts +7 -7
  36. package/dist/index.js +86 -283
  37. package/dist/index.js.map +1 -1
  38. package/dist/{llm-ByUFPcFH.d.ts → llm-DS_-l71X.d.ts} +11 -3
  39. package/dist/middleware/logging/index.d.ts +2 -2
  40. package/dist/middleware/parsed-object/index.d.ts +2 -2
  41. package/dist/middleware/parsed-object/index.js +1 -1
  42. package/dist/middleware/persistence/index.d.ts +128 -0
  43. package/dist/middleware/persistence/index.js +144 -0
  44. package/dist/middleware/persistence/index.js.map +1 -0
  45. package/dist/middleware/pubsub/index.d.ts +4 -4
  46. package/dist/middleware/pubsub/server/express/index.d.ts +2 -2
  47. package/dist/middleware/pubsub/server/fastify/index.d.ts +2 -2
  48. package/dist/middleware/pubsub/server/h3/index.d.ts +2 -2
  49. package/dist/middleware/pubsub/server/index.d.ts +2 -2
  50. package/dist/middleware/pubsub/server/webapi/index.d.ts +2 -2
  51. package/dist/ollama/index.d.ts +2 -2
  52. package/dist/ollama/index.js +12 -10
  53. package/dist/ollama/index.js.map +1 -1
  54. package/dist/openai/index.d.ts +2 -2
  55. package/dist/openai/index.js +12 -10
  56. package/dist/openai/index.js.map +1 -1
  57. package/dist/openrouter/index.d.ts +2 -2
  58. package/dist/openrouter/index.js +12 -10
  59. package/dist/openrouter/index.js.map +1 -1
  60. package/dist/proxy/index.d.ts +4 -4
  61. package/dist/proxy/index.js +20 -18
  62. package/dist/proxy/index.js.map +1 -1
  63. package/dist/proxy/server/express/index.d.ts +4 -4
  64. package/dist/proxy/server/express/index.js +3 -3
  65. package/dist/proxy/server/fastify/index.d.ts +4 -4
  66. package/dist/proxy/server/fastify/index.js +3 -3
  67. package/dist/proxy/server/h3/index.d.ts +4 -4
  68. package/dist/proxy/server/h3/index.js +3 -3
  69. package/dist/proxy/server/index.d.ts +4 -4
  70. package/dist/proxy/server/index.js +9 -9
  71. package/dist/proxy/server/webapi/index.d.ts +4 -4
  72. package/dist/proxy/server/webapi/index.js +3 -3
  73. package/dist/responses/index.d.ts +2 -2
  74. package/dist/responses/index.js +12 -10
  75. package/dist/responses/index.js.map +1 -1
  76. package/dist/{retry-BDMo4AVu.d.ts → retry-CgoBNa51.d.ts} +1 -1
  77. package/dist/{stream-S7nwQRqM.d.ts → stream-sXhBtWjl.d.ts} +4 -0
  78. package/dist/{types-CE4B7pno.d.ts → types-Cr4F0tVy.d.ts} +1 -1
  79. package/dist/xai/index.d.ts +2 -2
  80. package/dist/xai/index.js +12 -10
  81. package/dist/xai/index.js.map +1 -1
  82. package/package.json +6 -1
  83. package/dist/chunk-AY55T37A.js.map +0 -1
  84. package/dist/chunk-BRP5XJ6Q.js.map +0 -1
  85. package/dist/chunk-RJGTRQ47.js.map +0 -1
  86. /package/dist/{chunk-UFFJDYCE.js.map → chunk-7GTWHZY2.js.map} +0 -0
  87. /package/dist/{chunk-OIEWDFQU.js.map → chunk-FYSZFIZS.js.map} +0 -0
  88. /package/dist/{chunk-IDZOVWP3.js.map → chunk-IK6NRCW5.js.map} +0 -0
  89. /package/dist/{chunk-VGKZIGVI.js.map → chunk-LTEMH3CI.js.map} +0 -0
  90. /package/dist/{chunk-A2IM7PGT.js.map → chunk-TUTYMOBL.js.map} +0 -0
  91. /package/dist/{chunk-C4JP64VW.js.map → chunk-YQLR3XOA.js.map} +0 -0
  92. /package/dist/{chunk-4OGB7JZA.js.map → chunk-ZRVNAET3.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- import { I as ImageSource, c as ImageBlock, S as StreamEvent, d as Tool, M as Message, T as Turn, U as UserContent, A as AssistantContent, e as MessageType, a as MessageJSON, f as ToolUseStrategy, J as JSONSchema, g as AssistantMessage, h as TokenUsage, C as ContentBlock, i as StreamResult } from './stream-S7nwQRqM.js';
1
+ import { I as ImageSource, c as ImageBlock, T as Turn, S as StreamEvent, d as Tool, M as Message, U as UserContent, A as AssistantContent, e as MessageType, a as MessageJSON, f as ToolUseStrategy, J as JSONSchema, g as AssistantMessage, h as TokenUsage, C as ContentBlock, i as StreamResult } from './stream-sXhBtWjl.js';
2
2
 
3
3
  /**
4
4
  * @fileoverview Error types for the Unified Provider Protocol.
@@ -467,7 +467,7 @@ interface Middleware {
467
467
  */
468
468
  onEnd?(ctx: MiddlewareContext): void | Promise<void>;
469
469
  /**
470
- * Called on any error during execution.
470
+ * Called on non-cancellation errors during execution.
471
471
  * Called for all middleware that have this hook, regardless of order.
472
472
  *
473
473
  * @param error - The error that occurred
@@ -496,6 +496,14 @@ interface Middleware {
496
496
  * @param ctx - The middleware context with mutable response
497
497
  */
498
498
  onResponse?(ctx: MiddlewareContext): void | Promise<void>;
499
+ /**
500
+ * Called when a complete Turn has been assembled (LLM only).
501
+ * Called in reverse middleware order.
502
+ *
503
+ * @param turn - The completed Turn
504
+ * @param ctx - The middleware context
505
+ */
506
+ onTurn?(turn: Turn, ctx: MiddlewareContext): void | Promise<void>;
499
507
  /**
500
508
  * Called for each stream event. Can transform, filter, or expand events.
501
509
  *
@@ -1762,4 +1770,4 @@ interface BoundLLMModel<TParams = unknown> {
1762
1770
  stream(request: LLMRequest<TParams>): LLMStreamResult;
1763
1771
  }
1764
1772
 
1765
- export { type MiddlewareModality as $, type BoundLLMModel as A, type BoundEmbeddingModel as B, type InferenceInput as C, type ImageInput as D, type EmbeddingInput as E, type ImageEditInput as F, type ImageGenerateOptions as G, type GeneratedImage as H, type ImageStreamResult as I, type ImageUsage as J, type KeyStrategy as K, type LLMOptions as L, type Middleware as M, type ImageResult as N, type ImageStreamEvent as O, type ProviderIdentity as P, type ImageCapabilities as Q, type RetryStrategy as R, type ImageRequest as S, Thread as T, UPPError as U, type ImageEditRequest as V, type ImageResponse as W, type BoundImageModel as X, type ImageModelInput as Y, type MiddlewareContext as Z, type StreamContext as _, type ImageProviderStreamResult as a, type AnyRequest as a0, type AnyResponse as a1, type ProviderConfig as b, type EmbeddingUsage as c, type Provider as d, type Modality as e, ErrorCode as f, type ModelReference as g, type LLMInstance as h, type ImageOptions as i, type ImageInstance as j, type LLMHandler as k, type EmbeddingHandler as l, type ImageHandler as m, Image as n, ModalityType as o, type ThreadJSON as p, type LLMProvider as q, type EmbeddingProvider as r, type ImageProvider as s, type EmbeddingRequest as t, type EmbeddingResponse as u, type EmbeddingVector as v, type LLMCapabilities as w, type LLMRequest as x, type LLMResponse as y, type LLMStreamResult as z };
1773
+ export { type MiddlewareModality as $, type BoundLLMModel as A, type BoundEmbeddingModel as B, type InferenceInput as C, type ImageInput as D, type EmbeddingInput as E, type ImageEditInput as F, type ImageGenerateOptions as G, type GeneratedImage as H, type ImageStreamResult as I, type ImageUsage as J, type KeyStrategy as K, type LLMOptions as L, type Middleware as M, type ImageResult as N, type ImageStreamEvent as O, type ProviderIdentity as P, type ImageCapabilities as Q, type RetryStrategy as R, type ImageRequest as S, Thread as T, UPPError as U, type ImageEditRequest as V, type ImageResponse as W, type BoundImageModel as X, type ImageModelInput as Y, type MiddlewareContext as Z, type StreamContext as _, type ThreadJSON as a, type AnyRequest as a0, type AnyResponse as a1, type ImageProviderStreamResult as b, type ProviderConfig as c, type EmbeddingUsage as d, type Provider as e, type Modality as f, ErrorCode as g, type ModelReference as h, type LLMInstance as i, type ImageOptions as j, type ImageInstance as k, type LLMHandler as l, type EmbeddingHandler as m, type ImageHandler as n, Image as o, ModalityType as p, type LLMProvider as q, type EmbeddingProvider as r, type ImageProvider as s, type EmbeddingRequest as t, type EmbeddingResponse as u, type EmbeddingVector as v, type LLMCapabilities as w, type LLMRequest as x, type LLMResponse as y, type LLMStreamResult as z };
@@ -1,5 +1,5 @@
1
- import { M as Middleware } from '../../llm-ByUFPcFH.js';
2
- import '../../stream-S7nwQRqM.js';
1
+ import { M as Middleware } from '../../llm-DS_-l71X.js';
2
+ import '../../stream-sXhBtWjl.js';
3
3
 
4
4
  /**
5
5
  * @fileoverview Logging middleware for request/response visibility.
@@ -1,5 +1,5 @@
1
- import { M as Middleware } from '../../llm-ByUFPcFH.js';
2
- import { E as EventDelta, S as StreamEvent } from '../../stream-S7nwQRqM.js';
1
+ import { M as Middleware } from '../../llm-DS_-l71X.js';
2
+ import { E as EventDelta, S as StreamEvent } from '../../stream-sXhBtWjl.js';
3
3
 
4
4
  /**
5
5
  * @fileoverview Parsed object middleware for incremental JSON parsing.
@@ -3,7 +3,7 @@ import {
3
3
  } from "../../chunk-I53CI6ZZ.js";
4
4
  import {
5
5
  StreamEventType
6
- } from "../../chunk-RJGTRQ47.js";
6
+ } from "../../chunk-MJI74VEJ.js";
7
7
 
8
8
  // src/middleware/parsed-object.ts
9
9
  var ACCUMULATED_TEXT_KEY = "parsedObject:text";
@@ -0,0 +1,128 @@
1
+ import { T as Thread, a as ThreadJSON, M as Middleware } from '../../llm-DS_-l71X.js';
2
+ import { T as Turn } from '../../stream-sXhBtWjl.js';
3
+
4
+ /**
5
+ * @fileoverview Persistence middleware for thread storage.
6
+ *
7
+ * Loads a conversation thread before execution and saves it after completion.
8
+ * Designed for LLM requests; other modalities are ignored.
9
+ *
10
+ * @module middleware/persistence
11
+ */
12
+
13
+ /**
14
+ * Load result for persistence adapters.
15
+ */
16
+ type PersistenceLoadResult = Thread | ThreadJSON | null | undefined;
17
+ /**
18
+ * Adapter configuration for persistence middleware.
19
+ */
20
+ interface PersistenceAdapterConfig {
21
+ /**
22
+ * Unique identifier for the conversation.
23
+ */
24
+ id: string;
25
+ /**
26
+ * Loads a thread for the provided ID.
27
+ *
28
+ * Return a Thread instance, ThreadJSON, or null/undefined for new threads.
29
+ *
30
+ * @param id - Conversation identifier
31
+ */
32
+ load(id: string): Promise<PersistenceLoadResult>;
33
+ /**
34
+ * Persists the thread after a turn completes.
35
+ *
36
+ * @param id - Conversation identifier
37
+ * @param thread - Updated thread instance
38
+ * @param turn - Completed turn (undefined if not available)
39
+ */
40
+ save(id: string, thread: Thread, turn: Turn | undefined): Promise<void>;
41
+ }
42
+ /**
43
+ * Persistence adapter implementation.
44
+ *
45
+ * Provides a thin wrapper around load/save callbacks.
46
+ */
47
+ declare class PersistenceAdapter {
48
+ readonly id: string;
49
+ private readonly loader;
50
+ private readonly saver;
51
+ /**
52
+ * Creates a persistence adapter.
53
+ *
54
+ * @param config - Adapter configuration
55
+ */
56
+ constructor(config: PersistenceAdapterConfig);
57
+ /**
58
+ * Loads a thread for the provided ID.
59
+ *
60
+ * @param id - Conversation identifier
61
+ */
62
+ load(id: string): Promise<PersistenceLoadResult>;
63
+ /**
64
+ * Persists the thread after a turn completes.
65
+ *
66
+ * @param id - Conversation identifier
67
+ * @param thread - Updated thread instance
68
+ * @param turn - Completed turn (undefined if not available)
69
+ */
70
+ save(id: string, thread: Thread, turn: Turn | undefined): Promise<void>;
71
+ }
72
+ /**
73
+ * Options for persistence middleware.
74
+ */
75
+ interface PersistenceOptions {
76
+ /**
77
+ * Adapter instance for loading and saving threads.
78
+ */
79
+ adapter: PersistenceAdapter;
80
+ }
81
+ /**
82
+ * Gets the loaded thread from middleware state.
83
+ *
84
+ * @param state - Middleware state map
85
+ * @returns Thread instance or undefined if not set
86
+ */
87
+ declare function getThread(state: Map<string, unknown>): Thread | undefined;
88
+ /**
89
+ * Gets the conversation ID from middleware state.
90
+ *
91
+ * @param state - Middleware state map
92
+ * @returns Conversation ID or undefined if not set
93
+ */
94
+ declare function getThreadId(state: Map<string, unknown>): string | undefined;
95
+ /**
96
+ * Creates persistence middleware for thread storage.
97
+ *
98
+ * Loads a thread before requests and saves it after completion. The middleware
99
+ * prepends loaded messages that are not already present in the request so turn
100
+ * slicing excludes persisted history without duplicating explicit history.
101
+ *
102
+ * @param options - Middleware configuration
103
+ * @returns Middleware instance
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * import { llm } from '@providerprotocol/ai';
108
+ * import { anthropic } from '@providerprotocol/ai/anthropic';
109
+ * import { persistenceMiddleware, PersistenceAdapter } from '@providerprotocol/ai/middleware/persistence';
110
+ *
111
+ * const model = llm({
112
+ * model: anthropic('claude-sonnet-4-20250514'),
113
+ * system: 'You are a helpful assistant.',
114
+ * middleware: [
115
+ * persistenceMiddleware({
116
+ * adapter: new PersistenceAdapter({
117
+ * id: 'conversation-id',
118
+ * load: async (id) => loadThreadFromMemory(id),
119
+ * save: async (id, thread) => saveThreadToMemory(id, thread),
120
+ * }),
121
+ * }),
122
+ * ],
123
+ * });
124
+ * ```
125
+ */
126
+ declare function persistenceMiddleware(options: PersistenceOptions): Middleware;
127
+
128
+ export { PersistenceAdapter, type PersistenceAdapterConfig, type PersistenceLoadResult, type PersistenceOptions, getThread, getThreadId, persistenceMiddleware };
@@ -0,0 +1,144 @@
1
+ import {
2
+ Thread
3
+ } from "../../chunk-ZKNPQBIE.js";
4
+ import "../../chunk-WU4U6IHF.js";
5
+ import {
6
+ toError
7
+ } from "../../chunk-GIDT7C6I.js";
8
+ import "../../chunk-COS4ON4G.js";
9
+
10
+ // src/middleware/persistence.ts
11
+ var STATE_KEY_THREAD = "persistence:thread";
12
+ var STATE_KEY_ID = "persistence:id";
13
+ var TURN_START_INDEX_KEY = "llm:turnStartIndex";
14
+ var isLLMRequest = (request) => "messages" in request;
15
+ var PersistenceAdapter = class {
16
+ id;
17
+ loader;
18
+ saver;
19
+ /**
20
+ * Creates a persistence adapter.
21
+ *
22
+ * @param config - Adapter configuration
23
+ */
24
+ constructor(config) {
25
+ this.id = config.id;
26
+ this.loader = config.load;
27
+ this.saver = config.save;
28
+ }
29
+ /**
30
+ * Loads a thread for the provided ID.
31
+ *
32
+ * @param id - Conversation identifier
33
+ */
34
+ async load(id) {
35
+ return this.loader(id);
36
+ }
37
+ /**
38
+ * Persists the thread after a turn completes.
39
+ *
40
+ * @param id - Conversation identifier
41
+ * @param thread - Updated thread instance
42
+ * @param turn - Completed turn (undefined if not available)
43
+ */
44
+ async save(id, thread, turn) {
45
+ await this.saver(id, thread, turn);
46
+ }
47
+ };
48
+ function getThread(state) {
49
+ return state.get(STATE_KEY_THREAD);
50
+ }
51
+ function getThreadId(state) {
52
+ return state.get(STATE_KEY_ID);
53
+ }
54
+ function persistenceMiddleware(options) {
55
+ const { adapter } = options;
56
+ if (!adapter?.id) {
57
+ throw new Error("persistenceMiddleware requires an adapter with a non-empty id");
58
+ }
59
+ if (typeof adapter.load !== "function" || typeof adapter.save !== "function") {
60
+ throw new Error("persistenceMiddleware requires an adapter with load and save functions");
61
+ }
62
+ return {
63
+ name: "persistence",
64
+ async onRequest(ctx) {
65
+ if (ctx.modality !== "llm" || !isLLMRequest(ctx.request)) {
66
+ return;
67
+ }
68
+ ctx.state.set(STATE_KEY_ID, adapter.id);
69
+ let loaded;
70
+ try {
71
+ loaded = await adapter.load(adapter.id);
72
+ } catch (error) {
73
+ const err = toError(error);
74
+ throw new Error(`Persistence adapter failed to load thread "${adapter.id}": ${err.message}`, {
75
+ cause: err
76
+ });
77
+ }
78
+ let thread;
79
+ if (!loaded) {
80
+ thread = new Thread();
81
+ } else if (loaded instanceof Thread) {
82
+ thread = loaded;
83
+ } else {
84
+ try {
85
+ thread = Thread.fromJSON(loaded);
86
+ } catch (error) {
87
+ const err = toError(error);
88
+ throw new Error(`Persistence adapter failed to deserialize thread "${adapter.id}": ${err.message}`, {
89
+ cause: err
90
+ });
91
+ }
92
+ }
93
+ ctx.state.set(STATE_KEY_THREAD, thread);
94
+ if (thread.messages.length > 0) {
95
+ const existingIds = new Set(ctx.request.messages.map((message) => message.id));
96
+ const missing = thread.messages.filter((message) => !existingIds.has(message.id));
97
+ if (missing.length > 0) {
98
+ ctx.request.messages.unshift(...missing);
99
+ const currentIndex = ctx.state.get(TURN_START_INDEX_KEY);
100
+ const nextIndex = (typeof currentIndex === "number" ? currentIndex : 0) + missing.length;
101
+ ctx.state.set(TURN_START_INDEX_KEY, nextIndex);
102
+ }
103
+ }
104
+ },
105
+ async onTurn(turn, ctx) {
106
+ if (ctx.modality !== "llm") {
107
+ return;
108
+ }
109
+ const thread = getThread(ctx.state);
110
+ if (!thread) {
111
+ return;
112
+ }
113
+ if (isLLMRequest(ctx.request)) {
114
+ const turnMessageIds = new Set(turn.messages.map((message) => message.id));
115
+ const existingIds = new Set(thread.messages.map((message) => message.id));
116
+ for (const message of ctx.request.messages) {
117
+ if (turnMessageIds.has(message.id)) {
118
+ continue;
119
+ }
120
+ if (!existingIds.has(message.id)) {
121
+ thread.push(message);
122
+ existingIds.add(message.id);
123
+ }
124
+ }
125
+ }
126
+ thread.append(turn);
127
+ try {
128
+ await adapter.save(adapter.id, thread, turn);
129
+ } catch (error) {
130
+ const err = toError(error);
131
+ throw new Error(`Persistence adapter failed to save thread "${adapter.id}": ${err.message}`, {
132
+ cause: err
133
+ });
134
+ }
135
+ }
136
+ };
137
+ }
138
+ export {
139
+ PersistenceAdapter,
140
+ getThread,
141
+ getThreadId,
142
+ persistenceMiddleware
143
+ };
144
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/middleware/persistence.ts"],"sourcesContent":["/**\n * @fileoverview Persistence middleware for thread storage.\n *\n * Loads a conversation thread before execution and saves it after completion.\n * Designed for LLM requests; other modalities are ignored.\n *\n * @module middleware/persistence\n */\n\nimport type { Middleware, MiddlewareContext } from '../types/middleware.ts';\nimport type { LLMRequest } from '../types/llm.ts';\nimport type { Turn } from '../types/turn.ts';\nimport type { ThreadJSON } from '../types/thread.ts';\nimport { Thread } from '../types/thread.ts';\nimport { toError } from '../utils/error.ts';\n\nconst STATE_KEY_THREAD = 'persistence:thread';\nconst STATE_KEY_ID = 'persistence:id';\nconst TURN_START_INDEX_KEY = 'llm:turnStartIndex';\n\nconst isLLMRequest = (request: MiddlewareContext['request']): request is LLMRequest => (\n 'messages' in request\n);\n\n/**\n * Load result for persistence adapters.\n */\nexport type PersistenceLoadResult = Thread | ThreadJSON | null | undefined;\n\n/**\n * Adapter configuration for persistence middleware.\n */\nexport interface PersistenceAdapterConfig {\n /**\n * Unique identifier for the conversation.\n */\n id: string;\n\n /**\n * Loads a thread for the provided ID.\n *\n * Return a Thread instance, ThreadJSON, or null/undefined for new threads.\n *\n * @param id - Conversation identifier\n */\n load(id: string): Promise<PersistenceLoadResult>;\n\n /**\n * Persists the thread after a turn completes.\n *\n * @param id - Conversation identifier\n * @param thread - Updated thread instance\n * @param turn - Completed turn (undefined if not available)\n */\n save(id: string, thread: Thread, turn: Turn | undefined): Promise<void>;\n}\n\n/**\n * Persistence adapter implementation.\n *\n * Provides a thin wrapper around load/save callbacks.\n */\nexport class PersistenceAdapter {\n readonly id: string;\n\n private readonly loader: PersistenceAdapterConfig['load'];\n\n private readonly saver: PersistenceAdapterConfig['save'];\n\n /**\n * Creates a persistence adapter.\n *\n * @param config - Adapter configuration\n */\n constructor(config: PersistenceAdapterConfig) {\n this.id = config.id;\n this.loader = config.load;\n this.saver = config.save;\n }\n\n /**\n * Loads a thread for the provided ID.\n *\n * @param id - Conversation identifier\n */\n async load(id: string): Promise<PersistenceLoadResult> {\n return this.loader(id);\n }\n\n /**\n * Persists the thread after a turn completes.\n *\n * @param id - Conversation identifier\n * @param thread - Updated thread instance\n * @param turn - Completed turn (undefined if not available)\n */\n async save(id: string, thread: Thread, turn: Turn | undefined): Promise<void> {\n await this.saver(id, thread, turn);\n }\n}\n\n/**\n * Options for persistence middleware.\n */\nexport interface PersistenceOptions {\n /**\n * Adapter instance for loading and saving threads.\n */\n adapter: PersistenceAdapter;\n}\n\n/**\n * Gets the loaded thread from middleware state.\n *\n * @param state - Middleware state map\n * @returns Thread instance or undefined if not set\n */\nexport function getThread(state: Map<string, unknown>): Thread | undefined {\n return state.get(STATE_KEY_THREAD) as Thread | undefined;\n}\n\n/**\n * Gets the conversation ID from middleware state.\n *\n * @param state - Middleware state map\n * @returns Conversation ID or undefined if not set\n */\nexport function getThreadId(state: Map<string, unknown>): string | undefined {\n return state.get(STATE_KEY_ID) as string | undefined;\n}\n\n/**\n * Creates persistence middleware for thread storage.\n *\n * Loads a thread before requests and saves it after completion. The middleware\n * prepends loaded messages that are not already present in the request so turn\n * slicing excludes persisted history without duplicating explicit history.\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 { persistenceMiddleware, PersistenceAdapter } from '@providerprotocol/ai/middleware/persistence';\n *\n * const model = llm({\n * model: anthropic('claude-sonnet-4-20250514'),\n * system: 'You are a helpful assistant.',\n * middleware: [\n * persistenceMiddleware({\n * adapter: new PersistenceAdapter({\n * id: 'conversation-id',\n * load: async (id) => loadThreadFromMemory(id),\n * save: async (id, thread) => saveThreadToMemory(id, thread),\n * }),\n * }),\n * ],\n * });\n * ```\n */\nexport function persistenceMiddleware(options: PersistenceOptions): Middleware {\n const { adapter } = options;\n\n if (!adapter?.id) {\n throw new Error('persistenceMiddleware requires an adapter with a non-empty id');\n }\n if (typeof adapter.load !== 'function' || typeof adapter.save !== 'function') {\n throw new Error('persistenceMiddleware requires an adapter with load and save functions');\n }\n\n return {\n name: 'persistence',\n\n async onRequest(ctx: MiddlewareContext): Promise<void> {\n if (ctx.modality !== 'llm' || !isLLMRequest(ctx.request)) {\n return;\n }\n\n ctx.state.set(STATE_KEY_ID, adapter.id);\n\n let loaded: PersistenceLoadResult;\n try {\n loaded = await adapter.load(adapter.id);\n } catch (error) {\n const err = toError(error);\n throw new Error(`Persistence adapter failed to load thread \"${adapter.id}\": ${err.message}`, {\n cause: err,\n });\n }\n\n let thread: Thread;\n if (!loaded) {\n thread = new Thread();\n } else if (loaded instanceof Thread) {\n thread = loaded;\n } else {\n try {\n thread = Thread.fromJSON(loaded);\n } catch (error) {\n const err = toError(error);\n throw new Error(`Persistence adapter failed to deserialize thread \"${adapter.id}\": ${err.message}`, {\n cause: err,\n });\n }\n }\n\n ctx.state.set(STATE_KEY_THREAD, thread);\n\n if (thread.messages.length > 0) {\n const existingIds = new Set(ctx.request.messages.map((message) => message.id));\n const missing = thread.messages.filter((message) => !existingIds.has(message.id));\n if (missing.length > 0) {\n ctx.request.messages.unshift(...missing);\n const currentIndex = ctx.state.get(TURN_START_INDEX_KEY);\n const nextIndex = (typeof currentIndex === 'number' ? currentIndex : 0) + missing.length;\n ctx.state.set(TURN_START_INDEX_KEY, nextIndex);\n }\n }\n },\n\n async onTurn(turn: Turn, ctx: MiddlewareContext): Promise<void> {\n if (ctx.modality !== 'llm') {\n return;\n }\n\n const thread = getThread(ctx.state);\n if (!thread) {\n return;\n }\n\n if (isLLMRequest(ctx.request)) {\n const turnMessageIds = new Set(turn.messages.map((message) => message.id));\n const existingIds = new Set(thread.messages.map((message) => message.id));\n for (const message of ctx.request.messages) {\n if (turnMessageIds.has(message.id)) {\n continue;\n }\n if (!existingIds.has(message.id)) {\n thread.push(message);\n existingIds.add(message.id);\n }\n }\n }\n\n thread.append(turn);\n\n try {\n await adapter.save(adapter.id, thread, turn);\n } catch (error) {\n const err = toError(error);\n throw new Error(`Persistence adapter failed to save thread \"${adapter.id}\": ${err.message}`, {\n cause: err,\n });\n }\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
- import { M as Middleware } from '../../llm-ByUFPcFH.js';
2
- import { M as MemoryAdapterOptions, P as PubSubAdapter, a as PubSubOptions } from '../../types-CE4B7pno.js';
3
- export { C as CompletionCallback, S as StoredStream, b as SubscriptionCallback, U as Unsubscribe } from '../../types-CE4B7pno.js';
4
- import '../../stream-S7nwQRqM.js';
1
+ import { M as Middleware } from '../../llm-DS_-l71X.js';
2
+ import { M as MemoryAdapterOptions, P as PubSubAdapter, a as PubSubOptions } from '../../types-Cr4F0tVy.js';
3
+ export { C as CompletionCallback, S as StoredStream, b as SubscriptionCallback, U as Unsubscribe } from '../../types-Cr4F0tVy.js';
4
+ import '../../stream-sXhBtWjl.js';
5
5
 
6
6
  /**
7
7
  * @fileoverview In-memory storage adapter for pub-sub middleware.
@@ -1,5 +1,5 @@
1
- import { P as PubSubAdapter } from '../../../../types-CE4B7pno.js';
2
- import '../../../../stream-S7nwQRqM.js';
1
+ import { P as PubSubAdapter } from '../../../../types-Cr4F0tVy.js';
2
+ import '../../../../stream-sXhBtWjl.js';
3
3
 
4
4
  /**
5
5
  * @fileoverview Express/Connect adapter for pub-sub stream resumption.
@@ -1,5 +1,5 @@
1
- import { P as PubSubAdapter } from '../../../../types-CE4B7pno.js';
2
- import '../../../../stream-S7nwQRqM.js';
1
+ import { P as PubSubAdapter } from '../../../../types-Cr4F0tVy.js';
2
+ import '../../../../stream-sXhBtWjl.js';
3
3
 
4
4
  /**
5
5
  * @fileoverview Fastify adapter for pub-sub stream resumption.
@@ -1,5 +1,5 @@
1
- import { P as PubSubAdapter } from '../../../../types-CE4B7pno.js';
2
- import '../../../../stream-S7nwQRqM.js';
1
+ import { P as PubSubAdapter } from '../../../../types-Cr4F0tVy.js';
2
+ import '../../../../stream-sXhBtWjl.js';
3
3
 
4
4
  /**
5
5
  * @fileoverview H3/Nitro/Nuxt adapter for pub-sub stream resumption.
@@ -6,8 +6,8 @@ import { streamSubscriber } from './express/index.js';
6
6
  export { express } from './express/index.js';
7
7
  import { createSubscriberStream } from './webapi/index.js';
8
8
  export { webapi } from './webapi/index.js';
9
- export { P as PubSubAdapter } from '../../../types-CE4B7pno.js';
10
- import '../../../stream-S7nwQRqM.js';
9
+ export { P as PubSubAdapter } from '../../../types-Cr4F0tVy.js';
10
+ import '../../../stream-sXhBtWjl.js';
11
11
 
12
12
  /**
13
13
  * Server adapters namespace for pub-sub stream resumption.
@@ -1,5 +1,5 @@
1
- import { P as PubSubAdapter } from '../../../../types-CE4B7pno.js';
2
- import '../../../../stream-S7nwQRqM.js';
1
+ import { P as PubSubAdapter } from '../../../../types-Cr4F0tVy.js';
2
+ import '../../../../stream-sXhBtWjl.js';
3
3
 
4
4
  /**
5
5
  * @fileoverview Web API adapter for pub-sub stream resumption.
@@ -1,5 +1,5 @@
1
- import { d as Provider } from '../llm-ByUFPcFH.js';
2
- import '../stream-S7nwQRqM.js';
1
+ import { e as Provider } from '../llm-DS_-l71X.js';
2
+ import '../stream-sXhBtWjl.js';
3
3
 
4
4
  /**
5
5
  * @fileoverview Type definitions for the Ollama provider.
@@ -1,33 +1,35 @@
1
1
  import {
2
2
  parseJsonResponse
3
- } from "../chunk-A2IM7PGT.js";
3
+ } from "../chunk-TUTYMOBL.js";
4
4
  import {
5
5
  resolveApiKey
6
6
  } from "../chunk-ARVM24K2.js";
7
7
  import {
8
8
  createProvider
9
9
  } from "../chunk-JA3UZALR.js";
10
+ import {
11
+ doFetch,
12
+ doStreamFetch,
13
+ normalizeHttpError
14
+ } from "../chunk-SBGZJVTJ.js";
15
+ import {
16
+ StreamEventType,
17
+ objectDelta
18
+ } from "../chunk-MJI74VEJ.js";
10
19
  import {
11
20
  AssistantMessage,
12
21
  isAssistantMessage,
13
22
  isToolResultMessage,
14
23
  isUserMessage
15
- } from "../chunk-BRP5XJ6Q.js";
24
+ } from "../chunk-WU4U6IHF.js";
16
25
  import {
17
- doFetch,
18
- doStreamFetch,
19
- normalizeHttpError,
20
26
  toError
21
- } from "../chunk-AY55T37A.js";
27
+ } from "../chunk-GIDT7C6I.js";
22
28
  import {
23
29
  ErrorCode,
24
30
  ModalityType,
25
31
  UPPError
26
32
  } from "../chunk-COS4ON4G.js";
27
- import {
28
- StreamEventType,
29
- objectDelta
30
- } from "../chunk-RJGTRQ47.js";
31
33
 
32
34
  // src/providers/ollama/transform.ts
33
35
  function normalizeSystem(system) {