content.go

  1package fantasy
  2
  3import (
  4	"context"
  5	"encoding/json"
  6)
  7
  8// ProviderOptionsData is an interface for provider-specific options data.
  9// All implementations MUST also implement encoding/json.Marshaler and
 10// encoding/json.Unmarshaler interfaces to ensure proper JSON serialization
 11// with the provider registry system.
 12//
 13// Recommended implementation pattern using generic helpers:
 14//
 15//	// Define type constants at the top of your file
 16//	const TypeMyProviderOptions = "myprovider.options"
 17//
 18//	type MyProviderOptions struct {
 19//	    Field string `json:"field"`
 20//	}
 21//
 22//	// Register the type in init() - place at top of file after constants
 23//	func init() {
 24//	    fantasy.RegisterProviderType(TypeMyProviderOptions, func(data []byte) (fantasy.ProviderOptionsData, error) {
 25//	        var opts MyProviderOptions
 26//	        if err := json.Unmarshal(data, &opts); err != nil {
 27//	            return nil, err
 28//	        }
 29//	        return &opts, nil
 30//	    })
 31//	}
 32//
 33//	// Implement ProviderOptionsData interface
 34//	func (*MyProviderOptions) Options() {}
 35//
 36//	// Implement json.Marshaler using the generic helper
 37//	func (m MyProviderOptions) MarshalJSON() ([]byte, error) {
 38//	    type plain MyProviderOptions
 39//	    return fantasy.MarshalProviderType(TypeMyProviderOptions, plain(m))
 40//	}
 41//
 42//	// Implement json.Unmarshaler using the generic helper
 43//	// Note: Receives inner data after type routing by the registry.
 44//	func (m *MyProviderOptions) UnmarshalJSON(data []byte) error {
 45//	    type plain MyProviderOptions
 46//	    var p plain
 47//	    if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
 48//	        return err
 49//	    }
 50//	    *m = MyProviderOptions(p)
 51//	    return nil
 52//	}
 53type ProviderOptionsData interface {
 54	// Options is a marker method that identifies types implementing this interface.
 55	Options()
 56	json.Marshaler
 57	json.Unmarshaler
 58}
 59
 60// ProviderMetadata represents additional provider-specific metadata.
 61// They are passed through from the provider to the AI SDK and enable
 62// provider-specific results that can be fully encapsulated in the provider.
 63//
 64// The outer map is keyed by the provider name, and the inner
 65// map is keyed by the provider-specific metadata key.
 66//
 67// Example:
 68//
 69//	{
 70//	  "anthropic": {
 71//	    "signature": "sig....."
 72//	  }
 73//	}
 74type ProviderMetadata map[string]ProviderOptionsData
 75
 76// ProviderOptions represents additional provider-specific options.
 77// Options are additional input to the provider. They are passed through
 78// to the provider from the AI SDK and enable provider-specific functionality
 79// that can be fully encapsulated in the provider.
 80//
 81// This enables us to quickly ship provider-specific functionality
 82// without affecting the core AI SDK.
 83//
 84// The outer map is keyed by the provider name, and the inner
 85// map is keyed by the provider-specific option key.
 86//
 87// Example:
 88//
 89//	{
 90//	  "anthropic": {
 91//	    "cacheControl": { "type": "ephemeral" }
 92//	  }
 93//	}
 94type ProviderOptions map[string]ProviderOptionsData
 95
 96// FinishReason represents why a language model finished generating a response.
 97//
 98// Can be one of the following:
 99// - `stop`: model generated stop sequence
100// - `length`: model generated maximum number of tokens
101// - `content-filter`: content filter violation stopped the model
102// - `tool-calls`: model triggered tool calls
103// - `error`: model stopped because of an error
104// - `other`: model stopped for other reasons
105// - `unknown`: the model has not transmitted a finish reason.
106type FinishReason string
107
108const (
109	// FinishReasonStop indicates the model generated a stop sequence.
110	FinishReasonStop FinishReason = "stop" // model generated stop sequence
111	// FinishReasonLength indicates the model generated maximum number of tokens.
112	FinishReasonLength FinishReason = "length" // model generated maximum number of tokens
113	// FinishReasonContentFilter indicates content filter violation stopped the model.
114	FinishReasonContentFilter FinishReason = "content-filter" // content filter violation stopped the model
115	// FinishReasonToolCalls indicates the model triggered tool calls.
116	FinishReasonToolCalls FinishReason = "tool-calls" // model triggered tool calls
117	// FinishReasonError indicates the model stopped because of an error.
118	FinishReasonError FinishReason = "error" // model stopped because of an error
119	// FinishReasonOther indicates the model stopped for other reasons.
120	FinishReasonOther FinishReason = "other" // model stopped for other reasons
121	// FinishReasonUnknown indicates the model has not transmitted a finish reason.
122	FinishReasonUnknown FinishReason = "unknown" // the model has not transmitted a finish reason
123)
124
125// Prompt represents a list of messages for the language model.
126type Prompt []Message
127
128// MessageRole represents the role of a message.
129type MessageRole string
130
131const (
132	// MessageRoleSystem represents a system message.
133	MessageRoleSystem MessageRole = "system"
134	// MessageRoleUser represents a user message.
135	MessageRoleUser MessageRole = "user"
136	// MessageRoleAssistant represents an assistant message.
137	MessageRoleAssistant MessageRole = "assistant"
138	// MessageRoleTool represents a tool message.
139	MessageRoleTool MessageRole = "tool"
140)
141
142// Message represents a message in a prompt.
143type Message struct {
144	Role            MessageRole     `json:"role"`
145	Content         []MessagePart   `json:"content"`
146	ProviderOptions ProviderOptions `json:"provider_options"`
147}
148
149// AsContentType converts a Content interface to a specific content type.
150func AsContentType[T Content](content Content) (T, bool) {
151	var zero T
152	if content == nil {
153		return zero, false
154	}
155	switch v := any(content).(type) {
156	case T:
157		return v, true
158	case *T:
159		return *v, true
160	default:
161		return zero, false
162	}
163}
164
165// AsMessagePart converts a MessagePart interface to a specific message part type.
166func AsMessagePart[T MessagePart](content MessagePart) (T, bool) {
167	var zero T
168	if content == nil {
169		return zero, false
170	}
171	switch v := any(content).(type) {
172	case T:
173		return v, true
174	case *T:
175		return *v, true
176	default:
177		return zero, false
178	}
179}
180
181// MessagePart represents a part of a message content.
182type MessagePart interface {
183	GetType() ContentType
184	Options() ProviderOptions
185}
186
187// TextPart represents text content in a message.
188type TextPart struct {
189	Text            string          `json:"text"`
190	ProviderOptions ProviderOptions `json:"provider_options"`
191}
192
193// GetType returns the type of the text part.
194func (t TextPart) GetType() ContentType {
195	return ContentTypeText
196}
197
198// Options returns the provider options for the text part.
199func (t TextPart) Options() ProviderOptions {
200	return t.ProviderOptions
201}
202
203// ReasoningPart represents reasoning content in a message.
204type ReasoningPart struct {
205	Text            string          `json:"text"`
206	ProviderOptions ProviderOptions `json:"provider_options"`
207}
208
209// GetType returns the type of the reasoning part.
210func (r ReasoningPart) GetType() ContentType {
211	return ContentTypeReasoning
212}
213
214// Options returns the provider options for the reasoning part.
215func (r ReasoningPart) Options() ProviderOptions {
216	return r.ProviderOptions
217}
218
219// FilePart represents file content in a message.
220type FilePart struct {
221	Filename        string          `json:"filename"`
222	Data            []byte          `json:"data"`
223	MediaType       string          `json:"media_type"`
224	ProviderOptions ProviderOptions `json:"provider_options"`
225}
226
227// GetType returns the type of the file part.
228func (f FilePart) GetType() ContentType {
229	return ContentTypeFile
230}
231
232// Options returns the provider options for the file part.
233func (f FilePart) Options() ProviderOptions {
234	return f.ProviderOptions
235}
236
237// ToolCallPart represents a tool call in a message.
238type ToolCallPart struct {
239	ToolCallID       string          `json:"tool_call_id"`
240	ToolName         string          `json:"tool_name"`
241	Input            string          `json:"input"` // the json string
242	ProviderExecuted bool            `json:"provider_executed"`
243	ProviderOptions  ProviderOptions `json:"provider_options"`
244}
245
246// GetType returns the type of the tool call part.
247func (t ToolCallPart) GetType() ContentType {
248	return ContentTypeToolCall
249}
250
251// Options returns the provider options for the tool call part.
252func (t ToolCallPart) Options() ProviderOptions {
253	return t.ProviderOptions
254}
255
256// ToolResultPart represents a tool result in a message.
257type ToolResultPart struct {
258	ToolCallID       string                  `json:"tool_call_id"`
259	Output           ToolResultOutputContent `json:"output"`
260	ProviderExecuted bool                    `json:"provider_executed"`
261	ProviderOptions  ProviderOptions         `json:"provider_options"`
262}
263
264// GetType returns the type of the tool result part.
265func (t ToolResultPart) GetType() ContentType {
266	return ContentTypeToolResult
267}
268
269// Options returns the provider options for the tool result part.
270func (t ToolResultPart) Options() ProviderOptions {
271	return t.ProviderOptions
272}
273
274// ToolResultContentType represents the type of tool result output.
275type ToolResultContentType string
276
277const (
278	// ToolResultContentTypeText represents text output.
279	ToolResultContentTypeText ToolResultContentType = "text"
280	// ToolResultContentTypeError represents error text output.
281	ToolResultContentTypeError ToolResultContentType = "error"
282	// ToolResultContentTypeMedia represents content output.
283	ToolResultContentTypeMedia ToolResultContentType = "media"
284)
285
286// ToolResultOutputContent represents the output content of a tool result.
287type ToolResultOutputContent interface {
288	GetType() ToolResultContentType
289}
290
291// ToolResultOutputContentText represents text output content of a tool result.
292type ToolResultOutputContentText struct {
293	Text string `json:"text"`
294}
295
296// GetType returns the type of the tool result output content text.
297func (t ToolResultOutputContentText) GetType() ToolResultContentType {
298	return ToolResultContentTypeText
299}
300
301// ToolResultOutputContentError represents error output content of a tool result.
302type ToolResultOutputContentError struct {
303	Error error `json:"error"`
304}
305
306// GetType returns the type of the tool result output content error.
307func (t ToolResultOutputContentError) GetType() ToolResultContentType {
308	return ToolResultContentTypeError
309}
310
311// ToolResultOutputContentMedia represents media output content of a tool result.
312type ToolResultOutputContentMedia struct {
313	Data      string `json:"data"`           // for media type (base64)
314	MediaType string `json:"media_type"`     // for media type
315	Text      string `json:"text,omitempty"` // optional text content accompanying the media
316}
317
318// GetType returns the type of the tool result output content media.
319func (t ToolResultOutputContentMedia) GetType() ToolResultContentType {
320	return ToolResultContentTypeMedia
321}
322
323// AsToolResultOutputType converts a ToolResultOutputContent interface to a specific type.
324func AsToolResultOutputType[T ToolResultOutputContent](content ToolResultOutputContent) (T, bool) {
325	var zero T
326	if content == nil {
327		return zero, false
328	}
329	switch v := any(content).(type) {
330	case T:
331		return v, true
332	case *T:
333		return *v, true
334	default:
335		return zero, false
336	}
337}
338
339// ContentType represents the type of content.
340type ContentType string
341
342const (
343	// ContentTypeText represents text content.
344	ContentTypeText ContentType = "text"
345	// ContentTypeReasoning represents reasoning content.
346	ContentTypeReasoning ContentType = "reasoning"
347	// ContentTypeFile represents file content.
348	ContentTypeFile ContentType = "file"
349	// ContentTypeSource represents source content.
350	ContentTypeSource ContentType = "source"
351	// ContentTypeToolCall represents a tool call.
352	ContentTypeToolCall ContentType = "tool-call"
353	// ContentTypeToolResult represents a tool result.
354	ContentTypeToolResult ContentType = "tool-result"
355)
356
357// Content represents generated content from the model.
358type Content interface {
359	GetType() ContentType
360}
361
362// TextContent represents text that the model has generated.
363type TextContent struct {
364	// The text content.
365	Text             string           `json:"text"`
366	ProviderMetadata ProviderMetadata `json:"provider_metadata"`
367}
368
369// GetType returns the type of the text content.
370func (t TextContent) GetType() ContentType {
371	return ContentTypeText
372}
373
374// ReasoningContent represents reasoning that the model has generated.
375type ReasoningContent struct {
376	Text             string           `json:"text"`
377	ProviderMetadata ProviderMetadata `json:"provider_metadata"`
378}
379
380// GetType returns the type of the reasoning content.
381func (r ReasoningContent) GetType() ContentType {
382	return ContentTypeReasoning
383}
384
385// FileContent represents a file that has been generated by the model.
386// Generated files as base64 encoded strings or binary data.
387// The files should be returned without any unnecessary conversion.
388type FileContent struct {
389	// The IANA media type of the file, e.g. `image/png` or `audio/mp3`.
390	// @see https://www.iana.org/assignments/media-types/media-types.xhtml
391	MediaType string `json:"media_type"`
392	// Generated file data as binary data.
393	Data             []byte           `json:"data"`
394	ProviderMetadata ProviderMetadata `json:"provider_metadata"`
395}
396
397// GetType returns the type of the file content.
398func (f FileContent) GetType() ContentType {
399	return ContentTypeFile
400}
401
402// SourceType represents the type of source.
403type SourceType string
404
405const (
406	// SourceTypeURL represents a URL source.
407	SourceTypeURL SourceType = "url"
408	// SourceTypeDocument represents a document source.
409	SourceTypeDocument SourceType = "document"
410)
411
412// SourceContent represents a source that has been used as input to generate the response.
413type SourceContent struct {
414	SourceType       SourceType       `json:"source_type"` // "url" or "document"
415	ID               string           `json:"id"`
416	URL              string           `json:"url"` // for URL sources
417	Title            string           `json:"title"`
418	MediaType        string           `json:"media_type"` // for document sources (IANA media type)
419	Filename         string           `json:"filename"`   // for document sources
420	ProviderMetadata ProviderMetadata `json:"provider_metadata"`
421}
422
423// GetType returns the type of the source content.
424func (s SourceContent) GetType() ContentType {
425	return ContentTypeSource
426}
427
428// ToolCallContent represents tool calls that the model has generated.
429type ToolCallContent struct {
430	ToolCallID string `json:"tool_call_id"`
431	ToolName   string `json:"tool_name"`
432	// Stringified JSON object with the tool call arguments.
433	// Must match the parameters schema of the tool.
434	Input string `json:"input"`
435	// Whether the tool call will be executed by the provider.
436	// If this flag is not set or is false, the tool call will be executed by the client.
437	ProviderExecuted bool `json:"provider_executed"`
438	// Additional provider-specific metadata for the tool call.
439	ProviderMetadata ProviderMetadata `json:"provider_metadata"`
440	// Whether this tool call is invalid (failed validation/parsing)
441	Invalid bool `json:"invalid,omitempty"`
442	// Error that occurred during validation/parsing (only set if Invalid is true)
443	ValidationError error `json:"validation_error,omitempty"`
444}
445
446// GetType returns the type of the tool call content.
447func (t ToolCallContent) GetType() ContentType {
448	return ContentTypeToolCall
449}
450
451// ToolResultContent represents result of a tool call that has been executed by the provider.
452type ToolResultContent struct {
453	// The ID of the tool call that this result is associated with.
454	ToolCallID string `json:"tool_call_id"`
455	// Name of the tool that generated this result.
456	ToolName string `json:"tool_name"`
457	// Result of the tool call. This is a JSON-serializable object.
458	Result         ToolResultOutputContent `json:"result"`
459	ClientMetadata string                  `json:"client_metadata"` // Metadata from the client that executed the tool
460	// Whether the tool result was generated by the provider.
461	// If this flag is set to true, the tool result was generated by the provider.
462	// If this flag is not set or is false, the tool result was generated by the client.
463	ProviderExecuted bool `json:"provider_executed"`
464	// Additional provider-specific metadata for the tool result.
465	ProviderMetadata ProviderMetadata `json:"provider_metadata"`
466}
467
468// GetType returns the type of the tool result content.
469func (t ToolResultContent) GetType() ContentType {
470	return ContentTypeToolResult
471}
472
473// ToolType represents the type of tool.
474type ToolType string
475
476const (
477	// ToolTypeFunction represents a function tool.
478	ToolTypeFunction ToolType = "function"
479	// ToolTypeProviderDefined represents a provider-defined tool.
480	ToolTypeProviderDefined ToolType = "provider-defined"
481)
482
483// Tool represents a tool that can be used by the model.
484//
485// Note: this is **not** the user-facing tool definition. The AI SDK methods will
486// map the user-facing tool definitions to this format.
487type Tool interface {
488	GetType() ToolType
489	GetName() string
490}
491
492// FunctionTool represents a function tool.
493//
494// A tool has a name, a description, and a set of parameters.
495type FunctionTool struct {
496	// Name of the tool. Unique within this model call.
497	Name string `json:"name"`
498	// Description of the tool. The language model uses this to understand the
499	// tool's purpose and to provide better completion suggestions.
500	Description string `json:"description"`
501	// InputSchema - the parameters that the tool expects. The language model uses this to
502	// understand the tool's input requirements and to provide matching suggestions.
503	InputSchema map[string]any `json:"input_schema"` // JSON Schema
504	// ProviderOptions are provider-specific options for the tool.
505	ProviderOptions ProviderOptions `json:"provider_options"`
506}
507
508// GetType returns the type of the function tool.
509func (f FunctionTool) GetType() ToolType {
510	return ToolTypeFunction
511}
512
513// GetName returns the name of the function tool.
514func (f FunctionTool) GetName() string {
515	return f.Name
516}
517
518// ProviderTool is a tool whose schema and wire format are defined by
519// the model provider. Both pure provider-executed tools
520// (ProviderDefinedTool) and client-executed provider tools
521// (ExecutableProviderTool) implement this interface. The unexported
522// method seals this interface to the types in this package.
523// External packages should use NewExecutableProviderTool instead.
524type ProviderTool interface {
525	providerDefinedTool() ProviderDefinedTool
526}
527
528// ProviderDefinedTool represents the configuration of a tool that is defined by the provider.
529type ProviderDefinedTool struct {
530	// ID of the tool. Should follow the format `<provider-name>.<unique-tool-name>`.
531	ID string `json:"id"`
532	// Name of the tool that the user must use in the tool set.
533	Name string `json:"name"`
534	// Args for configuring the tool. Must match the expected arguments defined by the provider for this tool.
535	Args map[string]any `json:"args"`
536}
537
538// GetType returns the type of the provider-defined tool.
539func (p ProviderDefinedTool) GetType() ToolType {
540	return ToolTypeProviderDefined
541}
542
543// GetName returns the name of the provider-defined tool.
544func (p ProviderDefinedTool) GetName() string {
545	return p.Name
546}
547
548func (p ProviderDefinedTool) providerDefinedTool() ProviderDefinedTool {
549	return p
550}
551
552// ExecutableProviderTool pairs a ProviderDefinedTool with a
553// client-side execution function. Use this for provider-defined tools
554// that require local execution (e.g. Anthropic computer use). Register
555// it via WithProviderDefinedTools.
556type ExecutableProviderTool struct {
557	pdt ProviderDefinedTool
558	run func(ctx context.Context, call ToolCall) (ToolResponse, error)
559}
560
561func (e ExecutableProviderTool) providerDefinedTool() ProviderDefinedTool {
562	return e.pdt
563}
564
565// GetType returns the type of the underlying ProviderDefinedTool.
566func (e ExecutableProviderTool) GetType() ToolType {
567	return e.pdt.GetType()
568}
569
570// GetName returns the name of the underlying ProviderDefinedTool.
571func (e ExecutableProviderTool) GetName() string {
572	return e.pdt.GetName()
573}
574
575// Definition returns the underlying ProviderDefinedTool.
576func (e ExecutableProviderTool) Definition() ProviderDefinedTool {
577	return e.pdt
578}
579
580// Run executes the tool's client-side function.
581func (e ExecutableProviderTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error) {
582	return e.run(ctx, call)
583}
584
585// NewExecutableProviderTool creates a provider-defined tool with
586// client-side execution. The tool is sent to the API using the
587// provider's native wire format, but executed locally by run.
588func NewExecutableProviderTool(
589	pdt ProviderDefinedTool,
590	run func(ctx context.Context, call ToolCall) (ToolResponse, error),
591) ExecutableProviderTool {
592	return ExecutableProviderTool{pdt: pdt, run: run}
593}
594
595// NewUserMessage creates a new user message with the given prompt and optional files.
596func NewUserMessage(prompt string, files ...FilePart) Message {
597	content := make([]MessagePart, 0, len(files)+1)
598	content = append(content, TextPart{Text: prompt})
599
600	for _, f := range files {
601		content = append(content, f)
602	}
603
604	return Message{
605		Role:    MessageRoleUser,
606		Content: content,
607	}
608}
609
610// NewSystemMessage creates a new system message with the given prompts.
611func NewSystemMessage(prompt ...string) Message {
612	content := make([]MessagePart, 0, len(prompt))
613	for _, p := range prompt {
614		content = append(content, TextPart{Text: p})
615	}
616
617	return Message{
618		Role:    MessageRoleSystem,
619		Content: content,
620	}
621}