@tanstack/ai 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/esm/activities/chat/adapter.d.ts +14 -0
  2. package/dist/esm/activities/chat/adapter.js.map +1 -1
  3. package/dist/esm/activities/chat/index.d.ts +16 -6
  4. package/dist/esm/activities/chat/index.js +235 -9
  5. package/dist/esm/activities/chat/index.js.map +1 -1
  6. package/dist/esm/activities/error-payload.d.ts +0 -8
  7. package/dist/esm/activities/error-payload.js +20 -2
  8. package/dist/esm/activities/error-payload.js.map +1 -1
  9. package/dist/esm/activities/generateImage/adapter.d.ts +2 -2
  10. package/dist/esm/activities/generateImage/adapter.js.map +1 -1
  11. package/dist/esm/activities/generateVideo/adapter.d.ts +2 -2
  12. package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
  13. package/dist/esm/activities/index.d.ts +1 -0
  14. package/dist/esm/activities/index.js +2 -0
  15. package/dist/esm/activities/index.js.map +1 -1
  16. package/dist/esm/activities/stream-generation-result.js +0 -2
  17. package/dist/esm/activities/stream-generation-result.js.map +1 -1
  18. package/dist/esm/activities/summarize/adapter.d.ts +4 -4
  19. package/dist/esm/activities/summarize/adapter.js.map +1 -1
  20. package/dist/esm/activities/summarize/chat-stream-summarize.d.ts +45 -0
  21. package/dist/esm/activities/summarize/chat-stream-summarize.js +148 -0
  22. package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -0
  23. package/dist/esm/activities/summarize/index.d.ts +1 -0
  24. package/dist/esm/activities/summarize/index.js +4 -2
  25. package/dist/esm/activities/summarize/index.js.map +1 -1
  26. package/dist/esm/types.d.ts +94 -3
  27. package/package.json +2 -2
  28. package/skills/ai-core/structured-outputs/SKILL.md +92 -1
  29. package/src/activities/chat/adapter.ts +17 -0
  30. package/src/activities/chat/index.ts +368 -26
  31. package/src/activities/error-payload.ts +31 -2
  32. package/src/activities/generateImage/adapter.ts +8 -2
  33. package/src/activities/generateVideo/adapter.ts +8 -2
  34. package/src/activities/index.ts +5 -0
  35. package/src/activities/stream-generation-result.ts +4 -6
  36. package/src/activities/summarize/adapter.ts +8 -4
  37. package/src/activities/summarize/chat-stream-summarize.ts +238 -0
  38. package/src/activities/summarize/index.ts +12 -9
  39. package/src/types.ts +107 -3
@@ -2,6 +2,7 @@ import { chat, kind } from "./chat/index.js";
2
2
  import { BaseTextAdapter } from "./chat/adapter.js";
3
3
  import { summarize, kind as kind2 } from "./summarize/index.js";
4
4
  import { BaseSummarizeAdapter } from "./summarize/adapter.js";
5
+ import { ChatStreamSummarizeAdapter } from "./summarize/chat-stream-summarize.js";
5
6
  import { generateImage, kind as kind3 } from "./generateImage/index.js";
6
7
  import { BaseImageAdapter } from "./generateImage/adapter.js";
7
8
  import { kind as kind4, generateAudio } from "./generateAudio/index.js";
@@ -20,6 +21,7 @@ export {
20
21
  BaseTextAdapter,
21
22
  BaseTranscriptionAdapter,
22
23
  BaseVideoAdapter,
24
+ ChatStreamSummarizeAdapter,
23
25
  kind4 as audioKind,
24
26
  chat,
25
27
  generateAudio,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
@@ -31,8 +31,6 @@ async function* streamGenerationResult(generator, options) {
31
31
  const payload = toRunErrorPayload(error, "Generation failed");
32
32
  yield {
33
33
  type: EventType.RUN_ERROR,
34
- runId,
35
- threadId,
36
34
  message: payload.message,
37
35
  code: payload.code,
38
36
  // Deprecated nested form for backward compatibility
@@ -1 +1 @@
1
- {"version":3,"file":"stream-generation-result.js","sources":["../../../src/activities/stream-generation-result.ts"],"sourcesContent":["/**\n * Internal helper for wrapping one-shot generation results as StreamChunk\n * async iterables. NOT exported from the package — used only by activity\n * implementations to support `stream: true`.\n */\n\nimport { EventType } from '@ag-ui/core'\nimport { toRunErrorPayload } from './error-payload'\nimport type { StreamChunk } from '../types'\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n/**\n * Wrap a one-shot generation result as a StreamChunk async iterable.\n *\n * This allows non-streaming activities (image, speech, transcription, summarize)\n * to be sent over the same streaming transport as chat.\n *\n * @param generator - An async function that performs the generation and returns the result\n * @param options - Optional configuration (runId, threadId)\n * @returns An AsyncIterable of StreamChunks with RUN_STARTED, CUSTOM(generation:result), and RUN_FINISHED events on success, or RUN_STARTED and RUN_ERROR on failure\n */\nexport async function* streamGenerationResult<TResult>(\n generator: () => Promise<TResult>,\n options?: { runId?: string; threadId?: string },\n): AsyncIterable<StreamChunk> {\n const runId = options?.runId ?? createId('run')\n const threadId = options?.threadId ?? createId('thread')\n\n yield {\n type: EventType.RUN_STARTED,\n runId,\n threadId,\n timestamp: Date.now(),\n } as StreamChunk\n\n try {\n const result = await generator()\n\n yield {\n type: EventType.CUSTOM,\n name: 'generation:result',\n value: result as unknown,\n timestamp: Date.now(),\n } as StreamChunk\n\n yield {\n type: EventType.RUN_FINISHED,\n runId,\n threadId,\n finishReason: 'stop',\n timestamp: Date.now(),\n } as StreamChunk\n } catch (error: unknown) {\n const payload = toRunErrorPayload(error, 'Generation failed')\n yield {\n type: EventType.RUN_ERROR,\n runId,\n threadId,\n message: payload.message,\n code: payload.code,\n // Deprecated nested form for backward compatibility\n error: payload,\n timestamp: Date.now(),\n } as StreamChunk\n }\n}\n"],"names":[],"mappings":";;AAUA,SAAS,SAAS,QAAwB;AACxC,SAAO,GAAG,MAAM,IAAI,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC1E;AAYA,gBAAuB,uBACrB,WACA,SAC4B;AAC5B,QAAM,QAA0B,SAAS,KAAK;AAC9C,QAAM,WAAgC,SAAS,QAAQ;AAEvD,QAAM;AAAA,IACJ,MAAM,UAAU;AAAA,IAChB;AAAA,IACA;AAAA,IACA,WAAW,KAAK,IAAA;AAAA,EAAI;AAGtB,MAAI;AACF,UAAM,SAAS,MAAM,UAAA;AAErB,UAAM;AAAA,MACJ,MAAM,UAAU;AAAA,MAChB,MAAM;AAAA,MACN,OAAO;AAAA,MACP,WAAW,KAAK,IAAA;AAAA,IAAI;AAGtB,UAAM;AAAA,MACJ,MAAM,UAAU;AAAA,MAChB;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,WAAW,KAAK,IAAA;AAAA,IAAI;AAAA,EAExB,SAAS,OAAgB;AACvB,UAAM,UAAU,kBAAkB,OAAO,mBAAmB;AAC5D,UAAM;AAAA,MACJ,MAAM,UAAU;AAAA,MAChB;AAAA,MACA;AAAA,MACA,SAAS,QAAQ;AAAA,MACjB,MAAM,QAAQ;AAAA;AAAA,MAEd,OAAO;AAAA,MACP,WAAW,KAAK,IAAA;AAAA,IAAI;AAAA,EAExB;AACF;"}
1
+ {"version":3,"file":"stream-generation-result.js","sources":["../../../src/activities/stream-generation-result.ts"],"sourcesContent":["/**\n * Internal helper for wrapping one-shot generation results as StreamChunk\n * async iterables. NOT exported from the package — used only by activity\n * implementations to support `stream: true`.\n */\n\nimport { EventType } from '@ag-ui/core'\nimport { toRunErrorPayload } from './error-payload'\nimport type { StreamChunk } from '../types'\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n/**\n * Wrap a one-shot generation result as a StreamChunk async iterable.\n *\n * This allows non-streaming activities (image, speech, transcription, summarize)\n * to be sent over the same streaming transport as chat.\n *\n * @param generator - An async function that performs the generation and returns the result\n * @param options - Optional configuration (runId, threadId)\n * @returns An AsyncIterable of StreamChunks with RUN_STARTED, CUSTOM(generation:result), and RUN_FINISHED events on success, or RUN_STARTED and RUN_ERROR on failure\n */\nexport async function* streamGenerationResult<TResult>(\n generator: () => Promise<TResult>,\n options?: { runId?: string; threadId?: string },\n): AsyncIterable<StreamChunk> {\n const runId = options?.runId ?? createId('run')\n const threadId = options?.threadId ?? createId('thread')\n\n yield {\n type: EventType.RUN_STARTED,\n runId,\n threadId,\n timestamp: Date.now(),\n }\n\n try {\n const result = await generator()\n\n yield {\n type: EventType.CUSTOM,\n name: 'generation:result',\n value: result as unknown,\n timestamp: Date.now(),\n }\n\n yield {\n type: EventType.RUN_FINISHED,\n runId,\n threadId,\n finishReason: 'stop',\n timestamp: Date.now(),\n }\n } catch (error: unknown) {\n const payload = toRunErrorPayload(error, 'Generation failed')\n yield {\n type: EventType.RUN_ERROR,\n message: payload.message,\n code: payload.code,\n // Deprecated nested form for backward compatibility\n error: payload,\n timestamp: Date.now(),\n }\n }\n}\n"],"names":[],"mappings":";;AAUA,SAAS,SAAS,QAAwB;AACxC,SAAO,GAAG,MAAM,IAAI,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC1E;AAYA,gBAAuB,uBACrB,WACA,SAC4B;AAC5B,QAAM,QAA0B,SAAS,KAAK;AAC9C,QAAM,WAAgC,SAAS,QAAQ;AAEvD,QAAM;AAAA,IACJ,MAAM,UAAU;AAAA,IAChB;AAAA,IACA;AAAA,IACA,WAAW,KAAK,IAAA;AAAA,EAAI;AAGtB,MAAI;AACF,UAAM,SAAS,MAAM,UAAA;AAErB,UAAM;AAAA,MACJ,MAAM,UAAU;AAAA,MAChB,MAAM;AAAA,MACN,OAAO;AAAA,MACP,WAAW,KAAK,IAAA;AAAA,IAAI;AAGtB,UAAM;AAAA,MACJ,MAAM,UAAU;AAAA,MAChB;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,WAAW,KAAK,IAAA;AAAA,IAAI;AAAA,EAExB,SAAS,OAAgB;AACvB,UAAM,UAAU,kBAAkB,OAAO,mBAAmB;AAC5D,UAAM;AAAA,MACJ,MAAM,UAAU;AAAA,MAChB,SAAS,QAAQ;AAAA,MACjB,MAAM,QAAQ;AAAA;AAAA,MAEd,OAAO;AAAA,MACP,WAAW,KAAK,IAAA;AAAA,IAAI;AAAA,EAExB;AACF;"}
@@ -35,13 +35,13 @@ export interface SummarizeAdapter<TModel extends string = string, TProviderOptio
35
35
  /**
36
36
  * Summarize the given text
37
37
  */
38
- summarize: (options: SummarizationOptions) => Promise<SummarizationResult>;
38
+ summarize: (options: SummarizationOptions<TProviderOptions>) => Promise<SummarizationResult>;
39
39
  /**
40
40
  * Stream summarization of the given text.
41
41
  * Optional - if not implemented, the activity layer will fall back to
42
42
  * non-streaming summarize and yield the result as a single chunk.
43
43
  */
44
- summarizeStream?: (options: SummarizationOptions) => AsyncIterable<StreamChunk>;
44
+ summarizeStream?: (options: SummarizationOptions<TProviderOptions>) => AsyncIterable<StreamChunk>;
45
45
  }
46
46
  /**
47
47
  * A SummarizeAdapter with any/unknown type parameters.
@@ -63,12 +63,12 @@ export declare abstract class BaseSummarizeAdapter<TModel extends string = strin
63
63
  };
64
64
  protected config: SummarizeAdapterConfig;
65
65
  constructor(config: SummarizeAdapterConfig | undefined, model: TModel);
66
- abstract summarize(options: SummarizationOptions): Promise<SummarizationResult>;
66
+ abstract summarize(options: SummarizationOptions<TProviderOptions>): Promise<SummarizationResult>;
67
67
  /**
68
68
  * Stream summarization of the given text.
69
69
  * Override this method in concrete implementations to enable streaming.
70
70
  * If not overridden, the activity layer will fall back to non-streaming.
71
71
  */
72
- summarizeStream?(options: SummarizationOptions): AsyncIterable<StreamChunk>;
72
+ summarizeStream?(options: SummarizationOptions<TProviderOptions>): AsyncIterable<StreamChunk>;
73
73
  protected generateId(): string;
74
74
  }
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","sources":["../../../../src/activities/summarize/adapter.ts"],"sourcesContent":["import type {\n StreamChunk,\n SummarizationOptions,\n SummarizationResult,\n} from '../../types'\n\n/**\n * Configuration for summarize adapter instances\n */\nexport interface SummarizeAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n maxRetries?: number\n headers?: Record<string, string>\n}\n\n/**\n * Summarize adapter interface with pre-resolved generics.\n *\n * An adapter is created by a provider function: `provider('model')` → `adapter`\n * All type resolution happens at the provider call site, not in this interface.\n *\n * Generic parameters:\n * - TModel: The specific model name (e.g., 'gpt-4o')\n * - TProviderOptions: Provider-specific options (already resolved)\n */\nexport interface SummarizeAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n> {\n /** Discriminator for adapter kind - used by generate() to determine API shape */\n readonly kind: 'summarize'\n /** Adapter name identifier */\n readonly name: string\n /** The model this adapter is configured for */\n readonly model: TModel\n\n /**\n * @internal Type-only properties for inference. Not assigned at runtime.\n */\n '~types': {\n providerOptions: TProviderOptions\n }\n\n /**\n * Summarize the given text\n */\n summarize: (options: SummarizationOptions) => Promise<SummarizationResult>\n\n /**\n * Stream summarization of the given text.\n * Optional - if not implemented, the activity layer will fall back to\n * non-streaming summarize and yield the result as a single chunk.\n */\n summarizeStream?: (\n options: SummarizationOptions,\n ) => AsyncIterable<StreamChunk>\n}\n\n/**\n * A SummarizeAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnySummarizeAdapter = SummarizeAdapter<any, any>\n\n/**\n * Abstract base class for summarize adapters.\n * Extend this class to implement a summarize adapter for a specific provider.\n *\n * Generic parameters match SummarizeAdapter - all pre-resolved by the provider function.\n */\nexport abstract class BaseSummarizeAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n> implements SummarizeAdapter<TModel, TProviderOptions> {\n readonly kind = 'summarize' as const\n abstract readonly name: string\n readonly model: TModel\n\n // Type-only property - never assigned at runtime\n declare '~types': {\n providerOptions: TProviderOptions\n }\n\n protected config: SummarizeAdapterConfig\n\n constructor(config: SummarizeAdapterConfig = {}, model: TModel) {\n this.config = config\n this.model = model\n }\n\n abstract summarize(\n options: SummarizationOptions,\n ): Promise<SummarizationResult>\n\n /**\n * Stream summarization of the given text.\n * Override this method in concrete implementations to enable streaming.\n * If not overridden, the activity layer will fall back to non-streaming.\n */\n summarizeStream?(options: SummarizationOptions): AsyncIterable<StreamChunk>\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"names":[],"mappings":"AAwEO,MAAe,qBAGkC;AAAA,EAYtD,YAAY,SAAiC,CAAA,GAAI,OAAe;AAXhE,SAAS,OAAO;AAYd,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,EACf;AAAA,EAaU,aAAqB;AAC7B,WAAO,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;AAAA,EAC9E;AACF;"}
1
+ {"version":3,"file":"adapter.js","sources":["../../../../src/activities/summarize/adapter.ts"],"sourcesContent":["import type {\n StreamChunk,\n SummarizationOptions,\n SummarizationResult,\n} from '../../types'\n\n/**\n * Configuration for summarize adapter instances\n */\nexport interface SummarizeAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n maxRetries?: number\n headers?: Record<string, string>\n}\n\n/**\n * Summarize adapter interface with pre-resolved generics.\n *\n * An adapter is created by a provider function: `provider('model')` → `adapter`\n * All type resolution happens at the provider call site, not in this interface.\n *\n * Generic parameters:\n * - TModel: The specific model name (e.g., 'gpt-4o')\n * - TProviderOptions: Provider-specific options (already resolved)\n */\nexport interface SummarizeAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n> {\n /** Discriminator for adapter kind - used by generate() to determine API shape */\n readonly kind: 'summarize'\n /** Adapter name identifier */\n readonly name: string\n /** The model this adapter is configured for */\n readonly model: TModel\n\n /**\n * @internal Type-only properties for inference. Not assigned at runtime.\n */\n '~types': {\n providerOptions: TProviderOptions\n }\n\n /**\n * Summarize the given text\n */\n summarize: (\n options: SummarizationOptions<TProviderOptions>,\n ) => Promise<SummarizationResult>\n\n /**\n * Stream summarization of the given text.\n * Optional - if not implemented, the activity layer will fall back to\n * non-streaming summarize and yield the result as a single chunk.\n */\n summarizeStream?: (\n options: SummarizationOptions<TProviderOptions>,\n ) => AsyncIterable<StreamChunk>\n}\n\n/**\n * A SummarizeAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnySummarizeAdapter = SummarizeAdapter<any, any>\n\n/**\n * Abstract base class for summarize adapters.\n * Extend this class to implement a summarize adapter for a specific provider.\n *\n * Generic parameters match SummarizeAdapter - all pre-resolved by the provider function.\n */\nexport abstract class BaseSummarizeAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n> implements SummarizeAdapter<TModel, TProviderOptions> {\n readonly kind = 'summarize' as const\n abstract readonly name: string\n readonly model: TModel\n\n // Type-only property - never assigned at runtime\n declare '~types': {\n providerOptions: TProviderOptions\n }\n\n protected config: SummarizeAdapterConfig\n\n constructor(config: SummarizeAdapterConfig = {}, model: TModel) {\n this.config = config\n this.model = model\n }\n\n abstract summarize(\n options: SummarizationOptions<TProviderOptions>,\n ): Promise<SummarizationResult>\n\n /**\n * Stream summarization of the given text.\n * Override this method in concrete implementations to enable streaming.\n * If not overridden, the activity layer will fall back to non-streaming.\n */\n summarizeStream?(\n options: SummarizationOptions<TProviderOptions>,\n ): AsyncIterable<StreamChunk>\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"names":[],"mappings":"AA0EO,MAAe,qBAGkC;AAAA,EAYtD,YAAY,SAAiC,CAAA,GAAI,OAAe;AAXhE,SAAS,OAAO;AAYd,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,EACf;AAAA,EAeU,aAAqB;AAC7B,WAAO,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;AAAA,EAC9E;AACF;"}
@@ -0,0 +1,45 @@
1
+ import { BaseSummarizeAdapter } from './adapter.js';
2
+ import { StreamChunk, SummarizationOptions, SummarizationResult, TextOptions } from '../../types.js';
3
+ /**
4
+ * Minimal contract for a text adapter that supports `chatStream`. Lets
5
+ * `ChatStreamSummarizeAdapter` work with any text adapter without coupling
6
+ * to a specific implementation.
7
+ *
8
+ * The provider-options shape is intentionally `any` here — the wrapper only
9
+ * forwards `modelOptions` straight through, so a text adapter with a richer
10
+ * per-model options type (e.g. `ResolveProviderOptions<TModel>`) is still
11
+ * acceptable. Summarize-level type safety is enforced via
12
+ * `SummarizationOptions<TProviderOptions>` on the wrapper itself.
13
+ */
14
+ export interface ChatStreamCapable {
15
+ chatStream: (options: TextOptions<any>) => AsyncIterable<StreamChunk>;
16
+ }
17
+ /**
18
+ * Extract the per-model `modelOptions` type a text adapter accepts. Used by
19
+ * provider summarize factories so their `modelOptions` IntelliSense matches
20
+ * what the underlying text adapter actually understands.
21
+ */
22
+ export type InferTextProviderOptions<TAdapter> = TAdapter extends {
23
+ '~types': {
24
+ providerOptions: infer P;
25
+ };
26
+ } ? P extends object ? P : object : object;
27
+ /**
28
+ * Summarize adapter that wraps any `ChatStreamCapable` text adapter and
29
+ * prompts it for summarization. Not tied to any wire format.
30
+ */
31
+ export declare class ChatStreamSummarizeAdapter<TModel extends string, TProviderOptions extends object = Record<string, unknown>> extends BaseSummarizeAdapter<TModel, TProviderOptions> {
32
+ readonly name: string;
33
+ private textAdapter;
34
+ constructor(textAdapter: ChatStreamCapable, model: TModel, name?: string);
35
+ summarize(options: SummarizationOptions<TProviderOptions>): Promise<SummarizationResult>;
36
+ summarizeStream(options: SummarizationOptions<TProviderOptions>): AsyncIterable<StreamChunk>;
37
+ /**
38
+ * Build the TextOptions passed to the underlying chatStream. Provider
39
+ * `modelOptions` from the summarize call are forwarded as-is so knobs like
40
+ * Anthropic cache headers, Gemini safety settings, or Ollama tuning params
41
+ * still reach the wire layer.
42
+ */
43
+ protected buildTextOptions(options: SummarizationOptions<TProviderOptions>, systemPrompt: string): TextOptions<TProviderOptions>;
44
+ protected buildSummarizationPrompt(options: SummarizationOptions<TProviderOptions>): string;
45
+ }
@@ -0,0 +1,148 @@
1
+ import { EventType } from "@ag-ui/core";
2
+ import { toRunErrorPayload } from "../error-payload.js";
3
+ import { BaseSummarizeAdapter } from "./adapter.js";
4
+ class ChatStreamSummarizeAdapter extends BaseSummarizeAdapter {
5
+ constructor(textAdapter, model, name = "chat-stream-summarize") {
6
+ super({}, model);
7
+ this.name = name;
8
+ this.textAdapter = textAdapter;
9
+ }
10
+ async summarize(options) {
11
+ const systemPrompt = this.buildSummarizationPrompt(options);
12
+ let summary = "";
13
+ const id = this.generateId();
14
+ let model = options.model;
15
+ let usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
16
+ options.logger.request(
17
+ `activity=summarize provider=${this.name} model=${options.model} text-length=${options.text.length} maxLength=${options.maxLength ?? "unset"}`,
18
+ { provider: this.name, model: options.model }
19
+ );
20
+ try {
21
+ for await (const chunk of this.textAdapter.chatStream(
22
+ this.buildTextOptions(options, systemPrompt)
23
+ )) {
24
+ if (chunk.type === "TEXT_MESSAGE_CONTENT") {
25
+ if (chunk.content) {
26
+ summary = chunk.content;
27
+ } else if (chunk.delta) {
28
+ summary += chunk.delta;
29
+ }
30
+ model = chunk.model || model;
31
+ }
32
+ if (chunk.type === "RUN_FINISHED") {
33
+ if (chunk.usage) {
34
+ usage = chunk.usage;
35
+ }
36
+ }
37
+ if (chunk.type === "RUN_ERROR") {
38
+ const message = (chunk.error && typeof chunk.error.message === "string" ? chunk.error.message : null) ?? "Summarization failed";
39
+ const code = chunk.error && typeof chunk.error.code === "string" ? chunk.error.code : void 0;
40
+ const err = new Error(message);
41
+ if (code) {
42
+ ;
43
+ err.code = code;
44
+ }
45
+ throw err;
46
+ }
47
+ }
48
+ } catch (error) {
49
+ options.logger.errors(`${this.name}.summarize fatal`, {
50
+ error: toRunErrorPayload(error, `${this.name}.summarize failed`),
51
+ source: `${this.name}.summarize`
52
+ });
53
+ throw error;
54
+ }
55
+ return { id, model, summary, usage };
56
+ }
57
+ async *summarizeStream(options) {
58
+ const systemPrompt = this.buildSummarizationPrompt(options);
59
+ options.logger.request(
60
+ `activity=summarizeStream provider=${this.name} model=${options.model} text-length=${options.text.length} maxLength=${options.maxLength ?? "unset"}`,
61
+ { provider: this.name, model: options.model }
62
+ );
63
+ const id = this.generateId();
64
+ let summary = "";
65
+ let model = options.model;
66
+ let usage = {
67
+ promptTokens: 0,
68
+ completionTokens: 0,
69
+ totalTokens: 0
70
+ };
71
+ try {
72
+ for await (const chunk of this.textAdapter.chatStream(
73
+ this.buildTextOptions(options, systemPrompt)
74
+ )) {
75
+ if (chunk.type === "TEXT_MESSAGE_CONTENT") {
76
+ if (chunk.content) {
77
+ summary = chunk.content;
78
+ } else if (chunk.delta) {
79
+ summary += chunk.delta;
80
+ }
81
+ if (chunk.model) model = chunk.model;
82
+ }
83
+ if (chunk.type === "RUN_FINISHED") {
84
+ if (chunk.usage) usage = chunk.usage;
85
+ if (chunk.model) model = chunk.model;
86
+ yield {
87
+ type: EventType.CUSTOM,
88
+ name: "generation:result",
89
+ value: { id, model, summary, usage },
90
+ model,
91
+ timestamp: Date.now()
92
+ };
93
+ }
94
+ yield chunk;
95
+ }
96
+ } catch (error) {
97
+ options.logger.errors(`${this.name}.summarizeStream fatal`, {
98
+ error: toRunErrorPayload(error, `${this.name}.summarizeStream failed`),
99
+ source: `${this.name}.summarizeStream`
100
+ });
101
+ throw error;
102
+ }
103
+ }
104
+ /**
105
+ * Build the TextOptions passed to the underlying chatStream. Provider
106
+ * `modelOptions` from the summarize call are forwarded as-is so knobs like
107
+ * Anthropic cache headers, Gemini safety settings, or Ollama tuning params
108
+ * still reach the wire layer.
109
+ */
110
+ buildTextOptions(options, systemPrompt) {
111
+ return {
112
+ model: options.model,
113
+ messages: [{ role: "user", content: options.text }],
114
+ systemPrompts: [systemPrompt],
115
+ maxTokens: options.maxLength,
116
+ temperature: 0.3,
117
+ modelOptions: options.modelOptions,
118
+ logger: options.logger
119
+ };
120
+ }
121
+ buildSummarizationPrompt(options) {
122
+ let prompt = "You are a professional summarizer. ";
123
+ switch (options.style) {
124
+ case "bullet-points":
125
+ prompt += "Provide a summary in bullet point format. ";
126
+ break;
127
+ case "paragraph":
128
+ prompt += "Provide a summary in paragraph format. ";
129
+ break;
130
+ case "concise":
131
+ prompt += "Provide a very concise summary in 1-2 sentences. ";
132
+ break;
133
+ default:
134
+ prompt += "Provide a clear and concise summary. ";
135
+ }
136
+ if (options.focus && options.focus.length > 0) {
137
+ prompt += `Focus on the following aspects: ${options.focus.join(", ")}. `;
138
+ }
139
+ if (options.maxLength) {
140
+ prompt += `Keep the summary under ${options.maxLength} tokens. `;
141
+ }
142
+ return prompt;
143
+ }
144
+ }
145
+ export {
146
+ ChatStreamSummarizeAdapter
147
+ };
148
+ //# sourceMappingURL=chat-stream-summarize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-stream-summarize.js","sources":["../../../../src/activities/summarize/chat-stream-summarize.ts"],"sourcesContent":["import { EventType } from '@ag-ui/core'\nimport { toRunErrorPayload } from '../error-payload'\nimport { BaseSummarizeAdapter } from './adapter'\nimport type {\n StreamChunk,\n SummarizationOptions,\n SummarizationResult,\n TextOptions,\n} from '../../types'\n\n/**\n * Minimal contract for a text adapter that supports `chatStream`. Lets\n * `ChatStreamSummarizeAdapter` work with any text adapter without coupling\n * to a specific implementation.\n *\n * The provider-options shape is intentionally `any` here — the wrapper only\n * forwards `modelOptions` straight through, so a text adapter with a richer\n * per-model options type (e.g. `ResolveProviderOptions<TModel>`) is still\n * acceptable. Summarize-level type safety is enforced via\n * `SummarizationOptions<TProviderOptions>` on the wrapper itself.\n */\nexport interface ChatStreamCapable {\n chatStream: (options: TextOptions<any>) => AsyncIterable<StreamChunk>\n}\n\n/**\n * Extract the per-model `modelOptions` type a text adapter accepts. Used by\n * provider summarize factories so their `modelOptions` IntelliSense matches\n * what the underlying text adapter actually understands.\n */\nexport type InferTextProviderOptions<TAdapter> = TAdapter extends {\n '~types': { providerOptions: infer P }\n}\n ? P extends object\n ? P\n : object\n : object\n\n/**\n * Summarize adapter that wraps any `ChatStreamCapable` text adapter and\n * prompts it for summarization. Not tied to any wire format.\n */\nexport class ChatStreamSummarizeAdapter<\n TModel extends string,\n TProviderOptions extends object = Record<string, unknown>,\n> extends BaseSummarizeAdapter<TModel, TProviderOptions> {\n readonly name: string\n\n private textAdapter: ChatStreamCapable\n\n constructor(\n textAdapter: ChatStreamCapable,\n model: TModel,\n name: string = 'chat-stream-summarize',\n ) {\n super({}, model)\n this.name = name\n this.textAdapter = textAdapter\n }\n\n async summarize(\n options: SummarizationOptions<TProviderOptions>,\n ): Promise<SummarizationResult> {\n const systemPrompt = this.buildSummarizationPrompt(options)\n\n let summary = ''\n const id = this.generateId()\n let model = options.model\n let usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 }\n\n options.logger.request(\n `activity=summarize provider=${this.name} model=${options.model} text-length=${options.text.length} maxLength=${options.maxLength ?? 'unset'}`,\n { provider: this.name, model: options.model },\n )\n\n try {\n for await (const chunk of this.textAdapter.chatStream(\n this.buildTextOptions(options, systemPrompt),\n )) {\n if (chunk.type === 'TEXT_MESSAGE_CONTENT') {\n if (chunk.content) {\n summary = chunk.content\n } else if (chunk.delta) {\n // Append delta only when present — a content-less chunk with no\n // delta would otherwise concat literal `'undefined'`.\n summary += chunk.delta\n }\n model = chunk.model || model\n }\n if (chunk.type === 'RUN_FINISHED') {\n if (chunk.usage) {\n usage = chunk.usage\n }\n }\n // Surface failures: the underlying chatStream emits RUN_ERROR instead\n // of throwing, so without this branch summarize() would return an\n // empty summary and pretend a failed run succeeded.\n if (chunk.type === 'RUN_ERROR') {\n const message =\n (chunk.error && typeof chunk.error.message === 'string'\n ? chunk.error.message\n : null) ?? 'Summarization failed'\n const code =\n chunk.error && typeof chunk.error.code === 'string'\n ? chunk.error.code\n : undefined\n const err = new Error(message)\n if (code) {\n ;(err as Error & { code?: string }).code = code\n }\n throw err\n }\n }\n } catch (error: unknown) {\n // Narrow before logging: raw SDK errors can carry request metadata\n // (including auth headers) which we must never surface to user loggers.\n options.logger.errors(`${this.name}.summarize fatal`, {\n error: toRunErrorPayload(error, `${this.name}.summarize failed`),\n source: `${this.name}.summarize`,\n })\n throw error\n }\n\n return { id, model, summary, usage }\n }\n\n async *summarizeStream(\n options: SummarizationOptions<TProviderOptions>,\n ): AsyncIterable<StreamChunk> {\n const systemPrompt = this.buildSummarizationPrompt(options)\n\n options.logger.request(\n `activity=summarizeStream provider=${this.name} model=${options.model} text-length=${options.text.length} maxLength=${options.maxLength ?? 'unset'}`,\n { provider: this.name, model: options.model },\n )\n\n const id = this.generateId()\n let summary = ''\n let model = options.model\n let usage: SummarizationResult['usage'] = {\n promptTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n }\n\n try {\n for await (const chunk of this.textAdapter.chatStream(\n this.buildTextOptions(options, systemPrompt),\n )) {\n // Accumulate the same way `summarize()` does so consumers see deltas\n // AND the terminal `generation:result` event below carries the same\n // final summary that non-streaming returns.\n if (chunk.type === 'TEXT_MESSAGE_CONTENT') {\n if (chunk.content) {\n summary = chunk.content\n } else if (chunk.delta) {\n summary += chunk.delta\n }\n if (chunk.model) model = chunk.model\n }\n\n // Emit the GenerationClient-shaped result event just before the\n // terminal RUN_FINISHED so subscribers (useSummarize) populate\n // `result` before flipping `status` to success.\n if (chunk.type === 'RUN_FINISHED') {\n if (chunk.usage) usage = chunk.usage\n if (chunk.model) model = chunk.model\n yield {\n type: EventType.CUSTOM,\n name: 'generation:result',\n value: { id, model, summary, usage } satisfies SummarizationResult,\n model,\n timestamp: Date.now(),\n }\n }\n\n yield chunk\n }\n } catch (error: unknown) {\n options.logger.errors(`${this.name}.summarizeStream fatal`, {\n error: toRunErrorPayload(error, `${this.name}.summarizeStream failed`),\n source: `${this.name}.summarizeStream`,\n })\n throw error\n }\n }\n\n /**\n * Build the TextOptions passed to the underlying chatStream. Provider\n * `modelOptions` from the summarize call are forwarded as-is so knobs like\n * Anthropic cache headers, Gemini safety settings, or Ollama tuning params\n * still reach the wire layer.\n */\n protected buildTextOptions(\n options: SummarizationOptions<TProviderOptions>,\n systemPrompt: string,\n ): TextOptions<TProviderOptions> {\n return {\n model: options.model,\n messages: [{ role: 'user', content: options.text }],\n systemPrompts: [systemPrompt],\n maxTokens: options.maxLength,\n temperature: 0.3,\n modelOptions: options.modelOptions,\n logger: options.logger,\n }\n }\n\n protected buildSummarizationPrompt(\n options: SummarizationOptions<TProviderOptions>,\n ): string {\n let prompt = 'You are a professional summarizer. '\n\n switch (options.style) {\n case 'bullet-points':\n prompt += 'Provide a summary in bullet point format. '\n break\n case 'paragraph':\n prompt += 'Provide a summary in paragraph format. '\n break\n case 'concise':\n prompt += 'Provide a very concise summary in 1-2 sentences. '\n break\n default:\n prompt += 'Provide a clear and concise summary. '\n }\n\n if (options.focus && options.focus.length > 0) {\n prompt += `Focus on the following aspects: ${options.focus.join(', ')}. `\n }\n\n if (options.maxLength) {\n prompt += `Keep the summary under ${options.maxLength} tokens. `\n }\n\n return prompt\n }\n}\n"],"names":[],"mappings":"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"}
@@ -105,3 +105,4 @@ export declare function summarize<TAdapter extends SummarizeAdapter<string, obje
105
105
  export declare function createSummarizeOptions<TAdapter extends SummarizeAdapter<string, object>, TStream extends boolean = false>(options: SummarizeActivityOptions<TAdapter, TStream>): SummarizeActivityOptions<TAdapter, TStream>;
106
106
  export type { SummarizeAdapter, SummarizeAdapterConfig, AnySummarizeAdapter, } from './adapter.js';
107
107
  export { BaseSummarizeAdapter } from './adapter.js';
108
+ export { ChatStreamSummarizeAdapter, type ChatStreamCapable, type InferTextProviderOptions, } from './chat-stream-summarize.js';
@@ -17,7 +17,7 @@ function summarize(options) {
17
17
  );
18
18
  }
19
19
  async function runSummarize(options) {
20
- const { adapter, text, maxLength, style, focus } = options;
20
+ const { adapter, text, maxLength, style, focus, modelOptions } = options;
21
21
  const model = adapter.model;
22
22
  const requestId = createId("summarize");
23
23
  const inputLength = text.length;
@@ -41,6 +41,7 @@ async function runSummarize(options) {
41
41
  maxLength,
42
42
  style,
43
43
  focus,
44
+ modelOptions,
44
45
  logger
45
46
  };
46
47
  try {
@@ -70,7 +71,7 @@ async function runSummarize(options) {
70
71
  }
71
72
  }
72
73
  async function* runStreamingSummarize(options) {
73
- const { adapter, text, maxLength, style, focus } = options;
74
+ const { adapter, text, maxLength, style, focus, modelOptions } = options;
74
75
  const model = adapter.model;
75
76
  const logger = resolveDebugOption(options.debug);
76
77
  logger.request(`activity=summarize provider=${adapter.name}`, {
@@ -84,6 +85,7 @@ async function* runStreamingSummarize(options) {
84
85
  maxLength,
85
86
  style,
86
87
  focus,
88
+ modelOptions,
87
89
  logger
88
90
  };
89
91
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/activities/summarize/index.ts"],"sourcesContent":["/**\n * Summarize Activity\n *\n * Generates summaries from text input.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport { aiEventClient } from '@tanstack/ai-event-client'\nimport { streamGenerationResult } from '../stream-generation-result.js'\nimport { resolveDebugOption } from '../../logger/resolve'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { SummarizeAdapter } from './adapter'\nimport type {\n StreamChunk,\n SummarizationOptions,\n SummarizationResult,\n} from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'summarize' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/** Extract provider options from a SummarizeAdapter via ~types */\nexport type SummarizeProviderOptions<TAdapter> =\n TAdapter extends SummarizeAdapter<any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the summarize activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The summarize adapter type\n * @template TStream - Whether to stream the output\n */\nexport interface SummarizeActivityOptions<\n TAdapter extends SummarizeAdapter<string, object>,\n TStream extends boolean = false,\n> {\n /** The summarize adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** The text to summarize */\n text: string\n /** Maximum length of the summary (in words or characters, provider-dependent) */\n maxLength?: number\n /** Style of summary to generate */\n style?: 'bullet-points' | 'paragraph' | 'concise'\n /** Topics or aspects to focus on in the summary */\n focus?: Array<string>\n /** Provider-specific options */\n modelOptions?: SummarizeProviderOptions<TAdapter>\n /**\n * Whether to stream the summarization result.\n * When true, returns an AsyncIterable<StreamChunk> for streaming output.\n * When false or not provided, returns a Promise<SummarizationResult>.\n *\n * @default false\n */\n stream?: TStream\n /**\n * Enable debug logging. Pass `true` to enable all categories, `false` to\n * silence everything including errors, or a `DebugConfig` object for granular\n * control and/or a custom `Logger`.\n */\n debug?: DebugOption\n}\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/**\n * Result type for the summarize activity.\n * - If stream is true: AsyncIterable<StreamChunk>\n * - Otherwise: Promise<SummarizationResult>\n */\nexport type SummarizeActivityResult<TStream extends boolean> =\n TStream extends true\n ? AsyncIterable<StreamChunk>\n : Promise<SummarizationResult>\n\n// ===========================\n// Helper Functions\n// ===========================\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Summarize activity - generates summaries from text.\n *\n * Supports both streaming and non-streaming modes.\n *\n * @example Basic summarization\n * ```ts\n * import { summarize } from '@tanstack/ai'\n * import { openaiSummarize } from '@tanstack/ai-openai'\n *\n * const result = await summarize({\n * adapter: openaiSummarize('gpt-4o-mini'),\n * text: 'Long article text here...'\n * })\n *\n * console.log(result.summary)\n * ```\n *\n * @example Summarization with style\n * ```ts\n * const result = await summarize({\n * adapter: openaiSummarize('gpt-4o-mini'),\n * text: 'Long article text here...',\n * style: 'bullet-points',\n * maxLength: 100\n * })\n * ```\n *\n * @example Focused summarization\n * ```ts\n * const result = await summarize({\n * adapter: openaiSummarize('gpt-4o-mini'),\n * text: 'Long technical document...',\n * focus: ['key findings', 'methodology']\n * })\n * ```\n *\n * @example Streaming summarization\n * ```ts\n * for await (const chunk of summarize({\n * adapter: openaiSummarize('gpt-4o-mini'),\n * text: 'Long article text here...',\n * stream: true\n * })) {\n * if (chunk.type === 'content') {\n * process.stdout.write(chunk.delta)\n * }\n * }\n * ```\n */\nexport function summarize<\n TAdapter extends SummarizeAdapter<string, object>,\n TStream extends boolean = false,\n>(\n options: SummarizeActivityOptions<TAdapter, TStream>,\n): SummarizeActivityResult<TStream> {\n const { stream } = options\n\n if (stream) {\n return runStreamingSummarize(\n options as unknown as SummarizeActivityOptions<\n SummarizeAdapter<string, object>,\n true\n >,\n ) as SummarizeActivityResult<TStream>\n }\n\n return runSummarize(\n options as unknown as SummarizeActivityOptions<\n SummarizeAdapter<string, object>,\n false\n >,\n ) as SummarizeActivityResult<TStream>\n}\n\n/**\n * Run non-streaming summarization\n */\nasync function runSummarize(\n options: SummarizeActivityOptions<SummarizeAdapter<string, object>, false>,\n): Promise<SummarizationResult> {\n const { adapter, text, maxLength, style, focus } = options\n const model = adapter.model\n const requestId = createId('summarize')\n const inputLength = text.length\n const startTime = Date.now()\n const logger: InternalLogger = resolveDebugOption(options.debug)\n\n aiEventClient.emit('summarize:request:started', {\n requestId,\n provider: adapter.name,\n model,\n inputLength,\n timestamp: startTime,\n })\n\n logger.request(`activity=summarize provider=${adapter.name}`, {\n provider: adapter.name,\n model,\n inputLength,\n })\n\n const summarizeOptions: SummarizationOptions = {\n model,\n text,\n maxLength,\n style,\n focus,\n logger,\n }\n\n try {\n const result = await adapter.summarize(summarizeOptions)\n\n const duration = Date.now() - startTime\n const outputLength = result.summary.length\n\n aiEventClient.emit('summarize:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n inputLength,\n outputLength,\n duration,\n timestamp: Date.now(),\n })\n\n logger.output(`activity=summarize length=${outputLength}`, {\n hasSummary: !!result.summary,\n outputLength,\n })\n\n return result\n } catch (error) {\n logger.errors('summarize activity failed', {\n error,\n source: 'summarize',\n })\n throw error\n }\n}\n\n/**\n * Run streaming summarization\n * Uses the adapter's native streaming if available, otherwise falls back\n * to non-streaming and yields the result as a single chunk.\n */\nasync function* runStreamingSummarize(\n options: SummarizeActivityOptions<SummarizeAdapter<string, object>, true>,\n): AsyncIterable<StreamChunk> {\n const { adapter, text, maxLength, style, focus } = options\n const model = adapter.model\n const logger: InternalLogger = resolveDebugOption(options.debug)\n\n logger.request(`activity=summarize provider=${adapter.name}`, {\n provider: adapter.name,\n model,\n stream: true,\n })\n\n const summarizeOptions: SummarizationOptions = {\n model,\n text,\n maxLength,\n style,\n focus,\n logger,\n }\n\n try {\n // Use real streaming if the adapter supports it\n if (adapter.summarizeStream) {\n yield* adapter.summarizeStream(summarizeOptions)\n return\n }\n\n // Fall back to non-streaming — wrap result with streamGenerationResult\n yield* streamGenerationResult(() => adapter.summarize(summarizeOptions))\n } catch (error) {\n logger.errors('summarize activity failed', {\n error,\n source: 'summarize',\n })\n throw error\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the summarize() function without executing.\n */\nexport function createSummarizeOptions<\n TAdapter extends SummarizeAdapter<string, object>,\n TStream extends boolean = false,\n>(\n options: SummarizeActivityOptions<TAdapter, TStream>,\n): SummarizeActivityOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n SummarizeAdapter,\n SummarizeAdapterConfig,\n AnySummarizeAdapter,\n} from './adapter'\nexport { BaseSummarizeAdapter } from './adapter'\n"],"names":[],"mappings":";;;AAwBO,MAAM,OAAO;AAyEpB,SAAS,SAAS,QAAwB;AACxC,SAAO,GAAG,MAAM,IAAI,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC1E;AAwDO,SAAS,UAId,SACkC;AAClC,QAAM,EAAE,WAAW;AAEnB,MAAI,QAAQ;AACV,WAAO;AAAA,MACL;AAAA,IAAA;AAAA,EAKJ;AAEA,SAAO;AAAA,IACL;AAAA,EAAA;AAKJ;AAKA,eAAe,aACb,SAC8B;AAC9B,QAAM,EAAE,SAAS,MAAM,WAAW,OAAO,UAAU;AACnD,QAAM,QAAQ,QAAQ;AACtB,QAAM,YAAY,SAAS,WAAW;AACtC,QAAM,cAAc,KAAK;AACzB,QAAM,YAAY,KAAK,IAAA;AACvB,QAAM,SAAyB,mBAAmB,QAAQ,KAAK;AAE/D,gBAAc,KAAK,6BAA6B;AAAA,IAC9C;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EAAA,CACZ;AAED,SAAO,QAAQ,+BAA+B,QAAQ,IAAI,IAAI;AAAA,IAC5D,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA;AAAA,EAAA,CACD;AAED,QAAM,mBAAyC;AAAA,IAC7C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAGF,MAAI;AACF,UAAM,SAAS,MAAM,QAAQ,UAAU,gBAAgB;AAEvD,UAAM,WAAW,KAAK,IAAA,IAAQ;AAC9B,UAAM,eAAe,OAAO,QAAQ;AAEpC,kBAAc,KAAK,+BAA+B;AAAA,MAChD;AAAA,MACA,UAAU,QAAQ;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,IAAA;AAAA,IAAI,CACrB;AAED,WAAO,OAAO,6BAA6B,YAAY,IAAI;AAAA,MACzD,YAAY,CAAC,CAAC,OAAO;AAAA,MACrB;AAAA,IAAA,CACD;AAED,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO,OAAO,6BAA6B;AAAA,MACzC;AAAA,MACA,QAAQ;AAAA,IAAA,CACT;AACD,UAAM;AAAA,EACR;AACF;AAOA,gBAAgB,sBACd,SAC4B;AAC5B,QAAM,EAAE,SAAS,MAAM,WAAW,OAAO,UAAU;AACnD,QAAM,QAAQ,QAAQ;AACtB,QAAM,SAAyB,mBAAmB,QAAQ,KAAK;AAE/D,SAAO,QAAQ,+BAA+B,QAAQ,IAAI,IAAI;AAAA,IAC5D,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA,QAAQ;AAAA,EAAA,CACT;AAED,QAAM,mBAAyC;AAAA,IAC7C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAGF,MAAI;AAEF,QAAI,QAAQ,iBAAiB;AAC3B,aAAO,QAAQ,gBAAgB,gBAAgB;AAC/C;AAAA,IACF;AAGA,WAAO,uBAAuB,MAAM,QAAQ,UAAU,gBAAgB,CAAC;AAAA,EACzE,SAAS,OAAO;AACd,WAAO,OAAO,6BAA6B;AAAA,MACzC;AAAA,MACA,QAAQ;AAAA,IAAA,CACT;AACD,UAAM;AAAA,EACR;AACF;AASO,SAAS,uBAId,SAC6C;AAC7C,SAAO;AACT;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/activities/summarize/index.ts"],"sourcesContent":["/**\n * Summarize Activity\n *\n * Generates summaries from text input.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport { aiEventClient } from '@tanstack/ai-event-client'\nimport { streamGenerationResult } from '../stream-generation-result.js'\nimport { resolveDebugOption } from '../../logger/resolve'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { SummarizeAdapter } from './adapter'\nimport type { StreamChunk, SummarizationResult } from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'summarize' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/** Extract provider options from a SummarizeAdapter via ~types */\nexport type SummarizeProviderOptions<TAdapter> =\n TAdapter extends SummarizeAdapter<any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the summarize activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The summarize adapter type\n * @template TStream - Whether to stream the output\n */\nexport interface SummarizeActivityOptions<\n TAdapter extends SummarizeAdapter<string, object>,\n TStream extends boolean = false,\n> {\n /** The summarize adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** The text to summarize */\n text: string\n /** Maximum length of the summary (in words or characters, provider-dependent) */\n maxLength?: number\n /** Style of summary to generate */\n style?: 'bullet-points' | 'paragraph' | 'concise'\n /** Topics or aspects to focus on in the summary */\n focus?: Array<string>\n /** Provider-specific options */\n modelOptions?: SummarizeProviderOptions<TAdapter>\n /**\n * Whether to stream the summarization result.\n * When true, returns an AsyncIterable<StreamChunk> for streaming output.\n * When false or not provided, returns a Promise<SummarizationResult>.\n *\n * @default false\n */\n stream?: TStream\n /**\n * Enable debug logging. Pass `true` to enable all categories, `false` to\n * silence everything including errors, or a `DebugConfig` object for granular\n * control and/or a custom `Logger`.\n */\n debug?: DebugOption\n}\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/**\n * Result type for the summarize activity.\n * - If stream is true: AsyncIterable<StreamChunk>\n * - Otherwise: Promise<SummarizationResult>\n */\nexport type SummarizeActivityResult<TStream extends boolean> =\n TStream extends true\n ? AsyncIterable<StreamChunk>\n : Promise<SummarizationResult>\n\n// ===========================\n// Helper Functions\n// ===========================\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Summarize activity - generates summaries from text.\n *\n * Supports both streaming and non-streaming modes.\n *\n * @example Basic summarization\n * ```ts\n * import { summarize } from '@tanstack/ai'\n * import { openaiSummarize } from '@tanstack/ai-openai'\n *\n * const result = await summarize({\n * adapter: openaiSummarize('gpt-4o-mini'),\n * text: 'Long article text here...'\n * })\n *\n * console.log(result.summary)\n * ```\n *\n * @example Summarization with style\n * ```ts\n * const result = await summarize({\n * adapter: openaiSummarize('gpt-4o-mini'),\n * text: 'Long article text here...',\n * style: 'bullet-points',\n * maxLength: 100\n * })\n * ```\n *\n * @example Focused summarization\n * ```ts\n * const result = await summarize({\n * adapter: openaiSummarize('gpt-4o-mini'),\n * text: 'Long technical document...',\n * focus: ['key findings', 'methodology']\n * })\n * ```\n *\n * @example Streaming summarization\n * ```ts\n * for await (const chunk of summarize({\n * adapter: openaiSummarize('gpt-4o-mini'),\n * text: 'Long article text here...',\n * stream: true\n * })) {\n * if (chunk.type === 'content') {\n * process.stdout.write(chunk.delta)\n * }\n * }\n * ```\n */\nexport function summarize<\n TAdapter extends SummarizeAdapter<string, object>,\n TStream extends boolean = false,\n>(\n options: SummarizeActivityOptions<TAdapter, TStream>,\n): SummarizeActivityResult<TStream> {\n const { stream } = options\n\n if (stream) {\n return runStreamingSummarize(\n options as unknown as SummarizeActivityOptions<\n SummarizeAdapter<string, object>,\n true\n >,\n ) as SummarizeActivityResult<TStream>\n }\n\n return runSummarize(\n options as unknown as SummarizeActivityOptions<\n SummarizeAdapter<string, object>,\n false\n >,\n ) as SummarizeActivityResult<TStream>\n}\n\n/**\n * Run non-streaming summarization\n */\nasync function runSummarize(\n options: SummarizeActivityOptions<SummarizeAdapter<string, object>, false>,\n): Promise<SummarizationResult> {\n const { adapter, text, maxLength, style, focus, modelOptions } = options\n const model = adapter.model\n const requestId = createId('summarize')\n const inputLength = text.length\n const startTime = Date.now()\n const logger: InternalLogger = resolveDebugOption(options.debug)\n\n aiEventClient.emit('summarize:request:started', {\n requestId,\n provider: adapter.name,\n model,\n inputLength,\n timestamp: startTime,\n })\n\n logger.request(`activity=summarize provider=${adapter.name}`, {\n provider: adapter.name,\n model,\n inputLength,\n })\n\n const summarizeOptions = {\n model,\n text,\n maxLength,\n style,\n focus,\n modelOptions,\n logger,\n }\n\n try {\n const result = await adapter.summarize(summarizeOptions)\n\n const duration = Date.now() - startTime\n const outputLength = result.summary.length\n\n aiEventClient.emit('summarize:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n inputLength,\n outputLength,\n duration,\n timestamp: Date.now(),\n })\n\n logger.output(`activity=summarize length=${outputLength}`, {\n hasSummary: !!result.summary,\n outputLength,\n })\n\n return result\n } catch (error) {\n logger.errors('summarize activity failed', {\n error,\n source: 'summarize',\n })\n throw error\n }\n}\n\n/**\n * Run streaming summarization\n * Uses the adapter's native streaming if available, otherwise falls back\n * to non-streaming and yields the result as a single chunk.\n */\nasync function* runStreamingSummarize(\n options: SummarizeActivityOptions<SummarizeAdapter<string, object>, true>,\n): AsyncIterable<StreamChunk> {\n const { adapter, text, maxLength, style, focus, modelOptions } = options\n const model = adapter.model\n const logger: InternalLogger = resolveDebugOption(options.debug)\n\n logger.request(`activity=summarize provider=${adapter.name}`, {\n provider: adapter.name,\n model,\n stream: true,\n })\n\n const summarizeOptions = {\n model,\n text,\n maxLength,\n style,\n focus,\n modelOptions,\n logger,\n }\n\n try {\n // Use real streaming if the adapter supports it\n if (adapter.summarizeStream) {\n yield* adapter.summarizeStream(summarizeOptions)\n return\n }\n\n // Fall back to non-streaming — wrap result with streamGenerationResult\n yield* streamGenerationResult(() => adapter.summarize(summarizeOptions))\n } catch (error) {\n logger.errors('summarize activity failed', {\n error,\n source: 'summarize',\n })\n throw error\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the summarize() function without executing.\n */\nexport function createSummarizeOptions<\n TAdapter extends SummarizeAdapter<string, object>,\n TStream extends boolean = false,\n>(\n options: SummarizeActivityOptions<TAdapter, TStream>,\n): SummarizeActivityOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n SummarizeAdapter,\n SummarizeAdapterConfig,\n AnySummarizeAdapter,\n} from './adapter'\nexport { BaseSummarizeAdapter } from './adapter'\nexport {\n ChatStreamSummarizeAdapter,\n type ChatStreamCapable,\n type InferTextProviderOptions,\n} from './chat-stream-summarize'\n"],"names":[],"mappings":";;;AAoBO,MAAM,OAAO;AAyEpB,SAAS,SAAS,QAAwB;AACxC,SAAO,GAAG,MAAM,IAAI,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC1E;AAwDO,SAAS,UAId,SACkC;AAClC,QAAM,EAAE,WAAW;AAEnB,MAAI,QAAQ;AACV,WAAO;AAAA,MACL;AAAA,IAAA;AAAA,EAKJ;AAEA,SAAO;AAAA,IACL;AAAA,EAAA;AAKJ;AAKA,eAAe,aACb,SAC8B;AAC9B,QAAM,EAAE,SAAS,MAAM,WAAW,OAAO,OAAO,iBAAiB;AACjE,QAAM,QAAQ,QAAQ;AACtB,QAAM,YAAY,SAAS,WAAW;AACtC,QAAM,cAAc,KAAK;AACzB,QAAM,YAAY,KAAK,IAAA;AACvB,QAAM,SAAyB,mBAAmB,QAAQ,KAAK;AAE/D,gBAAc,KAAK,6BAA6B;AAAA,IAC9C;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EAAA,CACZ;AAED,SAAO,QAAQ,+BAA+B,QAAQ,IAAI,IAAI;AAAA,IAC5D,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA;AAAA,EAAA,CACD;AAED,QAAM,mBAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAGF,MAAI;AACF,UAAM,SAAS,MAAM,QAAQ,UAAU,gBAAgB;AAEvD,UAAM,WAAW,KAAK,IAAA,IAAQ;AAC9B,UAAM,eAAe,OAAO,QAAQ;AAEpC,kBAAc,KAAK,+BAA+B;AAAA,MAChD;AAAA,MACA,UAAU,QAAQ;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,IAAA;AAAA,IAAI,CACrB;AAED,WAAO,OAAO,6BAA6B,YAAY,IAAI;AAAA,MACzD,YAAY,CAAC,CAAC,OAAO;AAAA,MACrB;AAAA,IAAA,CACD;AAED,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO,OAAO,6BAA6B;AAAA,MACzC;AAAA,MACA,QAAQ;AAAA,IAAA,CACT;AACD,UAAM;AAAA,EACR;AACF;AAOA,gBAAgB,sBACd,SAC4B;AAC5B,QAAM,EAAE,SAAS,MAAM,WAAW,OAAO,OAAO,iBAAiB;AACjE,QAAM,QAAQ,QAAQ;AACtB,QAAM,SAAyB,mBAAmB,QAAQ,KAAK;AAE/D,SAAO,QAAQ,+BAA+B,QAAQ,IAAI,IAAI;AAAA,IAC5D,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA,QAAQ;AAAA,EAAA,CACT;AAED,QAAM,mBAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAGF,MAAI;AAEF,QAAI,QAAQ,iBAAiB;AAC3B,aAAO,QAAQ,gBAAgB,gBAAgB;AAC/C;AAAA,IACF;AAGA,WAAO,uBAAuB,MAAM,QAAQ,UAAU,gBAAgB,CAAC;AAAA,EACzE,SAAS,OAAO;AACd,WAAO,OAAO,6BAA6B;AAAA,MACzC;AAAA,MACA,QAAQ;AAAA,IAAA,CACT;AACD,UAAM;AAAA,EACR;AACF;AASO,SAAS,uBAId,SAC6C;AAC7C,SAAO;AACT;"}
@@ -895,6 +895,95 @@ export interface CustomEvent extends AGUICustomEvent {
895
895
  /** Model identifier for multi-model support */
896
896
  model?: string;
897
897
  }
898
+ /**
899
+ * Final event of a streaming structured-output run. Carries the validated
900
+ * `object` (typed as `T` after the orchestrator runs Standard Schema parsing),
901
+ * the `raw` JSON text that produced it, and — for thinking/reasoning models —
902
+ * the accumulated reasoning text. Adapters emit this with `T = unknown`; the
903
+ * chat orchestrator narrows to the schema's inferred type after validation.
904
+ *
905
+ * `reasoning` is `undefined` when the model produced none (most non-thinking
906
+ * models) and when the underlying adapter doesn't expose reasoning streams.
907
+ *
908
+ * `name` is a string literal so consumers can narrow directly:
909
+ *
910
+ * ```ts
911
+ * if (chunk.type === 'CUSTOM' && chunk.name === 'structured-output.complete') {
912
+ * chunk.value.object // typed as T
913
+ * }
914
+ * ```
915
+ */
916
+ export interface StructuredOutputCompleteEvent<T = unknown> extends Omit<CustomEvent, 'name' | 'value'> {
917
+ name: 'structured-output.complete';
918
+ value: {
919
+ object: T;
920
+ raw: string;
921
+ reasoning?: string;
922
+ };
923
+ }
924
+ /**
925
+ * Emitted when a server tool requires approval before execution. The agent
926
+ * loop yields this and pauses — `structured-output.complete` will not fire
927
+ * for that run. The shape is fixed by the orchestrator's tool-approval flow
928
+ * (see `buildApprovalChunks` in `activities/chat/index.ts`).
929
+ */
930
+ export interface ApprovalRequestedEvent extends Omit<CustomEvent, 'name' | 'value'> {
931
+ name: 'approval-requested';
932
+ value: {
933
+ toolCallId: string;
934
+ toolName: string;
935
+ input: unknown;
936
+ approval: {
937
+ id: string;
938
+ needsApproval: true;
939
+ };
940
+ };
941
+ }
942
+ /**
943
+ * Emitted when a client tool is invoked. The agent loop yields this and
944
+ * pauses to let the caller run the tool client-side — `structured-output.complete`
945
+ * will not fire for that run. Shape fixed by `buildClientToolChunks` in
946
+ * `activities/chat/index.ts`.
947
+ */
948
+ export interface ToolInputAvailableEvent extends Omit<CustomEvent, 'name' | 'value'> {
949
+ name: 'tool-input-available';
950
+ value: {
951
+ toolCallId: string;
952
+ toolName: string;
953
+ input: unknown;
954
+ };
955
+ }
956
+ /**
957
+ * Public type for streams returned by `chat({ outputSchema, stream: true })`.
958
+ *
959
+ * Yields all standard `StreamChunk` lifecycle events plus the three tagged
960
+ * `CUSTOM` events the orchestrator can emit through this path:
961
+ * - `structured-output.complete` — terminal event with typed `value.object: T`
962
+ * - `approval-requested` — server tool needs approval (pauses the run)
963
+ * - `tool-input-available` — client tool invocation (pauses the run)
964
+ *
965
+ * Each variant has a literal `name`, so a single discriminated narrow gives
966
+ * you a typed `value` with no helper or cast:
967
+ *
968
+ * ```ts
969
+ * for await (const chunk of stream) {
970
+ * if (chunk.type === 'CUSTOM' && chunk.name === 'structured-output.complete') {
971
+ * chunk.value.object // typed as T
972
+ * } else if (chunk.type === 'CUSTOM' && chunk.name === 'approval-requested') {
973
+ * chunk.value.toolCallId // typed as string
974
+ * }
975
+ * }
976
+ * ```
977
+ *
978
+ * Caveat: tools can emit arbitrary user-defined custom events via the
979
+ * `emitCustomEvent(name, value)` context API. Those flow through this stream
980
+ * at runtime but are intentionally absent from this type — including a bare
981
+ * `CustomEvent` (whose `value: any` would poison the union) would collapse
982
+ * `chunk.value` back to `any` after the narrow. If you rely on
983
+ * `emitCustomEvent` plus `outputSchema + stream: true`, branch on `CUSTOM`
984
+ * outside the literal-`name` narrows or cast explicitly.
985
+ */
986
+ export type StructuredOutputStream<T = unknown> = AsyncIterable<Exclude<StreamChunk, CustomEvent> | StructuredOutputCompleteEvent<T> | ApprovalRequestedEvent | ToolInputAvailableEvent>;
898
987
  /**
899
988
  * Emitted when reasoning starts for a message.
900
989
  *
@@ -976,12 +1065,14 @@ export interface TextCompletionChunk {
976
1065
  totalTokens: number;
977
1066
  };
978
1067
  }
979
- export interface SummarizationOptions {
1068
+ export interface SummarizationOptions<TProviderOptions extends object = Record<string, unknown>> {
980
1069
  model: string;
981
1070
  text: string;
982
1071
  maxLength?: number;
983
1072
  style?: 'bullet-points' | 'paragraph' | 'concise';
984
1073
  focus?: Array<string>;
1074
+ /** Provider-specific options forwarded by the summarize() activity. */
1075
+ modelOptions?: TProviderOptions;
985
1076
  /**
986
1077
  * Internal logger threaded from the summarize() entry point. Adapters must
987
1078
  * call logger.request() before the SDK call and logger.errors() in catch blocks.
@@ -1002,7 +1093,7 @@ export interface SummarizationResult {
1002
1093
  * Options for image generation.
1003
1094
  * These are the common options supported across providers.
1004
1095
  */
1005
- export interface ImageGenerationOptions<TProviderOptions extends object = object, TSize extends string = string> {
1096
+ export interface ImageGenerationOptions<TProviderOptions extends object = object, TSize extends string | undefined = string> {
1006
1097
  /** The model to use for image generation */
1007
1098
  model: string;
1008
1099
  /** Text description of the desired image(s) */
@@ -1110,7 +1201,7 @@ export interface AudioGenerationResult {
1110
1201
  *
1111
1202
  * @experimental Video generation is an experimental feature and may change.
1112
1203
  */
1113
- export interface VideoGenerationOptions<TProviderOptions extends object = object, TSize extends string = string> {
1204
+ export interface VideoGenerationOptions<TProviderOptions extends object = object, TSize extends string | undefined = string> {
1114
1205
  /** The model to use for video generation */
1115
1206
  model: string;
1116
1207
  /** Text description of the desired video */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "Core TanStack AI library - Open source AI SDK",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -55,7 +55,7 @@
55
55
  "dependencies": {
56
56
  "@ag-ui/core": "0.0.49",
57
57
  "partial-json": "^0.1.7",
58
- "@tanstack/ai-event-client": "0.3.0"
58
+ "@tanstack/ai-event-client": "0.3.1"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@opentelemetry/api": ">=1.9.0"