@tanstack/ai 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -0
- package/dist/esm/activities/chat/adapter.d.ts +100 -0
- package/dist/esm/activities/chat/adapter.js +14 -0
- package/dist/esm/activities/chat/adapter.js.map +1 -0
- package/dist/esm/{utilities → activities/chat}/agent-loop-strategies.d.ts +4 -4
- package/dist/esm/activities/chat/agent-loop-strategies.js.map +1 -0
- package/dist/esm/activities/chat/index.d.ts +165 -0
- package/dist/esm/{core/chat.js → activities/chat/index.js} +131 -33
- package/dist/esm/activities/chat/index.js.map +1 -0
- package/dist/esm/{message-converters.d.ts → activities/chat/messages.d.ts} +1 -1
- package/dist/esm/{message-converters.js → activities/chat/messages.js} +7 -7
- package/dist/esm/activities/chat/messages.js.map +1 -0
- package/dist/esm/activities/chat/stream/json-parser.js.map +1 -0
- package/dist/esm/{stream → activities/chat/stream}/message-updaters.d.ts +1 -1
- package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -0
- package/dist/esm/{stream → activities/chat/stream}/processor.d.ts +1 -1
- package/dist/esm/{stream → activities/chat/stream}/processor.js +1 -1
- package/dist/esm/activities/chat/stream/processor.js.map +1 -0
- package/dist/esm/activities/chat/stream/strategies.js.map +1 -0
- package/dist/esm/{stream → activities/chat/stream}/types.d.ts +2 -9
- package/dist/esm/{tools → activities/chat/tools}/tool-calls.d.ts +1 -1
- package/dist/esm/{tools → activities/chat/tools}/tool-calls.js +9 -5
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -0
- package/dist/esm/{tools → activities/chat/tools}/tool-definition.d.ts +14 -14
- package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -0
- package/dist/esm/activities/chat/tools/zod-converter.d.ts +69 -0
- package/dist/esm/activities/chat/tools/zod-converter.js +99 -0
- package/dist/esm/activities/chat/tools/zod-converter.js.map +1 -0
- package/dist/esm/activities/generateImage/adapter.d.ts +68 -0
- package/dist/esm/activities/generateImage/adapter.js +14 -0
- package/dist/esm/activities/generateImage/adapter.js.map +1 -0
- package/dist/esm/activities/generateImage/index.d.ts +89 -0
- package/dist/esm/activities/generateImage/index.js +15 -0
- package/dist/esm/activities/generateImage/index.js.map +1 -0
- package/dist/esm/activities/generateSpeech/adapter.d.ts +62 -0
- package/dist/esm/activities/generateSpeech/adapter.js +14 -0
- package/dist/esm/activities/generateSpeech/adapter.js.map +1 -0
- package/dist/esm/activities/generateSpeech/index.d.ts +69 -0
- package/dist/esm/activities/generateSpeech/index.js +15 -0
- package/dist/esm/activities/generateSpeech/index.js.map +1 -0
- package/dist/esm/activities/generateTranscription/adapter.d.ts +62 -0
- package/dist/esm/activities/generateTranscription/adapter.js +14 -0
- package/dist/esm/activities/generateTranscription/adapter.js.map +1 -0
- package/dist/esm/activities/generateTranscription/index.d.ts +71 -0
- package/dist/esm/activities/generateTranscription/index.js +15 -0
- package/dist/esm/activities/generateTranscription/index.js.map +1 -0
- package/dist/esm/activities/generateVideo/adapter.d.ts +80 -0
- package/dist/esm/activities/generateVideo/adapter.js +14 -0
- package/dist/esm/activities/generateVideo/adapter.js.map +1 -0
- package/dist/esm/activities/generateVideo/index.d.ts +136 -0
- package/dist/esm/activities/generateVideo/index.js +47 -0
- package/dist/esm/activities/generateVideo/index.js.map +1 -0
- package/dist/esm/activities/index.d.ts +22 -0
- package/dist/esm/activities/index.js +34 -0
- package/dist/esm/activities/index.js.map +1 -0
- package/dist/esm/activities/summarize/adapter.d.ts +74 -0
- package/dist/esm/activities/summarize/adapter.js +14 -0
- package/dist/esm/activities/summarize/adapter.js.map +1 -0
- package/dist/esm/activities/summarize/index.d.ts +100 -0
- package/dist/esm/activities/summarize/index.js +90 -0
- package/dist/esm/activities/summarize/index.js.map +1 -0
- package/dist/esm/event-client.d.ts +4 -45
- package/dist/esm/event-client.js +0 -49
- package/dist/esm/event-client.js.map +1 -1
- package/dist/esm/index.d.ts +16 -14
- package/dist/esm/index.js +28 -19
- package/dist/esm/stream-to-response.d.ts +95 -0
- package/dist/esm/stream-to-response.js +118 -0
- package/dist/esm/stream-to-response.js.map +1 -0
- package/dist/esm/types.d.ts +347 -129
- package/package.json +6 -2
- package/src/activities/chat/adapter.ts +150 -0
- package/src/{utilities → activities/chat}/agent-loop-strategies.ts +4 -4
- package/src/{core/chat.ts → activities/chat/index.ts} +427 -79
- package/src/{message-converters.ts → activities/chat/messages.ts} +10 -13
- package/src/{stream → activities/chat/stream}/message-updaters.ts +1 -1
- package/src/{stream → activities/chat/stream}/processor.ts +2 -5
- package/src/{stream → activities/chat/stream}/types.ts +8 -18
- package/src/{tools → activities/chat/tools}/tool-calls.ts +36 -11
- package/src/{tools → activities/chat/tools}/tool-definition.ts +36 -27
- package/src/activities/chat/tools/zod-converter.ts +235 -0
- package/src/activities/generateImage/adapter.ts +104 -0
- package/src/activities/generateImage/index.ts +162 -0
- package/src/activities/generateSpeech/adapter.ts +87 -0
- package/src/activities/generateSpeech/index.ts +122 -0
- package/src/activities/generateTranscription/adapter.ts +89 -0
- package/src/activities/generateTranscription/index.ts +132 -0
- package/src/activities/generateVideo/adapter.ts +116 -0
- package/src/activities/generateVideo/index.ts +261 -0
- package/src/activities/index.ts +164 -0
- package/src/activities/summarize/adapter.ts +107 -0
- package/src/activities/summarize/index.ts +287 -0
- package/src/event-client.ts +5 -101
- package/src/index.ts +58 -15
- package/src/stream-to-response.ts +237 -0
- package/src/types.ts +404 -280
- package/dist/esm/base-adapter.d.ts +0 -36
- package/dist/esm/base-adapter.js +0 -12
- package/dist/esm/base-adapter.js.map +0 -1
- package/dist/esm/core/chat-common-options.d.ts +0 -52
- package/dist/esm/core/chat.d.ts +0 -30
- package/dist/esm/core/chat.js.map +0 -1
- package/dist/esm/core/embedding.d.ts +0 -8
- package/dist/esm/core/embedding.js +0 -33
- package/dist/esm/core/embedding.js.map +0 -1
- package/dist/esm/core/summarize.d.ts +0 -9
- package/dist/esm/core/summarize.js +0 -36
- package/dist/esm/core/summarize.js.map +0 -1
- package/dist/esm/message-converters.js.map +0 -1
- package/dist/esm/stream/json-parser.js.map +0 -1
- package/dist/esm/stream/message-updaters.js.map +0 -1
- package/dist/esm/stream/processor.js.map +0 -1
- package/dist/esm/stream/strategies.js.map +0 -1
- package/dist/esm/tools/tool-calls.js.map +0 -1
- package/dist/esm/tools/tool-definition.js.map +0 -1
- package/dist/esm/tools/zod-converter.d.ts +0 -30
- package/dist/esm/tools/zod-converter.js +0 -36
- package/dist/esm/tools/zod-converter.js.map +0 -1
- package/dist/esm/utilities/agent-loop-strategies.js.map +0 -1
- package/dist/esm/utilities/chat-options.d.ts +0 -6
- package/dist/esm/utilities/chat-options.js +0 -7
- package/dist/esm/utilities/chat-options.js.map +0 -1
- package/dist/esm/utilities/messages.d.ts +0 -30
- package/dist/esm/utilities/messages.js +0 -7
- package/dist/esm/utilities/messages.js.map +0 -1
- package/dist/esm/utilities/stream-to-response.d.ts +0 -48
- package/dist/esm/utilities/stream-to-response.js +0 -62
- package/dist/esm/utilities/stream-to-response.js.map +0 -1
- package/src/base-adapter.ts +0 -86
- package/src/core/chat-common-options.ts +0 -55
- package/src/core/embedding.ts +0 -54
- package/src/core/summarize.ts +0 -56
- package/src/tools/zod-converter.ts +0 -85
- package/src/utilities/chat-options.ts +0 -35
- package/src/utilities/messages.ts +0 -63
- package/src/utilities/stream-to-response.ts +0 -116
- /package/dist/esm/{utilities → activities/chat}/agent-loop-strategies.js +0 -0
- /package/dist/esm/{stream → activities/chat/stream}/index.d.ts +0 -0
- /package/dist/esm/{stream → activities/chat/stream}/json-parser.d.ts +0 -0
- /package/dist/esm/{stream → activities/chat/stream}/json-parser.js +0 -0
- /package/dist/esm/{stream → activities/chat/stream}/message-updaters.js +0 -0
- /package/dist/esm/{stream → activities/chat/stream}/strategies.d.ts +0 -0
- /package/dist/esm/{stream → activities/chat/stream}/strategies.js +0 -0
- /package/dist/esm/{tools → activities/chat/tools}/tool-definition.js +0 -0
- /package/src/{stream → activities/chat/stream}/index.ts +0 -0
- /package/src/{stream → activities/chat/stream}/json-parser.ts +0 -0
- /package/src/{stream → activities/chat/stream}/strategies.ts +0 -0
package/README.md
CHANGED
|
@@ -38,7 +38,9 @@
|
|
|
38
38
|
A powerful, type-safe AI SDK for building AI-powered applications.
|
|
39
39
|
|
|
40
40
|
- Provider-agnostic adapters (OpenAI, Anthropic, Gemini, Ollama, etc.)
|
|
41
|
+
- **Tree-shakeable adapters** - Import only what you need for smaller bundles
|
|
41
42
|
- **Multimodal content support** - Send images, audio, video, and documents
|
|
43
|
+
- **Image generation** - Generate images with OpenAI DALL-E/GPT-Image and Gemini Imagen
|
|
42
44
|
- Chat completion, streaming, and agent loop strategies
|
|
43
45
|
- Headless chat state management with adapters (SSE, HTTP stream, custom)
|
|
44
46
|
- Isomorphic type-safe tools with server/client execution
|
|
@@ -46,6 +48,30 @@ A powerful, type-safe AI SDK for building AI-powered applications.
|
|
|
46
48
|
|
|
47
49
|
### <a href="https://tanstack.com/ai">Read the docs →</b></a>
|
|
48
50
|
|
|
51
|
+
## Tree-Shakeable Adapters
|
|
52
|
+
|
|
53
|
+
Import only the functionality you need for smaller bundle sizes:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// Only chat functionality - no summarization code bundled
|
|
57
|
+
import { openaiText } from '@tanstack/ai-openai/adapters'
|
|
58
|
+
import { generate } from '@tanstack/ai'
|
|
59
|
+
|
|
60
|
+
const textAdapter = openaiText()
|
|
61
|
+
|
|
62
|
+
const result = generate({
|
|
63
|
+
adapter: textAdapter,
|
|
64
|
+
model: 'gpt-4o',
|
|
65
|
+
messages: [{ role: 'user', content: [{ type: 'text', content: 'Hello!' }] }],
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
for await (const chunk of result) {
|
|
69
|
+
console.log(chunk)
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Available adapters: `openaiText`, `openaiEmbed`, `openaiSummarize`, `anthropicText`, `geminiText`, `ollamaText`, and more.
|
|
74
|
+
|
|
49
75
|
## Bonus: TanStack Start Integration
|
|
50
76
|
|
|
51
77
|
TanStack AI works with **any** framework (Next.js, Express, Remix, etc.).
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { DefaultMessageMetadataByModality, JSONSchema, Modality, StreamChunk, TextOptions } from '../../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for adapter instances
|
|
4
|
+
*/
|
|
5
|
+
export interface TextAdapterConfig {
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
timeout?: number;
|
|
9
|
+
maxRetries?: number;
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Options for structured output generation
|
|
14
|
+
*/
|
|
15
|
+
export interface StructuredOutputOptions<TProviderOptions extends object> {
|
|
16
|
+
/** Text options for the request */
|
|
17
|
+
chatOptions: TextOptions<TProviderOptions>;
|
|
18
|
+
/** JSON Schema for structured output - already converted from Zod in the ai layer */
|
|
19
|
+
outputSchema: JSONSchema;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Result from structured output generation
|
|
23
|
+
*/
|
|
24
|
+
export interface StructuredOutputResult<T = unknown> {
|
|
25
|
+
/** The parsed data conforming to the schema */
|
|
26
|
+
data: T;
|
|
27
|
+
/** The raw text response from the model before parsing */
|
|
28
|
+
rawText: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Text adapter interface with pre-resolved generics.
|
|
32
|
+
*
|
|
33
|
+
* An adapter is created by a provider function: `provider('model')` → `adapter`
|
|
34
|
+
* All type resolution happens at the provider call site, not in this interface.
|
|
35
|
+
*
|
|
36
|
+
* Generic parameters:
|
|
37
|
+
* - TModel: The specific model name (e.g., 'gpt-4o')
|
|
38
|
+
* - TProviderOptions: Provider-specific options for this model (already resolved)
|
|
39
|
+
* - TInputModalities: Supported input modalities for this model (already resolved)
|
|
40
|
+
* - TMessageMetadata: Metadata types for content parts (already resolved)
|
|
41
|
+
*/
|
|
42
|
+
export interface TextAdapter<TModel extends string, TProviderOptions extends Record<string, any>, TInputModalities extends ReadonlyArray<Modality>, TMessageMetadataByModality extends DefaultMessageMetadataByModality> {
|
|
43
|
+
/** Discriminator for adapter kind */
|
|
44
|
+
readonly kind: 'text';
|
|
45
|
+
/** Provider name identifier (e.g., 'openai', 'anthropic') */
|
|
46
|
+
readonly name: string;
|
|
47
|
+
/** The model this adapter is configured for */
|
|
48
|
+
readonly model: TModel;
|
|
49
|
+
/**
|
|
50
|
+
* @internal Type-only properties for inference. Not assigned at runtime.
|
|
51
|
+
*/
|
|
52
|
+
'~types': {
|
|
53
|
+
providerOptions: TProviderOptions;
|
|
54
|
+
inputModalities: TInputModalities;
|
|
55
|
+
messageMetadataByModality: TMessageMetadataByModality;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Stream text completions from the model
|
|
59
|
+
*/
|
|
60
|
+
chatStream: (options: TextOptions<TProviderOptions>) => AsyncIterable<StreamChunk>;
|
|
61
|
+
/**
|
|
62
|
+
* Generate structured output using the provider's native structured output API.
|
|
63
|
+
* This method uses stream: false and sends the JSON schema to the provider
|
|
64
|
+
* to ensure the response conforms to the expected structure.
|
|
65
|
+
*
|
|
66
|
+
* @param options - Structured output options containing chat options and JSON schema
|
|
67
|
+
* @returns Promise with the raw data (validation is done in the chat function)
|
|
68
|
+
*/
|
|
69
|
+
structuredOutput: (options: StructuredOutputOptions<TProviderOptions>) => Promise<StructuredOutputResult<unknown>>;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* A TextAdapter with any/unknown type parameters.
|
|
73
|
+
* Useful as a constraint in generic functions and interfaces.
|
|
74
|
+
*/
|
|
75
|
+
export type AnyTextAdapter = TextAdapter<any, any, any, any>;
|
|
76
|
+
/**
|
|
77
|
+
* Abstract base class for text adapters.
|
|
78
|
+
* Extend this class to implement a text adapter for a specific provider.
|
|
79
|
+
*
|
|
80
|
+
* Generic parameters match TextAdapter - all pre-resolved by the provider function.
|
|
81
|
+
*/
|
|
82
|
+
export declare abstract class BaseTextAdapter<TModel extends string, TProviderOptions extends Record<string, any>, TInputModalities extends ReadonlyArray<Modality>, TMessageMetadataByModality extends DefaultMessageMetadataByModality> implements TextAdapter<TModel, TProviderOptions, TInputModalities, TMessageMetadataByModality> {
|
|
83
|
+
readonly kind: "text";
|
|
84
|
+
abstract readonly name: string;
|
|
85
|
+
readonly model: TModel;
|
|
86
|
+
'~types': {
|
|
87
|
+
providerOptions: TProviderOptions;
|
|
88
|
+
inputModalities: TInputModalities;
|
|
89
|
+
messageMetadataByModality: TMessageMetadataByModality;
|
|
90
|
+
};
|
|
91
|
+
protected config: TextAdapterConfig;
|
|
92
|
+
constructor(config: TextAdapterConfig | undefined, model: TModel);
|
|
93
|
+
abstract chatStream(options: TextOptions<TProviderOptions>): AsyncIterable<StreamChunk>;
|
|
94
|
+
/**
|
|
95
|
+
* Generate structured output using the provider's native structured output API.
|
|
96
|
+
* Concrete implementations should override this to use provider-specific structured output.
|
|
97
|
+
*/
|
|
98
|
+
abstract structuredOutput(options: StructuredOutputOptions<TProviderOptions>): Promise<StructuredOutputResult<unknown>>;
|
|
99
|
+
protected generateId(): string;
|
|
100
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class BaseTextAdapter {
|
|
2
|
+
constructor(config = {}, model) {
|
|
3
|
+
this.kind = "text";
|
|
4
|
+
this.config = config;
|
|
5
|
+
this.model = model;
|
|
6
|
+
}
|
|
7
|
+
generateId() {
|
|
8
|
+
return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
BaseTextAdapter
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sources":["../../../../src/activities/chat/adapter.ts"],"sourcesContent":["import type {\n DefaultMessageMetadataByModality,\n JSONSchema,\n Modality,\n StreamChunk,\n TextOptions,\n} from '../../types'\n\n/**\n * Configuration for adapter instances\n */\nexport interface TextAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n maxRetries?: number\n headers?: Record<string, string>\n}\n\n/**\n * Options for structured output generation\n */\nexport interface StructuredOutputOptions<TProviderOptions extends object> {\n /** Text options for the request */\n chatOptions: TextOptions<TProviderOptions>\n /** JSON Schema for structured output - already converted from Zod in the ai layer */\n outputSchema: JSONSchema\n}\n\n/**\n * Result from structured output generation\n */\nexport interface StructuredOutputResult<T = unknown> {\n /** The parsed data conforming to the schema */\n data: T\n /** The raw text response from the model before parsing */\n rawText: string\n}\n\n/**\n * Text 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 for this model (already resolved)\n * - TInputModalities: Supported input modalities for this model (already resolved)\n * - TMessageMetadata: Metadata types for content parts (already resolved)\n */\nexport interface TextAdapter<\n TModel extends string,\n TProviderOptions extends Record<string, any>,\n TInputModalities extends ReadonlyArray<Modality>,\n TMessageMetadataByModality extends DefaultMessageMetadataByModality,\n> {\n /** Discriminator for adapter kind */\n readonly kind: 'text'\n /** Provider name identifier (e.g., 'openai', 'anthropic') */\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 inputModalities: TInputModalities\n messageMetadataByModality: TMessageMetadataByModality\n }\n\n /**\n * Stream text completions from the model\n */\n chatStream: (\n options: TextOptions<TProviderOptions>,\n ) => AsyncIterable<StreamChunk>\n\n /**\n * Generate structured output using the provider's native structured output API.\n * This method uses stream: false and sends the JSON schema to the provider\n * to ensure the response conforms to the expected structure.\n *\n * @param options - Structured output options containing chat options and JSON schema\n * @returns Promise with the raw data (validation is done in the chat function)\n */\n structuredOutput: (\n options: StructuredOutputOptions<TProviderOptions>,\n ) => Promise<StructuredOutputResult<unknown>>\n}\n\n/**\n * A TextAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnyTextAdapter = TextAdapter<any, any, any, any>\n\n/**\n * Abstract base class for text adapters.\n * Extend this class to implement a text adapter for a specific provider.\n *\n * Generic parameters match TextAdapter - all pre-resolved by the provider function.\n */\nexport abstract class BaseTextAdapter<\n TModel extends string,\n TProviderOptions extends Record<string, any>,\n TInputModalities extends ReadonlyArray<Modality>,\n TMessageMetadataByModality extends DefaultMessageMetadataByModality,\n> implements TextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n TMessageMetadataByModality\n> {\n readonly kind = 'text' 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 inputModalities: TInputModalities\n messageMetadataByModality: TMessageMetadataByModality\n }\n\n protected config: TextAdapterConfig\n\n constructor(config: TextAdapterConfig = {}, model: TModel) {\n this.config = config\n this.model = model\n }\n\n abstract chatStream(\n options: TextOptions<TProviderOptions>,\n ): AsyncIterable<StreamChunk>\n\n /**\n * Generate structured output using the provider's native structured output API.\n * Concrete implementations should override this to use provider-specific structured output.\n */\n abstract structuredOutput(\n options: StructuredOutputOptions<TProviderOptions>,\n ): Promise<StructuredOutputResult<unknown>>\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"names":[],"mappings":"AAyGO,MAAe,gBAUpB;AAAA,EAcA,YAAY,SAA4B,CAAA,GAAI,OAAe;AAb3D,SAAS,OAAO;AAcd,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,EACf;AAAA,EAcU,aAAqB;AAC7B,WAAO,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;AAAA,EAC9E;AACF;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AgentLoopStrategy } from '
|
|
1
|
+
import { AgentLoopStrategy } from '../../types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Creates a strategy that continues for a maximum number of iterations
|
|
4
4
|
*
|
|
@@ -8,7 +8,7 @@ import { AgentLoopStrategy } from '../types.js';
|
|
|
8
8
|
* @example
|
|
9
9
|
* ```typescript
|
|
10
10
|
* const stream = chat({
|
|
11
|
-
* adapter:
|
|
11
|
+
* adapter: openaiText(),
|
|
12
12
|
* model: "gpt-4o",
|
|
13
13
|
* messages: [...],
|
|
14
14
|
* tools: [weatherTool],
|
|
@@ -26,7 +26,7 @@ export declare function maxIterations(max: number): AgentLoopStrategy;
|
|
|
26
26
|
* @example
|
|
27
27
|
* ```typescript
|
|
28
28
|
* const stream = chat({
|
|
29
|
-
* adapter:
|
|
29
|
+
* adapter: openaiText(),
|
|
30
30
|
* model: "gpt-4o",
|
|
31
31
|
* messages: [...],
|
|
32
32
|
* tools: [weatherTool],
|
|
@@ -45,7 +45,7 @@ export declare function untilFinishReason(stopReasons: Array<string>): AgentLoop
|
|
|
45
45
|
* @example
|
|
46
46
|
* ```typescript
|
|
47
47
|
* const stream = chat({
|
|
48
|
-
* adapter:
|
|
48
|
+
* adapter: openaiText(),
|
|
49
49
|
* model: "gpt-4o",
|
|
50
50
|
* messages: [...],
|
|
51
51
|
* tools: [weatherTool],
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-loop-strategies.js","sources":["../../../../src/activities/chat/agent-loop-strategies.ts"],"sourcesContent":["import type { AgentLoopStrategy } from '../../types'\n\n/**\n * Creates a strategy that continues for a maximum number of iterations\n *\n * @param max - Maximum number of iterations to allow\n * @returns AgentLoopStrategy that stops after max iterations\n *\n * @example\n * ```typescript\n * const stream = chat({\n * adapter: openaiText(),\n * model: \"gpt-4o\",\n * messages: [...],\n * tools: [weatherTool],\n * agentLoopStrategy: maxIterations(3), // Max 3 iterations\n * });\n * ```\n */\nexport function maxIterations(max: number): AgentLoopStrategy {\n return ({ iterationCount }) => iterationCount < max\n}\n\n/**\n * Creates a strategy that continues until a specific finish reason is encountered\n *\n * @param stopReasons - Finish reasons that should stop the loop\n * @returns AgentLoopStrategy that stops on specific finish reasons\n *\n * @example\n * ```typescript\n * const stream = chat({\n * adapter: openaiText(),\n * model: \"gpt-4o\",\n * messages: [...],\n * tools: [weatherTool],\n * agentLoopStrategy: untilFinishReason([\"stop\", \"length\"]),\n * });\n * ```\n */\nexport function untilFinishReason(\n stopReasons: Array<string>,\n): AgentLoopStrategy {\n return ({ finishReason, iterationCount }) => {\n // Always allow at least one iteration\n if (iterationCount === 0) return true\n\n // Stop if we hit a stop reason\n if (finishReason && stopReasons.includes(finishReason)) {\n return false\n }\n\n // Otherwise continue\n return true\n }\n}\n\n/**\n * Creates a strategy that combines multiple strategies with AND logic\n * All strategies must return true to continue\n *\n * @param strategies - Array of strategies to combine\n * @returns AgentLoopStrategy that continues only if all strategies return true\n *\n * @example\n * ```typescript\n * const stream = chat({\n * adapter: openaiText(),\n * model: \"gpt-4o\",\n * messages: [...],\n * tools: [weatherTool],\n * agentLoopStrategy: combineStrategies([\n * maxIterations(10),\n * ({ messages }) => messages.length < 100,\n * ]),\n * });\n * ```\n */\nexport function combineStrategies(\n strategies: Array<AgentLoopStrategy>,\n): AgentLoopStrategy {\n return (state) => {\n return strategies.every((strategy) => strategy(state))\n }\n}\n"],"names":[],"mappings":"AAmBO,SAAS,cAAc,KAAgC;AAC5D,SAAO,CAAC,EAAE,qBAAqB,iBAAiB;AAClD;AAmBO,SAAS,kBACd,aACmB;AACnB,SAAO,CAAC,EAAE,cAAc,qBAAqB;AAE3C,QAAI,mBAAmB,EAAG,QAAO;AAGjC,QAAI,gBAAgB,YAAY,SAAS,YAAY,GAAG;AACtD,aAAO;AAAA,IACT;AAGA,WAAO;AAAA,EACT;AACF;AAuBO,SAAS,kBACd,YACmB;AACnB,SAAO,CAAC,UAAU;AAChB,WAAO,WAAW,MAAM,CAAC,aAAa,SAAS,KAAK,CAAC;AAAA,EACvD;AACF;"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { AnyTextAdapter } from './adapter.js';
|
|
3
|
+
import { ConstrainedModelMessage, StreamChunk, TextOptions } from '../../types.js';
|
|
4
|
+
/** The adapter kind this activity handles */
|
|
5
|
+
export declare const kind: "text";
|
|
6
|
+
/**
|
|
7
|
+
* Options for the text activity.
|
|
8
|
+
* Types are extracted directly from the adapter (which has pre-resolved generics).
|
|
9
|
+
*
|
|
10
|
+
* @template TAdapter - The text adapter type (created by a provider function)
|
|
11
|
+
* @template TSchema - Optional Zod schema for structured output
|
|
12
|
+
* @template TStream - Whether to stream the output (default: true)
|
|
13
|
+
*/
|
|
14
|
+
export interface TextActivityOptions<TAdapter extends AnyTextAdapter, TSchema extends z.ZodType | undefined, TStream extends boolean> {
|
|
15
|
+
/** The text adapter to use (created by a provider function like openaiText('gpt-4o')) */
|
|
16
|
+
adapter: TAdapter;
|
|
17
|
+
/** Conversation messages - content types are constrained by the adapter's input modalities and metadata */
|
|
18
|
+
messages?: Array<ConstrainedModelMessage<{
|
|
19
|
+
inputModalities: TAdapter['~types']['inputModalities'];
|
|
20
|
+
messageMetadataByModality: TAdapter['~types']['messageMetadataByModality'];
|
|
21
|
+
}>>;
|
|
22
|
+
/** System prompts to prepend to the conversation */
|
|
23
|
+
systemPrompts?: TextOptions['systemPrompts'];
|
|
24
|
+
/** Tools for function calling (auto-executed when called) */
|
|
25
|
+
tools?: TextOptions['tools'];
|
|
26
|
+
/** Controls the randomness of the output. Higher values make output more random. Range: [0.0, 2.0] */
|
|
27
|
+
temperature?: TextOptions['temperature'];
|
|
28
|
+
/** Nucleus sampling parameter. The model considers tokens with topP probability mass. */
|
|
29
|
+
topP?: TextOptions['topP'];
|
|
30
|
+
/** The maximum number of tokens to generate in the response. */
|
|
31
|
+
maxTokens?: TextOptions['maxTokens'];
|
|
32
|
+
/** Additional metadata to attach to the request. */
|
|
33
|
+
metadata?: TextOptions['metadata'];
|
|
34
|
+
/** Model-specific provider options (type comes from adapter) */
|
|
35
|
+
modelOptions?: TAdapter['~types']['providerOptions'];
|
|
36
|
+
/** AbortController for cancellation */
|
|
37
|
+
abortController?: TextOptions['abortController'];
|
|
38
|
+
/** Strategy for controlling the agent loop */
|
|
39
|
+
agentLoopStrategy?: TextOptions['agentLoopStrategy'];
|
|
40
|
+
/** Unique conversation identifier for tracking */
|
|
41
|
+
conversationId?: TextOptions['conversationId'];
|
|
42
|
+
/**
|
|
43
|
+
* Optional Zod schema for structured output.
|
|
44
|
+
* When provided, the activity will:
|
|
45
|
+
* 1. Run the full agentic loop (executing tools as needed)
|
|
46
|
+
* 2. Once complete, return a Promise with the parsed output matching the schema
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* const result = await chat({
|
|
51
|
+
* adapter: openaiText('gpt-4o'),
|
|
52
|
+
* messages: [{ role: 'user', content: 'Generate a person' }],
|
|
53
|
+
* outputSchema: z.object({ name: z.string(), age: z.number() })
|
|
54
|
+
* })
|
|
55
|
+
* // result is { name: string, age: number }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
outputSchema?: TSchema;
|
|
59
|
+
/**
|
|
60
|
+
* Whether to stream the text result.
|
|
61
|
+
* When true (default), returns an AsyncIterable<StreamChunk> for streaming output.
|
|
62
|
+
* When false, returns a Promise<string> with the collected text content.
|
|
63
|
+
*
|
|
64
|
+
* Note: If outputSchema is provided, this option is ignored and the result
|
|
65
|
+
* is always a Promise<z.infer<TSchema>>.
|
|
66
|
+
*
|
|
67
|
+
* @default true
|
|
68
|
+
*
|
|
69
|
+
* @example Non-streaming text
|
|
70
|
+
* ```ts
|
|
71
|
+
* const text = await chat({
|
|
72
|
+
* adapter: openaiText('gpt-4o'),
|
|
73
|
+
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
74
|
+
* stream: false
|
|
75
|
+
* })
|
|
76
|
+
* // text is a string with the full response
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
stream?: TStream;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Create typed options for the chat() function without executing.
|
|
83
|
+
* This is useful for pre-defining configurations with full type inference.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* const chatOptions = createChatOptions({
|
|
88
|
+
* adapter: anthropicText('claude-sonnet-4-5'),
|
|
89
|
+
* })
|
|
90
|
+
*
|
|
91
|
+
* const stream = chat({ ...chatOptions, messages })
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export declare function createChatOptions<TAdapter extends AnyTextAdapter, TSchema extends z.ZodType | undefined = undefined, TStream extends boolean = true>(options: TextActivityOptions<TAdapter, TSchema, TStream>): TextActivityOptions<TAdapter, TSchema, TStream>;
|
|
95
|
+
/**
|
|
96
|
+
* Result type for the text activity.
|
|
97
|
+
* - If outputSchema is provided: Promise<z.infer<TSchema>>
|
|
98
|
+
* - If stream is false: Promise<string>
|
|
99
|
+
* - Otherwise (stream is true, default): AsyncIterable<StreamChunk>
|
|
100
|
+
*/
|
|
101
|
+
export type TextActivityResult<TSchema extends z.ZodType | undefined, TStream extends boolean = true> = TSchema extends z.ZodType ? Promise<z.infer<TSchema>> : TStream extends false ? Promise<string> : AsyncIterable<StreamChunk>;
|
|
102
|
+
/**
|
|
103
|
+
* Text activity - handles agentic text generation, one-shot text generation, and agentic structured output.
|
|
104
|
+
*
|
|
105
|
+
* This activity supports four modes:
|
|
106
|
+
* 1. **Streaming agentic text**: Stream responses with automatic tool execution
|
|
107
|
+
* 2. **Streaming one-shot text**: Simple streaming request/response without tools
|
|
108
|
+
* 3. **Non-streaming text**: Returns collected text as a string (stream: false)
|
|
109
|
+
* 4. **Agentic structured output**: Run tools, then return structured data
|
|
110
|
+
*
|
|
111
|
+
* @example Full agentic text (streaming with tools)
|
|
112
|
+
* ```ts
|
|
113
|
+
* import { chat } from '@tanstack/ai'
|
|
114
|
+
* import { openaiText } from '@tanstack/ai-openai'
|
|
115
|
+
*
|
|
116
|
+
* for await (const chunk of chat({
|
|
117
|
+
* adapter: openaiText('gpt-4o'),
|
|
118
|
+
* messages: [{ role: 'user', content: 'What is the weather?' }],
|
|
119
|
+
* tools: [weatherTool]
|
|
120
|
+
* })) {
|
|
121
|
+
* if (chunk.type === 'content') {
|
|
122
|
+
* console.log(chunk.delta)
|
|
123
|
+
* }
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* @example One-shot text (streaming without tools)
|
|
128
|
+
* ```ts
|
|
129
|
+
* for await (const chunk of chat({
|
|
130
|
+
* adapter: openaiText('gpt-4o'),
|
|
131
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
132
|
+
* })) {
|
|
133
|
+
* console.log(chunk)
|
|
134
|
+
* }
|
|
135
|
+
* ```
|
|
136
|
+
*
|
|
137
|
+
* @example Non-streaming text (stream: false)
|
|
138
|
+
* ```ts
|
|
139
|
+
* const text = await chat({
|
|
140
|
+
* adapter: openaiText('gpt-4o'),
|
|
141
|
+
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
142
|
+
* stream: false
|
|
143
|
+
* })
|
|
144
|
+
* // text is a string with the full response
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* @example Agentic structured output (tools + structured response)
|
|
148
|
+
* ```ts
|
|
149
|
+
* import { z } from 'zod'
|
|
150
|
+
*
|
|
151
|
+
* const result = await chat({
|
|
152
|
+
* adapter: openaiText('gpt-4o'),
|
|
153
|
+
* messages: [{ role: 'user', content: 'Research and summarize the topic' }],
|
|
154
|
+
* tools: [researchTool, analyzeTool],
|
|
155
|
+
* outputSchema: z.object({
|
|
156
|
+
* summary: z.string(),
|
|
157
|
+
* keyPoints: z.array(z.string())
|
|
158
|
+
* })
|
|
159
|
+
* })
|
|
160
|
+
* // result is { summary: string, keyPoints: string[] }
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
export declare function chat<TAdapter extends AnyTextAdapter, TSchema extends z.ZodType | undefined = undefined, TStream extends boolean = true>(options: TextActivityOptions<TAdapter, TSchema, TStream>): TextActivityResult<TSchema, TStream>;
|
|
164
|
+
export type { TextAdapter, TextAdapterConfig, StructuredOutputOptions, StructuredOutputResult, } from './adapter.js';
|
|
165
|
+
export { BaseTextAdapter } from './adapter.js';
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import { aiEventClient } from "
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
import { aiEventClient } from "../../event-client.js";
|
|
2
|
+
import { streamToText } from "../../stream-to-response.js";
|
|
3
|
+
import { ToolCallManager, executeToolCalls } from "./tools/tool-calls.js";
|
|
4
|
+
import { convertZodToJsonSchema } from "./tools/zod-converter.js";
|
|
5
|
+
import { maxIterations } from "./agent-loop-strategies.js";
|
|
6
|
+
const kind = "text";
|
|
7
|
+
function createChatOptions(options) {
|
|
8
|
+
return options;
|
|
9
|
+
}
|
|
10
|
+
class TextEngine {
|
|
5
11
|
constructor(config) {
|
|
6
12
|
this.iterationCount = 0;
|
|
7
13
|
this.lastFinishReason = null;
|
|
@@ -13,7 +19,7 @@ class ChatEngine {
|
|
|
13
19
|
this.shouldEmitStreamEnd = true;
|
|
14
20
|
this.earlyTermination = false;
|
|
15
21
|
this.toolPhase = "continue";
|
|
16
|
-
this.cyclePhase = "
|
|
22
|
+
this.cyclePhase = "processText";
|
|
17
23
|
this.adapter = config.adapter;
|
|
18
24
|
this.params = config.params;
|
|
19
25
|
this.systemPrompts = config.params.systemPrompts || [];
|
|
@@ -27,8 +33,16 @@ class ChatEngine {
|
|
|
27
33
|
this.effectiveRequest = config.params.abortController ? { signal: config.params.abortController.signal } : void 0;
|
|
28
34
|
this.effectiveSignal = config.params.abortController?.signal;
|
|
29
35
|
}
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
/** Get the accumulated content after the chat loop completes */
|
|
37
|
+
getAccumulatedContent() {
|
|
38
|
+
return this.accumulatedContent;
|
|
39
|
+
}
|
|
40
|
+
/** Get the final messages array after the chat loop completes */
|
|
41
|
+
getMessages() {
|
|
42
|
+
return this.messages;
|
|
43
|
+
}
|
|
44
|
+
async *run() {
|
|
45
|
+
this.beforeRun();
|
|
32
46
|
try {
|
|
33
47
|
const pendingPhase = yield* this.checkForPendingToolCalls();
|
|
34
48
|
if (pendingPhase === "wait") {
|
|
@@ -39,7 +53,7 @@ class ChatEngine {
|
|
|
39
53
|
return;
|
|
40
54
|
}
|
|
41
55
|
this.beginCycle();
|
|
42
|
-
if (this.cyclePhase === "
|
|
56
|
+
if (this.cyclePhase === "processText") {
|
|
43
57
|
yield* this.streamModelResponse();
|
|
44
58
|
} else {
|
|
45
59
|
yield* this.processToolCalls();
|
|
@@ -47,13 +61,27 @@ class ChatEngine {
|
|
|
47
61
|
this.endCycle();
|
|
48
62
|
} while (this.shouldContinue());
|
|
49
63
|
} finally {
|
|
50
|
-
this.
|
|
64
|
+
this.afterRun();
|
|
51
65
|
}
|
|
52
66
|
}
|
|
53
|
-
|
|
67
|
+
beforeRun() {
|
|
54
68
|
this.streamStartTime = Date.now();
|
|
55
|
-
const {
|
|
56
|
-
|
|
69
|
+
const {
|
|
70
|
+
model,
|
|
71
|
+
tools,
|
|
72
|
+
temperature,
|
|
73
|
+
topP,
|
|
74
|
+
maxTokens,
|
|
75
|
+
metadata,
|
|
76
|
+
modelOptions,
|
|
77
|
+
conversationId
|
|
78
|
+
} = this.params;
|
|
79
|
+
const options = {};
|
|
80
|
+
if (temperature !== void 0) options.temperature = temperature;
|
|
81
|
+
if (topP !== void 0) options.topP = topP;
|
|
82
|
+
if (maxTokens !== void 0) options.maxTokens = maxTokens;
|
|
83
|
+
if (metadata !== void 0) options.metadata = metadata;
|
|
84
|
+
aiEventClient.emit("text:started", {
|
|
57
85
|
requestId: this.requestId,
|
|
58
86
|
streamId: this.streamId,
|
|
59
87
|
model,
|
|
@@ -64,8 +92,8 @@ class ChatEngine {
|
|
|
64
92
|
timestamp: Date.now(),
|
|
65
93
|
clientId: conversationId,
|
|
66
94
|
toolNames: tools?.map((t) => t.name),
|
|
67
|
-
options,
|
|
68
|
-
|
|
95
|
+
options: Object.keys(options).length > 0 ? options : void 0,
|
|
96
|
+
modelOptions
|
|
69
97
|
});
|
|
70
98
|
aiEventClient.emit("stream:started", {
|
|
71
99
|
streamId: this.streamId,
|
|
@@ -74,12 +102,12 @@ class ChatEngine {
|
|
|
74
102
|
timestamp: Date.now()
|
|
75
103
|
});
|
|
76
104
|
}
|
|
77
|
-
|
|
105
|
+
afterRun() {
|
|
78
106
|
if (!this.shouldEmitStreamEnd) {
|
|
79
107
|
return;
|
|
80
108
|
}
|
|
81
109
|
const now = Date.now();
|
|
82
|
-
aiEventClient.emit("
|
|
110
|
+
aiEventClient.emit("text:completed", {
|
|
83
111
|
requestId: this.requestId,
|
|
84
112
|
streamId: this.streamId,
|
|
85
113
|
model: this.params.model,
|
|
@@ -98,16 +126,16 @@ class ChatEngine {
|
|
|
98
126
|
});
|
|
99
127
|
}
|
|
100
128
|
beginCycle() {
|
|
101
|
-
if (this.cyclePhase === "
|
|
129
|
+
if (this.cyclePhase === "processText") {
|
|
102
130
|
this.beginIteration();
|
|
103
131
|
}
|
|
104
132
|
}
|
|
105
133
|
endCycle() {
|
|
106
|
-
if (this.cyclePhase === "
|
|
134
|
+
if (this.cyclePhase === "processText") {
|
|
107
135
|
this.cyclePhase = "executeToolCalls";
|
|
108
136
|
return;
|
|
109
137
|
}
|
|
110
|
-
this.cyclePhase = "
|
|
138
|
+
this.cyclePhase = "processText";
|
|
111
139
|
this.iterationCount++;
|
|
112
140
|
}
|
|
113
141
|
beginIteration() {
|
|
@@ -116,16 +144,23 @@ class ChatEngine {
|
|
|
116
144
|
this.doneChunk = null;
|
|
117
145
|
}
|
|
118
146
|
async *streamModelResponse() {
|
|
119
|
-
const
|
|
120
|
-
const providerOptions = this.params.providerOptions;
|
|
147
|
+
const { temperature, topP, maxTokens, metadata, modelOptions } = this.params;
|
|
121
148
|
const tools = this.params.tools;
|
|
149
|
+
const toolsWithJsonSchemas = tools?.map((tool) => ({
|
|
150
|
+
...tool,
|
|
151
|
+
inputSchema: tool.inputSchema ? convertZodToJsonSchema(tool.inputSchema) : void 0,
|
|
152
|
+
outputSchema: tool.outputSchema ? convertZodToJsonSchema(tool.outputSchema) : void 0
|
|
153
|
+
}));
|
|
122
154
|
for await (const chunk of this.adapter.chatStream({
|
|
123
155
|
model: this.params.model,
|
|
124
156
|
messages: this.messages,
|
|
125
|
-
tools,
|
|
126
|
-
|
|
157
|
+
tools: toolsWithJsonSchemas,
|
|
158
|
+
temperature,
|
|
159
|
+
topP,
|
|
160
|
+
maxTokens,
|
|
161
|
+
metadata,
|
|
127
162
|
request: this.effectiveRequest,
|
|
128
|
-
|
|
163
|
+
modelOptions,
|
|
129
164
|
systemPrompts: this.systemPrompts
|
|
130
165
|
})) {
|
|
131
166
|
if (this.isAborted()) {
|
|
@@ -259,7 +294,7 @@ class ChatEngine {
|
|
|
259
294
|
return "continue";
|
|
260
295
|
}
|
|
261
296
|
const doneChunk = this.createSyntheticDoneChunk();
|
|
262
|
-
aiEventClient.emit("
|
|
297
|
+
aiEventClient.emit("text:iteration", {
|
|
263
298
|
requestId: this.requestId,
|
|
264
299
|
streamId: this.streamId,
|
|
265
300
|
iterationNumber: this.iterationCount + 1,
|
|
@@ -310,7 +345,7 @@ class ChatEngine {
|
|
|
310
345
|
this.setToolPhase("stop");
|
|
311
346
|
return;
|
|
312
347
|
}
|
|
313
|
-
aiEventClient.emit("
|
|
348
|
+
aiEventClient.emit("text:iteration", {
|
|
314
349
|
requestId: this.requestId,
|
|
315
350
|
streamId: this.streamId,
|
|
316
351
|
iterationNumber: this.iterationCount + 1,
|
|
@@ -517,17 +552,80 @@ class ChatEngine {
|
|
|
517
552
|
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
518
553
|
}
|
|
519
554
|
}
|
|
520
|
-
|
|
521
|
-
const {
|
|
522
|
-
|
|
555
|
+
function chat(options) {
|
|
556
|
+
const { outputSchema, stream } = options;
|
|
557
|
+
if (outputSchema) {
|
|
558
|
+
return runAgenticStructuredOutput(
|
|
559
|
+
options
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
if (stream === false) {
|
|
563
|
+
return runNonStreamingText(
|
|
564
|
+
options
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
return runStreamingText(
|
|
568
|
+
options
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
async function* runStreamingText(options) {
|
|
572
|
+
const { adapter, ...textOptions } = options;
|
|
573
|
+
const model = adapter.model;
|
|
574
|
+
const engine = new TextEngine({
|
|
523
575
|
adapter,
|
|
524
|
-
params:
|
|
576
|
+
params: { ...textOptions, model }
|
|
525
577
|
});
|
|
526
|
-
for await (const chunk of engine.
|
|
578
|
+
for await (const chunk of engine.run()) {
|
|
527
579
|
yield chunk;
|
|
528
580
|
}
|
|
529
581
|
}
|
|
582
|
+
function runNonStreamingText(options) {
|
|
583
|
+
const stream = runStreamingText(
|
|
584
|
+
options
|
|
585
|
+
);
|
|
586
|
+
return streamToText(stream);
|
|
587
|
+
}
|
|
588
|
+
async function runAgenticStructuredOutput(options) {
|
|
589
|
+
const { adapter, outputSchema, ...textOptions } = options;
|
|
590
|
+
const model = adapter.model;
|
|
591
|
+
if (!outputSchema) {
|
|
592
|
+
throw new Error("outputSchema is required for structured output");
|
|
593
|
+
}
|
|
594
|
+
const engine = new TextEngine({
|
|
595
|
+
adapter,
|
|
596
|
+
params: { ...textOptions, model }
|
|
597
|
+
});
|
|
598
|
+
for await (const _chunk of engine.run()) {
|
|
599
|
+
}
|
|
600
|
+
const finalMessages = engine.getMessages();
|
|
601
|
+
const {
|
|
602
|
+
tools: _tools,
|
|
603
|
+
agentLoopStrategy: _als,
|
|
604
|
+
...structuredTextOptions
|
|
605
|
+
} = textOptions;
|
|
606
|
+
const jsonSchema = convertZodToJsonSchema(outputSchema);
|
|
607
|
+
if (!jsonSchema) {
|
|
608
|
+
throw new Error("Failed to convert output schema to JSON Schema");
|
|
609
|
+
}
|
|
610
|
+
const result = await adapter.structuredOutput({
|
|
611
|
+
chatOptions: {
|
|
612
|
+
...structuredTextOptions,
|
|
613
|
+
model,
|
|
614
|
+
messages: finalMessages
|
|
615
|
+
},
|
|
616
|
+
outputSchema: jsonSchema
|
|
617
|
+
});
|
|
618
|
+
const validationResult = outputSchema.safeParse(result.data);
|
|
619
|
+
if (!validationResult.success) {
|
|
620
|
+
throw new Error(
|
|
621
|
+
`Structured output validation failed: ${validationResult.error.message}`
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
return validationResult.data;
|
|
625
|
+
}
|
|
530
626
|
export {
|
|
531
|
-
chat
|
|
627
|
+
chat,
|
|
628
|
+
createChatOptions,
|
|
629
|
+
kind
|
|
532
630
|
};
|
|
533
|
-
//# sourceMappingURL=
|
|
631
|
+
//# sourceMappingURL=index.js.map
|