@tanstack/ai 0.23.1 → 0.25.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 +3 -1
- package/dist/esm/activities/chat/adapter.js.map +1 -1
- package/dist/esm/activities/chat/index.d.ts +33 -9
- package/dist/esm/activities/chat/index.js +19 -9
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/messages.js +2 -1
- package/dist/esm/activities/chat/messages.js.map +1 -1
- package/dist/esm/activities/chat/middleware/compose.d.ts +14 -14
- package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
- package/dist/esm/activities/chat/middleware/types.d.ts +21 -21
- package/dist/esm/activities/chat/runtime-context-types.d.ts +43 -0
- package/dist/esm/activities/chat/stream/message-updaters.d.ts +2 -2
- package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
- package/dist/esm/activities/chat/stream/processor.d.ts +1 -0
- package/dist/esm/activities/chat/stream/processor.js +35 -12
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-calls.d.ts +15 -5
- package/dist/esm/activities/chat/tools/tool-calls.js +59 -19
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-definition.d.ts +12 -8
- package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
- package/dist/esm/activities/error-payload.d.ts +26 -0
- package/dist/esm/activities/error-payload.js +12 -1
- package/dist/esm/activities/error-payload.js.map +1 -1
- package/dist/esm/activities/generateAudio/index.js +9 -0
- package/dist/esm/activities/generateAudio/index.js.map +1 -1
- package/dist/esm/activities/generateSpeech/index.js +9 -0
- package/dist/esm/activities/generateSpeech/index.js.map +1 -1
- package/dist/esm/adapter-internals.d.ts +1 -1
- package/dist/esm/adapter-internals.js +3 -2
- package/dist/esm/client.d.ts +1 -1
- package/dist/esm/client.js +3 -1
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +9 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/tool-registry.d.ts +7 -7
- package/dist/esm/tool-registry.js +1 -1
- package/dist/esm/tool-registry.js.map +1 -1
- package/dist/esm/types.d.ts +56 -59
- package/dist/esm/utilities/ag-ui-wire.js +1 -1
- package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
- package/dist/esm/utilities/chat-params.d.ts +8 -3
- package/dist/esm/utilities/chat-params.js +6 -2
- package/dist/esm/utilities/chat-params.js.map +1 -1
- package/dist/esm/utilities/tool-result.d.ts +21 -0
- package/dist/esm/utilities/tool-result.js +37 -0
- package/dist/esm/utilities/tool-result.js.map +1 -0
- package/dist/esm/utilities/usage.d.ts +31 -0
- package/dist/esm/utilities/usage.js +11 -0
- package/dist/esm/utilities/usage.js.map +1 -0
- package/package.json +2 -2
- package/src/activities/chat/adapter.ts +3 -0
- package/src/activities/chat/index.ts +219 -47
- package/src/activities/chat/messages.ts +2 -1
- package/src/activities/chat/middleware/compose.ts +23 -17
- package/src/activities/chat/middleware/types.ts +21 -21
- package/src/activities/chat/runtime-context-types.ts +68 -0
- package/src/activities/chat/stream/message-updaters.ts +2 -1
- package/src/activities/chat/stream/processor.ts +48 -8
- package/src/activities/chat/tools/tool-calls.ts +138 -43
- package/src/activities/chat/tools/tool-definition.ts +25 -31
- package/src/activities/error-payload.ts +44 -0
- package/src/activities/generateAudio/index.ts +10 -0
- package/src/activities/generateSpeech/index.ts +10 -0
- package/src/adapter-internals.ts +4 -1
- package/src/client.ts +5 -1
- package/src/index.ts +10 -0
- package/src/tool-registry.ts +16 -14
- package/src/types.ts +118 -79
- package/src/utilities/ag-ui-wire.ts +4 -1
- package/src/utilities/chat-params.ts +22 -7
- package/src/utilities/tool-result.ts +60 -0
- package/src/utilities/usage.ts +41 -0
package/src/types.ts
CHANGED
|
@@ -4,6 +4,16 @@ import type {
|
|
|
4
4
|
} from '@standard-schema/spec'
|
|
5
5
|
import type { InternalLogger } from './logger/internal-logger'
|
|
6
6
|
import type { SystemPrompt } from './system-prompts'
|
|
7
|
+
// The canonical usage types live in the leaf `@tanstack/ai-event-client`
|
|
8
|
+
// package (which `@tanstack/ai` already depends on) so there is a single source
|
|
9
|
+
// of truth without a dependency cycle. They are re-exported below.
|
|
10
|
+
import type {
|
|
11
|
+
CompletionTokensDetails,
|
|
12
|
+
PromptTokensDetails,
|
|
13
|
+
ProviderUsageDetails,
|
|
14
|
+
TokenUsage,
|
|
15
|
+
UsageCostBreakdown,
|
|
16
|
+
} from '@tanstack/ai-event-client'
|
|
7
17
|
import type {
|
|
8
18
|
BaseEvent as AGUIBaseEvent,
|
|
9
19
|
CustomEvent as AGUICustomEvent,
|
|
@@ -50,6 +60,8 @@ export type ToolResultState =
|
|
|
50
60
|
| 'complete' // Result is complete
|
|
51
61
|
| 'error' // Error occurred
|
|
52
62
|
|
|
63
|
+
export type ToolOutputState = 'output-available' | 'output-error'
|
|
64
|
+
|
|
53
65
|
/**
|
|
54
66
|
* JSON Schema type for defining tool input/output schemas as raw JSON Schema objects.
|
|
55
67
|
* This allows tools to be defined without schema libraries when you have JSON Schema definitions available.
|
|
@@ -355,7 +367,7 @@ export interface ToolCallPart<TMetadata = unknown> {
|
|
|
355
367
|
export interface ToolResultPart {
|
|
356
368
|
type: 'tool-result'
|
|
357
369
|
toolCallId: string
|
|
358
|
-
content: string
|
|
370
|
+
content: string | Array<ContentPart>
|
|
359
371
|
state: ToolResultState
|
|
360
372
|
error?: string // Error message if state is "error"
|
|
361
373
|
}
|
|
@@ -443,33 +455,75 @@ export type ConstrainedModelMessage<
|
|
|
443
455
|
content: ConstrainedContent<TInputModalitiesTypes>
|
|
444
456
|
}
|
|
445
457
|
|
|
458
|
+
type IsUnknown<T> = unknown extends T
|
|
459
|
+
? [T] extends [unknown]
|
|
460
|
+
? true
|
|
461
|
+
: false
|
|
462
|
+
: false
|
|
463
|
+
|
|
464
|
+
type RuntimeContextField<TContext> =
|
|
465
|
+
IsUnknown<TContext> extends true
|
|
466
|
+
? {
|
|
467
|
+
/**
|
|
468
|
+
* Runtime context provided by the caller.
|
|
469
|
+
*
|
|
470
|
+
* This is request-local application state for tool and middleware
|
|
471
|
+
* implementations, not the AG-UI `Context[]` protocol field.
|
|
472
|
+
*/
|
|
473
|
+
context?: TContext
|
|
474
|
+
}
|
|
475
|
+
: {
|
|
476
|
+
/**
|
|
477
|
+
* Runtime context provided by the caller.
|
|
478
|
+
*
|
|
479
|
+
* This is request-local application state for tool and middleware
|
|
480
|
+
* implementations, not the AG-UI `Context[]` protocol field.
|
|
481
|
+
*/
|
|
482
|
+
context: TContext
|
|
483
|
+
}
|
|
484
|
+
|
|
446
485
|
/**
|
|
447
486
|
* Context passed to tool execute functions, providing capabilities like
|
|
448
487
|
* emitting custom events during execution.
|
|
449
488
|
*/
|
|
450
|
-
export
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
489
|
+
export type ToolExecutionContext<TContext = unknown> =
|
|
490
|
+
RuntimeContextField<TContext> & {
|
|
491
|
+
/** The ID of the tool call being executed */
|
|
492
|
+
toolCallId?: string
|
|
493
|
+
/**
|
|
494
|
+
* Emit a custom event during tool execution.
|
|
495
|
+
* Events are streamed to the client in real-time as AG-UI CUSTOM events.
|
|
496
|
+
*
|
|
497
|
+
* @param eventName - Name of the custom event
|
|
498
|
+
* @param value - Event payload value
|
|
499
|
+
*
|
|
500
|
+
* @example
|
|
501
|
+
* ```ts
|
|
502
|
+
* const tool = toolDefinition({ ... }).server(async (args, context) => {
|
|
503
|
+
* context?.emitCustomEvent('progress', { step: 1, total: 3 })
|
|
504
|
+
* // ... do work ...
|
|
505
|
+
* context?.emitCustomEvent('progress', { step: 2, total: 3 })
|
|
506
|
+
* // ... do more work ...
|
|
507
|
+
* return result
|
|
508
|
+
* })
|
|
509
|
+
* ```
|
|
510
|
+
*/
|
|
511
|
+
emitCustomEvent: (eventName: string, value: Record<string, any>) => void
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export type ToolExecuteFunction<
|
|
515
|
+
TInput extends SchemaInput = SchemaInput,
|
|
516
|
+
TOutput extends SchemaInput = SchemaInput,
|
|
517
|
+
TContext = unknown,
|
|
518
|
+
> = undefined extends TContext
|
|
519
|
+
? (
|
|
520
|
+
args: InferSchemaType<TInput>,
|
|
521
|
+
context?: ToolExecutionContext<TContext>,
|
|
522
|
+
) => Promise<InferSchemaType<TOutput>> | InferSchemaType<TOutput>
|
|
523
|
+
: (
|
|
524
|
+
args: InferSchemaType<TInput>,
|
|
525
|
+
context: ToolExecutionContext<TContext>,
|
|
526
|
+
) => Promise<InferSchemaType<TOutput>> | InferSchemaType<TOutput>
|
|
473
527
|
|
|
474
528
|
/**
|
|
475
529
|
* Tool/Function definition for function calling.
|
|
@@ -488,6 +542,7 @@ export interface Tool<
|
|
|
488
542
|
TInput extends SchemaInput = SchemaInput,
|
|
489
543
|
TOutput extends SchemaInput = SchemaInput,
|
|
490
544
|
TName extends string = string,
|
|
545
|
+
TContext = unknown,
|
|
491
546
|
> {
|
|
492
547
|
/**
|
|
493
548
|
* Unique name of the tool (used by the model to call it).
|
|
@@ -587,9 +642,7 @@ export interface Tool<
|
|
|
587
642
|
* return weather; // Can return object or string
|
|
588
643
|
* }
|
|
589
644
|
*/
|
|
590
|
-
execute?:
|
|
591
|
-
| ((args: any, context?: ToolExecutionContext) => Promise<any> | any)
|
|
592
|
-
| undefined
|
|
645
|
+
execute?: ToolExecuteFunction<TInput, TOutput, TContext> | undefined
|
|
593
646
|
|
|
594
647
|
/** If true, tool execution requires user approval before running. Works with both server and client tools. */
|
|
595
648
|
needsApproval?: boolean
|
|
@@ -601,6 +654,10 @@ export interface Tool<
|
|
|
601
654
|
metadata?: Record<string, any> | undefined
|
|
602
655
|
}
|
|
603
656
|
|
|
657
|
+
export type AnyTool = Omit<Tool<any, any, any, any>, 'execute'> & {
|
|
658
|
+
execute?: ((args: any, context?: any) => any) | undefined
|
|
659
|
+
}
|
|
660
|
+
|
|
604
661
|
export interface ToolConfig {
|
|
605
662
|
[key: string]: Tool
|
|
606
663
|
}
|
|
@@ -729,10 +786,16 @@ export type AgentLoopStrategy = (state: AgentLoopState) => boolean
|
|
|
729
786
|
export interface TextOptions<
|
|
730
787
|
TProviderOptionsSuperset extends Record<string, any> = Record<string, any>,
|
|
731
788
|
TProviderOptionsForModel = TProviderOptionsSuperset,
|
|
789
|
+
TContext = unknown,
|
|
732
790
|
> {
|
|
733
791
|
model: string
|
|
734
792
|
messages: Array<ModelMessage>
|
|
735
|
-
tools?: Array<
|
|
793
|
+
tools?: Array<AnyTool> | undefined
|
|
794
|
+
/**
|
|
795
|
+
* Runtime context provided by the caller and passed to middleware and
|
|
796
|
+
* server-side tool implementations.
|
|
797
|
+
*/
|
|
798
|
+
context?: TContext
|
|
736
799
|
/**
|
|
737
800
|
* System prompts to include with the request.
|
|
738
801
|
*
|
|
@@ -925,38 +988,22 @@ export interface RunStartedEvent extends AGUIRunStartedEvent {
|
|
|
925
988
|
model?: string
|
|
926
989
|
}
|
|
927
990
|
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
/** Total cost the gateway paid the upstream provider. */
|
|
937
|
-
upstreamCost?: number
|
|
938
|
-
/** Upstream cost for input (prompt) tokens. */
|
|
939
|
-
upstreamInputCost?: number
|
|
940
|
-
/** Upstream cost for output (completion) tokens. */
|
|
941
|
-
upstreamOutputCost?: number
|
|
991
|
+
// Re-export the canonical usage types (defined in `@tanstack/ai-event-client`)
|
|
992
|
+
// so `@tanstack/ai` consumers keep importing them from here unchanged.
|
|
993
|
+
export type {
|
|
994
|
+
CompletionTokensDetails,
|
|
995
|
+
PromptTokensDetails,
|
|
996
|
+
ProviderUsageDetails,
|
|
997
|
+
TokenUsage,
|
|
998
|
+
UsageCostBreakdown,
|
|
942
999
|
}
|
|
943
1000
|
|
|
944
1001
|
/**
|
|
945
|
-
*
|
|
946
|
-
*
|
|
947
|
-
*
|
|
948
|
-
* authoritative per-request cost (e.g. OpenRouter). They are absent for adapters
|
|
949
|
-
* that do not report cost, so consumers must treat them as optional.
|
|
1002
|
+
* @deprecated Renamed to {@link TokenUsage}. Kept as an alias for backward
|
|
1003
|
+
* compatibility with `@tanstack/ai@0.23` and earlier; will be removed in a
|
|
1004
|
+
* future release.
|
|
950
1005
|
*/
|
|
951
|
-
export
|
|
952
|
-
promptTokens: number
|
|
953
|
-
completionTokens: number
|
|
954
|
-
totalTokens: number
|
|
955
|
-
/** Provider-reported cost for the request, when available. */
|
|
956
|
-
cost?: number
|
|
957
|
-
/** Provider-reported cost breakdown, when available. */
|
|
958
|
-
costDetails?: UsageCostBreakdown
|
|
959
|
-
}
|
|
1006
|
+
export type UsageTotals = TokenUsage
|
|
960
1007
|
|
|
961
1008
|
/**
|
|
962
1009
|
* Emitted when a run completes successfully.
|
|
@@ -969,8 +1016,8 @@ export interface RunFinishedEvent extends AGUIRunFinishedEvent {
|
|
|
969
1016
|
model?: string
|
|
970
1017
|
/** Why the generation stopped */
|
|
971
1018
|
finishReason?: 'stop' | 'length' | 'content_filter' | 'tool_calls' | null
|
|
972
|
-
/** Token usage statistics
|
|
973
|
-
usage?:
|
|
1019
|
+
/** Token usage statistics with optional detailed breakdowns and provider-reported cost. */
|
|
1020
|
+
usage?: TokenUsage
|
|
974
1021
|
}
|
|
975
1022
|
|
|
976
1023
|
/**
|
|
@@ -1084,7 +1131,9 @@ export interface ToolCallEndEvent extends AGUIToolCallEndEvent {
|
|
|
1084
1131
|
/** Final parsed input arguments (TanStack AI internal) */
|
|
1085
1132
|
input?: unknown
|
|
1086
1133
|
/** Tool execution result (TanStack AI internal) */
|
|
1087
|
-
result?: string
|
|
1134
|
+
result?: string | Array<ContentPart>
|
|
1135
|
+
/** Tool execution output state (TanStack AI internal) */
|
|
1136
|
+
state?: ToolOutputState
|
|
1088
1137
|
}
|
|
1089
1138
|
|
|
1090
1139
|
/**
|
|
@@ -1096,6 +1145,8 @@ export interface ToolCallEndEvent extends AGUIToolCallEndEvent {
|
|
|
1096
1145
|
export interface ToolCallResultEvent extends AGUIToolCallResultEvent {
|
|
1097
1146
|
/** Model identifier for multi-model support */
|
|
1098
1147
|
model?: string
|
|
1148
|
+
/** Tool execution output state (TanStack AI internal) */
|
|
1149
|
+
state?: ToolOutputState
|
|
1099
1150
|
}
|
|
1100
1151
|
|
|
1101
1152
|
/**
|
|
@@ -1416,11 +1467,7 @@ export interface TextCompletionChunk {
|
|
|
1416
1467
|
content: string
|
|
1417
1468
|
role?: 'assistant'
|
|
1418
1469
|
finishReason?: 'stop' | 'length' | 'content_filter' | null
|
|
1419
|
-
usage?:
|
|
1420
|
-
promptTokens: number
|
|
1421
|
-
completionTokens: number
|
|
1422
|
-
totalTokens: number
|
|
1423
|
-
}
|
|
1470
|
+
usage?: TokenUsage
|
|
1424
1471
|
}
|
|
1425
1472
|
|
|
1426
1473
|
export interface SummarizationOptions<
|
|
@@ -1444,11 +1491,7 @@ export interface SummarizationResult {
|
|
|
1444
1491
|
id: string
|
|
1445
1492
|
model: string
|
|
1446
1493
|
summary: string
|
|
1447
|
-
usage:
|
|
1448
|
-
promptTokens: number
|
|
1449
|
-
completionTokens: number
|
|
1450
|
-
totalTokens: number
|
|
1451
|
-
}
|
|
1494
|
+
usage: TokenUsage
|
|
1452
1495
|
}
|
|
1453
1496
|
|
|
1454
1497
|
// ============================================================================
|
|
@@ -1517,11 +1560,7 @@ export interface ImageGenerationResult {
|
|
|
1517
1560
|
/** Array of generated images */
|
|
1518
1561
|
images: Array<GeneratedImage>
|
|
1519
1562
|
/** Token usage information (if available) */
|
|
1520
|
-
usage?:
|
|
1521
|
-
inputTokens?: number
|
|
1522
|
-
outputTokens?: number
|
|
1523
|
-
totalTokens?: number
|
|
1524
|
-
}
|
|
1563
|
+
usage?: TokenUsage
|
|
1525
1564
|
}
|
|
1526
1565
|
|
|
1527
1566
|
// ============================================================================
|
|
@@ -1572,11 +1611,7 @@ export interface AudioGenerationResult {
|
|
|
1572
1611
|
/** The generated audio */
|
|
1573
1612
|
audio: GeneratedAudio
|
|
1574
1613
|
/** Token usage information (if available) */
|
|
1575
|
-
usage?:
|
|
1576
|
-
inputTokens?: number
|
|
1577
|
-
outputTokens?: number
|
|
1578
|
-
totalTokens?: number
|
|
1579
|
-
}
|
|
1614
|
+
usage?: TokenUsage
|
|
1580
1615
|
}
|
|
1581
1616
|
|
|
1582
1617
|
// ============================================================================
|
|
@@ -1697,6 +1732,8 @@ export interface TTSResult {
|
|
|
1697
1732
|
duration?: number
|
|
1698
1733
|
/** Content type of the audio (e.g., 'audio/mp3') */
|
|
1699
1734
|
contentType?: string
|
|
1735
|
+
/** Token usage information (if provided by the adapter) */
|
|
1736
|
+
usage?: TokenUsage
|
|
1700
1737
|
}
|
|
1701
1738
|
|
|
1702
1739
|
// ============================================================================
|
|
@@ -1778,6 +1815,8 @@ export interface TranscriptionResult {
|
|
|
1778
1815
|
segments?: Array<TranscriptionSegment>
|
|
1779
1816
|
/** Word-level timestamps, if available */
|
|
1780
1817
|
words?: Array<TranscriptionWord>
|
|
1818
|
+
/** Token usage information (if provided by the adapter) */
|
|
1819
|
+
usage?: TokenUsage
|
|
1781
1820
|
}
|
|
1782
1821
|
|
|
1783
1822
|
/**
|
|
@@ -103,7 +103,10 @@ export function uiMessagesToWire(
|
|
|
103
103
|
role: 'tool',
|
|
104
104
|
id: deriveToolMessageId(part.toolCallId),
|
|
105
105
|
toolCallId: part.toolCallId,
|
|
106
|
-
content:
|
|
106
|
+
content:
|
|
107
|
+
typeof part.content === 'string'
|
|
108
|
+
? part.content
|
|
109
|
+
: JSON.stringify(part.content),
|
|
107
110
|
...(part.error !== undefined && { error: part.error }),
|
|
108
111
|
})
|
|
109
112
|
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { AGUIError, RunAgentInputSchema } from '@ag-ui/core'
|
|
2
2
|
import type { Context as AGUIContext } from '@ag-ui/core'
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
JSONSchema,
|
|
5
|
+
ModelMessage,
|
|
6
|
+
SchemaInput,
|
|
7
|
+
Tool,
|
|
8
|
+
UIMessage,
|
|
9
|
+
} from '../types'
|
|
4
10
|
|
|
5
11
|
const KNOWN_PART_TYPES = new Set([
|
|
6
12
|
'text',
|
|
@@ -43,7 +49,12 @@ export function chatParamsFromRequestBody(body: unknown): Promise<{
|
|
|
43
49
|
tools: Array<{ name: string; description: string; parameters: JSONSchema }>
|
|
44
50
|
forwardedProps: Record<string, unknown>
|
|
45
51
|
state: unknown
|
|
52
|
+
/**
|
|
53
|
+
* @deprecated Use `aguiContext` instead. This alias will be removed in a
|
|
54
|
+
* future release.
|
|
55
|
+
*/
|
|
46
56
|
context: Array<AGUIContext>
|
|
57
|
+
aguiContext: Array<AGUIContext>
|
|
47
58
|
}> {
|
|
48
59
|
const parseResult = RunAgentInputSchema.safeParse(body)
|
|
49
60
|
if (!parseResult.success) {
|
|
@@ -58,6 +69,7 @@ export function chatParamsFromRequestBody(body: unknown): Promise<{
|
|
|
58
69
|
}
|
|
59
70
|
|
|
60
71
|
const parsed = parseResult.data
|
|
72
|
+
const aguiContext = parsed.context
|
|
61
73
|
|
|
62
74
|
// AG-UI Zod uses `.strip()` so extra fields like `parts` on messages are
|
|
63
75
|
// dropped during parse. We re-attach them from the original body so the
|
|
@@ -89,7 +101,8 @@ export function chatParamsFromRequestBody(body: unknown): Promise<{
|
|
|
89
101
|
}>,
|
|
90
102
|
forwardedProps: (parsed.forwardedProps ?? {}) as Record<string, unknown>,
|
|
91
103
|
state: parsed.state,
|
|
92
|
-
context:
|
|
104
|
+
context: aguiContext,
|
|
105
|
+
aguiContext,
|
|
93
106
|
})
|
|
94
107
|
}
|
|
95
108
|
|
|
@@ -171,16 +184,18 @@ export async function chatParamsFromRequest(
|
|
|
171
184
|
* `chatParamsFromRequest(...)` / `chatParamsFromRequestBody(...)`.
|
|
172
185
|
* @returns A merged array suitable for `chat({ tools })`.
|
|
173
186
|
*/
|
|
174
|
-
export function mergeAgentTools(
|
|
175
|
-
serverTools: ReadonlyArray<Tool
|
|
187
|
+
export function mergeAgentTools<TContext = unknown>(
|
|
188
|
+
serverTools: ReadonlyArray<Tool<SchemaInput, SchemaInput, string, TContext>>,
|
|
176
189
|
clientTools: ReadonlyArray<{
|
|
177
190
|
name: string
|
|
178
191
|
description: string
|
|
179
192
|
parameters: JSONSchema
|
|
180
193
|
}>,
|
|
181
|
-
): Array<Tool
|
|
194
|
+
): Array<Tool<SchemaInput, SchemaInput, string, TContext>> {
|
|
182
195
|
const seen = new Set(serverTools.map((t) => t.name))
|
|
183
|
-
const merged: Array<Tool
|
|
196
|
+
const merged: Array<Tool<SchemaInput, SchemaInput, string, TContext>> = [
|
|
197
|
+
...serverTools,
|
|
198
|
+
]
|
|
184
199
|
for (const ct of clientTools) {
|
|
185
200
|
if (seen.has(ct.name)) {
|
|
186
201
|
// Server wins on name collision.
|
|
@@ -193,7 +208,7 @@ export function mergeAgentTools(
|
|
|
193
208
|
inputSchema: ct.parameters,
|
|
194
209
|
// No `execute` — runtime treats this as a client-side tool and
|
|
195
210
|
// emits ClientToolRequest events.
|
|
196
|
-
} as Tool)
|
|
211
|
+
} as Tool<SchemaInput, SchemaInput, string, TContext>)
|
|
197
212
|
}
|
|
198
213
|
return merged
|
|
199
214
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ContentPart } from '../types'
|
|
2
|
+
|
|
3
|
+
const CONTENT_PART_TYPES = new Set([
|
|
4
|
+
'text',
|
|
5
|
+
'image',
|
|
6
|
+
'audio',
|
|
7
|
+
'video',
|
|
8
|
+
'document',
|
|
9
|
+
])
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Structural check for a single `ContentPart`. A text part must carry a string
|
|
13
|
+
* `content`; every other modality must carry a `source` with `type` of
|
|
14
|
+
* `'url' | 'data'` and a string `value`.
|
|
15
|
+
*/
|
|
16
|
+
export function isContentPart(value: unknown): value is ContentPart {
|
|
17
|
+
if (typeof value !== 'object' || value === null) return false
|
|
18
|
+
const part = value as Record<string, unknown>
|
|
19
|
+
if (typeof part.type !== 'string' || !CONTENT_PART_TYPES.has(part.type)) {
|
|
20
|
+
return false
|
|
21
|
+
}
|
|
22
|
+
if (part.type === 'text') {
|
|
23
|
+
return typeof part.content === 'string'
|
|
24
|
+
}
|
|
25
|
+
const source = part.source
|
|
26
|
+
if (typeof source !== 'object' || source === null) return false
|
|
27
|
+
const src = source as Record<string, unknown>
|
|
28
|
+
if (typeof src.value !== 'string') return false
|
|
29
|
+
// `data` sources require a mimeType (matches ContentPartDataSource); `url`
|
|
30
|
+
// sources don't. Requiring it here keeps the runtime guard consistent with
|
|
31
|
+
// the type and avoids emitting `data:undefined;base64,...` downstream.
|
|
32
|
+
if (src.type === 'data') return typeof src.mimeType === 'string'
|
|
33
|
+
return src.type === 'url'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* True iff `value` is a NON-EMPTY array whose every element is a valid
|
|
38
|
+
* `ContentPart`. Empty arrays and mixed arrays return false so they continue
|
|
39
|
+
* to be treated as ordinary (stringified) data — this keeps the auto-detection
|
|
40
|
+
* footgun narrow.
|
|
41
|
+
*/
|
|
42
|
+
export function isContentPartArray(
|
|
43
|
+
value: unknown,
|
|
44
|
+
): value is Array<ContentPart> {
|
|
45
|
+
return Array.isArray(value) && value.length > 0 && value.every(isContentPart)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Normalize a tool's return value for transport:
|
|
50
|
+
* - string → unchanged
|
|
51
|
+
* - ContentPart array → unchanged (multimodal, passed through to the adapter)
|
|
52
|
+
* - anything else → `JSON.stringify`
|
|
53
|
+
*/
|
|
54
|
+
export function normalizeToolResult(
|
|
55
|
+
result: unknown,
|
|
56
|
+
): string | Array<ContentPart> {
|
|
57
|
+
if (typeof result === 'string') return result
|
|
58
|
+
if (isContentPartArray(result)) return result
|
|
59
|
+
return JSON.stringify(result)
|
|
60
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ProviderUsageDetails, TokenUsage } from '../types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Input parameters for building base TokenUsage.
|
|
5
|
+
* Provider functions should extract these from their SDK's response.
|
|
6
|
+
*/
|
|
7
|
+
export interface BaseUsageInput {
|
|
8
|
+
/** Total input/prompt tokens */
|
|
9
|
+
promptTokens: number
|
|
10
|
+
/** Total output/completion tokens */
|
|
11
|
+
completionTokens: number
|
|
12
|
+
/** Total tokens (prompt + completion) */
|
|
13
|
+
totalTokens: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Builds the base TokenUsage object with core fields.
|
|
18
|
+
* Provider-specific functions should use this and then add their own details.
|
|
19
|
+
*
|
|
20
|
+
* @param input - The base token counts
|
|
21
|
+
* @returns A TokenUsage object with promptTokens, completionTokens, totalTokens
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const base = buildBaseUsage({
|
|
26
|
+
* promptTokens: 100,
|
|
27
|
+
* completionTokens: 50,
|
|
28
|
+
* totalTokens: 150
|
|
29
|
+
* });
|
|
30
|
+
* // Returns: { promptTokens: 100, completionTokens: 50, totalTokens: 150 }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function buildBaseUsage<TProviderDetails = ProviderUsageDetails>(
|
|
34
|
+
input: BaseUsageInput,
|
|
35
|
+
): TokenUsage<TProviderDetails> {
|
|
36
|
+
return {
|
|
37
|
+
promptTokens: input.promptTokens,
|
|
38
|
+
completionTokens: input.completionTokens,
|
|
39
|
+
totalTokens: input.totalTokens,
|
|
40
|
+
}
|
|
41
|
+
}
|