@providerprotocol/ai 0.0.10 → 0.0.11
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/index.d.ts +7 -1
- package/dist/index.js +34 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/llm.ts +34 -8
- package/src/types/stream.ts +42 -0
package/dist/index.d.ts
CHANGED
|
@@ -375,7 +375,7 @@ declare function aggregateUsage(usages: TokenUsage[]): TokenUsage;
|
|
|
375
375
|
/**
|
|
376
376
|
* Stream event types
|
|
377
377
|
*/
|
|
378
|
-
type StreamEventType = 'text_delta' | 'reasoning_delta' | 'image_delta' | 'audio_delta' | 'video_delta' | 'tool_call_delta' | 'message_start' | 'message_stop' | 'content_block_start' | 'content_block_stop';
|
|
378
|
+
type StreamEventType = 'text_delta' | 'reasoning_delta' | 'image_delta' | 'audio_delta' | 'video_delta' | 'tool_call_delta' | 'tool_execution_start' | 'tool_execution_end' | 'message_start' | 'message_stop' | 'content_block_start' | 'content_block_stop';
|
|
379
379
|
/**
|
|
380
380
|
* Event delta data (type-specific)
|
|
381
381
|
*/
|
|
@@ -385,6 +385,12 @@ interface EventDelta {
|
|
|
385
385
|
toolCallId?: string;
|
|
386
386
|
toolName?: string;
|
|
387
387
|
argumentsJson?: string;
|
|
388
|
+
/** Tool execution result (for tool_execution_end) */
|
|
389
|
+
result?: unknown;
|
|
390
|
+
/** Whether tool execution errored (for tool_execution_end) */
|
|
391
|
+
isError?: boolean;
|
|
392
|
+
/** Timestamp in ms (for tool_execution_start/end) */
|
|
393
|
+
timestamp?: number;
|
|
388
394
|
}
|
|
389
395
|
/**
|
|
390
396
|
* A streaming event
|
package/dist/index.js
CHANGED
|
@@ -123,6 +123,20 @@ function contentBlockStop(index) {
|
|
|
123
123
|
delta: {}
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
|
+
function toolExecutionStart(toolCallId, toolName, timestamp, index = 0) {
|
|
127
|
+
return {
|
|
128
|
+
type: "tool_execution_start",
|
|
129
|
+
index,
|
|
130
|
+
delta: { toolCallId, toolName, timestamp }
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function toolExecutionEnd(toolCallId, toolName, result, isError, timestamp, index = 0) {
|
|
134
|
+
return {
|
|
135
|
+
type: "tool_execution_end",
|
|
136
|
+
index,
|
|
137
|
+
delta: { toolCallId, toolName, result, isError, timestamp }
|
|
138
|
+
};
|
|
139
|
+
}
|
|
126
140
|
|
|
127
141
|
// src/core/llm.ts
|
|
128
142
|
var DEFAULT_MAX_ITERATIONS = 10;
|
|
@@ -362,12 +376,17 @@ function executeStream(model, config, system, params, tools, toolStrategy, struc
|
|
|
362
376
|
"llm"
|
|
363
377
|
);
|
|
364
378
|
}
|
|
379
|
+
const toolEvents = [];
|
|
365
380
|
const results = await executeTools(
|
|
366
381
|
response.message,
|
|
367
382
|
tools,
|
|
368
383
|
toolStrategy,
|
|
369
|
-
toolExecutions
|
|
384
|
+
toolExecutions,
|
|
385
|
+
(event) => toolEvents.push(event)
|
|
370
386
|
);
|
|
387
|
+
for (const event of toolEvents) {
|
|
388
|
+
yield event;
|
|
389
|
+
}
|
|
371
390
|
allMessages.push(new ToolResultMessage(results));
|
|
372
391
|
continue;
|
|
373
392
|
}
|
|
@@ -396,11 +415,11 @@ function executeStream(model, config, system, params, tools, toolStrategy, struc
|
|
|
396
415
|
})();
|
|
397
416
|
return createStreamResult(generateStream(), turnPromise, abortController);
|
|
398
417
|
}
|
|
399
|
-
async function executeTools(message, tools, toolStrategy, executions) {
|
|
418
|
+
async function executeTools(message, tools, toolStrategy, executions, onEvent) {
|
|
400
419
|
const toolCalls = message.toolCalls ?? [];
|
|
401
420
|
const results = [];
|
|
402
421
|
const toolMap = new Map(tools.map((t) => [t.name, t]));
|
|
403
|
-
const promises = toolCalls.map(async (call) => {
|
|
422
|
+
const promises = toolCalls.map(async (call, index) => {
|
|
404
423
|
const tool = toolMap.get(call.toolName);
|
|
405
424
|
if (!tool) {
|
|
406
425
|
return {
|
|
@@ -410,10 +429,13 @@ async function executeTools(message, tools, toolStrategy, executions) {
|
|
|
410
429
|
};
|
|
411
430
|
}
|
|
412
431
|
const startTime = Date.now();
|
|
432
|
+
onEvent?.(toolExecutionStart(call.toolCallId, tool.name, startTime, index));
|
|
413
433
|
await toolStrategy?.onToolCall?.(tool, call.arguments);
|
|
414
434
|
if (toolStrategy?.onBeforeCall) {
|
|
415
435
|
const shouldRun = await toolStrategy.onBeforeCall(tool, call.arguments);
|
|
416
436
|
if (!shouldRun) {
|
|
437
|
+
const endTime = Date.now();
|
|
438
|
+
onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, "Tool execution skipped", true, endTime, index));
|
|
417
439
|
return {
|
|
418
440
|
toolCallId: call.toolCallId,
|
|
419
441
|
result: "Tool execution skipped",
|
|
@@ -430,16 +452,18 @@ async function executeTools(message, tools, toolStrategy, executions) {
|
|
|
430
452
|
}
|
|
431
453
|
}
|
|
432
454
|
if (!approved) {
|
|
455
|
+
const endTime = Date.now();
|
|
433
456
|
const execution = {
|
|
434
457
|
toolName: tool.name,
|
|
435
458
|
toolCallId: call.toolCallId,
|
|
436
459
|
arguments: call.arguments,
|
|
437
460
|
result: "Tool execution denied",
|
|
438
461
|
isError: true,
|
|
439
|
-
duration:
|
|
462
|
+
duration: endTime - startTime,
|
|
440
463
|
approved: false
|
|
441
464
|
};
|
|
442
465
|
executions.push(execution);
|
|
466
|
+
onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, "Tool execution denied by approval handler", true, endTime, index));
|
|
443
467
|
return {
|
|
444
468
|
toolCallId: call.toolCallId,
|
|
445
469
|
result: "Tool execution denied by approval handler",
|
|
@@ -448,6 +472,7 @@ async function executeTools(message, tools, toolStrategy, executions) {
|
|
|
448
472
|
}
|
|
449
473
|
try {
|
|
450
474
|
const result = await tool.run(call.arguments);
|
|
475
|
+
const endTime = Date.now();
|
|
451
476
|
await toolStrategy?.onAfterCall?.(tool, call.arguments, result);
|
|
452
477
|
const execution = {
|
|
453
478
|
toolName: tool.name,
|
|
@@ -455,16 +480,18 @@ async function executeTools(message, tools, toolStrategy, executions) {
|
|
|
455
480
|
arguments: call.arguments,
|
|
456
481
|
result,
|
|
457
482
|
isError: false,
|
|
458
|
-
duration:
|
|
483
|
+
duration: endTime - startTime,
|
|
459
484
|
approved
|
|
460
485
|
};
|
|
461
486
|
executions.push(execution);
|
|
487
|
+
onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, result, false, endTime, index));
|
|
462
488
|
return {
|
|
463
489
|
toolCallId: call.toolCallId,
|
|
464
490
|
result,
|
|
465
491
|
isError: false
|
|
466
492
|
};
|
|
467
493
|
} catch (error) {
|
|
494
|
+
const endTime = Date.now();
|
|
468
495
|
await toolStrategy?.onError?.(tool, call.arguments, error);
|
|
469
496
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
470
497
|
const execution = {
|
|
@@ -473,10 +500,11 @@ async function executeTools(message, tools, toolStrategy, executions) {
|
|
|
473
500
|
arguments: call.arguments,
|
|
474
501
|
result: errorMessage,
|
|
475
502
|
isError: true,
|
|
476
|
-
duration:
|
|
503
|
+
duration: endTime - startTime,
|
|
477
504
|
approved
|
|
478
505
|
};
|
|
479
506
|
executions.push(execution);
|
|
507
|
+
onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, errorMessage, true, endTime, index));
|
|
480
508
|
return {
|
|
481
509
|
toolCallId: call.toolCallId,
|
|
482
510
|
result: errorMessage,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types/turn.ts","../src/types/stream.ts","../src/core/llm.ts","../src/core/image.ts","../src/types/content.ts","../src/types/thread.ts","../src/index.ts"],"sourcesContent":["import type { Message, AssistantMessage } from './messages.ts';\nimport type { ToolExecution } from './tool.ts';\n\n/**\n * Token usage information\n */\nexport interface TokenUsage {\n /** Input tokens across all cycles */\n inputTokens: number;\n\n /** Output tokens across all cycles */\n outputTokens: number;\n\n /** Total tokens */\n totalTokens: number;\n\n /** Per-cycle breakdown (if available) */\n cycles?: Array<{\n inputTokens: number;\n outputTokens: number;\n }>;\n}\n\n/**\n * A Turn represents the complete result of one inference call,\n * including all messages produced during tool execution loops.\n */\nexport interface Turn<TData = unknown> {\n /**\n * All messages produced during this inference, in chronological order.\n * Types: UserMessage, AssistantMessage (may include toolCalls), ToolResultMessage\n */\n readonly messages: Message[];\n\n /** The final assistant response (convenience accessor) */\n readonly response: AssistantMessage;\n\n /** Tool executions that occurred during this turn */\n readonly toolExecutions: ToolExecution[];\n\n /** Aggregate token usage for the entire turn */\n readonly usage: TokenUsage;\n\n /** Total number of inference cycles (1 + number of tool rounds) */\n readonly cycles: number;\n\n /**\n * Structured output data (if structure was provided).\n * Type is inferred from the schema when using TypeScript.\n */\n readonly data?: TData;\n}\n\n/**\n * Create a Turn from accumulated data\n */\nexport function createTurn<TData = unknown>(\n messages: Message[],\n toolExecutions: ToolExecution[],\n usage: TokenUsage,\n cycles: number,\n data?: TData\n): Turn<TData> {\n // Find the last assistant message as the response\n const response = messages\n .filter((m): m is AssistantMessage => m.type === 'assistant')\n .pop();\n\n if (!response) {\n throw new Error('Turn must contain at least one assistant message');\n }\n\n return {\n messages,\n response,\n toolExecutions,\n usage,\n cycles,\n data,\n };\n}\n\n/**\n * Create empty token usage\n */\nexport function emptyUsage(): TokenUsage {\n return {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n cycles: [],\n };\n}\n\n/**\n * Aggregate token usage from multiple cycles\n */\nexport function aggregateUsage(usages: TokenUsage[]): TokenUsage {\n const cycles: TokenUsage['cycles'] = [];\n let inputTokens = 0;\n let outputTokens = 0;\n\n for (const usage of usages) {\n inputTokens += usage.inputTokens;\n outputTokens += usage.outputTokens;\n cycles.push({\n inputTokens: usage.inputTokens,\n outputTokens: usage.outputTokens,\n });\n }\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n cycles,\n };\n}\n","import type { Turn } from './turn.ts';\n\n/**\n * Stream event types\n */\nexport type StreamEventType =\n | 'text_delta'\n | 'reasoning_delta'\n | 'image_delta'\n | 'audio_delta'\n | 'video_delta'\n | 'tool_call_delta'\n | 'message_start'\n | 'message_stop'\n | 'content_block_start'\n | 'content_block_stop';\n\n/**\n * Event delta data (type-specific)\n */\nexport interface EventDelta {\n text?: string;\n data?: Uint8Array;\n toolCallId?: string;\n toolName?: string;\n argumentsJson?: string;\n}\n\n/**\n * A streaming event\n */\nexport interface StreamEvent {\n /** Event type */\n type: StreamEventType;\n\n /** Index of the content block this event belongs to */\n index: number;\n\n /** Event data (type-specific) */\n delta: EventDelta;\n}\n\n/**\n * Stream result - async iterable that also provides final turn\n */\nexport interface StreamResult<TData = unknown>\n extends AsyncIterable<StreamEvent> {\n /**\n * Get the complete Turn after streaming finishes.\n * Resolves when the stream completes.\n */\n readonly turn: Promise<Turn<TData>>;\n\n /** Abort the stream */\n abort(): void;\n}\n\n/**\n * Create a stream result from an async generator and completion promise\n */\nexport function createStreamResult<TData = unknown>(\n generator: AsyncGenerator<StreamEvent, void, unknown>,\n turnPromise: Promise<Turn<TData>>,\n abortController: AbortController\n): StreamResult<TData> {\n return {\n [Symbol.asyncIterator]() {\n return generator;\n },\n turn: turnPromise,\n abort() {\n abortController.abort();\n },\n };\n}\n\n/**\n * Create a text delta event\n */\nexport function textDelta(text: string, index = 0): StreamEvent {\n return {\n type: 'text_delta',\n index,\n delta: { text },\n };\n}\n\n/**\n * Create a tool call delta event\n */\nexport function toolCallDelta(\n toolCallId: string,\n toolName: string,\n argumentsJson: string,\n index = 0\n): StreamEvent {\n return {\n type: 'tool_call_delta',\n index,\n delta: { toolCallId, toolName, argumentsJson },\n };\n}\n\n/**\n * Create a message start event\n */\nexport function messageStart(): StreamEvent {\n return {\n type: 'message_start',\n index: 0,\n delta: {},\n };\n}\n\n/**\n * Create a message stop event\n */\nexport function messageStop(): StreamEvent {\n return {\n type: 'message_stop',\n index: 0,\n delta: {},\n };\n}\n\n/**\n * Create a content block start event\n */\nexport function contentBlockStart(index: number): StreamEvent {\n return {\n type: 'content_block_start',\n index,\n delta: {},\n };\n}\n\n/**\n * Create a content block stop event\n */\nexport function contentBlockStop(index: number): StreamEvent {\n return {\n type: 'content_block_stop',\n index,\n delta: {},\n };\n}\n","import type {\n LLMOptions,\n LLMInstance,\n LLMRequest,\n LLMResponse,\n InferenceInput,\n BoundLLMModel,\n LLMCapabilities,\n} from '../types/llm.ts';\nimport type { UserMessage, AssistantMessage } from '../types/messages.ts';\nimport type { ContentBlock, TextBlock } from '../types/content.ts';\nimport type { Tool, ToolExecution, ToolResult } from '../types/tool.ts';\nimport type { Turn, TokenUsage } from '../types/turn.ts';\nimport type { StreamResult, StreamEvent } from '../types/stream.ts';\nimport type { Thread } from '../types/thread.ts';\nimport type { ProviderConfig } from '../types/provider.ts';\nimport { UPPError } from '../types/errors.ts';\nimport {\n Message,\n UserMessage as UserMessageClass,\n ToolResultMessage,\n isUserMessage,\n isAssistantMessage,\n} from '../types/messages.ts';\nimport { createTurn, aggregateUsage, emptyUsage } from '../types/turn.ts';\nimport { createStreamResult } from '../types/stream.ts';\nimport { generateShortId } from '../utils/id.ts';\n\n/**\n * Default maximum iterations for tool execution\n */\nconst DEFAULT_MAX_ITERATIONS = 10;\n\n/**\n * Create an LLM instance\n */\nexport function llm<TParams = unknown>(\n options: LLMOptions<TParams>\n): LLMInstance<TParams> {\n const { model: modelRef, config = {}, params, system, tools, toolStrategy, structure } = options;\n\n // Validate that the provider supports LLM\n const provider = modelRef.provider;\n if (!provider.modalities.llm) {\n throw new UPPError(\n `Provider '${provider.name}' does not support LLM modality`,\n 'INVALID_REQUEST',\n provider.name,\n 'llm'\n );\n }\n\n // Bind the model\n const boundModel = provider.modalities.llm.bind(modelRef.modelId) as BoundLLMModel<TParams>;\n\n // Validate capabilities at bind time\n const capabilities = boundModel.capabilities;\n\n // Check for structured output capability\n if (structure && !capabilities.structuredOutput) {\n throw new UPPError(\n `Provider '${provider.name}' does not support structured output`,\n 'INVALID_REQUEST',\n provider.name,\n 'llm'\n );\n }\n\n // Check for tools capability\n if (tools && tools.length > 0 && !capabilities.tools) {\n throw new UPPError(\n `Provider '${provider.name}' does not support tools`,\n 'INVALID_REQUEST',\n provider.name,\n 'llm'\n );\n }\n\n // Build the instance\n const instance: LLMInstance<TParams> = {\n model: boundModel,\n system,\n params,\n capabilities,\n\n async generate(\n historyOrInput: Message[] | Thread | InferenceInput,\n ...inputs: InferenceInput[]\n ): Promise<Turn> {\n const { history, messages } = parseInputs(historyOrInput, inputs);\n return executeGenerate(\n boundModel,\n config,\n system,\n params,\n tools,\n toolStrategy,\n structure,\n history,\n messages\n );\n },\n\n stream(\n historyOrInput: Message[] | Thread | InferenceInput,\n ...inputs: InferenceInput[]\n ): StreamResult {\n // Check streaming capability\n if (!capabilities.streaming) {\n throw new UPPError(\n `Provider '${provider.name}' does not support streaming`,\n 'INVALID_REQUEST',\n provider.name,\n 'llm'\n );\n }\n const { history, messages } = parseInputs(historyOrInput, inputs);\n return executeStream(\n boundModel,\n config,\n system,\n params,\n tools,\n toolStrategy,\n structure,\n history,\n messages\n );\n },\n };\n\n return instance;\n}\n\n/**\n * Type guard to check if a value is a Message instance.\n * Uses instanceof for class instances, with fallback to timestamp check\n * for deserialized/reconstructed Message objects.\n */\nfunction isMessageInstance(value: unknown): value is Message {\n if (value instanceof Message) {\n return true;\n }\n // Fallback for deserialized Messages that aren't class instances:\n // Messages have 'timestamp' (Date), ContentBlocks don't\n if (\n typeof value === 'object' &&\n value !== null &&\n 'timestamp' in value &&\n 'type' in value &&\n 'id' in value\n ) {\n const obj = value as Record<string, unknown>;\n // Message types are 'user', 'assistant', 'tool_result'\n // ContentBlock types are 'text', 'image', 'audio', 'video', 'binary'\n const messageTypes = ['user', 'assistant', 'tool_result'];\n return messageTypes.includes(obj.type as string);\n }\n return false;\n}\n\n/**\n * Parse inputs to determine history and new messages\n */\nfunction parseInputs(\n historyOrInput: Message[] | Thread | InferenceInput,\n inputs: InferenceInput[]\n): { history: Message[]; messages: Message[] } {\n // Check if it's a Thread first (has 'messages' array property)\n if (\n typeof historyOrInput === 'object' &&\n historyOrInput !== null &&\n 'messages' in historyOrInput &&\n Array.isArray((historyOrInput as Thread).messages)\n ) {\n const thread = historyOrInput as Thread;\n const newMessages = inputs.map(inputToMessage);\n return { history: [...thread.messages], messages: newMessages };\n }\n\n // Check if first arg is Message[] (history)\n if (Array.isArray(historyOrInput)) {\n // Empty array is empty history\n if (historyOrInput.length === 0) {\n const newMessages = inputs.map(inputToMessage);\n return { history: [], messages: newMessages };\n }\n const first = historyOrInput[0];\n if (isMessageInstance(first)) {\n // It's history (Message[])\n const newMessages = inputs.map(inputToMessage);\n return { history: historyOrInput as Message[], messages: newMessages };\n }\n }\n\n // It's input (no history) - could be string, single Message, or ContentBlock\n const allInputs = [historyOrInput as InferenceInput, ...inputs];\n const newMessages = allInputs.map(inputToMessage);\n return { history: [], messages: newMessages };\n}\n\n/**\n * Convert an InferenceInput to a Message\n */\nfunction inputToMessage(input: InferenceInput): Message {\n if (typeof input === 'string') {\n return new UserMessageClass(input);\n }\n\n // It's already a Message\n if ('type' in input && 'id' in input && 'timestamp' in input) {\n return input as Message;\n }\n\n // It's a ContentBlock - wrap in UserMessage\n const block = input as ContentBlock;\n if (block.type === 'text') {\n return new UserMessageClass((block as TextBlock).text);\n }\n\n return new UserMessageClass([block as any]);\n}\n\n/**\n * Execute a non-streaming generate call with tool loop\n */\nasync function executeGenerate<TParams>(\n model: BoundLLMModel<TParams>,\n config: ProviderConfig,\n system: string | undefined,\n params: TParams | undefined,\n tools: Tool[] | undefined,\n toolStrategy: LLMOptions<TParams>['toolStrategy'],\n structure: LLMOptions<TParams>['structure'],\n history: Message[],\n newMessages: Message[]\n): Promise<Turn> {\n // Validate media capabilities for all input messages\n validateMediaCapabilities(\n [...history, ...newMessages],\n model.capabilities,\n model.provider.name\n );\n const maxIterations = toolStrategy?.maxIterations ?? DEFAULT_MAX_ITERATIONS;\n const allMessages: Message[] = [...history, ...newMessages];\n const toolExecutions: ToolExecution[] = [];\n const usages: TokenUsage[] = [];\n let cycles = 0;\n\n // Track structured data from responses (providers handle extraction)\n let structuredData: unknown;\n\n // Tool loop\n while (cycles < maxIterations + 1) {\n cycles++;\n\n const request: LLMRequest<TParams> = {\n messages: allMessages,\n system,\n params,\n tools,\n structure,\n config,\n };\n\n const response = await model.complete(request);\n usages.push(response.usage);\n allMessages.push(response.message);\n\n // Track structured data from provider (if present)\n if (response.data !== undefined) {\n structuredData = response.data;\n }\n\n // Check for tool calls\n if (response.message.hasToolCalls && tools && tools.length > 0) {\n // If provider already extracted structured data, don't try to execute tool calls\n // (some providers use tool calls internally for structured output)\n if (response.data !== undefined) {\n break;\n }\n\n // Check if we've hit max iterations (subtract 1 because we already incremented)\n if (cycles >= maxIterations) {\n await toolStrategy?.onMaxIterations?.(maxIterations);\n throw new UPPError(\n `Tool execution exceeded maximum iterations (${maxIterations})`,\n 'INVALID_REQUEST',\n model.provider.name,\n 'llm'\n );\n }\n\n // Execute tools\n const results = await executeTools(\n response.message,\n tools,\n toolStrategy,\n toolExecutions\n );\n\n // Add tool results\n allMessages.push(new ToolResultMessage(results));\n\n continue;\n }\n\n // No tool calls - we're done\n break;\n }\n\n // Use structured data from provider if structure was requested\n const data = structure ? structuredData : undefined;\n\n return createTurn(\n allMessages.slice(history.length), // Only messages from this turn\n toolExecutions,\n aggregateUsage(usages),\n cycles,\n data\n );\n}\n\n/**\n * Execute a streaming generate call with tool loop\n */\nfunction executeStream<TParams>(\n model: BoundLLMModel<TParams>,\n config: ProviderConfig,\n system: string | undefined,\n params: TParams | undefined,\n tools: Tool[] | undefined,\n toolStrategy: LLMOptions<TParams>['toolStrategy'],\n structure: LLMOptions<TParams>['structure'],\n history: Message[],\n newMessages: Message[]\n): StreamResult {\n // Validate media capabilities for all input messages\n validateMediaCapabilities(\n [...history, ...newMessages],\n model.capabilities,\n model.provider.name\n );\n\n const abortController = new AbortController();\n\n // Shared state between generator and turn promise\n const allMessages: Message[] = [...history, ...newMessages];\n const toolExecutions: ToolExecution[] = [];\n const usages: TokenUsage[] = [];\n let cycles = 0;\n let generatorError: Error | null = null;\n let structuredData: unknown; // Providers extract this\n\n // Deferred to signal when generator completes\n let resolveGenerator: () => void;\n let rejectGenerator: (error: Error) => void;\n const generatorDone = new Promise<void>((resolve, reject) => {\n resolveGenerator = resolve;\n rejectGenerator = reject;\n });\n\n const maxIterations = toolStrategy?.maxIterations ?? DEFAULT_MAX_ITERATIONS;\n\n // Create the async generator - this is the ONLY place that calls the API\n async function* generateStream(): AsyncGenerator<StreamEvent, void, unknown> {\n try {\n while (cycles < maxIterations + 1) {\n cycles++;\n\n const request: LLMRequest<TParams> = {\n messages: allMessages,\n system,\n params,\n tools,\n structure,\n config,\n signal: abortController.signal,\n };\n\n const streamResult = model.stream(request);\n\n // Forward stream events\n for await (const event of streamResult) {\n yield event;\n }\n\n // Get the response\n const response = await streamResult.response;\n usages.push(response.usage);\n allMessages.push(response.message);\n\n // Track structured data from provider (if present)\n if (response.data !== undefined) {\n structuredData = response.data;\n }\n\n // Check for tool calls\n if (response.message.hasToolCalls && tools && tools.length > 0) {\n // If provider already extracted structured data, don't try to execute tool calls\n // (some providers use tool calls internally for structured output)\n if (response.data !== undefined) {\n break;\n }\n\n if (cycles >= maxIterations) {\n await toolStrategy?.onMaxIterations?.(maxIterations);\n throw new UPPError(\n `Tool execution exceeded maximum iterations (${maxIterations})`,\n 'INVALID_REQUEST',\n model.provider.name,\n 'llm'\n );\n }\n\n // Execute tools\n const results = await executeTools(\n response.message,\n tools,\n toolStrategy,\n toolExecutions\n );\n\n // Add tool results\n allMessages.push(new ToolResultMessage(results));\n\n continue;\n }\n\n break;\n }\n resolveGenerator();\n } catch (error) {\n generatorError = error as Error;\n rejectGenerator(error as Error);\n throw error;\n }\n }\n\n // Turn promise waits for the generator to complete, then builds the Turn\n const turnPromise = (async (): Promise<Turn> => {\n await generatorDone;\n\n if (generatorError) {\n throw generatorError;\n }\n\n // Use structured data from provider if structure was requested\n const data = structure ? structuredData : undefined;\n\n return createTurn(\n allMessages.slice(history.length),\n toolExecutions,\n aggregateUsage(usages),\n cycles,\n data\n );\n })();\n\n return createStreamResult(generateStream(), turnPromise, abortController);\n}\n\n/**\n * Execute tools from an assistant message\n */\nasync function executeTools(\n message: AssistantMessage,\n tools: Tool[],\n toolStrategy: LLMOptions<unknown>['toolStrategy'],\n executions: ToolExecution[]\n): Promise<ToolResult[]> {\n const toolCalls = message.toolCalls ?? [];\n const results: ToolResult[] = [];\n\n // Build tool map\n const toolMap = new Map(tools.map((t) => [t.name, t]));\n\n // Execute tools (in parallel)\n const promises = toolCalls.map(async (call) => {\n const tool = toolMap.get(call.toolName);\n if (!tool) {\n return {\n toolCallId: call.toolCallId,\n result: `Tool '${call.toolName}' not found`,\n isError: true,\n };\n }\n\n const startTime = Date.now();\n\n // Notify strategy\n await toolStrategy?.onToolCall?.(tool, call.arguments);\n\n // Check before call\n if (toolStrategy?.onBeforeCall) {\n const shouldRun = await toolStrategy.onBeforeCall(tool, call.arguments);\n if (!shouldRun) {\n return {\n toolCallId: call.toolCallId,\n result: 'Tool execution skipped',\n isError: true,\n };\n }\n }\n\n // Check approval\n let approved = true;\n if (tool.approval) {\n try {\n approved = await tool.approval(call.arguments);\n } catch (error) {\n // Approval threw - propagate\n throw error;\n }\n }\n\n if (!approved) {\n const execution: ToolExecution = {\n toolName: tool.name,\n toolCallId: call.toolCallId,\n arguments: call.arguments,\n result: 'Tool execution denied',\n isError: true,\n duration: Date.now() - startTime,\n approved: false,\n };\n executions.push(execution);\n\n return {\n toolCallId: call.toolCallId,\n result: 'Tool execution denied by approval handler',\n isError: true,\n };\n }\n\n // Execute tool\n try {\n const result = await tool.run(call.arguments);\n\n await toolStrategy?.onAfterCall?.(tool, call.arguments, result);\n\n const execution: ToolExecution = {\n toolName: tool.name,\n toolCallId: call.toolCallId,\n arguments: call.arguments,\n result,\n isError: false,\n duration: Date.now() - startTime,\n approved,\n };\n executions.push(execution);\n\n return {\n toolCallId: call.toolCallId,\n result,\n isError: false,\n };\n } catch (error) {\n await toolStrategy?.onError?.(tool, call.arguments, error as Error);\n\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n const execution: ToolExecution = {\n toolName: tool.name,\n toolCallId: call.toolCallId,\n arguments: call.arguments,\n result: errorMessage,\n isError: true,\n duration: Date.now() - startTime,\n approved,\n };\n executions.push(execution);\n\n return {\n toolCallId: call.toolCallId,\n result: errorMessage,\n isError: true,\n };\n }\n });\n\n results.push(...(await Promise.all(promises)));\n return results;\n}\n\n/**\n * Check if messages contain media that requires specific capabilities\n */\nfunction validateMediaCapabilities(\n messages: Message[],\n capabilities: LLMCapabilities,\n providerName: string\n): void {\n for (const msg of messages) {\n if (!isUserMessage(msg)) continue;\n\n for (const block of msg.content) {\n if (block.type === 'image' && !capabilities.imageInput) {\n throw new UPPError(\n `Provider '${providerName}' does not support image input`,\n 'INVALID_REQUEST',\n providerName,\n 'llm'\n );\n }\n if (block.type === 'video' && !capabilities.videoInput) {\n throw new UPPError(\n `Provider '${providerName}' does not support video input`,\n 'INVALID_REQUEST',\n providerName,\n 'llm'\n );\n }\n if (block.type === 'audio' && !capabilities.audioInput) {\n throw new UPPError(\n `Provider '${providerName}' does not support audio input`,\n 'INVALID_REQUEST',\n providerName,\n 'llm'\n );\n }\n }\n }\n}\n","import type { ImageSource, ImageBlock } from '../types/content.ts';\n\n/**\n * Image class for handling images in UPP\n */\nexport class Image {\n readonly source: ImageSource;\n readonly mimeType: string;\n readonly width?: number;\n readonly height?: number;\n\n private constructor(\n source: ImageSource,\n mimeType: string,\n width?: number,\n height?: number\n ) {\n this.source = source;\n this.mimeType = mimeType;\n this.width = width;\n this.height = height;\n }\n\n /**\n * Check if this image has data loaded (false for URL sources)\n */\n get hasData(): boolean {\n return this.source.type !== 'url';\n }\n\n /**\n * Convert to base64 string (throws if source is URL)\n */\n toBase64(): string {\n if (this.source.type === 'base64') {\n return this.source.data;\n }\n\n if (this.source.type === 'bytes') {\n return btoa(\n Array.from(this.source.data)\n .map((b) => String.fromCharCode(b))\n .join('')\n );\n }\n\n throw new Error('Cannot convert URL image to base64. Fetch the image first.');\n }\n\n /**\n * Convert to data URL (throws if source is URL)\n */\n toDataUrl(): string {\n const base64 = this.toBase64();\n return `data:${this.mimeType};base64,${base64}`;\n }\n\n /**\n * Get raw bytes (throws if source is URL)\n */\n toBytes(): Uint8Array {\n if (this.source.type === 'bytes') {\n return this.source.data;\n }\n\n if (this.source.type === 'base64') {\n const binaryString = atob(this.source.data);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes;\n }\n\n throw new Error('Cannot get bytes from URL image. Fetch the image first.');\n }\n\n /**\n * Get the URL (only for URL sources)\n */\n toUrl(): string {\n if (this.source.type === 'url') {\n return this.source.url;\n }\n\n throw new Error('This image does not have a URL source.');\n }\n\n /**\n * Convert to ImageBlock for use in messages\n */\n toBlock(): ImageBlock {\n return {\n type: 'image',\n source: this.source,\n mimeType: this.mimeType,\n width: this.width,\n height: this.height,\n };\n }\n\n /**\n * Create from file path (reads file into memory)\n */\n static async fromPath(path: string): Promise<Image> {\n const file = Bun.file(path);\n const data = await file.arrayBuffer();\n const mimeType = file.type || detectMimeType(path);\n\n return new Image(\n { type: 'bytes', data: new Uint8Array(data) },\n mimeType\n );\n }\n\n /**\n * Create from URL reference (does not fetch - providers handle URL conversion)\n */\n static fromUrl(url: string, mimeType?: string): Image {\n const detected = mimeType || detectMimeTypeFromUrl(url);\n return new Image({ type: 'url', url }, detected);\n }\n\n /**\n * Create from raw bytes\n */\n static fromBytes(data: Uint8Array, mimeType: string): Image {\n return new Image({ type: 'bytes', data }, mimeType);\n }\n\n /**\n * Create from base64 string\n */\n static fromBase64(base64: string, mimeType: string): Image {\n return new Image({ type: 'base64', data: base64 }, mimeType);\n }\n\n /**\n * Create from an existing ImageBlock\n */\n static fromBlock(block: ImageBlock): Image {\n return new Image(\n block.source,\n block.mimeType,\n block.width,\n block.height\n );\n }\n}\n\n/**\n * Detect MIME type from file extension\n */\nfunction detectMimeType(path: string): string {\n const ext = path.split('.').pop()?.toLowerCase();\n\n switch (ext) {\n case 'jpg':\n case 'jpeg':\n return 'image/jpeg';\n case 'png':\n return 'image/png';\n case 'gif':\n return 'image/gif';\n case 'webp':\n return 'image/webp';\n case 'svg':\n return 'image/svg+xml';\n case 'bmp':\n return 'image/bmp';\n case 'ico':\n return 'image/x-icon';\n default:\n return 'application/octet-stream';\n }\n}\n\n/**\n * Detect MIME type from URL\n */\nfunction detectMimeTypeFromUrl(url: string): string {\n try {\n const pathname = new URL(url).pathname;\n return detectMimeType(pathname);\n } catch {\n return 'application/octet-stream';\n }\n}\n","/**\n * Content block types for messages\n */\n\n/**\n * Image source types\n */\nexport type ImageSource =\n | { type: 'base64'; data: string }\n | { type: 'url'; url: string }\n | { type: 'bytes'; data: Uint8Array };\n\n/**\n * Text content block\n */\nexport interface TextBlock {\n type: 'text';\n text: string;\n}\n\n/**\n * Image content block\n */\nexport interface ImageBlock {\n type: 'image';\n source: ImageSource;\n mimeType: string;\n width?: number;\n height?: number;\n}\n\n/**\n * Audio content block\n */\nexport interface AudioBlock {\n type: 'audio';\n data: Uint8Array;\n mimeType: string;\n duration?: number;\n}\n\n/**\n * Video content block\n */\nexport interface VideoBlock {\n type: 'video';\n data: Uint8Array;\n mimeType: string;\n duration?: number;\n width?: number;\n height?: number;\n}\n\n/**\n * Binary content block for arbitrary data\n */\nexport interface BinaryBlock {\n type: 'binary';\n data: Uint8Array;\n mimeType: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * All content block types\n */\nexport type ContentBlock =\n | TextBlock\n | ImageBlock\n | AudioBlock\n | VideoBlock\n | BinaryBlock;\n\n/**\n * Content types allowed in user messages\n */\nexport type UserContent =\n | TextBlock\n | ImageBlock\n | AudioBlock\n | VideoBlock\n | BinaryBlock;\n\n/**\n * Content types allowed in assistant messages\n */\nexport type AssistantContent =\n | TextBlock\n | ImageBlock\n | AudioBlock\n | VideoBlock;\n\n/**\n * Helper to create a text block\n */\nexport function text(content: string): TextBlock {\n return { type: 'text', text: content };\n}\n\n/**\n * Type guard for TextBlock\n */\nexport function isTextBlock(block: ContentBlock): block is TextBlock {\n return block.type === 'text';\n}\n\n/**\n * Type guard for ImageBlock\n */\nexport function isImageBlock(block: ContentBlock): block is ImageBlock {\n return block.type === 'image';\n}\n\n/**\n * Type guard for AudioBlock\n */\nexport function isAudioBlock(block: ContentBlock): block is AudioBlock {\n return block.type === 'audio';\n}\n\n/**\n * Type guard for VideoBlock\n */\nexport function isVideoBlock(block: ContentBlock): block is VideoBlock {\n return block.type === 'video';\n}\n\n/**\n * Type guard for BinaryBlock\n */\nexport function isBinaryBlock(block: ContentBlock): block is BinaryBlock {\n return block.type === 'binary';\n}\n","import { generateId } from '../utils/id.ts';\nimport {\n Message,\n UserMessage,\n AssistantMessage,\n ToolResultMessage,\n} from './messages.ts';\nimport type { MessageType, MessageMetadata } from './messages.ts';\nimport type { ContentBlock, UserContent, AssistantContent } from './content.ts';\nimport type { Turn } from './turn.ts';\nimport type { ToolCall, ToolResult } from './tool.ts';\n\n/**\n * Serialized message format\n */\nexport interface MessageJSON {\n id: string;\n type: MessageType;\n content: ContentBlock[];\n toolCalls?: ToolCall[];\n results?: ToolResult[];\n metadata?: MessageMetadata;\n timestamp: string;\n}\n\n/**\n * Serialized thread format\n */\nexport interface ThreadJSON {\n id: string;\n messages: MessageJSON[];\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Thread - A utility class for managing conversation history\n * Users control their own history; Thread is optional\n */\nexport class Thread {\n /** Unique thread identifier */\n readonly id: string;\n\n /** Internal message storage */\n private _messages: Message[];\n\n /** Creation timestamp */\n private _createdAt: Date;\n\n /** Last update timestamp */\n private _updatedAt: Date;\n\n /**\n * Create a new thread, optionally with initial messages\n */\n constructor(messages?: Message[]) {\n this.id = generateId();\n this._messages = messages ? [...messages] : [];\n this._createdAt = new Date();\n this._updatedAt = new Date();\n }\n\n /** All messages in the thread (readonly) */\n get messages(): readonly Message[] {\n return this._messages;\n }\n\n /** Number of messages */\n get length(): number {\n return this._messages.length;\n }\n\n /**\n * Append messages from a turn\n */\n append(turn: Turn): this {\n this._messages.push(...turn.messages);\n this._updatedAt = new Date();\n return this;\n }\n\n /**\n * Add raw messages\n */\n push(...messages: Message[]): this {\n this._messages.push(...messages);\n this._updatedAt = new Date();\n return this;\n }\n\n /**\n * Add a user message\n */\n user(content: string | UserContent[]): this {\n this._messages.push(new UserMessage(content));\n this._updatedAt = new Date();\n return this;\n }\n\n /**\n * Add an assistant message\n */\n assistant(content: string | AssistantContent[]): this {\n this._messages.push(new AssistantMessage(content));\n this._updatedAt = new Date();\n return this;\n }\n\n /**\n * Get messages by type\n */\n filter(type: MessageType): Message[] {\n return this._messages.filter((m) => m.type === type);\n }\n\n /**\n * Get the last N messages\n */\n tail(count: number): Message[] {\n return this._messages.slice(-count);\n }\n\n /**\n * Create a new thread with a subset of messages\n */\n slice(start?: number, end?: number): Thread {\n return new Thread(this._messages.slice(start, end));\n }\n\n /**\n * Clear all messages\n */\n clear(): this {\n this._messages = [];\n this._updatedAt = new Date();\n return this;\n }\n\n /**\n * Convert to plain message array\n */\n toMessages(): Message[] {\n return [...this._messages];\n }\n\n /**\n * Serialize to JSON\n */\n toJSON(): ThreadJSON {\n return {\n id: this.id,\n messages: this._messages.map((m) => this.messageToJSON(m)),\n createdAt: this._createdAt.toISOString(),\n updatedAt: this._updatedAt.toISOString(),\n };\n }\n\n /**\n * Deserialize from JSON\n */\n static fromJSON(json: ThreadJSON): Thread {\n const messages = json.messages.map((m) => Thread.messageFromJSON(m));\n const thread = new Thread(messages);\n // Override the generated id with the serialized one\n (thread as { id: string }).id = json.id;\n thread._createdAt = new Date(json.createdAt);\n thread._updatedAt = new Date(json.updatedAt);\n return thread;\n }\n\n /**\n * Iterate over messages\n */\n [Symbol.iterator](): Iterator<Message> {\n return this._messages[Symbol.iterator]();\n }\n\n /**\n * Convert a message to JSON\n */\n private messageToJSON(m: Message): MessageJSON {\n const base: MessageJSON = {\n id: m.id,\n type: m.type,\n content: [],\n metadata: m.metadata,\n timestamp: m.timestamp.toISOString(),\n };\n\n if (m instanceof UserMessage) {\n base.content = m.content;\n } else if (m instanceof AssistantMessage) {\n base.content = m.content;\n base.toolCalls = m.toolCalls;\n } else if (m instanceof ToolResultMessage) {\n base.results = m.results;\n }\n\n return base;\n }\n\n /**\n * Reconstruct a message from JSON\n */\n private static messageFromJSON(json: MessageJSON): Message {\n const options = {\n id: json.id,\n metadata: json.metadata,\n };\n\n switch (json.type) {\n case 'user':\n return new UserMessage(json.content as UserContent[], options);\n case 'assistant':\n return new AssistantMessage(\n json.content as AssistantContent[],\n json.toolCalls,\n options\n );\n case 'tool_result':\n return new ToolResultMessage(json.results ?? [], options);\n default:\n throw new Error(`Unknown message type: ${json.type}`);\n }\n }\n}\n","// Core entry points\nexport { llm } from './core/llm.ts';\nexport { createProvider } from './core/provider.ts';\nexport { Image } from './core/image.ts';\n\n// Namespace object for alternative import style\nimport { llm } from './core/llm.ts';\n\n/**\n * UPP namespace object\n * Provides ai.llm(), ai.embedding(), ai.image() style access\n */\nexport const ai = {\n llm,\n // embedding, // Coming soon\n // image, // Coming soon\n};\n\n// Re-export all types from types/index.ts\nexport * from './types/index.ts';\n\n// Re-export HTTP utilities\nexport {\n RoundRobinKeys,\n WeightedKeys,\n DynamicKey,\n ExponentialBackoff,\n LinearBackoff,\n NoRetry,\n TokenBucket,\n RetryAfterStrategy,\n} from './http/index.ts';\n"],"mappings":"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","names":["text","newMessages"]}
|
|
1
|
+
{"version":3,"sources":["../src/types/turn.ts","../src/types/stream.ts","../src/core/llm.ts","../src/core/image.ts","../src/types/content.ts","../src/types/thread.ts","../src/index.ts"],"sourcesContent":["import type { Message, AssistantMessage } from './messages.ts';\nimport type { ToolExecution } from './tool.ts';\n\n/**\n * Token usage information\n */\nexport interface TokenUsage {\n /** Input tokens across all cycles */\n inputTokens: number;\n\n /** Output tokens across all cycles */\n outputTokens: number;\n\n /** Total tokens */\n totalTokens: number;\n\n /** Per-cycle breakdown (if available) */\n cycles?: Array<{\n inputTokens: number;\n outputTokens: number;\n }>;\n}\n\n/**\n * A Turn represents the complete result of one inference call,\n * including all messages produced during tool execution loops.\n */\nexport interface Turn<TData = unknown> {\n /**\n * All messages produced during this inference, in chronological order.\n * Types: UserMessage, AssistantMessage (may include toolCalls), ToolResultMessage\n */\n readonly messages: Message[];\n\n /** The final assistant response (convenience accessor) */\n readonly response: AssistantMessage;\n\n /** Tool executions that occurred during this turn */\n readonly toolExecutions: ToolExecution[];\n\n /** Aggregate token usage for the entire turn */\n readonly usage: TokenUsage;\n\n /** Total number of inference cycles (1 + number of tool rounds) */\n readonly cycles: number;\n\n /**\n * Structured output data (if structure was provided).\n * Type is inferred from the schema when using TypeScript.\n */\n readonly data?: TData;\n}\n\n/**\n * Create a Turn from accumulated data\n */\nexport function createTurn<TData = unknown>(\n messages: Message[],\n toolExecutions: ToolExecution[],\n usage: TokenUsage,\n cycles: number,\n data?: TData\n): Turn<TData> {\n // Find the last assistant message as the response\n const response = messages\n .filter((m): m is AssistantMessage => m.type === 'assistant')\n .pop();\n\n if (!response) {\n throw new Error('Turn must contain at least one assistant message');\n }\n\n return {\n messages,\n response,\n toolExecutions,\n usage,\n cycles,\n data,\n };\n}\n\n/**\n * Create empty token usage\n */\nexport function emptyUsage(): TokenUsage {\n return {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n cycles: [],\n };\n}\n\n/**\n * Aggregate token usage from multiple cycles\n */\nexport function aggregateUsage(usages: TokenUsage[]): TokenUsage {\n const cycles: TokenUsage['cycles'] = [];\n let inputTokens = 0;\n let outputTokens = 0;\n\n for (const usage of usages) {\n inputTokens += usage.inputTokens;\n outputTokens += usage.outputTokens;\n cycles.push({\n inputTokens: usage.inputTokens,\n outputTokens: usage.outputTokens,\n });\n }\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n cycles,\n };\n}\n","import type { Turn } from './turn.ts';\n\n/**\n * Stream event types\n */\nexport type StreamEventType =\n | 'text_delta'\n | 'reasoning_delta'\n | 'image_delta'\n | 'audio_delta'\n | 'video_delta'\n | 'tool_call_delta'\n | 'tool_execution_start'\n | 'tool_execution_end'\n | 'message_start'\n | 'message_stop'\n | 'content_block_start'\n | 'content_block_stop';\n\n/**\n * Event delta data (type-specific)\n */\nexport interface EventDelta {\n text?: string;\n data?: Uint8Array;\n toolCallId?: string;\n toolName?: string;\n argumentsJson?: string;\n /** Tool execution result (for tool_execution_end) */\n result?: unknown;\n /** Whether tool execution errored (for tool_execution_end) */\n isError?: boolean;\n /** Timestamp in ms (for tool_execution_start/end) */\n timestamp?: number;\n}\n\n/**\n * A streaming event\n */\nexport interface StreamEvent {\n /** Event type */\n type: StreamEventType;\n\n /** Index of the content block this event belongs to */\n index: number;\n\n /** Event data (type-specific) */\n delta: EventDelta;\n}\n\n/**\n * Stream result - async iterable that also provides final turn\n */\nexport interface StreamResult<TData = unknown>\n extends AsyncIterable<StreamEvent> {\n /**\n * Get the complete Turn after streaming finishes.\n * Resolves when the stream completes.\n */\n readonly turn: Promise<Turn<TData>>;\n\n /** Abort the stream */\n abort(): void;\n}\n\n/**\n * Create a stream result from an async generator and completion promise\n */\nexport function createStreamResult<TData = unknown>(\n generator: AsyncGenerator<StreamEvent, void, unknown>,\n turnPromise: Promise<Turn<TData>>,\n abortController: AbortController\n): StreamResult<TData> {\n return {\n [Symbol.asyncIterator]() {\n return generator;\n },\n turn: turnPromise,\n abort() {\n abortController.abort();\n },\n };\n}\n\n/**\n * Create a text delta event\n */\nexport function textDelta(text: string, index = 0): StreamEvent {\n return {\n type: 'text_delta',\n index,\n delta: { text },\n };\n}\n\n/**\n * Create a tool call delta event\n */\nexport function toolCallDelta(\n toolCallId: string,\n toolName: string,\n argumentsJson: string,\n index = 0\n): StreamEvent {\n return {\n type: 'tool_call_delta',\n index,\n delta: { toolCallId, toolName, argumentsJson },\n };\n}\n\n/**\n * Create a message start event\n */\nexport function messageStart(): StreamEvent {\n return {\n type: 'message_start',\n index: 0,\n delta: {},\n };\n}\n\n/**\n * Create a message stop event\n */\nexport function messageStop(): StreamEvent {\n return {\n type: 'message_stop',\n index: 0,\n delta: {},\n };\n}\n\n/**\n * Create a content block start event\n */\nexport function contentBlockStart(index: number): StreamEvent {\n return {\n type: 'content_block_start',\n index,\n delta: {},\n };\n}\n\n/**\n * Create a content block stop event\n */\nexport function contentBlockStop(index: number): StreamEvent {\n return {\n type: 'content_block_stop',\n index,\n delta: {},\n };\n}\n\n/**\n * Create a tool execution start event\n */\nexport function toolExecutionStart(\n toolCallId: string,\n toolName: string,\n timestamp: number,\n index = 0\n): StreamEvent {\n return {\n type: 'tool_execution_start',\n index,\n delta: { toolCallId, toolName, timestamp },\n };\n}\n\n/**\n * Create a tool execution end event\n */\nexport function toolExecutionEnd(\n toolCallId: string,\n toolName: string,\n result: unknown,\n isError: boolean,\n timestamp: number,\n index = 0\n): StreamEvent {\n return {\n type: 'tool_execution_end',\n index,\n delta: { toolCallId, toolName, result, isError, timestamp },\n };\n}\n","import type {\n LLMOptions,\n LLMInstance,\n LLMRequest,\n LLMResponse,\n InferenceInput,\n BoundLLMModel,\n LLMCapabilities,\n} from '../types/llm.ts';\nimport type { UserMessage, AssistantMessage } from '../types/messages.ts';\nimport type { ContentBlock, TextBlock } from '../types/content.ts';\nimport type { Tool, ToolExecution, ToolResult } from '../types/tool.ts';\nimport type { Turn, TokenUsage } from '../types/turn.ts';\nimport type { StreamResult, StreamEvent } from '../types/stream.ts';\nimport type { Thread } from '../types/thread.ts';\nimport type { ProviderConfig } from '../types/provider.ts';\nimport { UPPError } from '../types/errors.ts';\nimport {\n Message,\n UserMessage as UserMessageClass,\n ToolResultMessage,\n isUserMessage,\n isAssistantMessage,\n} from '../types/messages.ts';\nimport { createTurn, aggregateUsage, emptyUsage } from '../types/turn.ts';\nimport {\n createStreamResult,\n toolExecutionStart,\n toolExecutionEnd,\n} from '../types/stream.ts';\nimport { generateShortId } from '../utils/id.ts';\n\n/**\n * Default maximum iterations for tool execution\n */\nconst DEFAULT_MAX_ITERATIONS = 10;\n\n/**\n * Create an LLM instance\n */\nexport function llm<TParams = unknown>(\n options: LLMOptions<TParams>\n): LLMInstance<TParams> {\n const { model: modelRef, config = {}, params, system, tools, toolStrategy, structure } = options;\n\n // Validate that the provider supports LLM\n const provider = modelRef.provider;\n if (!provider.modalities.llm) {\n throw new UPPError(\n `Provider '${provider.name}' does not support LLM modality`,\n 'INVALID_REQUEST',\n provider.name,\n 'llm'\n );\n }\n\n // Bind the model\n const boundModel = provider.modalities.llm.bind(modelRef.modelId) as BoundLLMModel<TParams>;\n\n // Validate capabilities at bind time\n const capabilities = boundModel.capabilities;\n\n // Check for structured output capability\n if (structure && !capabilities.structuredOutput) {\n throw new UPPError(\n `Provider '${provider.name}' does not support structured output`,\n 'INVALID_REQUEST',\n provider.name,\n 'llm'\n );\n }\n\n // Check for tools capability\n if (tools && tools.length > 0 && !capabilities.tools) {\n throw new UPPError(\n `Provider '${provider.name}' does not support tools`,\n 'INVALID_REQUEST',\n provider.name,\n 'llm'\n );\n }\n\n // Build the instance\n const instance: LLMInstance<TParams> = {\n model: boundModel,\n system,\n params,\n capabilities,\n\n async generate(\n historyOrInput: Message[] | Thread | InferenceInput,\n ...inputs: InferenceInput[]\n ): Promise<Turn> {\n const { history, messages } = parseInputs(historyOrInput, inputs);\n return executeGenerate(\n boundModel,\n config,\n system,\n params,\n tools,\n toolStrategy,\n structure,\n history,\n messages\n );\n },\n\n stream(\n historyOrInput: Message[] | Thread | InferenceInput,\n ...inputs: InferenceInput[]\n ): StreamResult {\n // Check streaming capability\n if (!capabilities.streaming) {\n throw new UPPError(\n `Provider '${provider.name}' does not support streaming`,\n 'INVALID_REQUEST',\n provider.name,\n 'llm'\n );\n }\n const { history, messages } = parseInputs(historyOrInput, inputs);\n return executeStream(\n boundModel,\n config,\n system,\n params,\n tools,\n toolStrategy,\n structure,\n history,\n messages\n );\n },\n };\n\n return instance;\n}\n\n/**\n * Type guard to check if a value is a Message instance.\n * Uses instanceof for class instances, with fallback to timestamp check\n * for deserialized/reconstructed Message objects.\n */\nfunction isMessageInstance(value: unknown): value is Message {\n if (value instanceof Message) {\n return true;\n }\n // Fallback for deserialized Messages that aren't class instances:\n // Messages have 'timestamp' (Date), ContentBlocks don't\n if (\n typeof value === 'object' &&\n value !== null &&\n 'timestamp' in value &&\n 'type' in value &&\n 'id' in value\n ) {\n const obj = value as Record<string, unknown>;\n // Message types are 'user', 'assistant', 'tool_result'\n // ContentBlock types are 'text', 'image', 'audio', 'video', 'binary'\n const messageTypes = ['user', 'assistant', 'tool_result'];\n return messageTypes.includes(obj.type as string);\n }\n return false;\n}\n\n/**\n * Parse inputs to determine history and new messages\n */\nfunction parseInputs(\n historyOrInput: Message[] | Thread | InferenceInput,\n inputs: InferenceInput[]\n): { history: Message[]; messages: Message[] } {\n // Check if it's a Thread first (has 'messages' array property)\n if (\n typeof historyOrInput === 'object' &&\n historyOrInput !== null &&\n 'messages' in historyOrInput &&\n Array.isArray((historyOrInput as Thread).messages)\n ) {\n const thread = historyOrInput as Thread;\n const newMessages = inputs.map(inputToMessage);\n return { history: [...thread.messages], messages: newMessages };\n }\n\n // Check if first arg is Message[] (history)\n if (Array.isArray(historyOrInput)) {\n // Empty array is empty history\n if (historyOrInput.length === 0) {\n const newMessages = inputs.map(inputToMessage);\n return { history: [], messages: newMessages };\n }\n const first = historyOrInput[0];\n if (isMessageInstance(first)) {\n // It's history (Message[])\n const newMessages = inputs.map(inputToMessage);\n return { history: historyOrInput as Message[], messages: newMessages };\n }\n }\n\n // It's input (no history) - could be string, single Message, or ContentBlock\n const allInputs = [historyOrInput as InferenceInput, ...inputs];\n const newMessages = allInputs.map(inputToMessage);\n return { history: [], messages: newMessages };\n}\n\n/**\n * Convert an InferenceInput to a Message\n */\nfunction inputToMessage(input: InferenceInput): Message {\n if (typeof input === 'string') {\n return new UserMessageClass(input);\n }\n\n // It's already a Message\n if ('type' in input && 'id' in input && 'timestamp' in input) {\n return input as Message;\n }\n\n // It's a ContentBlock - wrap in UserMessage\n const block = input as ContentBlock;\n if (block.type === 'text') {\n return new UserMessageClass((block as TextBlock).text);\n }\n\n return new UserMessageClass([block as any]);\n}\n\n/**\n * Execute a non-streaming generate call with tool loop\n */\nasync function executeGenerate<TParams>(\n model: BoundLLMModel<TParams>,\n config: ProviderConfig,\n system: string | undefined,\n params: TParams | undefined,\n tools: Tool[] | undefined,\n toolStrategy: LLMOptions<TParams>['toolStrategy'],\n structure: LLMOptions<TParams>['structure'],\n history: Message[],\n newMessages: Message[]\n): Promise<Turn> {\n // Validate media capabilities for all input messages\n validateMediaCapabilities(\n [...history, ...newMessages],\n model.capabilities,\n model.provider.name\n );\n const maxIterations = toolStrategy?.maxIterations ?? DEFAULT_MAX_ITERATIONS;\n const allMessages: Message[] = [...history, ...newMessages];\n const toolExecutions: ToolExecution[] = [];\n const usages: TokenUsage[] = [];\n let cycles = 0;\n\n // Track structured data from responses (providers handle extraction)\n let structuredData: unknown;\n\n // Tool loop\n while (cycles < maxIterations + 1) {\n cycles++;\n\n const request: LLMRequest<TParams> = {\n messages: allMessages,\n system,\n params,\n tools,\n structure,\n config,\n };\n\n const response = await model.complete(request);\n usages.push(response.usage);\n allMessages.push(response.message);\n\n // Track structured data from provider (if present)\n if (response.data !== undefined) {\n structuredData = response.data;\n }\n\n // Check for tool calls\n if (response.message.hasToolCalls && tools && tools.length > 0) {\n // If provider already extracted structured data, don't try to execute tool calls\n // (some providers use tool calls internally for structured output)\n if (response.data !== undefined) {\n break;\n }\n\n // Check if we've hit max iterations (subtract 1 because we already incremented)\n if (cycles >= maxIterations) {\n await toolStrategy?.onMaxIterations?.(maxIterations);\n throw new UPPError(\n `Tool execution exceeded maximum iterations (${maxIterations})`,\n 'INVALID_REQUEST',\n model.provider.name,\n 'llm'\n );\n }\n\n // Execute tools\n const results = await executeTools(\n response.message,\n tools,\n toolStrategy,\n toolExecutions\n );\n\n // Add tool results\n allMessages.push(new ToolResultMessage(results));\n\n continue;\n }\n\n // No tool calls - we're done\n break;\n }\n\n // Use structured data from provider if structure was requested\n const data = structure ? structuredData : undefined;\n\n return createTurn(\n allMessages.slice(history.length), // Only messages from this turn\n toolExecutions,\n aggregateUsage(usages),\n cycles,\n data\n );\n}\n\n/**\n * Execute a streaming generate call with tool loop\n */\nfunction executeStream<TParams>(\n model: BoundLLMModel<TParams>,\n config: ProviderConfig,\n system: string | undefined,\n params: TParams | undefined,\n tools: Tool[] | undefined,\n toolStrategy: LLMOptions<TParams>['toolStrategy'],\n structure: LLMOptions<TParams>['structure'],\n history: Message[],\n newMessages: Message[]\n): StreamResult {\n // Validate media capabilities for all input messages\n validateMediaCapabilities(\n [...history, ...newMessages],\n model.capabilities,\n model.provider.name\n );\n\n const abortController = new AbortController();\n\n // Shared state between generator and turn promise\n const allMessages: Message[] = [...history, ...newMessages];\n const toolExecutions: ToolExecution[] = [];\n const usages: TokenUsage[] = [];\n let cycles = 0;\n let generatorError: Error | null = null;\n let structuredData: unknown; // Providers extract this\n\n // Deferred to signal when generator completes\n let resolveGenerator: () => void;\n let rejectGenerator: (error: Error) => void;\n const generatorDone = new Promise<void>((resolve, reject) => {\n resolveGenerator = resolve;\n rejectGenerator = reject;\n });\n\n const maxIterations = toolStrategy?.maxIterations ?? DEFAULT_MAX_ITERATIONS;\n\n // Create the async generator - this is the ONLY place that calls the API\n async function* generateStream(): AsyncGenerator<StreamEvent, void, unknown> {\n try {\n while (cycles < maxIterations + 1) {\n cycles++;\n\n const request: LLMRequest<TParams> = {\n messages: allMessages,\n system,\n params,\n tools,\n structure,\n config,\n signal: abortController.signal,\n };\n\n const streamResult = model.stream(request);\n\n // Forward stream events\n for await (const event of streamResult) {\n yield event;\n }\n\n // Get the response\n const response = await streamResult.response;\n usages.push(response.usage);\n allMessages.push(response.message);\n\n // Track structured data from provider (if present)\n if (response.data !== undefined) {\n structuredData = response.data;\n }\n\n // Check for tool calls\n if (response.message.hasToolCalls && tools && tools.length > 0) {\n // If provider already extracted structured data, don't try to execute tool calls\n // (some providers use tool calls internally for structured output)\n if (response.data !== undefined) {\n break;\n }\n\n if (cycles >= maxIterations) {\n await toolStrategy?.onMaxIterations?.(maxIterations);\n throw new UPPError(\n `Tool execution exceeded maximum iterations (${maxIterations})`,\n 'INVALID_REQUEST',\n model.provider.name,\n 'llm'\n );\n }\n\n // Execute tools with event emission\n const toolEvents: StreamEvent[] = [];\n const results = await executeTools(\n response.message,\n tools,\n toolStrategy,\n toolExecutions,\n (event) => toolEvents.push(event)\n );\n\n // Yield tool execution events\n for (const event of toolEvents) {\n yield event;\n }\n\n // Add tool results\n allMessages.push(new ToolResultMessage(results));\n\n continue;\n }\n\n break;\n }\n resolveGenerator();\n } catch (error) {\n generatorError = error as Error;\n rejectGenerator(error as Error);\n throw error;\n }\n }\n\n // Turn promise waits for the generator to complete, then builds the Turn\n const turnPromise = (async (): Promise<Turn> => {\n await generatorDone;\n\n if (generatorError) {\n throw generatorError;\n }\n\n // Use structured data from provider if structure was requested\n const data = structure ? structuredData : undefined;\n\n return createTurn(\n allMessages.slice(history.length),\n toolExecutions,\n aggregateUsage(usages),\n cycles,\n data\n );\n })();\n\n return createStreamResult(generateStream(), turnPromise, abortController);\n}\n\n/**\n * Execute tools from an assistant message\n */\nasync function executeTools(\n message: AssistantMessage,\n tools: Tool[],\n toolStrategy: LLMOptions<unknown>['toolStrategy'],\n executions: ToolExecution[],\n onEvent?: (event: StreamEvent) => void\n): Promise<ToolResult[]> {\n const toolCalls = message.toolCalls ?? [];\n const results: ToolResult[] = [];\n\n // Build tool map\n const toolMap = new Map(tools.map((t) => [t.name, t]));\n\n // Execute tools (in parallel)\n const promises = toolCalls.map(async (call, index) => {\n const tool = toolMap.get(call.toolName);\n if (!tool) {\n return {\n toolCallId: call.toolCallId,\n result: `Tool '${call.toolName}' not found`,\n isError: true,\n };\n }\n\n const startTime = Date.now();\n\n // Emit start event\n onEvent?.(toolExecutionStart(call.toolCallId, tool.name, startTime, index));\n\n // Notify strategy\n await toolStrategy?.onToolCall?.(tool, call.arguments);\n\n // Check before call\n if (toolStrategy?.onBeforeCall) {\n const shouldRun = await toolStrategy.onBeforeCall(tool, call.arguments);\n if (!shouldRun) {\n const endTime = Date.now();\n onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, 'Tool execution skipped', true, endTime, index));\n return {\n toolCallId: call.toolCallId,\n result: 'Tool execution skipped',\n isError: true,\n };\n }\n }\n\n // Check approval\n let approved = true;\n if (tool.approval) {\n try {\n approved = await tool.approval(call.arguments);\n } catch (error) {\n // Approval threw - propagate\n throw error;\n }\n }\n\n if (!approved) {\n const endTime = Date.now();\n const execution: ToolExecution = {\n toolName: tool.name,\n toolCallId: call.toolCallId,\n arguments: call.arguments,\n result: 'Tool execution denied',\n isError: true,\n duration: endTime - startTime,\n approved: false,\n };\n executions.push(execution);\n\n onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, 'Tool execution denied by approval handler', true, endTime, index));\n\n return {\n toolCallId: call.toolCallId,\n result: 'Tool execution denied by approval handler',\n isError: true,\n };\n }\n\n // Execute tool\n try {\n const result = await tool.run(call.arguments);\n const endTime = Date.now();\n\n await toolStrategy?.onAfterCall?.(tool, call.arguments, result);\n\n const execution: ToolExecution = {\n toolName: tool.name,\n toolCallId: call.toolCallId,\n arguments: call.arguments,\n result,\n isError: false,\n duration: endTime - startTime,\n approved,\n };\n executions.push(execution);\n\n onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, result, false, endTime, index));\n\n return {\n toolCallId: call.toolCallId,\n result,\n isError: false,\n };\n } catch (error) {\n const endTime = Date.now();\n await toolStrategy?.onError?.(tool, call.arguments, error as Error);\n\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n const execution: ToolExecution = {\n toolName: tool.name,\n toolCallId: call.toolCallId,\n arguments: call.arguments,\n result: errorMessage,\n isError: true,\n duration: endTime - startTime,\n approved,\n };\n executions.push(execution);\n\n onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, errorMessage, true, endTime, index));\n\n return {\n toolCallId: call.toolCallId,\n result: errorMessage,\n isError: true,\n };\n }\n });\n\n results.push(...(await Promise.all(promises)));\n return results;\n}\n\n/**\n * Check if messages contain media that requires specific capabilities\n */\nfunction validateMediaCapabilities(\n messages: Message[],\n capabilities: LLMCapabilities,\n providerName: string\n): void {\n for (const msg of messages) {\n if (!isUserMessage(msg)) continue;\n\n for (const block of msg.content) {\n if (block.type === 'image' && !capabilities.imageInput) {\n throw new UPPError(\n `Provider '${providerName}' does not support image input`,\n 'INVALID_REQUEST',\n providerName,\n 'llm'\n );\n }\n if (block.type === 'video' && !capabilities.videoInput) {\n throw new UPPError(\n `Provider '${providerName}' does not support video input`,\n 'INVALID_REQUEST',\n providerName,\n 'llm'\n );\n }\n if (block.type === 'audio' && !capabilities.audioInput) {\n throw new UPPError(\n `Provider '${providerName}' does not support audio input`,\n 'INVALID_REQUEST',\n providerName,\n 'llm'\n );\n }\n }\n }\n}\n","import type { ImageSource, ImageBlock } from '../types/content.ts';\n\n/**\n * Image class for handling images in UPP\n */\nexport class Image {\n readonly source: ImageSource;\n readonly mimeType: string;\n readonly width?: number;\n readonly height?: number;\n\n private constructor(\n source: ImageSource,\n mimeType: string,\n width?: number,\n height?: number\n ) {\n this.source = source;\n this.mimeType = mimeType;\n this.width = width;\n this.height = height;\n }\n\n /**\n * Check if this image has data loaded (false for URL sources)\n */\n get hasData(): boolean {\n return this.source.type !== 'url';\n }\n\n /**\n * Convert to base64 string (throws if source is URL)\n */\n toBase64(): string {\n if (this.source.type === 'base64') {\n return this.source.data;\n }\n\n if (this.source.type === 'bytes') {\n return btoa(\n Array.from(this.source.data)\n .map((b) => String.fromCharCode(b))\n .join('')\n );\n }\n\n throw new Error('Cannot convert URL image to base64. Fetch the image first.');\n }\n\n /**\n * Convert to data URL (throws if source is URL)\n */\n toDataUrl(): string {\n const base64 = this.toBase64();\n return `data:${this.mimeType};base64,${base64}`;\n }\n\n /**\n * Get raw bytes (throws if source is URL)\n */\n toBytes(): Uint8Array {\n if (this.source.type === 'bytes') {\n return this.source.data;\n }\n\n if (this.source.type === 'base64') {\n const binaryString = atob(this.source.data);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes;\n }\n\n throw new Error('Cannot get bytes from URL image. Fetch the image first.');\n }\n\n /**\n * Get the URL (only for URL sources)\n */\n toUrl(): string {\n if (this.source.type === 'url') {\n return this.source.url;\n }\n\n throw new Error('This image does not have a URL source.');\n }\n\n /**\n * Convert to ImageBlock for use in messages\n */\n toBlock(): ImageBlock {\n return {\n type: 'image',\n source: this.source,\n mimeType: this.mimeType,\n width: this.width,\n height: this.height,\n };\n }\n\n /**\n * Create from file path (reads file into memory)\n */\n static async fromPath(path: string): Promise<Image> {\n const file = Bun.file(path);\n const data = await file.arrayBuffer();\n const mimeType = file.type || detectMimeType(path);\n\n return new Image(\n { type: 'bytes', data: new Uint8Array(data) },\n mimeType\n );\n }\n\n /**\n * Create from URL reference (does not fetch - providers handle URL conversion)\n */\n static fromUrl(url: string, mimeType?: string): Image {\n const detected = mimeType || detectMimeTypeFromUrl(url);\n return new Image({ type: 'url', url }, detected);\n }\n\n /**\n * Create from raw bytes\n */\n static fromBytes(data: Uint8Array, mimeType: string): Image {\n return new Image({ type: 'bytes', data }, mimeType);\n }\n\n /**\n * Create from base64 string\n */\n static fromBase64(base64: string, mimeType: string): Image {\n return new Image({ type: 'base64', data: base64 }, mimeType);\n }\n\n /**\n * Create from an existing ImageBlock\n */\n static fromBlock(block: ImageBlock): Image {\n return new Image(\n block.source,\n block.mimeType,\n block.width,\n block.height\n );\n }\n}\n\n/**\n * Detect MIME type from file extension\n */\nfunction detectMimeType(path: string): string {\n const ext = path.split('.').pop()?.toLowerCase();\n\n switch (ext) {\n case 'jpg':\n case 'jpeg':\n return 'image/jpeg';\n case 'png':\n return 'image/png';\n case 'gif':\n return 'image/gif';\n case 'webp':\n return 'image/webp';\n case 'svg':\n return 'image/svg+xml';\n case 'bmp':\n return 'image/bmp';\n case 'ico':\n return 'image/x-icon';\n default:\n return 'application/octet-stream';\n }\n}\n\n/**\n * Detect MIME type from URL\n */\nfunction detectMimeTypeFromUrl(url: string): string {\n try {\n const pathname = new URL(url).pathname;\n return detectMimeType(pathname);\n } catch {\n return 'application/octet-stream';\n }\n}\n","/**\n * Content block types for messages\n */\n\n/**\n * Image source types\n */\nexport type ImageSource =\n | { type: 'base64'; data: string }\n | { type: 'url'; url: string }\n | { type: 'bytes'; data: Uint8Array };\n\n/**\n * Text content block\n */\nexport interface TextBlock {\n type: 'text';\n text: string;\n}\n\n/**\n * Image content block\n */\nexport interface ImageBlock {\n type: 'image';\n source: ImageSource;\n mimeType: string;\n width?: number;\n height?: number;\n}\n\n/**\n * Audio content block\n */\nexport interface AudioBlock {\n type: 'audio';\n data: Uint8Array;\n mimeType: string;\n duration?: number;\n}\n\n/**\n * Video content block\n */\nexport interface VideoBlock {\n type: 'video';\n data: Uint8Array;\n mimeType: string;\n duration?: number;\n width?: number;\n height?: number;\n}\n\n/**\n * Binary content block for arbitrary data\n */\nexport interface BinaryBlock {\n type: 'binary';\n data: Uint8Array;\n mimeType: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * All content block types\n */\nexport type ContentBlock =\n | TextBlock\n | ImageBlock\n | AudioBlock\n | VideoBlock\n | BinaryBlock;\n\n/**\n * Content types allowed in user messages\n */\nexport type UserContent =\n | TextBlock\n | ImageBlock\n | AudioBlock\n | VideoBlock\n | BinaryBlock;\n\n/**\n * Content types allowed in assistant messages\n */\nexport type AssistantContent =\n | TextBlock\n | ImageBlock\n | AudioBlock\n | VideoBlock;\n\n/**\n * Helper to create a text block\n */\nexport function text(content: string): TextBlock {\n return { type: 'text', text: content };\n}\n\n/**\n * Type guard for TextBlock\n */\nexport function isTextBlock(block: ContentBlock): block is TextBlock {\n return block.type === 'text';\n}\n\n/**\n * Type guard for ImageBlock\n */\nexport function isImageBlock(block: ContentBlock): block is ImageBlock {\n return block.type === 'image';\n}\n\n/**\n * Type guard for AudioBlock\n */\nexport function isAudioBlock(block: ContentBlock): block is AudioBlock {\n return block.type === 'audio';\n}\n\n/**\n * Type guard for VideoBlock\n */\nexport function isVideoBlock(block: ContentBlock): block is VideoBlock {\n return block.type === 'video';\n}\n\n/**\n * Type guard for BinaryBlock\n */\nexport function isBinaryBlock(block: ContentBlock): block is BinaryBlock {\n return block.type === 'binary';\n}\n","import { generateId } from '../utils/id.ts';\nimport {\n Message,\n UserMessage,\n AssistantMessage,\n ToolResultMessage,\n} from './messages.ts';\nimport type { MessageType, MessageMetadata } from './messages.ts';\nimport type { ContentBlock, UserContent, AssistantContent } from './content.ts';\nimport type { Turn } from './turn.ts';\nimport type { ToolCall, ToolResult } from './tool.ts';\n\n/**\n * Serialized message format\n */\nexport interface MessageJSON {\n id: string;\n type: MessageType;\n content: ContentBlock[];\n toolCalls?: ToolCall[];\n results?: ToolResult[];\n metadata?: MessageMetadata;\n timestamp: string;\n}\n\n/**\n * Serialized thread format\n */\nexport interface ThreadJSON {\n id: string;\n messages: MessageJSON[];\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Thread - A utility class for managing conversation history\n * Users control their own history; Thread is optional\n */\nexport class Thread {\n /** Unique thread identifier */\n readonly id: string;\n\n /** Internal message storage */\n private _messages: Message[];\n\n /** Creation timestamp */\n private _createdAt: Date;\n\n /** Last update timestamp */\n private _updatedAt: Date;\n\n /**\n * Create a new thread, optionally with initial messages\n */\n constructor(messages?: Message[]) {\n this.id = generateId();\n this._messages = messages ? [...messages] : [];\n this._createdAt = new Date();\n this._updatedAt = new Date();\n }\n\n /** All messages in the thread (readonly) */\n get messages(): readonly Message[] {\n return this._messages;\n }\n\n /** Number of messages */\n get length(): number {\n return this._messages.length;\n }\n\n /**\n * Append messages from a turn\n */\n append(turn: Turn): this {\n this._messages.push(...turn.messages);\n this._updatedAt = new Date();\n return this;\n }\n\n /**\n * Add raw messages\n */\n push(...messages: Message[]): this {\n this._messages.push(...messages);\n this._updatedAt = new Date();\n return this;\n }\n\n /**\n * Add a user message\n */\n user(content: string | UserContent[]): this {\n this._messages.push(new UserMessage(content));\n this._updatedAt = new Date();\n return this;\n }\n\n /**\n * Add an assistant message\n */\n assistant(content: string | AssistantContent[]): this {\n this._messages.push(new AssistantMessage(content));\n this._updatedAt = new Date();\n return this;\n }\n\n /**\n * Get messages by type\n */\n filter(type: MessageType): Message[] {\n return this._messages.filter((m) => m.type === type);\n }\n\n /**\n * Get the last N messages\n */\n tail(count: number): Message[] {\n return this._messages.slice(-count);\n }\n\n /**\n * Create a new thread with a subset of messages\n */\n slice(start?: number, end?: number): Thread {\n return new Thread(this._messages.slice(start, end));\n }\n\n /**\n * Clear all messages\n */\n clear(): this {\n this._messages = [];\n this._updatedAt = new Date();\n return this;\n }\n\n /**\n * Convert to plain message array\n */\n toMessages(): Message[] {\n return [...this._messages];\n }\n\n /**\n * Serialize to JSON\n */\n toJSON(): ThreadJSON {\n return {\n id: this.id,\n messages: this._messages.map((m) => this.messageToJSON(m)),\n createdAt: this._createdAt.toISOString(),\n updatedAt: this._updatedAt.toISOString(),\n };\n }\n\n /**\n * Deserialize from JSON\n */\n static fromJSON(json: ThreadJSON): Thread {\n const messages = json.messages.map((m) => Thread.messageFromJSON(m));\n const thread = new Thread(messages);\n // Override the generated id with the serialized one\n (thread as { id: string }).id = json.id;\n thread._createdAt = new Date(json.createdAt);\n thread._updatedAt = new Date(json.updatedAt);\n return thread;\n }\n\n /**\n * Iterate over messages\n */\n [Symbol.iterator](): Iterator<Message> {\n return this._messages[Symbol.iterator]();\n }\n\n /**\n * Convert a message to JSON\n */\n private messageToJSON(m: Message): MessageJSON {\n const base: MessageJSON = {\n id: m.id,\n type: m.type,\n content: [],\n metadata: m.metadata,\n timestamp: m.timestamp.toISOString(),\n };\n\n if (m instanceof UserMessage) {\n base.content = m.content;\n } else if (m instanceof AssistantMessage) {\n base.content = m.content;\n base.toolCalls = m.toolCalls;\n } else if (m instanceof ToolResultMessage) {\n base.results = m.results;\n }\n\n return base;\n }\n\n /**\n * Reconstruct a message from JSON\n */\n private static messageFromJSON(json: MessageJSON): Message {\n const options = {\n id: json.id,\n metadata: json.metadata,\n };\n\n switch (json.type) {\n case 'user':\n return new UserMessage(json.content as UserContent[], options);\n case 'assistant':\n return new AssistantMessage(\n json.content as AssistantContent[],\n json.toolCalls,\n options\n );\n case 'tool_result':\n return new ToolResultMessage(json.results ?? [], options);\n default:\n throw new Error(`Unknown message type: ${json.type}`);\n }\n }\n}\n","// Core entry points\nexport { llm } from './core/llm.ts';\nexport { createProvider } from './core/provider.ts';\nexport { Image } from './core/image.ts';\n\n// Namespace object for alternative import style\nimport { llm } from './core/llm.ts';\n\n/**\n * UPP namespace object\n * Provides ai.llm(), ai.embedding(), ai.image() style access\n */\nexport const ai = {\n llm,\n // embedding, // Coming soon\n // image, // Coming soon\n};\n\n// Re-export all types from types/index.ts\nexport * from './types/index.ts';\n\n// Re-export HTTP utilities\nexport {\n RoundRobinKeys,\n WeightedKeys,\n DynamicKey,\n ExponentialBackoff,\n LinearBackoff,\n NoRetry,\n TokenBucket,\n RetryAfterStrategy,\n} from './http/index.ts';\n"],"mappings":"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","names":["text","newMessages"]}
|
package/package.json
CHANGED
package/src/core/llm.ts
CHANGED
|
@@ -23,7 +23,11 @@ import {
|
|
|
23
23
|
isAssistantMessage,
|
|
24
24
|
} from '../types/messages.ts';
|
|
25
25
|
import { createTurn, aggregateUsage, emptyUsage } from '../types/turn.ts';
|
|
26
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
createStreamResult,
|
|
28
|
+
toolExecutionStart,
|
|
29
|
+
toolExecutionEnd,
|
|
30
|
+
} from '../types/stream.ts';
|
|
27
31
|
import { generateShortId } from '../utils/id.ts';
|
|
28
32
|
|
|
29
33
|
/**
|
|
@@ -413,14 +417,21 @@ function executeStream<TParams>(
|
|
|
413
417
|
);
|
|
414
418
|
}
|
|
415
419
|
|
|
416
|
-
// Execute tools
|
|
420
|
+
// Execute tools with event emission
|
|
421
|
+
const toolEvents: StreamEvent[] = [];
|
|
417
422
|
const results = await executeTools(
|
|
418
423
|
response.message,
|
|
419
424
|
tools,
|
|
420
425
|
toolStrategy,
|
|
421
|
-
toolExecutions
|
|
426
|
+
toolExecutions,
|
|
427
|
+
(event) => toolEvents.push(event)
|
|
422
428
|
);
|
|
423
429
|
|
|
430
|
+
// Yield tool execution events
|
|
431
|
+
for (const event of toolEvents) {
|
|
432
|
+
yield event;
|
|
433
|
+
}
|
|
434
|
+
|
|
424
435
|
// Add tool results
|
|
425
436
|
allMessages.push(new ToolResultMessage(results));
|
|
426
437
|
|
|
@@ -467,7 +478,8 @@ async function executeTools(
|
|
|
467
478
|
message: AssistantMessage,
|
|
468
479
|
tools: Tool[],
|
|
469
480
|
toolStrategy: LLMOptions<unknown>['toolStrategy'],
|
|
470
|
-
executions: ToolExecution[]
|
|
481
|
+
executions: ToolExecution[],
|
|
482
|
+
onEvent?: (event: StreamEvent) => void
|
|
471
483
|
): Promise<ToolResult[]> {
|
|
472
484
|
const toolCalls = message.toolCalls ?? [];
|
|
473
485
|
const results: ToolResult[] = [];
|
|
@@ -476,7 +488,7 @@ async function executeTools(
|
|
|
476
488
|
const toolMap = new Map(tools.map((t) => [t.name, t]));
|
|
477
489
|
|
|
478
490
|
// Execute tools (in parallel)
|
|
479
|
-
const promises = toolCalls.map(async (call) => {
|
|
491
|
+
const promises = toolCalls.map(async (call, index) => {
|
|
480
492
|
const tool = toolMap.get(call.toolName);
|
|
481
493
|
if (!tool) {
|
|
482
494
|
return {
|
|
@@ -488,6 +500,9 @@ async function executeTools(
|
|
|
488
500
|
|
|
489
501
|
const startTime = Date.now();
|
|
490
502
|
|
|
503
|
+
// Emit start event
|
|
504
|
+
onEvent?.(toolExecutionStart(call.toolCallId, tool.name, startTime, index));
|
|
505
|
+
|
|
491
506
|
// Notify strategy
|
|
492
507
|
await toolStrategy?.onToolCall?.(tool, call.arguments);
|
|
493
508
|
|
|
@@ -495,6 +510,8 @@ async function executeTools(
|
|
|
495
510
|
if (toolStrategy?.onBeforeCall) {
|
|
496
511
|
const shouldRun = await toolStrategy.onBeforeCall(tool, call.arguments);
|
|
497
512
|
if (!shouldRun) {
|
|
513
|
+
const endTime = Date.now();
|
|
514
|
+
onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, 'Tool execution skipped', true, endTime, index));
|
|
498
515
|
return {
|
|
499
516
|
toolCallId: call.toolCallId,
|
|
500
517
|
result: 'Tool execution skipped',
|
|
@@ -515,17 +532,20 @@ async function executeTools(
|
|
|
515
532
|
}
|
|
516
533
|
|
|
517
534
|
if (!approved) {
|
|
535
|
+
const endTime = Date.now();
|
|
518
536
|
const execution: ToolExecution = {
|
|
519
537
|
toolName: tool.name,
|
|
520
538
|
toolCallId: call.toolCallId,
|
|
521
539
|
arguments: call.arguments,
|
|
522
540
|
result: 'Tool execution denied',
|
|
523
541
|
isError: true,
|
|
524
|
-
duration:
|
|
542
|
+
duration: endTime - startTime,
|
|
525
543
|
approved: false,
|
|
526
544
|
};
|
|
527
545
|
executions.push(execution);
|
|
528
546
|
|
|
547
|
+
onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, 'Tool execution denied by approval handler', true, endTime, index));
|
|
548
|
+
|
|
529
549
|
return {
|
|
530
550
|
toolCallId: call.toolCallId,
|
|
531
551
|
result: 'Tool execution denied by approval handler',
|
|
@@ -536,6 +556,7 @@ async function executeTools(
|
|
|
536
556
|
// Execute tool
|
|
537
557
|
try {
|
|
538
558
|
const result = await tool.run(call.arguments);
|
|
559
|
+
const endTime = Date.now();
|
|
539
560
|
|
|
540
561
|
await toolStrategy?.onAfterCall?.(tool, call.arguments, result);
|
|
541
562
|
|
|
@@ -545,17 +566,20 @@ async function executeTools(
|
|
|
545
566
|
arguments: call.arguments,
|
|
546
567
|
result,
|
|
547
568
|
isError: false,
|
|
548
|
-
duration:
|
|
569
|
+
duration: endTime - startTime,
|
|
549
570
|
approved,
|
|
550
571
|
};
|
|
551
572
|
executions.push(execution);
|
|
552
573
|
|
|
574
|
+
onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, result, false, endTime, index));
|
|
575
|
+
|
|
553
576
|
return {
|
|
554
577
|
toolCallId: call.toolCallId,
|
|
555
578
|
result,
|
|
556
579
|
isError: false,
|
|
557
580
|
};
|
|
558
581
|
} catch (error) {
|
|
582
|
+
const endTime = Date.now();
|
|
559
583
|
await toolStrategy?.onError?.(tool, call.arguments, error as Error);
|
|
560
584
|
|
|
561
585
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -566,11 +590,13 @@ async function executeTools(
|
|
|
566
590
|
arguments: call.arguments,
|
|
567
591
|
result: errorMessage,
|
|
568
592
|
isError: true,
|
|
569
|
-
duration:
|
|
593
|
+
duration: endTime - startTime,
|
|
570
594
|
approved,
|
|
571
595
|
};
|
|
572
596
|
executions.push(execution);
|
|
573
597
|
|
|
598
|
+
onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, errorMessage, true, endTime, index));
|
|
599
|
+
|
|
574
600
|
return {
|
|
575
601
|
toolCallId: call.toolCallId,
|
|
576
602
|
result: errorMessage,
|
package/src/types/stream.ts
CHANGED
|
@@ -10,6 +10,8 @@ export type StreamEventType =
|
|
|
10
10
|
| 'audio_delta'
|
|
11
11
|
| 'video_delta'
|
|
12
12
|
| 'tool_call_delta'
|
|
13
|
+
| 'tool_execution_start'
|
|
14
|
+
| 'tool_execution_end'
|
|
13
15
|
| 'message_start'
|
|
14
16
|
| 'message_stop'
|
|
15
17
|
| 'content_block_start'
|
|
@@ -24,6 +26,12 @@ export interface EventDelta {
|
|
|
24
26
|
toolCallId?: string;
|
|
25
27
|
toolName?: string;
|
|
26
28
|
argumentsJson?: string;
|
|
29
|
+
/** Tool execution result (for tool_execution_end) */
|
|
30
|
+
result?: unknown;
|
|
31
|
+
/** Whether tool execution errored (for tool_execution_end) */
|
|
32
|
+
isError?: boolean;
|
|
33
|
+
/** Timestamp in ms (for tool_execution_start/end) */
|
|
34
|
+
timestamp?: number;
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
/**
|
|
@@ -144,3 +152,37 @@ export function contentBlockStop(index: number): StreamEvent {
|
|
|
144
152
|
delta: {},
|
|
145
153
|
};
|
|
146
154
|
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Create a tool execution start event
|
|
158
|
+
*/
|
|
159
|
+
export function toolExecutionStart(
|
|
160
|
+
toolCallId: string,
|
|
161
|
+
toolName: string,
|
|
162
|
+
timestamp: number,
|
|
163
|
+
index = 0
|
|
164
|
+
): StreamEvent {
|
|
165
|
+
return {
|
|
166
|
+
type: 'tool_execution_start',
|
|
167
|
+
index,
|
|
168
|
+
delta: { toolCallId, toolName, timestamp },
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Create a tool execution end event
|
|
174
|
+
*/
|
|
175
|
+
export function toolExecutionEnd(
|
|
176
|
+
toolCallId: string,
|
|
177
|
+
toolName: string,
|
|
178
|
+
result: unknown,
|
|
179
|
+
isError: boolean,
|
|
180
|
+
timestamp: number,
|
|
181
|
+
index = 0
|
|
182
|
+
): StreamEvent {
|
|
183
|
+
return {
|
|
184
|
+
type: 'tool_execution_end',
|
|
185
|
+
index,
|
|
186
|
+
delta: { toolCallId, toolName, result, isError, timestamp },
|
|
187
|
+
};
|
|
188
|
+
}
|