@tanstack/ai 0.11.1 → 0.13.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/dist/esm/activities/chat/adapter.d.ts +12 -4
- package/dist/esm/activities/chat/adapter.js.map +1 -1
- package/dist/esm/activities/chat/index.d.ts +23 -3
- package/dist/esm/activities/chat/index.js +78 -17
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/middleware/compose.d.ts +3 -1
- package/dist/esm/activities/chat/middleware/compose.js +79 -1
- package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
- package/dist/esm/activities/generateImage/index.d.ts +7 -0
- package/dist/esm/activities/generateImage/index.js +19 -3
- package/dist/esm/activities/generateImage/index.js.map +1 -1
- package/dist/esm/activities/generateSpeech/index.d.ts +7 -0
- package/dist/esm/activities/generateSpeech/index.js +21 -3
- package/dist/esm/activities/generateSpeech/index.js.map +1 -1
- package/dist/esm/activities/generateTranscription/index.d.ts +7 -0
- package/dist/esm/activities/generateTranscription/index.js +32 -13
- package/dist/esm/activities/generateTranscription/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.d.ts +7 -0
- package/dist/esm/activities/generateVideo/index.js +49 -7
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/activities/summarize/index.d.ts +7 -0
- package/dist/esm/activities/summarize/index.js +54 -19
- package/dist/esm/activities/summarize/index.js.map +1 -1
- package/dist/esm/adapter-internals.d.ts +3 -0
- package/dist/esm/adapter-internals.js +7 -0
- package/dist/esm/adapter-internals.js.map +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/logger/console-logger.d.ts +11 -0
- package/dist/esm/logger/console-logger.js +27 -0
- package/dist/esm/logger/console-logger.js.map +1 -0
- package/dist/esm/logger/internal-logger.d.ts +33 -0
- package/dist/esm/logger/internal-logger.js +69 -0
- package/dist/esm/logger/internal-logger.js.map +1 -0
- package/dist/esm/logger/resolve.d.ts +14 -0
- package/dist/esm/logger/resolve.js +54 -0
- package/dist/esm/logger/resolve.js.map +1 -0
- package/dist/esm/logger/types.d.ts +75 -0
- package/dist/esm/tools/provider-tool.d.ts +21 -0
- package/dist/esm/types.d.ts +34 -0
- package/package.json +6 -2
- package/skills/ai-core/SKILL.md +5 -3
- package/skills/ai-core/debug-logging/SKILL.md +263 -0
- package/src/activities/chat/adapter.ts +14 -3
- package/src/activities/chat/index.ts +119 -24
- package/src/activities/chat/middleware/compose.ts +84 -1
- package/src/activities/generateImage/index.ts +29 -3
- package/src/activities/generateSpeech/index.ts +35 -3
- package/src/activities/generateTranscription/index.ts +45 -13
- package/src/activities/generateVideo/index.ts +65 -6
- package/src/activities/summarize/index.ts +66 -20
- package/src/adapter-internals.ts +7 -0
- package/src/index.ts +12 -0
- package/src/logger/console-logger.ts +49 -0
- package/src/logger/internal-logger.ts +107 -0
- package/src/logger/resolve.ts +72 -0
- package/src/logger/types.ts +78 -0
- package/src/tools/provider-tool.ts +25 -0
- package/src/types.ts +36 -0
|
@@ -10,7 +10,12 @@ export interface TextAdapterConfig {
|
|
|
10
10
|
headers?: Record<string, string>;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* Options for structured output generation
|
|
13
|
+
* Options for structured output generation.
|
|
14
|
+
*
|
|
15
|
+
* The internal logger is threaded through `chatOptions.logger` (inherited from
|
|
16
|
+
* `TextOptions`). Adapter implementations must call `logger.request()` before
|
|
17
|
+
* SDK calls, `logger.provider()` for each chunk received, and `logger.errors()`
|
|
18
|
+
* in catch blocks.
|
|
14
19
|
*/
|
|
15
20
|
export interface StructuredOutputOptions<TProviderOptions extends object> {
|
|
16
21
|
/** Text options for the request */
|
|
@@ -38,8 +43,9 @@ export interface StructuredOutputResult<T = unknown> {
|
|
|
38
43
|
* - TProviderOptions: Provider-specific options for this model (already resolved)
|
|
39
44
|
* - TInputModalities: Supported input modalities for this model (already resolved)
|
|
40
45
|
* - TMessageMetadata: Metadata types for content parts (already resolved)
|
|
46
|
+
* - TToolCapabilities: Tuple of tool-kind strings supported by this model, resolved from `supports.tools`
|
|
41
47
|
*/
|
|
42
|
-
export interface TextAdapter<TModel extends string, TProviderOptions extends Record<string, any>, TInputModalities extends ReadonlyArray<Modality>, TMessageMetadataByModality extends DefaultMessageMetadataByModality> {
|
|
48
|
+
export interface TextAdapter<TModel extends string, TProviderOptions extends Record<string, any>, TInputModalities extends ReadonlyArray<Modality>, TMessageMetadataByModality extends DefaultMessageMetadataByModality, TToolCapabilities extends ReadonlyArray<string> = ReadonlyArray<string>> {
|
|
43
49
|
/** Discriminator for adapter kind */
|
|
44
50
|
readonly kind: 'text';
|
|
45
51
|
/** Provider name identifier (e.g., 'openai', 'anthropic') */
|
|
@@ -53,6 +59,7 @@ export interface TextAdapter<TModel extends string, TProviderOptions extends Rec
|
|
|
53
59
|
providerOptions: TProviderOptions;
|
|
54
60
|
inputModalities: TInputModalities;
|
|
55
61
|
messageMetadataByModality: TMessageMetadataByModality;
|
|
62
|
+
toolCapabilities: TToolCapabilities;
|
|
56
63
|
};
|
|
57
64
|
/**
|
|
58
65
|
* Stream text completions from the model
|
|
@@ -72,14 +79,14 @@ export interface TextAdapter<TModel extends string, TProviderOptions extends Rec
|
|
|
72
79
|
* A TextAdapter with any/unknown type parameters.
|
|
73
80
|
* Useful as a constraint in generic functions and interfaces.
|
|
74
81
|
*/
|
|
75
|
-
export type AnyTextAdapter = TextAdapter<any, any, any, any>;
|
|
82
|
+
export type AnyTextAdapter = TextAdapter<any, any, any, any, any>;
|
|
76
83
|
/**
|
|
77
84
|
* Abstract base class for text adapters.
|
|
78
85
|
* Extend this class to implement a text adapter for a specific provider.
|
|
79
86
|
*
|
|
80
87
|
* Generic parameters match TextAdapter - all pre-resolved by the provider function.
|
|
81
88
|
*/
|
|
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> {
|
|
89
|
+
export declare abstract class BaseTextAdapter<TModel extends string, TProviderOptions extends Record<string, any>, TInputModalities extends ReadonlyArray<Modality>, TMessageMetadataByModality extends DefaultMessageMetadataByModality, TToolCapabilities extends ReadonlyArray<string> = ReadonlyArray<string>> implements TextAdapter<TModel, TProviderOptions, TInputModalities, TMessageMetadataByModality, TToolCapabilities> {
|
|
83
90
|
readonly kind: "text";
|
|
84
91
|
abstract readonly name: string;
|
|
85
92
|
readonly model: TModel;
|
|
@@ -87,6 +94,7 @@ export declare abstract class BaseTextAdapter<TModel extends string, TProviderOp
|
|
|
87
94
|
providerOptions: TProviderOptions;
|
|
88
95
|
inputModalities: TInputModalities;
|
|
89
96
|
messageMetadataByModality: TMessageMetadataByModality;
|
|
97
|
+
toolCapabilities: TToolCapabilities;
|
|
90
98
|
};
|
|
91
99
|
protected config: TextAdapterConfig;
|
|
92
100
|
constructor(config: TextAdapterConfig | undefined, model: TModel);
|
|
@@ -1 +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":"
|
|
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 *\n * The internal logger is threaded through `chatOptions.logger` (inherited from\n * `TextOptions`). Adapter implementations must call `logger.request()` before\n * SDK calls, `logger.provider()` for each chunk received, and `logger.errors()`\n * in catch blocks.\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 * - TToolCapabilities: Tuple of tool-kind strings supported by this model, resolved from `supports.tools`\n */\nexport interface TextAdapter<\n TModel extends string,\n TProviderOptions extends Record<string, any>,\n TInputModalities extends ReadonlyArray<Modality>,\n TMessageMetadataByModality extends DefaultMessageMetadataByModality,\n TToolCapabilities extends ReadonlyArray<string> = ReadonlyArray<string>,\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 toolCapabilities: TToolCapabilities\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, 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 TToolCapabilities extends ReadonlyArray<string> = ReadonlyArray<string>,\n> implements TextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n TMessageMetadataByModality,\n TToolCapabilities\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 toolCapabilities: TToolCapabilities\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":"AAiHO,MAAe,gBAYpB;AAAA,EAeA,YAAY,SAA4B,CAAA,GAAI,OAAe;AAd3D,SAAS,OAAO;AAed,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,6 +1,8 @@
|
|
|
1
1
|
import { AnyTextAdapter } from './adapter.js';
|
|
2
|
-
import { ConstrainedModelMessage, InferSchemaType, SchemaInput, StreamChunk, TextOptions } from '../../types.js';
|
|
2
|
+
import { ConstrainedModelMessage, InferSchemaType, SchemaInput, StreamChunk, TextOptions, Tool } from '../../types.js';
|
|
3
3
|
import { ChatMiddleware } from './middleware/types.js';
|
|
4
|
+
import { DebugOption } from '../../logger/types.js';
|
|
5
|
+
import { ProviderTool } from '../../tools/provider-tool.js';
|
|
4
6
|
/** The adapter kind this activity handles */
|
|
5
7
|
export declare const kind: "text";
|
|
6
8
|
/**
|
|
@@ -21,8 +23,19 @@ export interface TextActivityOptions<TAdapter extends AnyTextAdapter, TSchema ex
|
|
|
21
23
|
}>>;
|
|
22
24
|
/** System prompts to prepend to the conversation */
|
|
23
25
|
systemPrompts?: TextOptions['systemPrompts'];
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Tools for function calling (auto-executed when called).
|
|
28
|
+
*
|
|
29
|
+
* Accepts two shapes:
|
|
30
|
+
* - User-defined tools via `toolDefinition()` — plain `Tool`, always assignable.
|
|
31
|
+
* - Provider tools from `@tanstack/ai-<provider>/tools` (e.g. `webSearchTool`)
|
|
32
|
+
* — branded and type-checked against the selected model's
|
|
33
|
+
* `supports.tools` list. Passing an unsupported tool produces a
|
|
34
|
+
* compile-time error on the array element.
|
|
35
|
+
*/
|
|
36
|
+
tools?: Array<(Tool & {
|
|
37
|
+
readonly '~toolKind'?: never;
|
|
38
|
+
}) | ProviderTool<string, TAdapter['~types']['toolCapabilities'][number]>>;
|
|
26
39
|
/** Controls the randomness of the output. Higher values make output more random. Range: [0.0, 2.0] */
|
|
27
40
|
temperature?: TextOptions['temperature'];
|
|
28
41
|
/** Nucleus sampling parameter. The model considers tokens with topP probability mass. */
|
|
@@ -102,6 +115,13 @@ export interface TextActivityOptions<TAdapter extends AnyTextAdapter, TSchema ex
|
|
|
102
115
|
* Can be used to pass request-scoped data (e.g., user ID, request context).
|
|
103
116
|
*/
|
|
104
117
|
context?: unknown;
|
|
118
|
+
/**
|
|
119
|
+
* Enable debug logging. Pass `true` to enable all categories with the default
|
|
120
|
+
* console logger, `false` to silence everything, or a `DebugConfig` object for
|
|
121
|
+
* granular control and/or a custom `Logger`. Defaults to `undefined`, which
|
|
122
|
+
* means only the `errors` category is active.
|
|
123
|
+
*/
|
|
124
|
+
debug?: DebugOption;
|
|
105
125
|
}
|
|
106
126
|
/**
|
|
107
127
|
* Create typed options for the chat() function without executing.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { devtoolsMiddleware } from "@tanstack/ai-event-client";
|
|
2
2
|
import { stripToSpecMiddleware } from "../../strip-to-spec-middleware.js";
|
|
3
3
|
import { streamToText } from "../../stream-to-response.js";
|
|
4
|
+
import { resolveDebugOption } from "../../logger/resolve.js";
|
|
4
5
|
import { LazyToolManager } from "./tools/lazy-tool-manager.js";
|
|
5
6
|
import { ToolCallManager, MiddlewareAbortError, executeToolCalls } from "./tools/tool-calls.js";
|
|
6
7
|
import { convertSchemaToJsonSchema, isStandardSchema, parseWithStandardSchema } from "./tools/schema-converter.js";
|
|
@@ -12,7 +13,7 @@ function createChatOptions(options) {
|
|
|
12
13
|
return options;
|
|
13
14
|
}
|
|
14
15
|
class TextEngine {
|
|
15
|
-
constructor(config) {
|
|
16
|
+
constructor(config, logger) {
|
|
16
17
|
this.iterationCount = 0;
|
|
17
18
|
this.lastFinishReason = null;
|
|
18
19
|
this.streamStartTime = 0;
|
|
@@ -25,6 +26,7 @@ class TextEngine {
|
|
|
25
26
|
this.cyclePhase = "processText";
|
|
26
27
|
this.deferredPromises = [];
|
|
27
28
|
this.terminalHookCalled = false;
|
|
29
|
+
this.logger = logger;
|
|
28
30
|
this.adapter = config.adapter;
|
|
29
31
|
this.params = config.params;
|
|
30
32
|
this.systemPrompts = config.params.systemPrompts || [];
|
|
@@ -55,7 +57,7 @@ class TextEngine {
|
|
|
55
57
|
...config.middleware || [],
|
|
56
58
|
stripToSpecMiddleware()
|
|
57
59
|
];
|
|
58
|
-
this.middlewareRunner = new MiddlewareRunner(allMiddleware);
|
|
60
|
+
this.middlewareRunner = new MiddlewareRunner(allMiddleware, logger);
|
|
59
61
|
this.middlewareAbortController = new AbortController();
|
|
60
62
|
this.middlewareCtx = {
|
|
61
63
|
requestId: this.requestId,
|
|
@@ -104,6 +106,9 @@ class TextEngine {
|
|
|
104
106
|
}
|
|
105
107
|
async *run() {
|
|
106
108
|
this.beforeRun();
|
|
109
|
+
this.logger.agentLoop("run started", {
|
|
110
|
+
conversationId: this.middlewareCtx.conversationId
|
|
111
|
+
});
|
|
107
112
|
try {
|
|
108
113
|
this.middlewareCtx.phase = "init";
|
|
109
114
|
const initialConfig = this.buildMiddlewareConfig();
|
|
@@ -121,6 +126,9 @@ class TextEngine {
|
|
|
121
126
|
if (this.earlyTermination || this.isCancelled()) {
|
|
122
127
|
return;
|
|
123
128
|
}
|
|
129
|
+
this.logger.agentLoop(`iteration=${this.middlewareCtx.iteration}`, {
|
|
130
|
+
iteration: this.middlewareCtx.iteration
|
|
131
|
+
});
|
|
124
132
|
await this.beginCycle();
|
|
125
133
|
if (this.cyclePhase === "processText") {
|
|
126
134
|
this.middlewareCtx.phase = "beforeModel";
|
|
@@ -137,6 +145,9 @@ class TextEngine {
|
|
|
137
145
|
}
|
|
138
146
|
this.endCycle();
|
|
139
147
|
} while (this.shouldContinue());
|
|
148
|
+
this.logger.agentLoop("run finished", {
|
|
149
|
+
finishReason: this.lastFinishReason
|
|
150
|
+
});
|
|
140
151
|
if (!this.terminalHookCalled && this.toolPhase !== "wait") {
|
|
141
152
|
this.terminalHookCalled = true;
|
|
142
153
|
await this.middlewareRunner.runOnFinish(this.middlewareCtx, {
|
|
@@ -156,6 +167,10 @@ class TextEngine {
|
|
|
156
167
|
duration: Date.now() - this.streamStartTime
|
|
157
168
|
});
|
|
158
169
|
} else {
|
|
170
|
+
this.logger.errors("chat run failed", {
|
|
171
|
+
error,
|
|
172
|
+
conversationId: this.middlewareCtx.conversationId
|
|
173
|
+
});
|
|
159
174
|
await this.middlewareRunner.runOnError(this.middlewareCtx, {
|
|
160
175
|
error,
|
|
161
176
|
duration: Date.now() - this.streamStartTime
|
|
@@ -224,6 +239,16 @@ class TextEngine {
|
|
|
224
239
|
outputSchema: tool.outputSchema ? convertSchemaToJsonSchema(tool.outputSchema) : void 0
|
|
225
240
|
}));
|
|
226
241
|
this.middlewareCtx.phase = "modelStream";
|
|
242
|
+
const providerName = this.adapter.provider ?? this.adapter.name;
|
|
243
|
+
this.logger.request(
|
|
244
|
+
`activity=chat provider=${providerName} model=${this.params.model} messages=${this.messages.length} tools=${this.tools.length} stream=true`,
|
|
245
|
+
{
|
|
246
|
+
provider: providerName,
|
|
247
|
+
model: this.params.model,
|
|
248
|
+
messageCount: this.messages.length,
|
|
249
|
+
toolCount: this.tools.length
|
|
250
|
+
}
|
|
251
|
+
);
|
|
227
252
|
for await (const chunk of this.adapter.chatStream({
|
|
228
253
|
model: this.params.model,
|
|
229
254
|
messages: this.messages,
|
|
@@ -235,6 +260,7 @@ class TextEngine {
|
|
|
235
260
|
request: this.effectiveRequest,
|
|
236
261
|
modelOptions,
|
|
237
262
|
systemPrompts: this.systemPrompts,
|
|
263
|
+
logger: this.logger,
|
|
238
264
|
threadId: this.threadId,
|
|
239
265
|
runId: this.runIdOverride
|
|
240
266
|
})) {
|
|
@@ -248,6 +274,7 @@ class TextEngine {
|
|
|
248
274
|
chunk
|
|
249
275
|
);
|
|
250
276
|
for (const outputChunk of outputChunks) {
|
|
277
|
+
this.logger.output(`type=${outputChunk.type}`, { chunk: outputChunk });
|
|
251
278
|
yield outputChunk;
|
|
252
279
|
this.middlewareCtx.chunkIndex++;
|
|
253
280
|
}
|
|
@@ -357,6 +384,10 @@ class TextEngine {
|
|
|
357
384
|
(eventName, data) => this.createCustomEventChunk(eventName, data),
|
|
358
385
|
{
|
|
359
386
|
onBeforeToolCall: async (toolCall, tool, args) => {
|
|
387
|
+
this.logger.tools(`phase=before name=${toolCall.function.name}`, {
|
|
388
|
+
name: toolCall.function.name,
|
|
389
|
+
args
|
|
390
|
+
});
|
|
360
391
|
const hookCtx = {
|
|
361
392
|
toolCall,
|
|
362
393
|
tool,
|
|
@@ -370,6 +401,10 @@ class TextEngine {
|
|
|
370
401
|
);
|
|
371
402
|
},
|
|
372
403
|
onAfterToolCall: async (info) => {
|
|
404
|
+
this.logger.tools(`phase=after name=${info.toolName}`, {
|
|
405
|
+
name: info.toolName,
|
|
406
|
+
result: info.result
|
|
407
|
+
});
|
|
373
408
|
await this.middlewareRunner.runOnAfterToolCall(
|
|
374
409
|
this.middlewareCtx,
|
|
375
410
|
info
|
|
@@ -480,6 +515,10 @@ class TextEngine {
|
|
|
480
515
|
(eventName, data) => this.createCustomEventChunk(eventName, data),
|
|
481
516
|
{
|
|
482
517
|
onBeforeToolCall: async (toolCall, tool, args) => {
|
|
518
|
+
this.logger.tools(`phase=before name=${toolCall.function.name}`, {
|
|
519
|
+
name: toolCall.function.name,
|
|
520
|
+
args
|
|
521
|
+
});
|
|
483
522
|
const hookCtx = {
|
|
484
523
|
toolCall,
|
|
485
524
|
tool,
|
|
@@ -493,6 +532,10 @@ class TextEngine {
|
|
|
493
532
|
);
|
|
494
533
|
},
|
|
495
534
|
onAfterToolCall: async (info) => {
|
|
535
|
+
this.logger.tools(`phase=after name=${info.toolName}`, {
|
|
536
|
+
name: info.toolName,
|
|
537
|
+
result: info.result
|
|
538
|
+
});
|
|
496
539
|
await this.middlewareRunner.runOnAfterToolCall(
|
|
497
540
|
this.middlewareCtx,
|
|
498
541
|
info
|
|
@@ -846,14 +889,18 @@ function chat(options) {
|
|
|
846
889
|
);
|
|
847
890
|
}
|
|
848
891
|
async function* runStreamingText(options) {
|
|
849
|
-
const { adapter, middleware, context, ...textOptions } = options;
|
|
892
|
+
const { adapter, middleware, context, debug, ...textOptions } = options;
|
|
850
893
|
const model = adapter.model;
|
|
851
|
-
const
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
894
|
+
const logger = resolveDebugOption(debug);
|
|
895
|
+
const engine = new TextEngine(
|
|
896
|
+
{
|
|
897
|
+
adapter,
|
|
898
|
+
params: { ...textOptions, model, logger },
|
|
899
|
+
middleware,
|
|
900
|
+
context
|
|
901
|
+
},
|
|
902
|
+
logger
|
|
903
|
+
);
|
|
857
904
|
for await (const chunk of engine.run()) {
|
|
858
905
|
yield chunk;
|
|
859
906
|
}
|
|
@@ -865,17 +912,21 @@ function runNonStreamingText(options) {
|
|
|
865
912
|
return streamToText(stream);
|
|
866
913
|
}
|
|
867
914
|
async function runAgenticStructuredOutput(options) {
|
|
868
|
-
const { adapter, outputSchema, middleware, context, ...textOptions } = options;
|
|
915
|
+
const { adapter, outputSchema, middleware, context, debug, ...textOptions } = options;
|
|
869
916
|
const model = adapter.model;
|
|
917
|
+
const logger = resolveDebugOption(debug);
|
|
870
918
|
if (!outputSchema) {
|
|
871
919
|
throw new Error("outputSchema is required for structured output");
|
|
872
920
|
}
|
|
873
|
-
const engine = new TextEngine(
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
921
|
+
const engine = new TextEngine(
|
|
922
|
+
{
|
|
923
|
+
adapter,
|
|
924
|
+
params: { ...textOptions, model, logger },
|
|
925
|
+
middleware,
|
|
926
|
+
context
|
|
927
|
+
},
|
|
928
|
+
logger
|
|
929
|
+
);
|
|
879
930
|
for await (const _chunk of engine.run()) {
|
|
880
931
|
}
|
|
881
932
|
const finalMessages = engine.getMessages();
|
|
@@ -888,11 +939,21 @@ async function runAgenticStructuredOutput(options) {
|
|
|
888
939
|
if (!jsonSchema) {
|
|
889
940
|
throw new Error("Failed to convert output schema to JSON Schema");
|
|
890
941
|
}
|
|
942
|
+
const providerName = adapter.provider ?? adapter.name;
|
|
943
|
+
logger.request(
|
|
944
|
+
`activity=chat-structured provider=${providerName} model=${model} messages=${finalMessages.length}`,
|
|
945
|
+
{
|
|
946
|
+
provider: providerName,
|
|
947
|
+
model,
|
|
948
|
+
messageCount: finalMessages.length
|
|
949
|
+
}
|
|
950
|
+
);
|
|
891
951
|
const result = await adapter.structuredOutput({
|
|
892
952
|
chatOptions: {
|
|
893
953
|
...structuredTextOptions,
|
|
894
954
|
model,
|
|
895
|
-
messages: finalMessages
|
|
955
|
+
messages: finalMessages,
|
|
956
|
+
logger
|
|
896
957
|
},
|
|
897
958
|
outputSchema: jsonSchema
|
|
898
959
|
});
|