Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions pkg/agents/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package agents

import (
"context"
"fmt"

"github.com/COG-GTM/teal-agents/pkg/kernel"
"github.com/COG-GTM/teal-agents/pkg/plugins"
)

type AgentBuilder struct {
kernelBuilder KernelBuilder
authorization string
}

type KernelBuilder interface {
BuildKernel(ctx context.Context, modelName, serviceID string, pluginNames, remotePluginNames []string, auth string, extraCollector plugins.ExtraDataCollector) (kernel.Kernel, error)
GetModelTypeForName(modelName string) kernel.ModelType
ModelSupportsStructuredOutput(modelName string) bool
}

func NewAgentBuilder(kernelBuilder KernelBuilder, authorization string) *AgentBuilder {
return &AgentBuilder{
kernelBuilder: kernelBuilder,
authorization: authorization,
}
}

func (b *AgentBuilder) BuildAgent(ctx context.Context, config AgentConfig, extraCollector plugins.ExtraDataCollector, outputType string) (*SKAgent, error) {
kern, err := b.kernelBuilder.BuildKernel(
ctx,
config.Model,
config.Name,
config.Plugins,
config.RemotePlugins,
b.authorization,
extraCollector,
)
if err != nil {
return nil, fmt.Errorf("failed to build kernel: %w", err)
}

soSupported := b.kernelBuilder.ModelSupportsStructuredOutput(config.Model)

modelType := b.kernelBuilder.GetModelTypeForName(config.Model)

service, err := kern.GetService(config.Name)
if err != nil {
return nil, fmt.Errorf("failed to get service: %w", err)
}

settings := &PromptExecutionSettings{
Temperature: config.Temperature,
FunctionChoiceBehavior: kernel.FunctionChoiceAuto,
}

if soSupported && outputType != "" {
settings.ResponseFormat = outputType
}

agent := &basicChatAgent{
kernel: kern,
service: service,
instructions: config.SystemPrompt,
name: config.Name,
settings: settings,
}

return &SKAgent{
ModelName: config.Model,
ModelType: modelType,
Agent: agent,
SOSupported: soSupported,
ExtraCollector: extraCollector,
}, nil
}

type basicChatAgent struct {
kernel kernel.Kernel
service kernel.ChatCompletionClient
instructions string
name string
settings *PromptExecutionSettings
}

func (a *basicChatAgent) Invoke(ctx context.Context, history *kernel.ChatHistory) (<-chan kernel.ChatMessageContent, error) {
resultChan := make(chan kernel.ChatMessageContent, 1)
close(resultChan)
return resultChan, fmt.Errorf("not implemented yet - to be completed in Session 4")
}

func (a *basicChatAgent) InvokeStream(ctx context.Context, history *kernel.ChatHistory) (<-chan StreamingContent, error) {
resultChan := make(chan StreamingContent, 1)
close(resultChan)
return resultChan, fmt.Errorf("not implemented yet - to be completed in Session 4")
}
44 changes: 44 additions & 0 deletions pkg/agents/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package agents

import (
"context"

"github.com/COG-GTM/teal-agents/pkg/kernel"
"github.com/COG-GTM/teal-agents/pkg/plugins"
)

type SKAgent struct {
ModelName string
ModelType kernel.ModelType
Agent ChatCompletionAgent
SOSupported bool
ExtraCollector plugins.ExtraDataCollector
}

type ChatCompletionAgent interface {
Invoke(ctx context.Context, history *kernel.ChatHistory) (<-chan kernel.ChatMessageContent, error)
InvokeStream(ctx context.Context, history *kernel.ChatHistory) (<-chan StreamingContent, error)
}

type StreamingContent struct {
Content string
Role kernel.AuthorRole
IsComplete bool
FunctionCall *kernel.FunctionCallContent
}

type AgentConfig struct {
Name string `yaml:"name"`
Model string `yaml:"model"`
SystemPrompt string `yaml:"system_prompt"`
Temperature *float64 `yaml:"temperature,omitempty"`
Plugins []string `yaml:"plugins,omitempty"`
RemotePlugins []string `yaml:"remote_plugins,omitempty"`
}

type PromptExecutionSettings struct {
Temperature *float64
MaxTokens *int
FunctionChoiceBehavior kernel.FunctionChoiceBehavior
ResponseFormat interface{}
}
71 changes: 71 additions & 0 deletions pkg/errors/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package errors

import "fmt"

type AgentError struct {
Message string
Cause error
}

func (e *AgentError) Error() string {
if e.Cause != nil {
return fmt.Sprintf("%s: %v", e.Message, e.Cause)
}
return e.Message
}

func (e *AgentError) Unwrap() error {
return e.Cause
}

type AuthenticationError struct {
AgentError
}

func NewAuthenticationError(message string, cause error) *AuthenticationError {
return &AuthenticationError{
AgentError: AgentError{Message: message, Cause: cause},
}
}

type AgentInvokeError struct {
AgentError
}

func NewAgentInvokeError(message string, cause error) *AgentInvokeError {
return &AgentInvokeError{
AgentError: AgentError{Message: message, Cause: cause},
}
}

type PersistenceError struct {
AgentError
}

func NewPersistenceError(message string, cause error) *PersistenceError {
return &PersistenceError{
AgentError: AgentError{Message: message, Cause: cause},
}
}

type ConfigurationError struct {
AgentError
}

func NewConfigurationError(message string, cause error) *ConfigurationError {
return &ConfigurationError{
AgentError: AgentError{Message: message, Cause: cause},
}
}

type HITLInterventionRequired struct {
AgentError
FunctionCalls []interface{}
}

func NewHITLInterventionRequired(message string, functionCalls []interface{}) *HITLInterventionRequired {
return &HITLInterventionRequired{
AgentError: AgentError{Message: message},
FunctionCalls: functionCalls,
}
}
75 changes: 75 additions & 0 deletions pkg/kernel/chat_history.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package kernel

import (
"time"
)

type AuthorRole string

const (
AuthorRoleUser AuthorRole = "user"
AuthorRoleAssistant AuthorRole = "assistant"
AuthorRoleSystem AuthorRole = "system"
AuthorRoleTool AuthorRole = "tool"
)

type ContentItem interface {
GetType() string
GetContent() interface{}
}

type TextContent struct {
Text string `json:"text"`
}

func (t TextContent) GetType() string { return "text" }
func (t TextContent) GetContent() interface{} { return t.Text }

type ImageContent struct {
DataURI string `json:"data_uri"`
URL string `json:"url,omitempty"`
}

func (i ImageContent) GetType() string { return "image" }
func (i ImageContent) GetContent() interface{} { return i.DataURI }

type ChatMessageContent struct {
Role AuthorRole `json:"role"`
Items []ContentItem `json:"items"`
Name string `json:"name,omitempty"`
Timestamp time.Time `json:"timestamp,omitempty"`
}

type ChatHistory struct {
Messages []ChatMessageContent
}

func NewChatHistory() *ChatHistory {
return &ChatHistory{
Messages: make([]ChatMessageContent, 0),
}
}

func (h *ChatHistory) AddMessage(message ChatMessageContent) {
h.Messages = append(h.Messages, message)
}

func (h *ChatHistory) AddUserMessage(text string) {
h.AddMessage(ChatMessageContent{
Role: AuthorRoleUser,
Items: []ContentItem{TextContent{Text: text}},
Timestamp: time.Now(),
})
}

func (h *ChatHistory) AddAssistantMessage(text string) {
h.AddMessage(ChatMessageContent{
Role: AuthorRoleAssistant,
Items: []ContentItem{TextContent{Text: text}},
Timestamp: time.Now(),
})
}

func (h *ChatHistory) GetMessages() []ChatMessageContent {
return h.Messages
}
48 changes: 48 additions & 0 deletions pkg/kernel/function_calling.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package kernel

import (
"context"
)

type FunctionCallContent struct {
ID string `json:"id"`
PluginName string `json:"plugin_name"`
FunctionName string `json:"function_name"`
Arguments map[string]interface{} `json:"arguments"`
}

type FunctionResultContent struct {
CallID string `json:"call_id"`
PluginName string `json:"plugin_name"`
FunctionName string `json:"function_name"`
Result interface{} `json:"result"`
Error error `json:"error,omitempty"`
}

type FunctionChoiceBehavior string

const (
FunctionChoiceAuto FunctionChoiceBehavior = "auto"
FunctionChoiceNone FunctionChoiceBehavior = "none"
FunctionChoiceRequired FunctionChoiceBehavior = "required"
)

type KernelFunction interface {
GetName() string
GetDescription() string
GetPluginName() string
Invoke(ctx context.Context, args map[string]interface{}) (interface{}, error)
}

type Kernel interface {
AddService(client ChatCompletionClient) error
AddPlugin(name string, plugin Plugin) error
GetFunction(pluginName, functionName string) (KernelFunction, error)
GetService(serviceID string) (ChatCompletionClient, error)
}

type Plugin interface {
GetName() string
GetDescription() string
GetFunctions() []KernelFunction
}
37 changes: 37 additions & 0 deletions pkg/models/anthropic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package models

import (
"github.com/COG-GTM/teal-agents/pkg/kernel"
)

type AnthropicProvider struct {
apiKey string
models map[string]bool
}

func NewAnthropicProvider(apiKey string) *AnthropicProvider {
return &AnthropicProvider{
apiKey: apiKey,
models: map[string]bool{
"claude-3-5-sonnet-20241022": true,
"claude-3-opus-20240229": true,
"claude-3-sonnet-20240229": true,
},
}
}

func (p *AnthropicProvider) GetModelType() kernel.ModelType {
return kernel.ModelTypeAnthropic
}

func (p *AnthropicProvider) CreateClient(modelName, serviceID string) (kernel.ChatCompletionClient, error) {
return nil, &NotImplementedError{Feature: "Anthropic client creation"}
}

func (p *AnthropicProvider) SupportsModel(modelName string) bool {
return p.models[modelName]
}

func (p *AnthropicProvider) SupportsStructuredOutput(modelName string) bool {
return true
}
Loading
Loading