role

package
v0.56.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 24, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package role is a convenience facade that presents an interaction as a business-typed, composable Deployment: New wraps an interaction with input and output adapters, composing the canonical workflow and interaction atoms into one plain agent.Deployment. It adds no execution, working context, or persistence of its own, so the result stays composable like any other.

role is the sanctioned composition tier: unlike the strategies, which never import one another, role may depend on the specific strategies it adapts.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrInvalidConfig = errors.New("role: invalid config")

Functions

func New

func New[I, O any](config Config[I, O]) (agent.Deployment, error)

New composes the role into one ordinary agent.Deployment with an I -> O contract, reusing the canonical workflow and interaction atoms.

Example
package main

import (
	"context"
	jsonv2 "encoding/json/v2"
	"errors"
	"fmt"

	agent "github.com/Tangerg/scope/agent"
	"github.com/Tangerg/scope/agent/strategy/interaction"
	"github.com/Tangerg/scope/agent/strategy/role"
	"github.com/Tangerg/scope/core/chat"
	"github.com/Tangerg/scope/core/chatclient"
)

func main() {
	format := chatclient.JSON[greeting]()
	greeter := exampleValue(role.New(role.Config[greetRequest, greeting]{
		Name: "example.greeter", Description: "Greet a caller by name.",
		Interaction: greetDeployment(),
		BuildInput: func(_ context.Context, req greetRequest) (interaction.Input, error) {
			data, err := jsonv2.Marshal(req)
			if err != nil {
				return interaction.Input{}, err
			}
			return interaction.Input{Messages: []chat.Message{chat.NewUserMessage(chat.NewTextPart(string(data)))}}, nil
		},
		DecodeOutput: func(_ context.Context, output interaction.Output) (greeting, error) {
			return format.Decode(output.ModelResponse)
		},
		Budget:               agent.Budget{Steps: agent.NewQuota(16), Effects: agent.NewQuota(16), Signals: agent.NewQuota(16)},
		ImplementationDigest: agent.ComputeDigest([]byte("example-greeter")),
		ConfigurationDigest:  agent.ComputeDigest([]byte("example-greeter-config")),
	}))

	ctx := context.Background()
	engine := exampleValue(agent.NewEngine(agent.EngineConfig{TreeCommitter: agent.NewMemoryTreeCommitter()}))
	defer func() {
		if err := engine.Close(ctx); err != nil {
			panic(err)
		}
	}()
	process := exampleValue(engine.Start(ctx, greeter, exampleValue(agent.EncodePayload(greetRequest{Name: "ada"}))))
	result := exampleValue(process.Await(ctx))
	output, _ := result.Termination().Output()
	fmt.Println(exampleValue(output.Decode[greeting]()).Message)
}

type greetRequest struct {
	Name string `json:"name"`
}

type greeting struct {
	Message string `json:"message"`
}

type greetModel struct{}

func (greetModel) Call(_ context.Context, request *chat.Request) (*chat.Response, error) {
	var req greetRequest
	if err := jsonv2.Unmarshal([]byte(request.Messages[len(request.Messages)-1].Text()), &req); err != nil || req.Name == "" {
		return nil, errors.New("greet model received an invalid request")
	}
	data, err := jsonv2.Marshal(greeting{Message: "hi " + req.Name})
	if err != nil {
		return nil, err
	}
	message := chat.NewAssistantMessage(chat.NewTextPart(string(data)))
	return chat.NewResponse(&chat.Output{Message: &message, FinishReason: chat.FinishReasonStop}, nil)
}

func greetDeployment() agent.Deployment {
	client := exampleValue(chatclient.New(greetModel{}, chatclient.Config{}))
	definition := exampleValue(interaction.NewDefinition(interaction.DefinitionConfig{
		Name: "example.greet", Description: "Produce a greeting from the request.", MaxModelCalls: agent.NewQuota(1),
	}))
	dispatcher := exampleValue(interaction.NewDispatcher(definition, interaction.DispatcherConfig{Model: client}))
	return exampleValue(agent.NewDeployment(agent.DeploymentConfig{
		Definition: definition, Dispatcher: dispatcher,
		ImplementationDigest: agent.ComputeDigest([]byte("example-greet")),
		ConfigurationDigest:  agent.ComputeDigest([]byte("example-greet-config")),
	}))
}

func exampleValue[T any](value T, err error) T {
	if err != nil {
		panic(err)
	}
	return value
}
Output:
hi ada

Types

type Config

type Config[I, O any] struct {
	Name        string
	Description string

	Interaction agent.Deployment

	BuildInput func(context.Context, I) (interaction.Input, error)

	// DecodeOutput should reuse an authoritative decode rule, such as
	// [github.com/Tangerg/scope/core/chatclient.OutputFormat.Decode], so the role
	// does not grow a second, weaker structured-output rule.
	DecodeOutput func(context.Context, interaction.Output) (O, error)

	Budget agent.Budget

	ImplementationDigest agent.Digest
	ConfigurationDigest  agent.Digest
}

Config binds one interaction to a business input and output through pure adapters; the interaction, not role, owns the model-and-tool loop.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL