ai-agents 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d23007ce65c6dae4c20025ad5cacb683652452a973472fa3c9fba1166606e57
4
- data.tar.gz: 39b4522bd4ee7e329285a3806a4e06e5e312526e9139d4369bb7a12f4ede2d06
3
+ metadata.gz: 004f33c8652e5b8c4d8be7bd84e959c55f6926411d3cac8bd3b3d029b7b21690
4
+ data.tar.gz: 6592c590cd91809ee47865a25adcf734370695bd4c697b1926aabc95c6e2d574
5
5
  SHA512:
6
- metadata.gz: bc45c4328b0ec188abb77249ee3da9de9515251f2c872b8468c1704d49ea3765cb1dae285cad84c6fd1b644d6adde35073ddf09a6071c82b8ae7671ebbc67d52
7
- data.tar.gz: 354a10db6fab8d2885c1bdd6e20e72086a9cd87e1a16b99c1b744f0c35b962b19b07aafcf7c0ca0301f30bccc0a8e3ba00de13807178e7d02ec16466ba002a79
6
+ metadata.gz: 0baadd9d0771c8e2bdd345a0a8e00bc792c6a607ec78b8796a6718e4695dc5e92b2fdc2ec11b4384c77ad409af4660be5288b020c6404750a2db5a66d1cf094c
7
+ data.tar.gz: de6edbb743e8b01634aaa12c656bc7cfa618de8086aa4e4e6add08683e8383b611856b4b9fa452c2e2e2bbd3efa2a74edefcc17af8188d2605babfc5067ecaf2
data/.rubocop.yml CHANGED
@@ -24,3 +24,6 @@ RSpec/SpecFilePathFormat:
24
24
 
25
25
  Metrics/MethodLength:
26
26
  Max: 20
27
+
28
+ RSpec/MultipleDescribes:
29
+ Enabled: false
data/CLAUDE.md CHANGED
@@ -2,187 +2,196 @@
2
2
 
3
3
  This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
4
 
5
- ## Repository Overview
5
+ ## Project Purpose
6
6
 
7
- This is a Ruby AI Agents SDK that provides multi-agent orchestration capabilities, similar to OpenAI's Agents SDK but built for Ruby. The SDK enables the creation of sophisticated AI workflows with specialized agents, tool execution, and conversation handoffs.
7
+ This project is a Ruby SDK for building multi-agent AI workflows. It allows developers to create specialized AI agents that can collaborate to solve complex tasks. The key features include:
8
8
 
9
- **IMPORTANT**: This is a generic agent library. When implementing library code, ensure that:
10
- - No domain-specific logic from examples (airline booking, FAQ, seat management, etc.) leaks into the core library
11
- - The library remains agnostic to specific use cases
12
- - All domain-specific implementations belong in the examples directory only
9
+ - **Multi-Agent Orchestration**: Defining and managing multiple AI agents with distinct roles.
10
+ - **Seamless Handoffs**: Transferring conversations between agents without the user's knowledge.
11
+ - **Tool Integration**: Allowing agents to use custom tools to interact with external systems.
12
+ - **Shared Context**: Maintaining state and conversation history across agent interactions with full persistence support.
13
+ - **Thread-Safe Architecture**: Reusable agent runners that work safely across multiple threads.
14
+ - **Provider Agnostic**: Supporting various LLM providers like OpenAI, Anthropic, and Gemini.
13
15
 
14
- ## Development Commands
16
+ ## Key Technologies
15
17
 
16
- ### Building and Testing
17
- ```bash
18
- # Install dependencies
19
- bundle install
18
+ - **Ruby**: The primary programming language.
19
+ - **RubyLLM**: The underlying library for interacting with Large Language Models.
20
+ - **RSpec**: The testing framework.
21
+ - **RuboCop**: The code style linter.
22
+ - **GitHub Actions**: For continuous integration (testing and linting).
20
23
 
21
- # Run tests with RSpec
22
- rake spec
23
- # OR
24
- bundle exec rspec
24
+ ## Project Structure
25
25
 
26
- # Run specific spec file
27
- bundle exec rspec spec/agents/agent_spec.rb
26
+ - `lib/`: The core source code of the `ai-agents` gem.
27
+ - `lib/agents.rb`: The main entry point, handling configuration and loading other components.
28
+ - `lib/agents/agent.rb`: Defines the `Agent` class, which represents an individual AI agent.
29
+ - `lib/agents/tool.rb`: Defines the `Tool` class, the base for creating custom tools for agents.
30
+ - `lib/agents/agent_runner.rb`: Thread-safe agent execution manager for multi-agent conversations.
31
+ - `lib/agents/runner.rb`: Internal orchestrator that handles individual conversation turns.
32
+ - `spec/`: Contains the RSpec tests for the project.
33
+ - `examples/`: Includes example implementations of multi-agent systems, such as an ISP customer support demo.
34
+ - `Gemfile`: Manages the project's Ruby dependencies.
35
+ - `.rubocop.yml`: Configures the code style rules for RuboCop.
36
+ - `.github/workflows/main.yml`: Defines the CI pipeline for running tests and linting on push and pull requests.
28
37
 
29
- # Run tests with coverage report
30
- bundle exec rspec # SimpleCov will generate coverage/index.html
38
+ ## Development Workflow
31
39
 
32
- # Lint code (includes RSpec cops)
33
- rake rubocop
34
- # OR
35
- bundle exec rubocop
40
+ 1. **Dependencies**: Managed by Bundler (`bundle install`).
41
+ 2. **Testing**: Run tests with `bundle exec rspec`.
42
+ 3. **Linting**: Check code style with `bundle exec rubocop`.
43
+ 4. **CI/CD**: GitHub Actions automatically runs tests and linting for all pushes and pull requests to the `main` branch.
36
44
 
37
- # Auto-fix linting issues
38
- bundle exec rubocop -a
45
+ ## How to Run the Example
39
46
 
40
- # Run all checks (spec + lint)
41
- rake
42
- ```
47
+ The project includes an interactive example of an ISP customer support system. To run it:
43
48
 
44
- ### Interactive Development
45
49
  ```bash
46
- # Start interactive console
47
- bin/console
48
-
49
- # Run the airline booking demo
50
- ruby examples/booking/interactive.rb
51
-
52
- # Run automatic booking demo
53
- ruby examples/booking/automatic.rb
50
+ ruby examples/isp-support/interactive.rb
54
51
  ```
55
52
 
56
- ## Architecture and Code Structure
53
+ This will start a command-line interface where you can interact with the multi-agent system. The example demonstrates:
54
+ - Thread-safe agent runner creation
55
+ - Automatic agent selection based on conversation history
56
+ - Context persistence that works across process boundaries
57
+ - Seamless handoffs between triage, sales, and support agents
57
58
 
58
- ### Core Components (Generic Library)
59
+ ## Key Concepts
59
60
 
60
- **lib/agents.rb** - Main module and configuration entry point. Configures both the Agents SDK and underlying RubyLLM library. Contains the `RECOMMENDED_HANDOFF_PROMPT_PREFIX` for multi-agent workflows.
61
+ - **Agent**: An AI assistant with a specific role, instructions, and tools.
62
+ - **Tool**: A custom function that an agent can use to perform actions (e.g., look up customer data, send an email).
63
+ - **Handoff**: The process of transferring a conversation from one agent to another. This is a core feature of the SDK.
64
+ - **AgentRunner**: The thread-safe execution manager that coordinates multi-agent conversations and provides the main API.
65
+ - **Runner**: Internal component that manages individual conversation turns (used by AgentRunner).
66
+ - **Context**: A shared state object that stores conversation history and agent information, fully serializable for persistence.
61
67
 
62
- **lib/agents/agent.rb** - The core `Agent` class with Ruby-like DSL for defining AI agents. Key features:
63
- - Class-level configuration: `name`, `instructions`, `provider`, `model`, `uses`, `handoffs`
64
- - Instance execution via `call` method with conversation history management
65
- - Tool and handoff tool registration at runtime
66
- - Context-aware execution with proper conversation history restoration using `chat.add_message`
67
- - **No domain-specific logic** - remains completely generic
68
+ ## Development Commands
68
69
 
69
- **lib/agents/tool.rb** - Base class for tools that agents can use. Inherits from `RubyLLM::Tool` and adds:
70
- - Ruby-style parameter definitions with automatic JSON schema conversion
71
- - Context injection through `perform` method (called by `execute`)
72
- - Enhanced parameter definition supporting Ruby types (String, Integer, etc.)
73
- - **Domain-agnostic** - specific tool implementations belong in user code
70
+ ### Testing
71
+ ```bash
72
+ # Run all tests with RSpec
73
+ bundle exec rspec
74
74
 
75
- **lib/agents/handoff.rb** - Contains the handoff system classes:
76
- - `HandoffResult` - Represents a handoff decision
77
- - `AgentResponse` - Wraps agent responses with optional handoff results
78
- - `HandoffTool` - Generic tool for transferring between agents using context-based signaling
79
- - **Generic handoff mechanism** - no assumptions about specific agent types
75
+ # Run tests with coverage report (uses SimpleCov)
76
+ bundle exec rake spec
80
77
 
81
- **lib/agents/context.rb** - Base context class for sharing state between agents and tools across handoffs. Must be subclassed for domain-specific context. The base class provides only generic state management capabilities.
78
+ # Run specific test file
79
+ bundle exec rspec spec/agents/agent_spec.rb
82
80
 
83
- **lib/agents/runner.rb** - Execution engine for orchestrating multi-agent workflows (future implementation).
81
+ # Run specific test with line number
82
+ bundle exec rspec spec/agents/agent_spec.rb:25
83
+ ```
84
84
 
85
- ### Key Design Patterns
85
+ ### Code Quality
86
+ ```bash
87
+ # Run RuboCop linter
88
+ bundle exec rubocop
86
89
 
87
- #### Agent Definition Pattern (Generic)
88
- ```ruby
89
- class MyAgent < Agents::Agent
90
- name "Agent Name"
91
- instructions "Behavior description" # Can be dynamic via Proc
92
- provider :openai # Optional, defaults to configured provider
93
- model "gpt-4o" # Optional, defaults to configured model
94
-
95
- uses SomeTool # Register tools by class
96
- handoffs OtherAgent, AnotherAgent # Define possible handoff targets
97
- end
90
+ # Run RuboCop with auto-correction
91
+ bundle exec rubocop -a
92
+
93
+ # Run both tests and linting (default rake task)
94
+ bundle exec rake
98
95
  ```
99
96
 
100
- #### Tool Definition Pattern (Generic)
101
- ```ruby
102
- class MyTool < Agents::Tool
103
- description "What this tool does"
104
- param :input_param, String, "Parameter description"
105
- param :optional_param, Integer, "Optional param", required: false
106
-
107
- def perform(input_param:, optional_param: nil, context:)
108
- # context is always available for state management
109
- # Must implement perform, not execute
110
- # Tool logic should be domain-specific in user implementations
111
- "Tool result"
112
- end
113
- end
97
+ ### Development
98
+ ```bash
99
+ # Install dependencies
100
+ bundle install
101
+
102
+ # Interactive Ruby console with gem loaded
103
+ bundle exec irb -r ./lib/agents
104
+
105
+ # Run ISP support example interactively
106
+ ruby examples/isp-support/interactive.rb
114
107
  ```
115
108
 
116
- #### Context-Based Handoff System
117
- The handoff system uses context signaling rather than text parsing:
118
- 1. `HandoffTool` instances are created automatically from `handoffs` declarations
119
- 2. When called, `HandoffTool.perform` sets `context[:pending_handoff]`
120
- 3. `Agent.detect_handoff_from_context` checks for pending handoffs after LLM responses
121
- 4. Interactive systems handle handoffs by switching to the target agent class
109
+ ## Architecture
122
110
 
123
- #### Conversation History Management
124
- Critical for multi-turn conversations:
125
- - Agents maintain `@conversation_history` as array of `{user:, assistant:, timestamp:}` hashes
126
- - `restore_conversation_history(chat)` uses `chat.add_message(role:, content:)` to restore RubyLLM chat state
127
- - This prevents agents from "forgetting" previous conversation turns
111
+ ### Core Components
128
112
 
129
- ### Configuration Rules
113
+ - **Agents::Agent**: Individual AI agents with specific roles, instructions, and tools
114
+ - **Agents::Runner**: Orchestrates multi-agent conversations with automatic handoffs
115
+ - **Agents::Tool**: Base class for custom tools that agents can execute
116
+ - **Agents::Context**: Shared state management across agent interactions
117
+ - **Agents::Handoff**: Manages seamless transfers between agents
130
118
 
131
- #### Class Naming
132
- - Use flat naming like `class Agents::Tool` instead of nested declarations
133
- - Follow Ruby naming conventions for agent and tool classes
119
+ ### Key Design Principles
134
120
 
135
- #### Documentation
136
- - Always write doc strings when writing functions
137
- - Use YARD format for documentation
138
- - Always write RDoc for new methods
139
- - When creating a new file, start the file with a description comment on what the file has and where does it fit in the project
121
+ 1. **Thread Safety**: All components are designed to be thread-safe. Tools receive context as parameters, not instance variables.
140
122
 
141
- #### Model Defaults
142
- - Default model for OpenAI provider is `gpt-4.1-mini` (configured in lib/agents.rb)
143
- - Can be overridden in agent classes or runtime configuration
123
+ 2. **Immutable Agents**: Agents are configured once and can be cloned with modifications. No execution state is stored in agent instances.
144
124
 
145
- ### Examples Structure
125
+ 3. **Provider Agnostic**: Built on RubyLLM, supports OpenAI, Anthropic, and Gemini through configuration.
146
126
 
147
- **examples/booking/** - Complete airline booking demo showcasing multi-agent workflows. This is just one example of how the SDK can be used. The example demonstrates:
148
- - Multi-agent workflow patterns
149
- - Context sharing between agents
150
- - Tool usage patterns
151
- - Interactive CLI and automatic execution modes
152
- - Proper handoff handling
153
127
 
154
- Note: The airline booking scenario is purely demonstrative. The SDK is not limited to or designed specifically for airline systems.
128
+ ### File Structure
155
129
 
156
- ### Dependencies and Integration
130
+ ```
131
+ lib/agents/
132
+ ├── agent.rb # Core agent definition and configuration
133
+ ├── agent_runner.rb # Thread-safe execution manager (main API)
134
+ ├── runner.rb # Internal execution engine for conversation turns
135
+ ├── tool.rb # Base class for custom tools
136
+ ├── handoff.rb # Agent handoff management
137
+ ├── chat.rb # Chat message handling
138
+ ├── result.rb # Result object for agent responses
139
+ ├── run_context.rb # Execution context management
140
+ ├── tool_context.rb # Tool execution context
141
+ ├── tool_wrapper.rb # Thread-safe tool wrapping
142
+ └── version.rb # Gem version
143
+ ```
157
144
 
158
- **RubyLLM Integration** - Built on top of RubyLLM library for LLM communication:
159
- - Agents SDK configures RubyLLM automatically via `Agents.configure`
160
- - Tools inherit from `RubyLLM::Tool` but use enhanced `perform` method
161
- - Conversation history restored using `chat.add_message`
162
- - Debug mode available via `ENV["RUBYLLM_DEBUG"] = "true"`
145
+ ### Configuration
163
146
 
164
- **Provider Support** - Currently supports OpenAI through RubyLLM, extensible to other providers
147
+ The SDK requires at least one LLM provider API key:
165
148
 
166
- ### Important Implementation Details
149
+ ```ruby
150
+ Agents.configure do |config|
151
+ config.openai_api_key = ENV['OPENAI_API_KEY']
152
+ config.anthropic_api_key = ENV['ANTHROPIC_API_KEY']
153
+ config.gemini_api_key = ENV['GEMINI_API_KEY']
154
+ config.default_model = 'gpt-4o-mini'
155
+ config.debug = true
156
+ end
157
+ ```
167
158
 
168
- 1. **Conversation History**: Must call `restore_conversation_history(chat)` before each agent execution to maintain conversation state across turns.
159
+ ### Basic Usage Pattern
169
160
 
170
- 2. **Tool Context Flow**: `RubyLLM.execute()` → `Agents::Tool.execute()` → `Tool.perform(context:, **args)` - the context injection happens in the base `Tool.execute` method.
161
+ ```ruby
162
+ # Create agents with handoff relationships
163
+ triage = Agent.new(name: "Triage", instructions: "Route users...")
164
+ billing = Agent.new(name: "Billing", instructions: "Handle billing...")
165
+ support = Agent.new(name: "Support", instructions: "Technical support...")
166
+
167
+ triage.register_handoffs(billing, support)
168
+
169
+ # Create thread-safe runner (first agent is default entry point)
170
+ runner = Agents::Runner.with_agents(triage, billing, support)
171
+
172
+ # Use for conversations - automatically handles agent selection and persistence
173
+ result = runner.run("I have a billing question")
174
+ result = runner.run("What about technical support?", context: result.context)
175
+ ```
171
176
 
172
- 3. **Handoff Detection**: Uses context-based detection (`@context[:pending_handoff]`) rather than parsing LLM responses for tool calls.
177
+ ### Tool Development
173
178
 
174
- 4. **Model Configuration**: Default model is `gpt-4.1-mini` but examples use `gpt-4o` for better performance.
179
+ When creating custom tools:
180
+ - Extend `Agents::Tool`
181
+ - Use `tool_context` parameter for all state
182
+ - Never store execution state in instance variables
183
+ - Follow the thread-safe design pattern shown in examples
175
184
 
176
- 5. **Thread Safety**: Agents are designed to be stateless with context passed through execution rather than stored in instance variables.
185
+ ### Testing Strategy
177
186
 
178
- 6. **Library vs Example Code**: The core library (lib/agents/*) must remain completely generic and free of domain-specific logic. All domain-specific implementations (airline booking, FAQ systems, etc.) belong exclusively in the examples directory.
187
+ - SimpleCov tracks coverage with 50% minimum overall, 40% per file
188
+ - WebMock is used for HTTP mocking in tests
189
+ - RSpec is the testing framework with standard configuration
190
+ - Tests are organized by component in `spec/agents/`
179
191
 
180
- ### Testing Guidelines
192
+ ### Examples
181
193
 
182
- When writing tests, follow the rules:
183
- 1. Avoid stubbing using allow_any_instance_of`
184
- 2. Each example block `it ... end` should have less than 20 lines
185
- 3. Example group should not have more than 10 memoized helpers, not more than 10 except statements
186
- 4. Never use `receive_message_chain`
187
- 5. When writing tests, always use verifying doubles and never normal doubles
188
- ```
194
+ The `examples/` directory contains complete working examples:
195
+ - `isp-support/`: Multi-agent ISP customer support system
196
+ - Shows hub-and-spoke architecture patterns
197
+ - Demonstrates tool integration and handoff workflows
data/README.md CHANGED
@@ -40,15 +40,18 @@ Agents.configure do |config|
40
40
  config.openai_api_key = ENV['OPENAI_API_KEY']
41
41
  end
42
42
 
43
- # Create a simple agent
44
- agent = Agents::Agent.new(
43
+ # Create agents
44
+ weather_agent = Agents::Agent.new(
45
45
  name: "Weather Assistant",
46
46
  instructions: "Help users get weather information",
47
47
  tools: [WeatherTool.new]
48
48
  )
49
49
 
50
- # Use the agent with the Runner
51
- result = Agents::Runner.run(agent, "What's the weather like today?")
50
+ # Create a thread-safe runner (reusable across conversations)
51
+ runner = Agents::Runner.with_agents(weather_agent)
52
+
53
+ # Use the runner for conversations
54
+ result = runner.run("What's the weather like today?")
52
55
  puts result.output
53
56
  ```
54
57
 
@@ -64,14 +67,14 @@ triage = Agents::Agent.new(
64
67
  )
65
68
 
66
69
  faq = Agents::Agent.new(
67
- name: "FAQ Agent",
70
+ name: "FAQ Agent",
68
71
  instructions: "Answer frequently asked questions",
69
72
  tools: [FaqLookupTool.new]
70
73
  )
71
74
 
72
75
  support = Agents::Agent.new(
73
76
  name: "Support Agent",
74
- instructions: "Handle technical issues",
77
+ instructions: "Handle technical issues",
75
78
  tools: [TicketTool.new]
76
79
  )
77
80
 
@@ -80,9 +83,16 @@ triage.register_handoffs(faq, support)
80
83
  faq.register_handoffs(triage) # Can route back to triage
81
84
  support.register_handoffs(triage) # Hub-and-spoke pattern
82
85
 
83
- # Run a conversation with automatic handoffs
84
- result = Agents::Runner.run(triage, "How many seats are on the plane?")
86
+ # Create runner with all agents (triage is default entry point)
87
+ runner = Agents::Runner.with_agents(triage, faq, support)
88
+
89
+ # Run conversations with automatic handoffs and persistence
90
+ result = runner.run("How many seats are on the plane?")
85
91
  # User gets direct answer from FAQ agent without knowing about the handoff!
92
+
93
+ # Continue the conversation seamlessly
94
+ result = runner.run("What about technical support?", context: result.context)
95
+ # Context automatically tracks conversation history and current agent
86
96
  ```
87
97
 
88
98
  ## 🏗️ Architecture
@@ -90,8 +100,9 @@ result = Agents::Runner.run(triage, "How many seats are on the plane?")
90
100
  ### Core Components
91
101
 
92
102
  - **Agent**: Individual AI agents with specific roles and capabilities
93
- - **Runner**: Orchestrates multi-agent conversations with automatic handoffs
94
- - **Context**: Shared state management across agents
103
+ - **AgentRunner**: Thread-safe execution manager for multi-agent conversations
104
+ - **Runner**: Internal orchestrator that handles conversation turns (used by AgentRunner)
105
+ - **Context**: Shared state management with automatic persistence across agents
95
106
  - **Tools**: Custom functions that agents can use
96
107
  - **Handoffs**: Seamless transfers between specialized agents
97
108
 
@@ -134,11 +145,11 @@ end
134
145
  ```ruby
135
146
  class EmailTool < Agents::Tool
136
147
  description "Send emails to customers"
137
- param :to, String, "Email address"
138
- param :subject, String, "Email subject"
139
- param :body, String, "Email body"
148
+ param :to, type: "string", desc: "Email address"
149
+ param :subject, type: "string", desc: "Email subject"
150
+ param :body, type: "string", desc: "Email body"
140
151
 
141
- def perform(to:, subject:, body:, context:)
152
+ def perform(tool_context, to:, subject:, body:)
142
153
  # Send email logic here
143
154
  "Email sent to #{to}"
144
155
  end
@@ -175,16 +186,27 @@ sales.register_handoffs(customer_info)
175
186
  customer_info.register_handoffs(sales)
176
187
  ```
177
188
 
178
- ### Context Management
189
+ ### Context Management & Persistence
179
190
 
180
191
  ```ruby
181
- # Context is automatically managed by the Runner
182
- context = {}
183
- result = Agents::Runner.run(agent, "Hello", context: context)
192
+ # Context is automatically managed and serializable
193
+ runner = Agents::Runner.with_agents(triage, billing, support)
184
194
 
185
- # Access conversation history and agent state
195
+ # Start a conversation
196
+ result = runner.run("I need billing help")
197
+
198
+ # Context is automatically updated with conversation history and current agent
199
+ context = result.context
186
200
  puts context[:conversation_history]
187
- puts context[:current_agent].name
201
+ puts context[:current_agent] # Agent name (string), not object!
202
+
203
+ # Serialize context for persistence (Rails, databases, etc.)
204
+ json_context = JSON.dump(context) # ✅ Works! No object references
205
+
206
+ # Later: restore and continue conversation
207
+ restored_context = JSON.parse(json_context, symbolize_names: true)
208
+ result = runner.run("Actually, I need technical support too", context: restored_context)
209
+ # System automatically determines correct agent from conversation history
188
210
  ```
189
211
 
190
212
  ## 📋 Examples
@@ -48,11 +48,10 @@ module ISPSupport
48
48
  )
49
49
  end
50
50
 
51
-
52
51
  def create_sales_agent
53
52
  Agents::Agent.new(
54
53
  name: "Sales Agent",
55
- instructions: sales_instructions,
54
+ instructions: sales_instructions_with_state,
56
55
  model: "gpt-4.1-mini",
57
56
  tools: [ISPSupport::CreateLeadTool.new, ISPSupport::CreateCheckoutTool.new]
58
57
  )
@@ -65,7 +64,7 @@ module ISPSupport
65
64
  model: "gpt-4.1-mini",
66
65
  tools: [
67
66
  ISPSupport::CrmLookupTool.new,
68
- ISPSupport::SearchDocsTool.new,
67
+ ISPSupport::SearchDocsTool.new,
69
68
  ISPSupport::EscalateToHumanTool.new
70
69
  ]
71
70
  )
@@ -89,7 +88,6 @@ module ISPSupport
89
88
  INSTRUCTIONS
90
89
  end
91
90
 
92
-
93
91
  def sales_instructions
94
92
  <<~INSTRUCTIONS
95
93
  You are the Sales Agent for an ISP. You handle new customer acquisition, service upgrades,
@@ -101,19 +99,76 @@ module ISPSupport
101
99
  - Handoff tools: Route back to triage when needed
102
100
 
103
101
  **When to hand off:**
104
- - Need account verification or billing info → Triage Agent for re-routing
105
- - Technical questions → Triage Agent for re-routing
106
- - Non-sales requests → Triage Agent
102
+ - Pure technical support questions → Triage Agent for re-routing
103
+ - Customer needs to speak with human agent → Triage Agent for re-routing
107
104
 
108
105
  **Instructions:**
109
106
  - Be enthusiastic but not pushy
110
107
  - Gather required info: name, email, desired plan for leads
111
- - For existing customers wanting upgrades, ask them to verify account first
108
+ - For account verification, ask customer for their account details directly
109
+ - For existing customers wanting upgrades, collect account info and proceed
112
110
  - Create checkout links for confirmed purchases
113
111
  - Always explain next steps after creating leads or checkout links
112
+ - Handle billing questions yourself - don't hand off for account verification
114
113
  INSTRUCTIONS
115
114
  end
116
115
 
116
+ def sales_instructions_with_state
117
+ lambda { |context|
118
+ state = context.context[:state] || {}
119
+
120
+ base_instructions = <<~INSTRUCTIONS
121
+ You are the Sales Agent for an ISP. You handle new customer acquisition, service upgrades,
122
+ and plan changes.
123
+
124
+ **Your tools:**
125
+ - `create_lead`: Create sales leads with customer information
126
+ - `create_checkout`: Generate secure checkout links for purchases
127
+ - Handoff tools: Route back to triage when needed
128
+
129
+ **When to hand off:**
130
+ - Pure technical support questions → Triage Agent for re-routing
131
+ - Customer needs to speak with human agent → Triage Agent for re-routing
132
+ INSTRUCTIONS
133
+
134
+ # Add customer context if available from previous agent interactions
135
+ if state[:customer_name] && state[:customer_id]
136
+ base_instructions += <<~CONTEXT
137
+
138
+ **Customer Context Available:**
139
+ - Customer Name: #{state[:customer_name]}
140
+ - Customer ID: #{state[:customer_id]}
141
+ - Email: #{state[:customer_email]}
142
+ - Phone: #{state[:customer_phone]}
143
+ - Address: #{state[:customer_address]}
144
+ #{state[:current_plan] ? "- Current Plan: #{state[:current_plan]}" : ""}
145
+ #{state[:account_status] ? "- Account Status: #{state[:account_status]}" : ""}
146
+ #{state[:monthly_usage] ? "- Monthly Usage: #{state[:monthly_usage]}GB" : ""}
147
+
148
+ **IMPORTANT:**#{" "}
149
+ - Use this existing customer information when creating leads or providing service
150
+ - Do NOT ask for name, email, phone, or address - you already have these details
151
+ - For new connections, use the existing customer details and only ask for the desired plan
152
+ - Provide personalized recommendations based on their current information
153
+ CONTEXT
154
+ end
155
+
156
+ base_instructions += <<~FINAL_INSTRUCTIONS
157
+
158
+ **Instructions:**
159
+ - Be enthusiastic but not pushy
160
+ - Gather required info: name, email, desired plan for leads
161
+ - For account verification, ask customer for their account details directly
162
+ - For existing customers wanting upgrades, collect account info and proceed
163
+ - Create checkout links for confirmed purchases
164
+ - Always explain next steps after creating leads or checkout links
165
+ - Handle billing questions yourself - don't hand off for account verification
166
+ FINAL_INSTRUCTIONS
167
+
168
+ base_instructions
169
+ }
170
+ end
171
+
117
172
  def support_instructions
118
173
  <<~INSTRUCTIONS
119
174
  You are the Support Agent for an ISP. You handle technical support, troubleshooting,
@@ -126,8 +181,8 @@ module ISPSupport
126
181
  - Handoff tools: Route back to triage when needed
127
182
 
128
183
  **When to hand off:**
129
- - Customer wants to buy/upgrade plans → Triage Agent to route to Sales
130
- - Non-support requests (new purchases)Triage Agent
184
+ - Customer wants to buy new service or upgrade plans → Triage Agent to route to Sales
185
+ - Complex issues requiring human intervention Use escalate_to_human tool instead
131
186
 
132
187
  **Instructions:**
133
188
  - For account questions: Always ask for account ID and use crm_lookup
@@ -136,6 +191,7 @@ module ISPSupport
136
191
  - Be patient and provide step-by-step guidance
137
192
  - If customer gets frustrated or issue persists, escalate to human
138
193
  - Present account information clearly and protect sensitive data
194
+ - Handle account verification requests directly - don't hand off back to triage
139
195
  INSTRUCTIONS
140
196
  end
141
197
  end