@providerprotocol/ai 0.0.1
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/LICENSE +21 -0
- package/README.md +84 -0
- package/dist/anthropic/index.d.ts +41 -0
- package/dist/anthropic/index.js +500 -0
- package/dist/anthropic/index.js.map +1 -0
- package/dist/chunk-CUCRF5W6.js +136 -0
- package/dist/chunk-CUCRF5W6.js.map +1 -0
- package/dist/chunk-FTFX2VET.js +424 -0
- package/dist/chunk-FTFX2VET.js.map +1 -0
- package/dist/chunk-QUUX4G7U.js +117 -0
- package/dist/chunk-QUUX4G7U.js.map +1 -0
- package/dist/chunk-Y6Q7JCNP.js +39 -0
- package/dist/chunk-Y6Q7JCNP.js.map +1 -0
- package/dist/google/index.d.ts +69 -0
- package/dist/google/index.js +517 -0
- package/dist/google/index.js.map +1 -0
- package/dist/http/index.d.ts +61 -0
- package/dist/http/index.js +43 -0
- package/dist/http/index.js.map +1 -0
- package/dist/index.d.ts +792 -0
- package/dist/index.js +898 -0
- package/dist/index.js.map +1 -0
- package/dist/openai/index.d.ts +204 -0
- package/dist/openai/index.js +1340 -0
- package/dist/openai/index.js.map +1 -0
- package/dist/provider-CUJWjgNl.d.ts +192 -0
- package/dist/retry-I2661_rv.d.ts +118 -0
- package/package.json +88 -0
- package/src/anthropic/index.ts +3 -0
- package/src/core/image.ts +188 -0
- package/src/core/llm.ts +619 -0
- package/src/core/provider.ts +92 -0
- package/src/google/index.ts +3 -0
- package/src/http/errors.ts +112 -0
- package/src/http/fetch.ts +210 -0
- package/src/http/index.ts +31 -0
- package/src/http/keys.ts +136 -0
- package/src/http/retry.ts +205 -0
- package/src/http/sse.ts +136 -0
- package/src/index.ts +32 -0
- package/src/openai/index.ts +9 -0
- package/src/providers/anthropic/index.ts +17 -0
- package/src/providers/anthropic/llm.ts +196 -0
- package/src/providers/anthropic/transform.ts +452 -0
- package/src/providers/anthropic/types.ts +213 -0
- package/src/providers/google/index.ts +17 -0
- package/src/providers/google/llm.ts +203 -0
- package/src/providers/google/transform.ts +487 -0
- package/src/providers/google/types.ts +214 -0
- package/src/providers/openai/index.ts +151 -0
- package/src/providers/openai/llm.completions.ts +201 -0
- package/src/providers/openai/llm.responses.ts +211 -0
- package/src/providers/openai/transform.completions.ts +628 -0
- package/src/providers/openai/transform.responses.ts +718 -0
- package/src/providers/openai/types.ts +711 -0
- package/src/types/content.ts +133 -0
- package/src/types/errors.ts +85 -0
- package/src/types/index.ts +105 -0
- package/src/types/llm.ts +211 -0
- package/src/types/messages.ts +182 -0
- package/src/types/provider.ts +195 -0
- package/src/types/schema.ts +58 -0
- package/src/types/stream.ts +146 -0
- package/src/types/thread.ts +226 -0
- package/src/types/tool.ts +88 -0
- package/src/types/turn.ts +118 -0
- package/src/utils/id.ts +28 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content block types for messages
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Image source types
|
|
7
|
+
*/
|
|
8
|
+
export type ImageSource =
|
|
9
|
+
| { type: 'base64'; data: string }
|
|
10
|
+
| { type: 'url'; url: string }
|
|
11
|
+
| { type: 'bytes'; data: Uint8Array };
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Text content block
|
|
15
|
+
*/
|
|
16
|
+
export interface TextBlock {
|
|
17
|
+
type: 'text';
|
|
18
|
+
text: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Image content block
|
|
23
|
+
*/
|
|
24
|
+
export interface ImageBlock {
|
|
25
|
+
type: 'image';
|
|
26
|
+
source: ImageSource;
|
|
27
|
+
mimeType: string;
|
|
28
|
+
width?: number;
|
|
29
|
+
height?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Audio content block
|
|
34
|
+
*/
|
|
35
|
+
export interface AudioBlock {
|
|
36
|
+
type: 'audio';
|
|
37
|
+
data: Uint8Array;
|
|
38
|
+
mimeType: string;
|
|
39
|
+
duration?: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Video content block
|
|
44
|
+
*/
|
|
45
|
+
export interface VideoBlock {
|
|
46
|
+
type: 'video';
|
|
47
|
+
data: Uint8Array;
|
|
48
|
+
mimeType: string;
|
|
49
|
+
duration?: number;
|
|
50
|
+
width?: number;
|
|
51
|
+
height?: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Binary content block for arbitrary data
|
|
56
|
+
*/
|
|
57
|
+
export interface BinaryBlock {
|
|
58
|
+
type: 'binary';
|
|
59
|
+
data: Uint8Array;
|
|
60
|
+
mimeType: string;
|
|
61
|
+
metadata?: Record<string, unknown>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* All content block types
|
|
66
|
+
*/
|
|
67
|
+
export type ContentBlock =
|
|
68
|
+
| TextBlock
|
|
69
|
+
| ImageBlock
|
|
70
|
+
| AudioBlock
|
|
71
|
+
| VideoBlock
|
|
72
|
+
| BinaryBlock;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Content types allowed in user messages
|
|
76
|
+
*/
|
|
77
|
+
export type UserContent =
|
|
78
|
+
| TextBlock
|
|
79
|
+
| ImageBlock
|
|
80
|
+
| AudioBlock
|
|
81
|
+
| VideoBlock
|
|
82
|
+
| BinaryBlock;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Content types allowed in assistant messages
|
|
86
|
+
*/
|
|
87
|
+
export type AssistantContent =
|
|
88
|
+
| TextBlock
|
|
89
|
+
| ImageBlock
|
|
90
|
+
| AudioBlock
|
|
91
|
+
| VideoBlock;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Helper to create a text block
|
|
95
|
+
*/
|
|
96
|
+
export function text(content: string): TextBlock {
|
|
97
|
+
return { type: 'text', text: content };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Type guard for TextBlock
|
|
102
|
+
*/
|
|
103
|
+
export function isTextBlock(block: ContentBlock): block is TextBlock {
|
|
104
|
+
return block.type === 'text';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Type guard for ImageBlock
|
|
109
|
+
*/
|
|
110
|
+
export function isImageBlock(block: ContentBlock): block is ImageBlock {
|
|
111
|
+
return block.type === 'image';
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Type guard for AudioBlock
|
|
116
|
+
*/
|
|
117
|
+
export function isAudioBlock(block: ContentBlock): block is AudioBlock {
|
|
118
|
+
return block.type === 'audio';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Type guard for VideoBlock
|
|
123
|
+
*/
|
|
124
|
+
export function isVideoBlock(block: ContentBlock): block is VideoBlock {
|
|
125
|
+
return block.type === 'video';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Type guard for BinaryBlock
|
|
130
|
+
*/
|
|
131
|
+
export function isBinaryBlock(block: ContentBlock): block is BinaryBlock {
|
|
132
|
+
return block.type === 'binary';
|
|
133
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UPP Error Codes
|
|
3
|
+
* Normalized error codes for cross-provider error handling
|
|
4
|
+
*/
|
|
5
|
+
export type ErrorCode =
|
|
6
|
+
| 'AUTHENTICATION_FAILED'
|
|
7
|
+
| 'RATE_LIMITED'
|
|
8
|
+
| 'CONTEXT_LENGTH_EXCEEDED'
|
|
9
|
+
| 'MODEL_NOT_FOUND'
|
|
10
|
+
| 'INVALID_REQUEST'
|
|
11
|
+
| 'INVALID_RESPONSE'
|
|
12
|
+
| 'CONTENT_FILTERED'
|
|
13
|
+
| 'QUOTA_EXCEEDED'
|
|
14
|
+
| 'PROVIDER_ERROR'
|
|
15
|
+
| 'NETWORK_ERROR'
|
|
16
|
+
| 'TIMEOUT'
|
|
17
|
+
| 'CANCELLED';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Modality types supported by UPP
|
|
21
|
+
*/
|
|
22
|
+
export type Modality = 'llm' | 'embedding' | 'image' | 'audio' | 'video';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Unified Provider Protocol Error
|
|
26
|
+
* All provider errors are normalized to this type
|
|
27
|
+
*/
|
|
28
|
+
export class UPPError extends Error {
|
|
29
|
+
readonly code: ErrorCode;
|
|
30
|
+
readonly provider: string;
|
|
31
|
+
readonly modality: Modality;
|
|
32
|
+
readonly statusCode?: number;
|
|
33
|
+
override readonly cause?: Error;
|
|
34
|
+
|
|
35
|
+
override readonly name = 'UPPError';
|
|
36
|
+
|
|
37
|
+
constructor(
|
|
38
|
+
message: string,
|
|
39
|
+
code: ErrorCode,
|
|
40
|
+
provider: string,
|
|
41
|
+
modality: Modality,
|
|
42
|
+
statusCode?: number,
|
|
43
|
+
cause?: Error
|
|
44
|
+
) {
|
|
45
|
+
super(message);
|
|
46
|
+
this.code = code;
|
|
47
|
+
this.provider = provider;
|
|
48
|
+
this.modality = modality;
|
|
49
|
+
this.statusCode = statusCode;
|
|
50
|
+
this.cause = cause;
|
|
51
|
+
|
|
52
|
+
// Maintain proper stack trace in V8 environments
|
|
53
|
+
if (Error.captureStackTrace) {
|
|
54
|
+
Error.captureStackTrace(this, UPPError);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Create a string representation of the error
|
|
60
|
+
*/
|
|
61
|
+
override toString(): string {
|
|
62
|
+
let str = `UPPError [${this.code}]: ${this.message}`;
|
|
63
|
+
str += ` (provider: ${this.provider}, modality: ${this.modality}`;
|
|
64
|
+
if (this.statusCode) {
|
|
65
|
+
str += `, status: ${this.statusCode}`;
|
|
66
|
+
}
|
|
67
|
+
str += ')';
|
|
68
|
+
return str;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Convert to JSON for serialization
|
|
73
|
+
*/
|
|
74
|
+
toJSON(): Record<string, unknown> {
|
|
75
|
+
return {
|
|
76
|
+
name: this.name,
|
|
77
|
+
message: this.message,
|
|
78
|
+
code: this.code,
|
|
79
|
+
provider: this.provider,
|
|
80
|
+
modality: this.modality,
|
|
81
|
+
statusCode: this.statusCode,
|
|
82
|
+
cause: this.cause?.message,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Error types
|
|
2
|
+
export { UPPError, type ErrorCode, type Modality } from './errors.ts';
|
|
3
|
+
|
|
4
|
+
// Schema types
|
|
5
|
+
export type {
|
|
6
|
+
JSONSchema,
|
|
7
|
+
JSONSchemaProperty,
|
|
8
|
+
JSONSchemaPropertyType,
|
|
9
|
+
} from './schema.ts';
|
|
10
|
+
|
|
11
|
+
// Content block types
|
|
12
|
+
export type {
|
|
13
|
+
ContentBlock,
|
|
14
|
+
TextBlock,
|
|
15
|
+
ImageBlock,
|
|
16
|
+
AudioBlock,
|
|
17
|
+
VideoBlock,
|
|
18
|
+
BinaryBlock,
|
|
19
|
+
ImageSource,
|
|
20
|
+
UserContent,
|
|
21
|
+
AssistantContent,
|
|
22
|
+
} from './content.ts';
|
|
23
|
+
export {
|
|
24
|
+
text,
|
|
25
|
+
isTextBlock,
|
|
26
|
+
isImageBlock,
|
|
27
|
+
isAudioBlock,
|
|
28
|
+
isVideoBlock,
|
|
29
|
+
isBinaryBlock,
|
|
30
|
+
} from './content.ts';
|
|
31
|
+
|
|
32
|
+
// Tool types
|
|
33
|
+
export type {
|
|
34
|
+
Tool,
|
|
35
|
+
ToolCall,
|
|
36
|
+
ToolResult,
|
|
37
|
+
ToolUseStrategy,
|
|
38
|
+
ToolExecution,
|
|
39
|
+
} from './tool.ts';
|
|
40
|
+
|
|
41
|
+
// Message types
|
|
42
|
+
export {
|
|
43
|
+
Message,
|
|
44
|
+
UserMessage,
|
|
45
|
+
AssistantMessage,
|
|
46
|
+
ToolResultMessage,
|
|
47
|
+
isUserMessage,
|
|
48
|
+
isAssistantMessage,
|
|
49
|
+
isToolResultMessage,
|
|
50
|
+
} from './messages.ts';
|
|
51
|
+
export type { MessageType, MessageMetadata, MessageOptions } from './messages.ts';
|
|
52
|
+
|
|
53
|
+
// Turn types
|
|
54
|
+
export type { Turn, TokenUsage } from './turn.ts';
|
|
55
|
+
export { createTurn, emptyUsage, aggregateUsage } from './turn.ts';
|
|
56
|
+
|
|
57
|
+
// Thread types
|
|
58
|
+
export { Thread } from './thread.ts';
|
|
59
|
+
export type { ThreadJSON, MessageJSON } from './thread.ts';
|
|
60
|
+
|
|
61
|
+
// Stream types
|
|
62
|
+
export type {
|
|
63
|
+
StreamEvent,
|
|
64
|
+
StreamEventType,
|
|
65
|
+
EventDelta,
|
|
66
|
+
StreamResult,
|
|
67
|
+
} from './stream.ts';
|
|
68
|
+
export {
|
|
69
|
+
createStreamResult,
|
|
70
|
+
textDelta,
|
|
71
|
+
toolCallDelta,
|
|
72
|
+
messageStart,
|
|
73
|
+
messageStop,
|
|
74
|
+
contentBlockStart,
|
|
75
|
+
contentBlockStop,
|
|
76
|
+
} from './stream.ts';
|
|
77
|
+
|
|
78
|
+
// Provider types
|
|
79
|
+
export type {
|
|
80
|
+
Provider,
|
|
81
|
+
ModelReference,
|
|
82
|
+
ProviderConfig,
|
|
83
|
+
KeyStrategy,
|
|
84
|
+
RetryStrategy,
|
|
85
|
+
LLMProvider,
|
|
86
|
+
EmbeddingProvider,
|
|
87
|
+
ImageProvider,
|
|
88
|
+
EmbeddingHandler,
|
|
89
|
+
ImageHandler,
|
|
90
|
+
BoundEmbeddingModel,
|
|
91
|
+
BoundImageModel,
|
|
92
|
+
} from './provider.ts';
|
|
93
|
+
|
|
94
|
+
// LLM types
|
|
95
|
+
export type {
|
|
96
|
+
LLMOptions,
|
|
97
|
+
LLMInstance,
|
|
98
|
+
LLMCapabilities,
|
|
99
|
+
LLMRequest,
|
|
100
|
+
LLMResponse,
|
|
101
|
+
LLMStreamResult,
|
|
102
|
+
BoundLLMModel,
|
|
103
|
+
LLMHandler,
|
|
104
|
+
InferenceInput,
|
|
105
|
+
} from './llm.ts';
|
package/src/types/llm.ts
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import type { Message, AssistantMessage } from './messages.ts';
|
|
2
|
+
import type { ContentBlock } from './content.ts';
|
|
3
|
+
import type { Tool, ToolUseStrategy } from './tool.ts';
|
|
4
|
+
import type { JSONSchema } from './schema.ts';
|
|
5
|
+
import type { Turn, TokenUsage } from './turn.ts';
|
|
6
|
+
import type { StreamEvent, StreamResult } from './stream.ts';
|
|
7
|
+
import type {
|
|
8
|
+
ModelReference,
|
|
9
|
+
ProviderConfig,
|
|
10
|
+
LLMProvider,
|
|
11
|
+
} from './provider.ts';
|
|
12
|
+
import type { Thread } from './thread.ts';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* LLMCapabilities declares what the provider's API supports, not individual model capabilities.
|
|
16
|
+
* If a user attempts to use a feature with a model that doesn't support it,
|
|
17
|
+
* the provider's API will return an error—this is expected behavior.
|
|
18
|
+
*
|
|
19
|
+
* Capabilities are static - they are constant for the lifetime of the provider instance
|
|
20
|
+
* and do not vary per-request or per-model.
|
|
21
|
+
*/
|
|
22
|
+
export interface LLMCapabilities {
|
|
23
|
+
/** Provider API supports streaming responses */
|
|
24
|
+
streaming: boolean;
|
|
25
|
+
|
|
26
|
+
/** Provider API supports tool/function calling */
|
|
27
|
+
tools: boolean;
|
|
28
|
+
|
|
29
|
+
/** Provider API supports native structured output (JSON schema) */
|
|
30
|
+
structuredOutput: boolean;
|
|
31
|
+
|
|
32
|
+
/** Provider API supports image input */
|
|
33
|
+
imageInput: boolean;
|
|
34
|
+
|
|
35
|
+
/** Provider API supports video input */
|
|
36
|
+
videoInput: boolean;
|
|
37
|
+
|
|
38
|
+
/** Provider API supports audio input */
|
|
39
|
+
audioInput: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Input types for inference
|
|
44
|
+
*/
|
|
45
|
+
export type InferenceInput = string | Message | ContentBlock;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Options for llm() function
|
|
49
|
+
*/
|
|
50
|
+
export interface LLMOptions<TParams = unknown> {
|
|
51
|
+
/** A model reference from a provider factory */
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
|
+
model: ModelReference<any>;
|
|
54
|
+
|
|
55
|
+
/** Provider infrastructure configuration (optional - uses env vars if omitted) */
|
|
56
|
+
config?: ProviderConfig;
|
|
57
|
+
|
|
58
|
+
/** Model-specific parameters (temperature, max_tokens, etc.) */
|
|
59
|
+
params?: TParams;
|
|
60
|
+
|
|
61
|
+
/** System prompt for all inferences */
|
|
62
|
+
system?: string;
|
|
63
|
+
|
|
64
|
+
/** Tools available to the model */
|
|
65
|
+
tools?: Tool[];
|
|
66
|
+
|
|
67
|
+
/** Tool execution strategy */
|
|
68
|
+
toolStrategy?: ToolUseStrategy;
|
|
69
|
+
|
|
70
|
+
/** Structured output schema (JSON Schema) */
|
|
71
|
+
structure?: JSONSchema;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* LLM instance returned by llm()
|
|
76
|
+
*/
|
|
77
|
+
export interface LLMInstance<TParams = unknown> {
|
|
78
|
+
/**
|
|
79
|
+
* Execute inference and return complete Turn
|
|
80
|
+
*
|
|
81
|
+
* @overload No history - single input
|
|
82
|
+
* generate(input: InferenceInput): Promise<Turn>
|
|
83
|
+
*
|
|
84
|
+
* @overload No history - multiple inputs
|
|
85
|
+
* generate(...inputs: InferenceInput[]): Promise<Turn>
|
|
86
|
+
*
|
|
87
|
+
* @overload With history
|
|
88
|
+
* generate(history: Message[] | Thread, ...inputs: InferenceInput[]): Promise<Turn>
|
|
89
|
+
*/
|
|
90
|
+
generate(
|
|
91
|
+
historyOrInput: Message[] | Thread | InferenceInput,
|
|
92
|
+
...input: InferenceInput[]
|
|
93
|
+
): Promise<Turn>;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Execute streaming inference
|
|
97
|
+
*
|
|
98
|
+
* @overload No history - single input
|
|
99
|
+
* stream(input: InferenceInput): StreamResult
|
|
100
|
+
*
|
|
101
|
+
* @overload No history - multiple inputs
|
|
102
|
+
* stream(...inputs: InferenceInput[]): StreamResult
|
|
103
|
+
*
|
|
104
|
+
* @overload With history
|
|
105
|
+
* stream(history: Message[] | Thread, ...inputs: InferenceInput[]): StreamResult
|
|
106
|
+
*/
|
|
107
|
+
stream(
|
|
108
|
+
historyOrInput: Message[] | Thread | InferenceInput,
|
|
109
|
+
...input: InferenceInput[]
|
|
110
|
+
): StreamResult;
|
|
111
|
+
|
|
112
|
+
/** The bound model */
|
|
113
|
+
readonly model: BoundLLMModel<TParams>;
|
|
114
|
+
|
|
115
|
+
/** Current system prompt */
|
|
116
|
+
readonly system: string | undefined;
|
|
117
|
+
|
|
118
|
+
/** Current parameters */
|
|
119
|
+
readonly params: TParams | undefined;
|
|
120
|
+
|
|
121
|
+
/** Provider API capabilities */
|
|
122
|
+
readonly capabilities: LLMCapabilities;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Request passed from llm() core to providers
|
|
127
|
+
* Note: config is required here because llm() core resolves defaults
|
|
128
|
+
* before passing to providers
|
|
129
|
+
*/
|
|
130
|
+
export interface LLMRequest<TParams = unknown> {
|
|
131
|
+
/** All messages for this request (history + new input) */
|
|
132
|
+
messages: Message[];
|
|
133
|
+
|
|
134
|
+
/** System prompt */
|
|
135
|
+
system?: string;
|
|
136
|
+
|
|
137
|
+
/** Model-specific parameters (passed through unchanged) */
|
|
138
|
+
params?: TParams;
|
|
139
|
+
|
|
140
|
+
/** Tools available for this request */
|
|
141
|
+
tools?: Tool[];
|
|
142
|
+
|
|
143
|
+
/** Structured output schema (if requested) */
|
|
144
|
+
structure?: JSONSchema;
|
|
145
|
+
|
|
146
|
+
/** Provider infrastructure config (resolved by llm() core) */
|
|
147
|
+
config: ProviderConfig;
|
|
148
|
+
|
|
149
|
+
/** Abort signal for cancellation */
|
|
150
|
+
signal?: AbortSignal;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Raw provider response (single cycle, no tool loop)
|
|
155
|
+
*/
|
|
156
|
+
export interface LLMResponse {
|
|
157
|
+
message: AssistantMessage;
|
|
158
|
+
usage: TokenUsage;
|
|
159
|
+
stopReason: string;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Structured output data extracted by the provider.
|
|
163
|
+
* Present when a structure schema was requested and the provider
|
|
164
|
+
* successfully extracted the data (via tool call or native JSON mode).
|
|
165
|
+
* Providers handle their own extraction logic - core just uses this value.
|
|
166
|
+
*/
|
|
167
|
+
data?: unknown;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Raw provider stream result
|
|
172
|
+
*/
|
|
173
|
+
export interface LLMStreamResult extends AsyncIterable<StreamEvent> {
|
|
174
|
+
readonly response: Promise<LLMResponse>;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Bound LLM model - full definition
|
|
179
|
+
*/
|
|
180
|
+
export interface BoundLLMModel<TParams = unknown> {
|
|
181
|
+
/** The model identifier */
|
|
182
|
+
readonly modelId: string;
|
|
183
|
+
|
|
184
|
+
/** Reference to the parent provider */
|
|
185
|
+
readonly provider: LLMProvider<TParams>;
|
|
186
|
+
|
|
187
|
+
/** Provider API capabilities */
|
|
188
|
+
readonly capabilities: LLMCapabilities;
|
|
189
|
+
|
|
190
|
+
/** Execute a single non-streaming inference request */
|
|
191
|
+
complete(request: LLMRequest<TParams>): Promise<LLMResponse>;
|
|
192
|
+
|
|
193
|
+
/** Execute a single streaming inference request */
|
|
194
|
+
stream(request: LLMRequest<TParams>): LLMStreamResult;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* LLM Handler for providers
|
|
199
|
+
*/
|
|
200
|
+
export interface LLMHandler<TParams = unknown> {
|
|
201
|
+
/** Bind model ID to create executable model */
|
|
202
|
+
bind(modelId: string): BoundLLMModel<TParams>;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Internal: Set the parent provider reference.
|
|
206
|
+
* Called by createProvider() after the provider is constructed.
|
|
207
|
+
* This allows bind() to return models with the correct provider reference.
|
|
208
|
+
* @internal
|
|
209
|
+
*/
|
|
210
|
+
_setProvider?(provider: LLMProvider<TParams>): void;
|
|
211
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { generateId } from '../utils/id.ts';
|
|
2
|
+
import type {
|
|
3
|
+
ContentBlock,
|
|
4
|
+
TextBlock,
|
|
5
|
+
UserContent,
|
|
6
|
+
AssistantContent,
|
|
7
|
+
isTextBlock,
|
|
8
|
+
} from './content.ts';
|
|
9
|
+
import type { ToolCall, ToolResult } from './tool.ts';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Message type discriminator
|
|
13
|
+
*/
|
|
14
|
+
export type MessageType = 'user' | 'assistant' | 'tool_result';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Provider-namespaced metadata
|
|
18
|
+
* Each provider uses its own namespace
|
|
19
|
+
*/
|
|
20
|
+
export interface MessageMetadata {
|
|
21
|
+
[provider: string]: Record<string, unknown> | undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Options for message construction
|
|
26
|
+
*/
|
|
27
|
+
export interface MessageOptions {
|
|
28
|
+
id?: string;
|
|
29
|
+
metadata?: MessageMetadata;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Base message class
|
|
34
|
+
* All messages inherit from this
|
|
35
|
+
*/
|
|
36
|
+
export abstract class Message {
|
|
37
|
+
/** Unique message identifier */
|
|
38
|
+
readonly id: string;
|
|
39
|
+
|
|
40
|
+
/** Timestamp */
|
|
41
|
+
readonly timestamp: Date;
|
|
42
|
+
|
|
43
|
+
/** Provider-specific metadata, namespaced by provider */
|
|
44
|
+
readonly metadata?: MessageMetadata;
|
|
45
|
+
|
|
46
|
+
/** Message type discriminator */
|
|
47
|
+
abstract readonly type: MessageType;
|
|
48
|
+
|
|
49
|
+
/** Raw content - implemented by subclasses */
|
|
50
|
+
protected abstract getContent(): ContentBlock[];
|
|
51
|
+
|
|
52
|
+
constructor(options?: MessageOptions) {
|
|
53
|
+
this.id = options?.id ?? generateId();
|
|
54
|
+
this.timestamp = new Date();
|
|
55
|
+
this.metadata = options?.metadata;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Convenience accessor for text content
|
|
60
|
+
* Concatenates all text blocks with '\n\n'
|
|
61
|
+
*/
|
|
62
|
+
get text(): string {
|
|
63
|
+
return this.getContent()
|
|
64
|
+
.filter((block): block is TextBlock => block.type === 'text')
|
|
65
|
+
.map((block) => block.text)
|
|
66
|
+
.join('\n\n');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* User input message
|
|
72
|
+
*/
|
|
73
|
+
export class UserMessage extends Message {
|
|
74
|
+
readonly type = 'user' as const;
|
|
75
|
+
readonly content: UserContent[];
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param content - String (converted to TextBlock) or array of content blocks
|
|
79
|
+
*/
|
|
80
|
+
constructor(content: string | UserContent[], options?: MessageOptions) {
|
|
81
|
+
super(options);
|
|
82
|
+
if (typeof content === 'string') {
|
|
83
|
+
this.content = [{ type: 'text', text: content }];
|
|
84
|
+
} else {
|
|
85
|
+
this.content = content;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
protected getContent(): ContentBlock[] {
|
|
90
|
+
return this.content;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Assistant response message
|
|
96
|
+
* May contain text, media, and/or tool calls
|
|
97
|
+
*/
|
|
98
|
+
export class AssistantMessage extends Message {
|
|
99
|
+
readonly type = 'assistant' as const;
|
|
100
|
+
readonly content: AssistantContent[];
|
|
101
|
+
|
|
102
|
+
/** Tool calls requested by the model (if any) */
|
|
103
|
+
readonly toolCalls?: ToolCall[];
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @param content - String (converted to TextBlock) or array of content blocks
|
|
107
|
+
* @param toolCalls - Tool calls requested by the model
|
|
108
|
+
* @param options - Message ID and metadata
|
|
109
|
+
*/
|
|
110
|
+
constructor(
|
|
111
|
+
content: string | AssistantContent[],
|
|
112
|
+
toolCalls?: ToolCall[],
|
|
113
|
+
options?: MessageOptions
|
|
114
|
+
) {
|
|
115
|
+
super(options);
|
|
116
|
+
if (typeof content === 'string') {
|
|
117
|
+
this.content = [{ type: 'text', text: content }];
|
|
118
|
+
} else {
|
|
119
|
+
this.content = content;
|
|
120
|
+
}
|
|
121
|
+
this.toolCalls = toolCalls;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
protected getContent(): ContentBlock[] {
|
|
125
|
+
return this.content;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Check if this message requests tool execution */
|
|
129
|
+
get hasToolCalls(): boolean {
|
|
130
|
+
return this.toolCalls !== undefined && this.toolCalls.length > 0;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Result of tool execution (sent back to model)
|
|
136
|
+
*/
|
|
137
|
+
export class ToolResultMessage extends Message {
|
|
138
|
+
readonly type = 'tool_result' as const;
|
|
139
|
+
readonly results: ToolResult[];
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @param results - Array of tool execution results
|
|
143
|
+
* @param options - Message ID and metadata
|
|
144
|
+
*/
|
|
145
|
+
constructor(results: ToolResult[], options?: MessageOptions) {
|
|
146
|
+
super(options);
|
|
147
|
+
this.results = results;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
protected getContent(): ContentBlock[] {
|
|
151
|
+
// Tool results don't have traditional content blocks
|
|
152
|
+
// Return text representations of results
|
|
153
|
+
return this.results.map((result) => ({
|
|
154
|
+
type: 'text' as const,
|
|
155
|
+
text:
|
|
156
|
+
typeof result.result === 'string'
|
|
157
|
+
? result.result
|
|
158
|
+
: JSON.stringify(result.result),
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Type guard for UserMessage
|
|
165
|
+
*/
|
|
166
|
+
export function isUserMessage(msg: Message): msg is UserMessage {
|
|
167
|
+
return msg.type === 'user';
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Type guard for AssistantMessage
|
|
172
|
+
*/
|
|
173
|
+
export function isAssistantMessage(msg: Message): msg is AssistantMessage {
|
|
174
|
+
return msg.type === 'assistant';
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Type guard for ToolResultMessage
|
|
179
|
+
*/
|
|
180
|
+
export function isToolResultMessage(msg: Message): msg is ToolResultMessage {
|
|
181
|
+
return msg.type === 'tool_result';
|
|
182
|
+
}
|