Files
2026-07-13 12:49:10 +08:00

110 lines
4.5 KiB
Go

/*
* Copyright 2024 CloudWeGo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package model
import (
"context"
"github.com/cloudwego/eino/schema"
)
// messageType is the sealed type constraint for message types used in BaseModel.
// Only *schema.Message and *schema.AgenticMessage satisfy this constraint.
type messageType interface {
*schema.Message | *schema.AgenticMessage
}
// BaseModel is the generic base model interface parameterized by message type M.
// It exposes two modes of interaction:
// - [BaseModel.Generate]: blocks until the model returns a complete response.
// - [BaseModel.Stream]: returns a [schema.StreamReader] that yields message
// chunks incrementally as the model generates them.
type BaseModel[M messageType] interface {
Generate(ctx context.Context, input []M, opts ...Option) (M, error)
Stream(ctx context.Context, input []M, opts ...Option) (*schema.StreamReader[M], error)
}
// BaseChatModel is a backward-compatible type alias for BaseModel specialized
// with *schema.Message. All existing code using model.BaseChatModel continues
// to work without modification.
//
// It exposes two modes of interaction:
// - [BaseChatModel.Generate]: blocks until the model returns a complete response.
// - [BaseChatModel.Stream]: returns a [schema.StreamReader] that yields message
// chunks incrementally as the model generates them.
//
// The input is a slice of [schema.Message] representing the conversation history.
// Messages carry a role (system, user, assistant, tool) and support multimodal
// content (text, images, audio, video). Tool messages must include a ToolCallID
// that correlates them with a prior assistant tool-call message.
//
// Stream usage — the caller is responsible for closing the reader:
//
// reader, err := m.Stream(ctx, messages)
// if err != nil { ... }
// defer reader.Close()
// for {
// chunk, err := reader.Recv()
// if errors.Is(err, io.EOF) { break }
// if err != nil { ... }
// // handle chunk
// }
//
// Note: a [schema.StreamReader] can only be read once. If multiple consumers
// need the stream, it must be copied before reading.
//
//go:generate mockgen -destination ../../internal/mock/components/model/ChatModel_mock.go --package model github.com/cloudwego/eino/components/model BaseChatModel,ChatModel,ToolCallingChatModel
type BaseChatModel = BaseModel[*schema.Message]
// Deprecated: Use [ToolCallingChatModel] instead.
//
// ChatModel extends [BaseChatModel] with tool binding via [ChatModel.BindTools].
// BindTools mutates the instance in place, which causes a race condition when
// the same instance is used concurrently: one goroutine's tool list can
// overwrite another's. Prefer [ToolCallingChatModel.WithTools], which returns
// a new immutable instance and is safe for concurrent use.
type ChatModel interface {
BaseChatModel
// BindTools bind tools to the model.
// BindTools before requesting ChatModel generally.
// notice the non-atomic problem of BindTools and Generate.
BindTools(tools []*schema.ToolInfo) error
}
// ToolCallingChatModel extends [BaseChatModel] with safe tool binding.
//
// Unlike the deprecated [ChatModel.BindTools], [ToolCallingChatModel.WithTools]
// does not mutate the receiver — it returns a new instance with the given tools
// attached. This makes it safe to share a base model instance across goroutines
// and derive per-request variants with different tool sets:
//
// base, _ := openai.NewChatModel(ctx, cfg) // shared, no tools
// withSearch, _ := base.WithTools([]*schema.ToolInfo{searchTool})
// withCalc, _ := base.WithTools([]*schema.ToolInfo{calcTool})
type ToolCallingChatModel interface {
BaseChatModel
WithTools(tools []*schema.ToolInfo) (ToolCallingChatModel, error)
}
// AgenticModel is a type alias for BaseModel specialized with
// *schema.AgenticMessage. Unlike ToolCallingChatModel, agentic models do NOT
// expose a WithTools method; tools are passed at request time via the
// model.WithTools option, consistent with how ChatModelAgent binds tools.
type AgenticModel = BaseModel[*schema.AgenticMessage]