content.go

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