Documentation
¶
Overview ¶
Package chatclient provides direct, optional conveniences around the minimal chat protocols and model capabilities defined by Core. Client.Output applies a provider-neutral OutputFormat and strictly decodes naturally completed text; a caller that already holds a response, such as a managed Agent, reuses that one decode rule through Format.Decode without another model call. Other completion reasons remain identifiable as OutputCompletionError. Typed output has only a terminal value; callers that need transport deltas use StreamClient.Stream with a required streaming dependency. Scope-driven tool batches and continuations use the Agent runtime; direct model calls never dispatch local tools.
Example ¶
package main
import (
"context"
"fmt"
"github.com/Tangerg/scope/core/chat"
"github.com/Tangerg/scope/core/chatclient"
)
func main() {
model := chat.ModelFunc(func(context.Context, *chat.Request) (*chat.Response, error) {
return textResponse("Hello from the model"), nil
})
client, err := chatclient.New(model, chatclient.Config{})
if err != nil {
panic(err)
}
request, err := chat.NewRequest(chat.NewUserMessage(chat.NewTextPart("Hello")))
if err != nil {
panic(err)
}
request.Options.Model = "example"
response, err := client.Call(context.Background(), request)
if err != nil {
panic(err)
}
fmt.Println(response.Text())
}
func textResponse(text string) *chat.Response {
message := chat.NewAssistantMessage(chat.NewTextPart(text))
return &chat.Response{Output: &chat.Output{
Message: &message,
FinishReason: chat.FinishReasonStop,
}}
}
Output: Hello from the model
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrNilModel = errors.New("chatclient: nil model") ErrInvalidClient = errors.New("chatclient: uninitialized client") )
var ( ErrInvalidOutputFormat = errors.New("chatclient: invalid output format") ErrInvalidOutput = errors.New("chatclient: invalid output") )
var ErrInvalidTemplate = errors.New("chatclient: invalid template")
var ErrNilStreamer = errors.New("chatclient: nil streamer")
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is an immutable composition of a chat model and its middleware. It is as safe for concurrent use as the underlying model. Streaming has its own construction boundary in StreamClient.
func (Client) Output ¶
Output asks the provider to enforce format, then strictly decodes naturally completed text. Refusal and other non-successful completion reasons return OutputCompletionError. Media and tool requests cannot become typed values. Output never repairs JSON or injects format instructions into the prompt.
Example ¶
package main
import (
"context"
"fmt"
"github.com/Tangerg/scope/core/chat"
"github.com/Tangerg/scope/core/chatclient"
)
func main() {
type answer struct {
Value int `json:"value"`
}
model := chat.ModelFunc(func(context.Context, *chat.Request) (*chat.Response, error) {
return textResponse(`{"value":42}`), nil
})
client, err := chatclient.New(model, chatclient.Config{})
if err != nil {
panic(err)
}
request, err := chat.NewRequest(chat.NewUserMessage(chat.NewTextPart("What is six times seven?")))
if err != nil {
panic(err)
}
result, err := client.Output(context.Background(), request, chatclient.JSON[answer]())
if err != nil {
panic(err)
}
fmt.Println(result.Value)
}
func textResponse(text string) *chat.Response {
message := chat.NewAssistantMessage(chat.NewTextPart(text))
return &chat.Response{Output: &chat.Output{
Message: &message,
FinishReason: chat.FinishReasonStop,
}}
}
Output: 42
type Config ¶
type Config struct {
CallMiddleware []chat.CallMiddleware
}
Config supplies synchronous middleware. The first entry is the outermost wrapper. New consumes the slice during construction and does not retain it.
type Format ¶ added in v0.59.0
type Format[T any] struct { // contains filtered or unexported fields }
Format couples a provider-neutral request contract with the decoder for its complete response. Pass one to Client.Output, or call its Decode on a response obtained elsewhere so every caller shares one decode rule.
func JSON ¶
JSON selects provider-native JSON output and rejects unknown object members when decoding T.
func JSONSchema ¶
func JSONSchema[T any](config JSONSchemaConfig) (Format[T], error)
func (Format[T]) Contract ¶ added in v0.59.0
func (f Format[T]) Contract() chat.OutputFormat
The compiled schema owns both request bytes and response admission; a retained wire copy could drift from the decoder's contract.
func (Format[T]) Decode ¶ added in v0.59.0
Decode decodes an already-obtained response into T under the same rule as Client.Output, without a model call, so a caller that already holds a response, such as a managed Agent, reuses one structured-output rule instead of a weaker copy.
type JSONSchemaConfig ¶ added in v0.13.0
type OutputCompletionError ¶ added in v0.15.0
type OutputCompletionError struct {
FinishReason chat.FinishReason
Refusal string
}
OutputCompletionError preserves a provider outcome that cannot become the requested typed value. It unwraps to ErrInvalidOutput; callers may inspect FinishReason and Refusal without parsing an error message.
func (*OutputCompletionError) Error ¶ added in v0.15.0
func (o *OutputCompletionError) Error() string
func (*OutputCompletionError) Unwrap ¶ added in v0.15.0
func (*OutputCompletionError) Unwrap() error
type StreamClient ¶ added in v0.17.0
type StreamClient struct {
// contains filtered or unexported fields
}
StreamClient owns a required streaming capability and its middleware chain. It is immutable; concurrent use requires a concurrency-safe Streamer. It does not implement chat.Model or require an unused synchronous capability.
func NewStreamClient ¶ added in v0.17.0
func NewStreamClient(streamer chat.Streamer, config StreamConfig) (StreamClient, error)
func (StreamClient) Stream ¶ added in v0.17.0
func (s StreamClient) Stream(ctx context.Context, request *chat.Request) iter.Seq2[*chat.ResponseDelta, error]
Stream snapshots the request at invocation. Provider work remains lazy until iteration; stopping iteration synchronously releases the provider resources.
Example ¶
package main
import (
"context"
"fmt"
"iter"
"github.com/Tangerg/scope/core/chat"
"github.com/Tangerg/scope/core/chatclient"
)
func main() {
streamer := chat.StreamerFunc(func(context.Context, *chat.Request) iter.Seq2[*chat.ResponseDelta, error] {
return func(yield func(*chat.ResponseDelta, error) bool) {
if !yield(delta("Hello ", ""), nil) {
return
}
yield(delta("stream", chat.FinishReasonStop), nil)
}
})
client, err := chatclient.NewStreamClient(streamer, chatclient.StreamConfig{})
if err != nil {
panic(err)
}
request, err := chat.NewRequest(chat.NewUserMessage(chat.NewTextPart("Hello")))
if err != nil {
panic(err)
}
for response, streamErr := range client.Stream(context.Background(), request) {
if streamErr != nil {
panic(streamErr)
}
fmt.Print(response.Text())
}
fmt.Println()
}
func delta(text string, reason chat.FinishReason) *chat.ResponseDelta {
return &chat.ResponseDelta{Parts: []chat.PartDelta{chat.NewTextDelta(text)}, FinishReason: reason}
}
Output: Hello stream
type StreamConfig ¶ added in v0.17.0
type StreamConfig struct {
Middleware []chat.StreamMiddleware
}
StreamConfig supplies streaming middleware. The first entry is the outermost wrapper. NewStreamClient consumes the slice without retaining it.
type Template ¶
type Template struct {
// contains filtered or unexported fields
}
Template is an immutable, parsed prompt template safe for concurrent use. Rendering fails on missing map keys instead of emitting placeholder text.
Example ¶
package main
import (
"fmt"
"github.com/Tangerg/scope/core/chatclient"
)
func main() {
prompt, err := chatclient.ParseTemplate("Explain {{.Topic}} in one sentence.")
if err != nil {
panic(err)
}
message, err := prompt.UserMessage(struct{ Topic string }{Topic: "Go interfaces"})
if err != nil {
panic(err)
}
fmt.Println(message.Text())
}
Output: Explain Go interfaces in one sentence.
func ParseTemplate ¶
ParseTemplate compiles an immutable prompt template from a non-empty source. It rejects a blank source and any parse error, and configures rendering to fail on a missing map key rather than emit placeholder text.
func (*Template) Require ¶
Require counts reachable static field references that retain the Render input's identity across scopes and called templates. It follows break and continue; conditional references count without promising that each Render evaluates them. Computed lookups and function-returned aliases are not inferred.