pixie-examples 0.1.1.dev3__py3-none-any.whl

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.
@@ -0,0 +1,299 @@
1
+ # OpenAI Agents SDK Examples - Pixie Integration
2
+
3
+ This directory contains Pixie-integrated versions of OpenAI Agents SDK examples, demonstrating various agent patterns and workflows.
4
+
5
+ ## Examples Overview
6
+
7
+ ### 1. LLM as a Judge (`llm_as_a_judge.py`)
8
+
9
+ **Pattern**: Multi-Step Workflow
10
+ **Original**: [GitHub](https://github.com/openai/openai-agents-python/blob/main/examples/agent_patterns/llm_as_a_judge.py)
11
+
12
+ Demonstrates the LLM-as-a-judge pattern where one agent generates content and another evaluates it iteratively.
13
+
14
+ **Features**:
15
+
16
+ - Story outline generator
17
+ - Quality evaluator agent
18
+ - Iterative improvement loop
19
+ - Feedback incorporation
20
+
21
+ **Pixie Handler**: `llm_judge_story_generator(topic: str)`
22
+
23
+ **Usage**:
24
+
25
+ ```python
26
+ # Via Pixie GraphQL API
27
+ subscription {
28
+ run(name: "llm_judge_story_generator", inputData: "a sci-fi adventure") {
29
+ runId
30
+ status
31
+ data
32
+ }
33
+ }
34
+ ```
35
+
36
+ ---
37
+
38
+ ### 2. Customer Service (`customer_service.py`)
39
+
40
+ **Pattern**: Multi-Agent & Multi-Turn
41
+ **Original**: [GitHub](https://github.com/openai/openai-agents-python/blob/main/examples/customer_service/main.py)
42
+
43
+ A complete customer service system for an airline with multiple specialized agents that hand off to each other.
44
+
45
+ **Features**:
46
+
47
+ - Multi-agent architecture (Triage, FAQ, Seat Booking)
48
+ - Agent handoffs based on customer needs
49
+ - Shared context across agents
50
+ - Tool usage (FAQ lookup, seat updates)
51
+ - Interactive multi-turn conversation
52
+
53
+ **Pixie Handler**: `airline_customer_service()`
54
+
55
+ **Agents**:
56
+
57
+ - **Triage Agent**: Routes requests to appropriate specialists
58
+ - **FAQ Agent**: Answers common questions about baggage, seats, wifi
59
+ - **Seat Booking Agent**: Handles seat change requests
60
+
61
+ **Usage**:
62
+
63
+ ```python
64
+ # Via Pixie GraphQL API
65
+ subscription {
66
+ run(name: "airline_customer_service", inputData: null) {
67
+ runId
68
+ status
69
+ data
70
+ }
71
+ }
72
+ ```
73
+
74
+ ---
75
+
76
+ ### 3. Routing/Handoffs (`routing.py`)
77
+
78
+ **Pattern**: Graph/State-Machine
79
+ **Original**: [GitHub](https://github.com/openai/openai-agents-python/blob/main/examples/agent_patterns/routing.py)
80
+
81
+ Language-based routing where a triage agent hands off to specialized language agents.
82
+
83
+ **Features**:
84
+
85
+ - Automatic language detection
86
+ - Agent routing based on language
87
+ - Streaming responses
88
+ - Support for French, Spanish, and English
89
+
90
+ **Pixie Handlers**:
91
+
92
+ - `multilingual_routing()` - No initial message required
93
+ - `multilingual_routing_simple(initial_message: str)` - Start with a message
94
+
95
+ **Usage**:
96
+
97
+ ```python
98
+ # Interactive version
99
+ subscription {
100
+ run(name: "multilingual_routing", inputData: null) {
101
+ runId
102
+ status
103
+ data
104
+ }
105
+ }
106
+
107
+ # With initial message
108
+ subscription {
109
+ run(name: "multilingual_routing_simple", inputData: "Bonjour, comment allez-vous?") {
110
+ runId
111
+ status
112
+ data
113
+ }
114
+ }
115
+ ```
116
+
117
+ ---
118
+
119
+ ### 4. Financial Research Agent (`financial_research_agent.py`)
120
+
121
+ **Pattern**: Multi-Step Workflow with Multi-Agent
122
+ **Original**: [GitHub](https://github.com/openai/openai-agents-python/tree/main/examples/financial_research_agent)
123
+
124
+ Comprehensive financial research workflow with specialized agents for analysis.
125
+
126
+ **Features**:
127
+
128
+ - Structured research workflow
129
+ - Parallel web searches
130
+ - Specialist analysts (fundamentals, risk)
131
+ - Report synthesis
132
+ - Quality verification
133
+ - Markdown report generation
134
+
135
+ **Architecture**:
136
+
137
+ 1. **Planner Agent** - Creates search strategy
138
+ 2. **Search Agent** - Performs web searches
139
+ 3. **Fundamentals Analyst** - Analyzes financial metrics
140
+ 4. **Risk Analyst** - Identifies risk factors
141
+ 5. **Writer Agent** - Synthesizes final report
142
+ 6. **Verifier Agent** - Quality checks
143
+
144
+ **Pixie Handler**: `financial_research(query: str)`
145
+
146
+ **Usage**:
147
+
148
+ ```python
149
+ # Via Pixie GraphQL API
150
+ subscription {
151
+ run(
152
+ name: "financial_research",
153
+ inputData: "Write up an analysis of Apple Inc.'s most recent quarter."
154
+ ) {
155
+ runId
156
+ status
157
+ data
158
+ }
159
+ }
160
+ ```
161
+
162
+ **Example Queries**:
163
+
164
+ - "Analyze Tesla's financial performance and growth prospects"
165
+ - "What are the key risks facing Microsoft in 2026?"
166
+ - "Provide a comprehensive analysis of NVIDIA's market position"
167
+
168
+ ---
169
+
170
+ ## Setup
171
+
172
+ ### 1. Install Dependencies
173
+
174
+ The OpenAI Agents SDK is already installed in the project:
175
+
176
+ ```bash
177
+ poetry install
178
+ ```
179
+
180
+ ### 2. Configure Environment Variables
181
+
182
+ Make sure you have your OpenAI API key configured in `.env`:
183
+
184
+ ```bash
185
+ OPENAI_API_KEY=sk-...
186
+ ```
187
+
188
+ ### 3. Run Pixie Server
189
+
190
+ Start the Pixie server to access the examples:
191
+
192
+ ```bash
193
+ poetry run pixie
194
+ ```
195
+
196
+ Then navigate to `http://127.0.0.1:8000/graphql` to use the GraphiQL interface.
197
+
198
+ ---
199
+
200
+ ## Key Patterns Demonstrated
201
+
202
+ ### Multi-Turn Conversations
203
+
204
+ Examples use `PixieGenerator[str, str]` with `UserInputRequirement(str)` for interactive dialogues:
205
+
206
+ ```python
207
+ @app
208
+ async def my_chatbot(_: None) -> PixieGenerator[str, str]:
209
+ yield "Hello! How can I help?"
210
+
211
+ while True:
212
+ user_input = yield UserInputRequirement(str)
213
+ # Process and respond
214
+ ```
215
+
216
+ ### Agent Handoffs
217
+
218
+ Multiple agents collaborate by handing off to specialists:
219
+
220
+ ```python
221
+ triage_agent = Agent(
222
+ handoffs=[specialist_agent_1, specialist_agent_2]
223
+ )
224
+ ```
225
+
226
+ ### Streaming Responses
227
+
228
+ Real-time response streaming for better UX:
229
+
230
+ ```python
231
+ result = Runner.run_streamed(agent, inputs)
232
+ async for event in result.stream_events():
233
+ if isinstance(data, ResponseTextDeltaEvent):
234
+ yield data.delta
235
+ ```
236
+
237
+ ### Structured Outputs
238
+
239
+ Using Pydantic models for type-safe outputs:
240
+
241
+ ```python
242
+ class ReportData(BaseModel):
243
+ summary: str
244
+ full_report: str
245
+
246
+ agent = Agent(output_type=ReportData)
247
+ ```
248
+
249
+ ---
250
+
251
+ ## Differences from Original Examples
252
+
253
+ These Pixie-integrated versions differ from the originals in several ways:
254
+
255
+ 1. **Async Generators**: Use `PixieGenerator` for streaming outputs
256
+ 2. **User Input**: Use `UserInputRequirement` instead of `input()`
257
+ 3. **Instrumentation**: Pixie automatically handles tracing
258
+ 4. **No Main Loop**: No `if __name__ == "__main__"` - runs via Pixie server
259
+ 5. **GraphQL Interface**: Accessed via GraphQL subscriptions instead of CLI
260
+
261
+ ---
262
+
263
+ ## Testing
264
+
265
+ Check for syntax errors:
266
+
267
+ ```bash
268
+ poetry run python -m py_compile examples/openai_agents_sdk/*.py
269
+ ```
270
+
271
+ Verify imports:
272
+
273
+ ```bash
274
+ poetry run python -c "from examples.openai_agents_sdk.llm_as_a_judge import llm_judge_story_generator"
275
+ poetry run python -c "from examples.openai_agents_sdk.customer_service import airline_customer_service"
276
+ poetry run python -c "from examples.openai_agents_sdk.routing import multilingual_routing"
277
+ poetry run python -c "from examples.openai_agents_sdk.financial_research_agent import financial_research"
278
+ ```
279
+
280
+ ---
281
+
282
+ ## Resources
283
+
284
+ - [OpenAI Agents SDK Documentation](https://github.com/openai/openai-agents-python)
285
+ - [Pixie SDK Documentation](../.github/copilot-instructions.md)
286
+ - [Original Examples](https://github.com/openai/openai-agents-python/tree/main/examples)
287
+
288
+ ---
289
+
290
+ ## Contributing
291
+
292
+ To add more OpenAI Agents SDK examples:
293
+
294
+ 1. Create a new `.py` file in this directory
295
+ 2. Import required modules from `agents` and `pixie`
296
+ 3. Define your agents and tools
297
+ 4. Create a Pixie handler with `@app` decorator
298
+ 5. Use `PixieGenerator` for multi-turn or streaming applications
299
+ 6. Update this README with example details
File without changes
@@ -0,0 +1,258 @@
1
+ """
2
+ Customer Service - Multi-Agent & Multi-Turn Chatbot - Pixie Integration
3
+
4
+ This example demonstrates a customer service system with multiple specialized agents
5
+ that can hand off to each other based on customer needs.
6
+
7
+ Pattern: Multi-Agent & Multi-Turn
8
+ Original: https://github.com/openai/openai-agents-python/blob/main/examples/customer_service/main.py
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import random
14
+
15
+ from pydantic import BaseModel
16
+ from agents import (
17
+ Agent,
18
+ HandoffOutputItem,
19
+ ItemHelpers,
20
+ MessageOutputItem,
21
+ RunContextWrapper,
22
+ Runner,
23
+ ToolCallItem,
24
+ ToolCallOutputItem,
25
+ TResponseInputItem,
26
+ function_tool,
27
+ handoff,
28
+ )
29
+ from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX
30
+ import pixie
31
+
32
+
33
+ # ============================================================================
34
+ # CONTEXT
35
+ # ============================================================================
36
+
37
+
38
+ class AirlineAgentContext(BaseModel):
39
+ """Shared context across all airline customer service agents"""
40
+
41
+ passenger_name: str | None = None
42
+ confirmation_number: str | None = None
43
+ seat_number: str | None = None
44
+ flight_number: str | None = None
45
+
46
+
47
+ # ============================================================================
48
+ # TOOLS
49
+ # ============================================================================
50
+
51
+
52
+ @function_tool(
53
+ name_override="faq_lookup_tool",
54
+ description_override="Lookup frequently asked questions.",
55
+ )
56
+ async def faq_lookup_tool(question: str) -> str:
57
+ """Simulates FAQ lookup for common airline questions"""
58
+ question_lower = question.lower()
59
+
60
+ if any(
61
+ keyword in question_lower
62
+ for keyword in [
63
+ "bag",
64
+ "baggage",
65
+ "luggage",
66
+ "carry-on",
67
+ "hand luggage",
68
+ "hand carry",
69
+ ]
70
+ ):
71
+ return (
72
+ "You are allowed to bring one bag on the plane. "
73
+ "It must be under 50 pounds and 22 inches x 14 inches x 9 inches."
74
+ )
75
+ elif any(
76
+ keyword in question_lower for keyword in ["seat", "seats", "seating", "plane"]
77
+ ):
78
+ return (
79
+ "There are 120 seats on the plane. "
80
+ "There are 22 business class seats and 98 economy seats. "
81
+ "Exit rows are rows 4 and 16. "
82
+ "Rows 5-8 are Economy Plus, with extra legroom."
83
+ )
84
+ elif any(
85
+ keyword in question_lower
86
+ for keyword in [
87
+ "wifi",
88
+ "internet",
89
+ "wireless",
90
+ "connectivity",
91
+ "network",
92
+ "online",
93
+ ]
94
+ ):
95
+ return "We have free wifi on the plane, join Airline-Wifi"
96
+
97
+ return "I'm sorry, I don't know the answer to that question."
98
+
99
+
100
+ @function_tool
101
+ async def update_seat(
102
+ context: RunContextWrapper[AirlineAgentContext],
103
+ confirmation_number: str,
104
+ new_seat: str,
105
+ ) -> str:
106
+ """
107
+ Update the seat for a given confirmation number.
108
+
109
+ Args:
110
+ confirmation_number: The confirmation number for the flight.
111
+ new_seat: The new seat to update to.
112
+ """
113
+ # Update the context based on the customer's input
114
+ context.context.confirmation_number = confirmation_number
115
+ context.context.seat_number = new_seat
116
+
117
+ # Ensure that the flight number has been set by the incoming handoff
118
+ assert context.context.flight_number is not None, "Flight number is required"
119
+
120
+ return f"Updated seat to {new_seat} for confirmation number {confirmation_number}"
121
+
122
+
123
+ # ============================================================================
124
+ # HOOKS
125
+ # ============================================================================
126
+
127
+
128
+ async def on_seat_booking_handoff(
129
+ context: RunContextWrapper[AirlineAgentContext],
130
+ ) -> None:
131
+ """Generate a flight number when handing off to seat booking agent"""
132
+ flight_number = f"FLT-{random.randint(100, 999)}"
133
+ context.context.flight_number = flight_number
134
+
135
+
136
+ # ============================================================================
137
+ # AGENTS
138
+ # ============================================================================
139
+
140
+ faq_agent = Agent[AirlineAgentContext](
141
+ name="FAQ Agent",
142
+ handoff_description="A helpful agent that can answer questions about the airline.",
143
+ instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
144
+
145
+ You are an FAQ agent. If you are speaking to a customer, you probably were
146
+ transferred to from the triage agent.
147
+
148
+ Use the following routine to support the customer.
149
+
150
+ # Routine
151
+ 1. Identify the last question asked by the customer.
152
+ 2. Use the faq lookup tool to answer the question. Do not rely on your own knowledge.
153
+ 3. If you cannot answer the question, transfer back to the triage agent.""",
154
+ tools=[faq_lookup_tool],
155
+ )
156
+
157
+ seat_booking_agent = Agent[AirlineAgentContext](
158
+ name="Seat Booking Agent",
159
+ handoff_description="A helpful agent that can update a seat on a flight.",
160
+ instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
161
+
162
+ You are a seat booking agent. If you are speaking to a customer, you probably were
163
+ transferred to from the triage agent.
164
+
165
+ Use the following routine to support the customer.
166
+
167
+ # Routine
168
+ 1. Ask for their confirmation number.
169
+ 2. Ask the customer what their desired seat number is.
170
+ 3. Use the update seat tool to update the seat on the flight.
171
+
172
+ If the customer asks a question that is not related to the routine, transfer back to the
173
+ triage agent.""",
174
+ tools=[update_seat],
175
+ )
176
+
177
+ triage_agent = Agent[AirlineAgentContext](
178
+ name="Triage Agent",
179
+ handoff_description="A triage agent that can delegate a customer's request to the appropriate agent.",
180
+ instructions=(
181
+ f"{RECOMMENDED_PROMPT_PREFIX} "
182
+ "You are a helpful triaging agent. You can use your tools to delegate questions to other appropriate agents."
183
+ ),
184
+ handoffs=[
185
+ faq_agent,
186
+ handoff(agent=seat_booking_agent, on_handoff=on_seat_booking_handoff),
187
+ ],
188
+ )
189
+
190
+ # Set up bidirectional handoffs
191
+ faq_agent.handoffs.append(triage_agent)
192
+ seat_booking_agent.handoffs.append(triage_agent)
193
+
194
+
195
+ @pixie.app
196
+ async def openai_agents_airline_customer_service() -> pixie.PixieGenerator[str, str]:
197
+ """
198
+ Multi-agent customer service chatbot for an airline.
199
+
200
+ This system uses three specialized agents:
201
+ - Triage Agent: Routes customer requests to appropriate agents
202
+ - FAQ Agent: Answers common questions using FAQ lookup
203
+ - Seat Booking Agent: Handles seat change requests
204
+
205
+ Agents can hand off to each other based on customer needs.
206
+
207
+ Yields:
208
+ Agent responses and status updates
209
+
210
+ Receives:
211
+ User messages via InputRequired
212
+ """
213
+ current_agent: Agent[AirlineAgentContext] = triage_agent
214
+ input_items: list[TResponseInputItem] = []
215
+ context = AirlineAgentContext()
216
+
217
+ yield "Welcome to Airline Customer Service! How can I help you today?"
218
+ yield "(Type 'exit', 'quit', or 'bye' to end the conversation)"
219
+
220
+ while True:
221
+ # Get user input
222
+ user_input = yield pixie.InputRequired(str)
223
+
224
+ # Check for exit commands
225
+ if user_input.lower() in {"exit", "quit", "bye"}:
226
+ yield "Thank you for contacting us. Have a great flight!"
227
+ break
228
+
229
+ # Add user message to input
230
+ input_items.append({"content": user_input, "role": "user"})
231
+
232
+ # Run the current agent
233
+ result = await Runner.run(current_agent, input_items, context=context)
234
+
235
+ # Process and yield all new items from the result
236
+ for new_item in result.new_items:
237
+ agent_name = new_item.agent.name
238
+
239
+ if isinstance(new_item, MessageOutputItem):
240
+ message_text = ItemHelpers.text_message_output(new_item)
241
+ yield f"{agent_name}: {message_text}"
242
+
243
+ elif isinstance(new_item, HandoffOutputItem):
244
+ handoff_msg = (
245
+ f"[Handed off from {new_item.source_agent.name} "
246
+ f"to {new_item.target_agent.name}]"
247
+ )
248
+ yield handoff_msg
249
+
250
+ elif isinstance(new_item, ToolCallItem):
251
+ yield f"{agent_name}: [Calling a tool...]"
252
+
253
+ elif isinstance(new_item, ToolCallOutputItem):
254
+ yield f"{agent_name}: [Tool result: {new_item.output}]"
255
+
256
+ # Update state for next iteration
257
+ input_items = result.to_input_list()
258
+ current_agent = result.last_agent