solana-agent 20.1.2__py3-none-any.whl → 31.4.0__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.
Files changed (45) hide show
  1. solana_agent/__init__.py +10 -5
  2. solana_agent/adapters/ffmpeg_transcoder.py +375 -0
  3. solana_agent/adapters/mongodb_adapter.py +15 -2
  4. solana_agent/adapters/openai_adapter.py +679 -0
  5. solana_agent/adapters/openai_realtime_ws.py +1813 -0
  6. solana_agent/adapters/pinecone_adapter.py +543 -0
  7. solana_agent/cli.py +128 -0
  8. solana_agent/client/solana_agent.py +180 -20
  9. solana_agent/domains/agent.py +13 -13
  10. solana_agent/domains/routing.py +18 -8
  11. solana_agent/factories/agent_factory.py +239 -38
  12. solana_agent/guardrails/pii.py +107 -0
  13. solana_agent/interfaces/client/client.py +95 -12
  14. solana_agent/interfaces/guardrails/guardrails.py +26 -0
  15. solana_agent/interfaces/plugins/plugins.py +2 -1
  16. solana_agent/interfaces/providers/__init__.py +0 -0
  17. solana_agent/interfaces/providers/audio.py +40 -0
  18. solana_agent/interfaces/providers/data_storage.py +9 -2
  19. solana_agent/interfaces/providers/llm.py +86 -9
  20. solana_agent/interfaces/providers/memory.py +13 -1
  21. solana_agent/interfaces/providers/realtime.py +212 -0
  22. solana_agent/interfaces/providers/vector_storage.py +53 -0
  23. solana_agent/interfaces/services/agent.py +27 -12
  24. solana_agent/interfaces/services/knowledge_base.py +59 -0
  25. solana_agent/interfaces/services/query.py +41 -8
  26. solana_agent/interfaces/services/routing.py +0 -1
  27. solana_agent/plugins/manager.py +37 -16
  28. solana_agent/plugins/registry.py +34 -19
  29. solana_agent/plugins/tools/__init__.py +0 -5
  30. solana_agent/plugins/tools/auto_tool.py +1 -0
  31. solana_agent/repositories/memory.py +332 -111
  32. solana_agent/services/__init__.py +1 -1
  33. solana_agent/services/agent.py +390 -241
  34. solana_agent/services/knowledge_base.py +768 -0
  35. solana_agent/services/query.py +1858 -153
  36. solana_agent/services/realtime.py +626 -0
  37. solana_agent/services/routing.py +104 -51
  38. solana_agent-31.4.0.dist-info/METADATA +1070 -0
  39. solana_agent-31.4.0.dist-info/RECORD +49 -0
  40. {solana_agent-20.1.2.dist-info → solana_agent-31.4.0.dist-info}/WHEEL +1 -1
  41. solana_agent-31.4.0.dist-info/entry_points.txt +3 -0
  42. solana_agent/adapters/llm_adapter.py +0 -160
  43. solana_agent-20.1.2.dist-info/METADATA +0 -464
  44. solana_agent-20.1.2.dist-info/RECORD +0 -35
  45. {solana_agent-20.1.2.dist-info → solana_agent-31.4.0.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,1070 @@
1
+ Metadata-Version: 2.4
2
+ Name: solana-agent
3
+ Version: 31.4.0
4
+ Summary: AI Agents for Solana
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Keywords: solana,solana ai,solana agent,ai,ai agent,ai agents
8
+ Author: Bevan Hunt
9
+ Author-email: bevan@bevanhunt.com
10
+ Requires-Python: >=3.12,<4.0
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Dist: instructor (==1.13.0)
20
+ Requires-Dist: llama-index-core (==0.14.8)
21
+ Requires-Dist: llama-index-embeddings-openai (==0.5.1)
22
+ Requires-Dist: logfire (==4.15.1)
23
+ Requires-Dist: openai (==2.8.1)
24
+ Requires-Dist: pillow (==12.0.0)
25
+ Requires-Dist: pinecone[asyncio] (==8.0.0)
26
+ Requires-Dist: pydantic (>=2)
27
+ Requires-Dist: pymongo (==4.15.4)
28
+ Requires-Dist: pypdf (==6.4.0)
29
+ Requires-Dist: rich (>=13,<14.0)
30
+ Requires-Dist: scrubadub (==2.0.1)
31
+ Requires-Dist: typer (==0.20.0)
32
+ Requires-Dist: websockets (>=13,<16)
33
+ Requires-Dist: zep-cloud (==3.13.0)
34
+ Project-URL: Documentation, https://docs.solana-agent.com
35
+ Project-URL: Homepage, https://solana-agent.com
36
+ Project-URL: Repository, https://github.com/truemagic-coder/solana-agent
37
+ Description-Content-Type: text/markdown
38
+
39
+ # Solana Agent
40
+
41
+ [![PyPI - Version](https://img.shields.io/pypi/v/solana-agent)](https://pypi.org/project/solana-agent/)
42
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
43
+ [![PyPI - Downloads](https://img.shields.io/pypi/dm/solana-agent)](https://pypi.org/project/solana-agent/)
44
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
45
+ [![codecov](https://img.shields.io/codecov/c/github/truemagic-coder/solana-agent/main.svg)](https://codecov.io/gh/truemagic-coder/solana-agent)
46
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/truemagic-coder/solana-agent/ci.yml?branch=main)](https://github.com/truemagic-coder/solana-agent/actions/workflows/ci.yml)
47
+ [![Ruff Style](https://img.shields.io/badge/style-ruff-41B5BE)](https://github.com/astral-sh/ruff)
48
+
49
+ ![Solana Agent Logo](https://dl.walletbubbles.com/solana-agent-logo.png?width=200)
50
+
51
+ ## AI Agents for Solana
52
+
53
+ Build your AI agents in three lines of code!
54
+
55
+ ## Why?
56
+ * Three lines of code setup
57
+ * Simple Agent Definition
58
+ * Streaming or Realtime Responses
59
+ * Solana Integration
60
+ * Multi-Agent Swarm
61
+ * Multi-Modal (Images & Audio & Text)
62
+ * Conversational Memory & History
63
+ * Internet Search
64
+ * Intelligent Routing
65
+ * Business Alignment
66
+ * Extensible Tooling
67
+ * Autonomous Operation
68
+ * Smart Workflows
69
+ * Agentic Forms
70
+ * Knowledge Base
71
+ * MCP Support
72
+ * Guardrails
73
+ * Image Generation
74
+ * Pydantic Logfire
75
+ * Tested & Secure
76
+ * Built in Python
77
+ * Powers [CometHeart](https://cometheart.com)
78
+
79
+ ## Unique Selling Proposition (USP) - Smart Workflows
80
+
81
+ Solana Agent is the first AI agent framework to deliver truly intelligent, dynamic workflows.
82
+
83
+ With Solana Agent, you can seamlessly define and integrate tools — such as Zapier MCP (for sending emails via Mailgun) and the Solana Balance tool — directly into your agent’s capabilities.
84
+
85
+ Then prompt your agent with natural language, for example:
86
+ “Get my balances for my Solana wallet and then email them to me.”
87
+
88
+ Solana Agent will automatically orchestrate the workflow:
89
+ It will first use the Solana Balance tool to retrieve your balances, then invoke the Zapier MCP tool to send the results via email — all without manual intervention or brittle, hardcoded logic.
90
+
91
+ You can also chain tool outputs (structured or unstructured) as inputs for subsequent tasks, enabling complex, multi-step automations with ease.
92
+
93
+ **The result?**
94
+ A framework that is both powerful and simple — eliminating the need for static, fragile workflow definitions.
95
+ Smart workflows are as easy as combining your tools and prompts.
96
+
97
+ ## Features
98
+
99
+ * Easy three lines of code setup
100
+ * Simple agent definition using JSON
101
+ * Designed for a multi-agent swarm
102
+ * Fast multi-modal processing of text, audio, and images
103
+ * Dual modality realtime streaming with simultaneous audio and text output
104
+ * Smart workflows that keep flows simple and smart
105
+ * Interact with the Solana blockchain with many useful tools
106
+ * MCP tool usage with first-class support for [Zapier](https://zapier.com/mcp)
107
+ * Integrated observability and tracing via [Pydantic Logfire](https://pydantic.dev/logfire)
108
+ * Persistent memory that preserves context across all agent interactions
109
+ * Quick Internet search to answer users' queries
110
+ * Streamlined message history for all agent interactions
111
+ * Intelligent query routing to agents with optimal domain expertise or your own custom routing
112
+ * Unified value system ensuring brand-aligned agent responses
113
+ * Powerful tool integration using standard Python packages and/or inline tools
114
+ * Assigned tools are utilized by agents automatically and effectively
115
+ * Integrated Knowledge Base with semantic search and automatic PDF chunking
116
+ * Input and output guardrails for content filtering, safety, and data sanitization
117
+ * Generate custom images based on text prompts with storage on S3 compatible services
118
+ * Deterministic agentic form filling in natural conversation
119
+ * Combine with event-driven systems to create autonomous agents
120
+
121
+ ## Stack
122
+
123
+ ### Tech
124
+
125
+ * [Python](https://python.org) - Programming Language
126
+ * [OpenAI](https://openai.com) - AI Model Provider
127
+ * [Grok](https://x.ai) - Alternative AI Model Provider (optional)
128
+ * [MongoDB](https://mongodb.com) - Conversational History (optional)
129
+ * [Zep Cloud](https://getzep.com) - Conversational Memory (optional)
130
+ * [Pinecone](https://pinecone.io) - Knowledge Base (optional)
131
+ * [Zapier](https://zapier.com) - App Integrations (optional)
132
+ * [Pydantic Logfire](https://pydantic.dev/logfire) - Observability and Tracing (optional)
133
+
134
+ ### AI Models Used
135
+
136
+ **OpenAI**
137
+ * [gpt-4.1](https://platform.openai.com/docs/models/gpt-4.1) (agent & router)
138
+ * [text-embedding-3-large](https://platform.openai.com/docs/models/text-embedding-3-large) (embedding)
139
+ * [gpt-realtime](https://platform.openai.com/docs/models/gpt-realtime) (realtime audio agent with dual modality support)
140
+ * [tts-1](https://platform.openai.com/docs/models/tts-1) (audio TTS)
141
+ * [gpt-4o-mini-transcribe](https://platform.openai.com/docs/models/gpt-4o-mini-transcribe) (audio transcription)
142
+
143
+ ## Installation
144
+
145
+ You can install Solana Agent using pip:
146
+
147
+ `pip install solana-agent`
148
+
149
+ ## Flows
150
+
151
+ In both flows of single and multiple agents - it is one user query to one agent using one or many tools (if needed).
152
+
153
+ An agent can have multiple tools and will choose the best ones to fulfill the user's query.
154
+
155
+ Routing is determined by optimal domain expertise of the agent for the user's query.
156
+
157
+ When the agent uses tools it feeds the tools output back to itself to generate the final response.
158
+
159
+ This is important as tools generally output unstructured and unformatted data that the agent needs to prepare for the user.
160
+
161
+ Keep this in mind while designing your agentic systems using Solana Agent.
162
+
163
+ ```ascii
164
+ Single Agent
165
+
166
+ ┌────────┐ ┌─────────┐ ┌────────-┐
167
+ │ │ │ │ │ │
168
+ │ │ │ │ │ │
169
+ │ User │◄──────►│ Agent │◄──────►│ Tools │
170
+ │ │ │ │ │ │
171
+ │ │ │ │ │ │
172
+ └────────┘ └─────────┘ └────────-┘
173
+
174
+
175
+
176
+
177
+
178
+ Multiple Agents
179
+
180
+ ┌────────┐ ┌──────────┐ ┌─────────┐ ┌────────-┐
181
+ │ │ │ │ │ │ │ │
182
+ │ │ │ │ │ │ │ │
183
+ ┌───►│ User ├───────►│ Router ├───────►│ Agent │◄──────►│ Tools │
184
+ │ │ │ │ │ │ │ │ │
185
+ │ │ │ │ │ │ │ │ │
186
+ │ └────────┘ └──────────┘ └────┬────┘ └────────-┘
187
+ │ │
188
+ │ │
189
+ │ │
190
+ │ │
191
+ └───────────────────────────────────────────────┘
192
+ ```
193
+
194
+ ## Usage
195
+
196
+ ### Text/Text Streaming
197
+
198
+ ```python
199
+ from solana_agent import SolanaAgent
200
+
201
+ config = {
202
+ "openai": {
203
+ "api_key": "your-openai-api-key",
204
+ },
205
+ "agents": [
206
+ {
207
+ "name": "research_specialist",
208
+ "instructions": "You are an expert researcher who synthesizes complex information clearly.",
209
+ "specialization": "Research and knowledge synthesis",
210
+ },
211
+ {
212
+ "name": "customer_support",
213
+ "instructions": "You provide friendly, helpful customer support responses.",
214
+ "specialization": "Customer inquiries",
215
+ }
216
+ ],
217
+ }
218
+
219
+ solana_agent = SolanaAgent(config=config)
220
+
221
+ async for response in solana_agent.process("user123", "What are the latest AI developments?"):
222
+ print(response, end="")
223
+ ```
224
+
225
+ ### Audio/Audio Streaming
226
+
227
+ ```python
228
+ from solana_agent import SolanaAgent
229
+
230
+ config = {
231
+ "openai": {
232
+ "api_key": "your-openai-api-key",
233
+ },
234
+ "agents": [
235
+ {
236
+ "name": "research_specialist",
237
+ "instructions": "You are an expert researcher who synthesizes complex information clearly.",
238
+ "specialization": "Research and knowledge synthesis",
239
+ },
240
+ {
241
+ "name": "customer_support",
242
+ "instructions": "You provide friendly, helpful customer support responses.",
243
+ "specialization": "Customer inquiries",
244
+ }
245
+ ],
246
+ }
247
+
248
+ solana_agent = SolanaAgent(config=config)
249
+
250
+ audio_content = await audio_file.read()
251
+
252
+ async for response in solana_agent.process("user123", audio_content, output_format="audio", audio_voice="nova", audio_input_format="webm", audio_output_format="aac"):
253
+ print(response, end="")
254
+ ```
255
+
256
+ ### Text/Audio Streaming
257
+
258
+ ```python
259
+ from solana_agent import SolanaAgent
260
+
261
+ config = {
262
+ "openai": {
263
+ "api_key": "your-openai-api-key",
264
+ },
265
+ "agents": [
266
+ {
267
+ "name": "research_specialist",
268
+ "instructions": "You are an expert researcher who synthesizes complex information clearly.",
269
+ "specialization": "Research and knowledge synthesis",
270
+ },
271
+ {
272
+ "name": "customer_support",
273
+ "instructions": "You provide friendly, helpful customer support responses.",
274
+ "specialization": "Customer inquiries",
275
+ }
276
+ ],
277
+ }
278
+
279
+ solana_agent = SolanaAgent(config=config)
280
+
281
+ async for response in solana_agent.process("user123", "What is the latest news on Elon Musk?", output_format="audio", audio_voice="nova", audio_output_format="aac"):
282
+ print(response, end="")
283
+ ```
284
+
285
+ ### Audio/Text Streaming
286
+
287
+ ```python
288
+ ## Realtime Usage
289
+ from solana_agent import SolanaAgent
290
+
291
+ config = {
292
+ "openai": {
293
+ "api_key": "your-openai-api-key",
294
+ },
295
+ "agents": [
296
+ {
297
+ "name": "research_specialist",
298
+ "instructions": "You are an expert researcher who synthesizes complex information clearly.",
299
+ "specialization": "Research and knowledge synthesis",
300
+ },
301
+ {
302
+ "name": "customer_support",
303
+ "instructions": "You provide friendly, helpful customer support responses.",
304
+ "specialization": "Customer inquiries",
305
+ }
306
+ ],
307
+ }
308
+
309
+ solana_agent = SolanaAgent(config=config)
310
+
311
+ audio_content = await audio_file.read()
312
+
313
+ async for response in solana_agent.process("user123", audio_content, audio_input_format="aac"):
314
+ print(response, end="")
315
+ ```
316
+
317
+ ### Realtime Audio Streaming
318
+
319
+ If input and/or output is encoded (compressed) like mp4/mp3 then you must have `ffmpeg` installed.
320
+
321
+ Due to the overhead of the router (API call) - realtime only supports a single agent setup.
322
+
323
+ Realtime uses MongoDB for memory so Zep is not needed.
324
+
325
+ By default, when `realtime=True` and you supply raw/encoded audio bytes as input, the system **always skips the HTTP transcription (STT) path** and relies solely on the realtime websocket session for input transcription. If you don't specify `rt_transcription_model`, a sensible default (`gpt-4o-mini-transcribe`) is auto-selected so you still receive input transcript events with minimal latency.
326
+
327
+ Implications:
328
+ - `llm_provider.transcribe_audio` is never invoked for realtime turns.
329
+ - Lower end-to-end latency (no duplicate network round trip for STT).
330
+ - Unified transcript sourcing from realtime events.
331
+ - If you explicitly want to disable transcription altogether, send text (not audio bytes) or ignore transcript events client-side.
332
+
333
+ This example will work using expo-audio on Android and iOS.
334
+
335
+ ```python
336
+ from solana_agent import SolanaAgent
337
+
338
+ solana_agent = SolanaAgent(config=config)
339
+ user_id="user123",
340
+ message=audio_content,
341
+ realtime=True,
342
+ rt_encode_input=True,
343
+ rt_encode_output=True,
344
+ rt_output_modalities=["audio"],
345
+ rt_voice="marin",
346
+ output_format="audio",
347
+ audio_output_format="mp3",
348
+ audio_input_format="mp4",
349
+ ):
350
+ yield chunk
351
+
352
+ return StreamingResponse(
353
+ content=generate(),
354
+ media_type="audio/mp3",
355
+ headers={
356
+ "Cache-Control": "no-store",
357
+ "Pragma": "no-cache",
358
+ "Content-Disposition": "inline; filename=stream.mp3",
359
+ "X-Accel-Buffering": "no",
360
+ },
361
+ )
362
+ ```
363
+
364
+ ### Realtime Text Streaming
365
+
366
+ Due to the overhead of the router (API call) - realtime only supports a single agent setup.
367
+
368
+ Realtime uses MongoDB for memory so Zep is not needed.
369
+
370
+ When using realtime with text input, no audio transcription is needed. The same bypass rules apply—HTTP STT is never called in realtime mode.
371
+
372
+ ```python
373
+ from solana_agent import SolanaAgent
374
+
375
+ solana_agent = SolanaAgent(config=config)
376
+
377
+ async def generate():
378
+ async for chunk in solana_agent.process(
379
+ user_id="user123",
380
+ message="What is the latest news on Solana?",
381
+ realtime=True,
382
+ rt_output_modalities=["text"],
383
+ ):
384
+ yield chunk
385
+ ```
386
+
387
+ ### Dual Modality Realtime Streaming
388
+
389
+ Solana Agent supports **dual modality realtime streaming**, allowing you to stream both audio and text simultaneously from a single realtime session. This enables rich conversational experiences where users can receive both voice responses and text transcripts in real-time.
390
+
391
+ #### Features
392
+ - **Simultaneous Audio & Text**: Stream both modalities from the same conversation
393
+ - **Flexible Output**: Choose audio-only, text-only, or both modalities
394
+ - **Real-time Demuxing**: Automatically separate audio and text streams
395
+ - **Mobile Optimized**: Works seamlessly with compressed audio formats (MP4/AAC)
396
+ - **Memory Efficient**: Smart buffering and streaming for optimal performance
397
+
398
+ #### Mobile App Integration Example
399
+
400
+ ```python
401
+ from fastapi import UploadFile
402
+ from fastapi.responses import StreamingResponse
403
+ from solana_agent import SolanaAgent
404
+ from solana_agent.interfaces.providers.realtime import RealtimeChunk
405
+ import base64
406
+
407
+ solana_agent = SolanaAgent(config=config)
408
+
409
+ @app.post("/realtime/dual")
410
+ async def realtime_dual_endpoint(audio_file: UploadFile):
411
+ """
412
+ Dual modality (audio + text) realtime endpoint using Server-Sent Events (SSE).
413
+ Emits:
414
+ event: audio (base64 encoded audio frames)
415
+ event: transcript (incremental text)
416
+ Notes:
417
+ - Do NOT set output_format when using both modalities.
418
+ - If only one modality is requested, plain str (text) or raw audio bytes may be yielded instead of RealtimeChunk.
419
+ """
420
+ audio_content = await audio_file.read()
421
+
422
+ async def event_stream():
423
+ async for chunk in solana_agent.process(
424
+ user_id="mobile_user",
425
+ message=audio_content,
426
+ realtime=True,
427
+ rt_encode_input=True,
428
+ rt_encode_output=True,
429
+ rt_output_modalities=["audio", "text"],
430
+ rt_voice="marin",
431
+ audio_input_format="mp4",
432
+ audio_output_format="mp3",
433
+ # Optionally lock transcription model (otherwise default is auto-selected):
434
+ # rt_transcription_model="gpt-4o-mini-transcribe",
435
+ ):
436
+ if isinstance(chunk, RealtimeChunk):
437
+ if chunk.is_audio and chunk.audio_data:
438
+ b64 = base64.b64encode(chunk.audio_data).decode("ascii")
439
+ yield f"event: audio\ndata: {b64}\n\n"
440
+ elif chunk.is_text and chunk.text_data:
441
+ # Incremental transcript (not duplicated at finalize)
442
+ yield f"event: transcript\ndata: {chunk.text_data}\n\n"
443
+ continue
444
+ # (Defensive) fallback: if something else appears
445
+ if isinstance(chunk, bytes):
446
+ b64 = base64.b64encode(chunk).decode("ascii")
447
+ yield f"event: audio\ndata: {b64}\n\n"
448
+ elif isinstance(chunk, str):
449
+ yield f"event: transcript\ndata: {chunk}\n\n"
450
+
451
+ yield "event: done\ndata: end\n\n"
452
+
453
+ return StreamingResponse(
454
+ event_stream(),
455
+ media_type="text/event-stream",
456
+ headers={
457
+ "Cache-Control": "no-store",
458
+ "Access-Control-Allow-Origin": "*",
459
+ },
460
+ )
461
+ ```
462
+
463
+ ### Image/Text Streaming
464
+
465
+ ```python
466
+ from solana_agent import SolanaAgent
467
+
468
+ config = {
469
+ "openai": {
470
+ "api_key": "your-openai-api-key",
471
+ },
472
+ "agents": [
473
+ {
474
+ "name": "vision_expert",
475
+ "instructions": "You are an expert at analyzing images and answering questions about them.",
476
+ "specialization": "Image analysis",
477
+ }
478
+ ],
479
+ }
480
+
481
+ solana_agent = SolanaAgent(config=config)
482
+
483
+ # Example with an image URL
484
+ image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
485
+
486
+ # Example reading image bytes from a file
487
+ image_bytes = await image_file.read()
488
+
489
+ # You can mix URLs and bytes in the list
490
+ images_to_process = [
491
+ image_url,
492
+ image_bytes,
493
+ ]
494
+
495
+ async for response in solana_agent.process("user123", "What is in this image? Describe the scene.", images=images_to_process):
496
+ print(response, end="")
497
+ ```
498
+
499
+ ### Agentic Forms
500
+
501
+ You can attach a JSON Schema to any agent in your config so it can collect structured data conversationally.
502
+
503
+ ```python
504
+ from solana_agent import SolanaAgent
505
+
506
+ config = {
507
+ "openai": {
508
+ "api_key": "your-openai-api-key",
509
+ },
510
+ "agents": [
511
+ {
512
+ "name": "customer_support",
513
+ "instructions": "You provide friendly, helpful customer support responses.",
514
+ "specialization": "Customer inquiries",
515
+ "capture_name": "contact_info",
516
+ "capture_schema": {
517
+ "type": "object",
518
+ "properties": {
519
+ "email": { "type": "string" },
520
+ "phone": { "type": "string" },
521
+ "newsletter_subscribe": { "type": "boolean" }
522
+ },
523
+ "required": ["email"]
524
+ }
525
+ }
526
+ ]
527
+ }
528
+
529
+ solana_agent = SolanaAgent(config=config)
530
+
531
+ async for response in solana_agent.process("user123", "What are the latest AI developments?"):
532
+ print(response, end="")
533
+ ```
534
+
535
+ ### Command Line Interface (CLI)
536
+
537
+ Solana Agent includes a command-line interface (CLI) for text-based chat using a configuration file.
538
+
539
+ Ensure you have a valid configuration file (e.g., `config.json`) containing at least your OpenAI API key and agent definitions.
540
+
541
+ **./config.json**
542
+ ```json
543
+ {
544
+ "openai": {
545
+ "api_key": "your-openai-api-key"
546
+ },
547
+ "agents": [
548
+ {
549
+ "name": "default_agent",
550
+ "instructions": "You are a helpful AI assistant.",
551
+ "specialization": "general"
552
+ }
553
+ ]
554
+ }
555
+ ```
556
+
557
+ Also ensure that you have `pip install uv` to call `uvx`.
558
+
559
+ ```bash
560
+ uvx solana-agent [OPTIONS]
561
+
562
+ Options:
563
+
564
+ --user-id TEXT: The user ID for the conversation (default: cli_user).
565
+ --config TEXT: Path to the configuration JSON file (default: config.json).
566
+ --prompt TEXT: Optional system prompt override for the agent.
567
+ --help: Show help message and exit.
568
+
569
+ # Using default config.json and user_id
570
+ uvx solana-agent
571
+
572
+ # Specifying user ID and config path
573
+ uvx solana-agent --user-id my_cli_session --config ./my_agent_config.json
574
+ ```
575
+
576
+ ## Optional Feature Configs
577
+
578
+ ### Grok
579
+
580
+ Solana Agent supports using Grok from xAI as an alternative to OpenAI. When Grok is configured, it will be used for all LLM operations except embeddings, TTS, and STT (which still require OpenAI).
581
+
582
+ **Note:** Grok configuration takes priority over OpenAI. If both are present, Grok will be used.
583
+
584
+ ```python
585
+ config = {
586
+ "grok": {
587
+ "api_key": "your-grok-api-key",
588
+ "base_url": "https://api.x.ai/v1", # Optional, defaults to https://api.x.ai/v1
589
+ "model": "grok-4-1-fast-non-reasoning" # Optional, defaults to grok-4-1-fast-non-reasoning
590
+ },
591
+ # You can still include OpenAI for embeddings, TTS, and STT
592
+ "openai": {
593
+ "api_key": "your-openai-api-key"
594
+ },
595
+ "agents": [
596
+ {
597
+ "name": "research_specialist",
598
+ "instructions": "You are an expert researcher.",
599
+ "specialization": "Research",
600
+ }
601
+ ],
602
+ }
603
+ ```
604
+
605
+ **Verified Capabilities:**
606
+ - ✅ Chat completions
607
+ - ✅ Streaming responses
608
+ - ✅ Function calling/Tool usage
609
+ - ✅ Structured outputs (via Instructor TOOLS_STRICT and JSON modes)
610
+ - ✅ Native JSON mode
611
+
612
+ ### Business Alignment
613
+
614
+ ```python
615
+ config = {
616
+ "business": {
617
+ "mission": "To provide users with a one-stop shop for their queries.",
618
+ "values": {
619
+ "Friendliness": "Users must be treated fairly, openly, and with friendliness.",
620
+ "Ethical": "Agents must use a strong ethical framework in their interactions with users.",
621
+ },
622
+ "goals": [
623
+ "Empower users with great answers to their queries.",
624
+ ],
625
+ "voice": "The voice of the brand is that of a research business."
626
+ },
627
+ }
628
+ ```
629
+
630
+ ### Conversational History
631
+
632
+ ```python
633
+ config = {
634
+ "mongo": {
635
+ "connection_string": "your-mongo-connection-string",
636
+ "database": "your-database-name"
637
+ },
638
+ }
639
+ ```
640
+
641
+ ### Conversational Memory
642
+
643
+ ```python
644
+ config = {
645
+ "zep": {
646
+ "api_key": "your-zep-cloud-api-key",
647
+ },
648
+ }
649
+ ```
650
+
651
+ ### Observability and Tracing
652
+
653
+ ```python
654
+ config = {
655
+ "logfire": {
656
+ "api_key": "your-logfire-write-token",
657
+ },
658
+ }
659
+ ```
660
+
661
+ ### Knowledge Base
662
+
663
+ The Knowledge Base (KB) is meant to store text values and/or PDFs (extracts text) - can handle very large PDFs.
664
+
665
+ ```python
666
+ config = {
667
+ "knowledge_base": {
668
+ "pinecone": {
669
+ "api_key": "your-pinecone-api-key",
670
+ "index_name": "your-pinecone-index-name",
671
+ }
672
+ },
673
+ "mongo": {
674
+ "connection_string": "your-mongo-connection-string",
675
+ "database": "your-database-name"
676
+ },
677
+ }
678
+ ```
679
+
680
+ #### Example for KB (text)
681
+
682
+ ```python
683
+ from solana_agent import SolanaAgent
684
+
685
+ config = {
686
+ "openai": {
687
+ "api_key": "your-openai-api-key",
688
+ },
689
+ "knowledge_base": {
690
+ "pinecone": {
691
+ "api_key": "your-pinecone-api-key",
692
+ "index_name": "your-pinecone-index-name",
693
+ }
694
+ },
695
+ "mongo": {
696
+ "connection_string": "your-mongo-connection-string",
697
+ "database": "your-database-name"
698
+ },
699
+ "agents": [
700
+ {
701
+ "name": "kb_expert",
702
+ "instructions": "You answer questions based on the provided knowledge base documents.",
703
+ "specialization": "Company Knowledge",
704
+ }
705
+ ]
706
+ }
707
+
708
+ solana_agent = SolanaAgent(config=config)
709
+
710
+ doc_text = "Solana Agent is a Python framework for building multi-agent AI systems."
711
+ doc_metadata = {
712
+ "source": "internal_docs",
713
+ "version": "1.0",
714
+ "tags": ["framework", "python", "ai"]
715
+ }
716
+ await solana_agent.kb_add_document(text=doc_text, metadata=doc_metadata)
717
+
718
+ async for response in solana_agent.process("user123", "What is Solana Agent?"):
719
+ print(response, end="")
720
+ ```
721
+
722
+ #### Example for KB (pdf)
723
+
724
+ ```python
725
+ from solana_agent import SolanaAgent
726
+
727
+ config = {
728
+ "openai": {
729
+ "api_key": "your-openai-api-key",
730
+ },
731
+ "knowledge_base": {
732
+ "pinecone": {
733
+ "api_key": "your-pinecone-api-key",
734
+ "index_name": "your-pinecone-index-name",
735
+ }
736
+ },
737
+ "mongo": {
738
+ "connection_string": "your-mongo-connection-string",
739
+ "database": "your-database-name"
740
+ },
741
+ "agents": [
742
+ {
743
+ "name": "kb_expert",
744
+ "instructions": "You answer questions based on the provided knowledge base documents.",
745
+ "specialization": "Company Knowledge",
746
+ }
747
+ ]
748
+ }
749
+
750
+ solana_agent = SolanaAgent(config=config)
751
+
752
+ pdf_bytes = await pdf_file.read()
753
+
754
+ pdf_metadata = {
755
+ "source": "annual_report_2024.pdf",
756
+ "year": 2024,
757
+ "tags": ["finance", "report"]
758
+ }
759
+
760
+ await solana_agent.kb_add_pdf_document(
761
+ pdf_data=pdf_bytes,
762
+ metadata=pdf_metadata,
763
+ )
764
+
765
+ async for response in solana_agent.process("user123", "Summarize the annual report for 2024."):
766
+ print(response, end="")
767
+ ```
768
+
769
+ ### Guardrails
770
+
771
+ Guardrails allow you to process and potentially modify user input before it reaches the agent (Input Guardrails) and agent output before it's sent back to the user (Output Guardrails). This is useful for implementing safety checks, content moderation, data sanitization, or custom transformations.
772
+
773
+ Guardrails don't work with structured outputs.
774
+
775
+ Solana Agent provides a built-in PII scrubber based on [scrubadub](https://github.com/LeapBeyond/scrubadub).
776
+
777
+ ```python
778
+ from solana_agent import SolanaAgent
779
+
780
+ config = {
781
+ "guardrails": {
782
+ "input": [
783
+ # Example using a custom input guardrail
784
+ {
785
+ "class": "MyInputGuardrail",
786
+ "config": {"setting1": "value1"}
787
+ },
788
+ # Example using the built-in PII guardrail for input
789
+ {
790
+ "class": "solana_agent.guardrails.pii.PII",
791
+ "config": {
792
+ "locale": "en_GB", # Optional: Specify locale (default: en_US)
793
+ "replacement": "[REDACTED]" # Optional: Custom replacement format
794
+ }
795
+ }
796
+ ],
797
+ "output": [
798
+ # Example using a custom output guardrail
799
+ {
800
+ "class": "MyOutputGuardrail",
801
+ "config": {"filter_level": "high"}
802
+ },
803
+ # Example using the built-in PII guardrail for output (with defaults)
804
+ {
805
+ "class": "solana_agent.guardrails.pii.PII"
806
+ # No config needed to use defaults
807
+ }
808
+ ]
809
+ },
810
+ }
811
+ ```
812
+
813
+ #### Example Custom Guardrails
814
+
815
+ Guardrails don't work with structured outputs.
816
+
817
+ ```python
818
+ from solana_agent import InputGuardrail, OutputGuardrail
819
+ import logging
820
+
821
+ logger = logging.getLogger(__name__)
822
+
823
+ class MyInputGuardrail(InputGuardrail):
824
+ def __init__(self, config=None):
825
+ super().__init__(config)
826
+ self.setting1 = self.config.get("setting1", "default_value")
827
+ logger.info(f"MyInputGuardrail initialized with setting1: {self.setting1}")
828
+
829
+ async def process(self, text: str) -> str:
830
+ # Example: Convert input to lowercase
831
+ processed_text = text.lower()
832
+ logger.debug(f"Input Guardrail processed: {text} -> {processed_text}")
833
+ return processed_text
834
+
835
+ class MyOutputGuardrail(OutputGuardrail):
836
+ def __init__(self, config=None):
837
+ super().__init__(config)
838
+ self.filter_level = self.config.get("filter_level", "low")
839
+ logger.info(f"MyOutputGuardrail initialized with filter_level: {self.filter_level}")
840
+
841
+ async def process(self, text: str) -> str:
842
+ # Example: Basic profanity filtering (replace with a real library)
843
+ if self.filter_level == "high" and "badword" in text:
844
+ processed_text = text.replace("badword", "*******")
845
+ logger.warning(f"Output Guardrail filtered content.")
846
+ return processed_text
847
+ logger.debug("Output Guardrail passed text through.")
848
+ return text
849
+ ```
850
+
851
+ ## Tools
852
+
853
+ Tools empower agents to interact with external systems, fetch data, or perform actions. They can be used reactively within a user conversation or proactively when an agent is triggered autonomously.
854
+
855
+ Tools can be used from plugins like Solana Agent Kit (sakit) or via inline tools. Tools available via plugins integrate automatically with Solana Agent.
856
+
857
+ ### Solana Agent Kit
858
+
859
+ [Solana Agent Kit](https://github.com/truemagic-coder/solana-agent-kit)
860
+
861
+ ```bash
862
+ pip install sakit
863
+ ```
864
+
865
+ ### Inline Tool Example
866
+
867
+ ```python
868
+ from solana_agent import SolanaAgent, Tool
869
+
870
+ class TestTool(Tool):
871
+ def __init__(self):
872
+ # your tool initialization - delete the following pass
873
+ pass
874
+
875
+ @property
876
+ def name(self) -> str:
877
+ return "test_function"
878
+
879
+ @property
880
+ def description(self) -> str:
881
+ return "Test function for Solana Agent"
882
+
883
+ def configure(self, config: Dict[str, Any]) -> None:
884
+ """Configure with all possible API key locations."""
885
+ super().configure(config)
886
+
887
+ # read your config values - delete the following pass
888
+ pass
889
+
890
+ def get_schema(self) -> Dict[str, Any]:
891
+ # this is an example schema
892
+ return {
893
+ "type": "object",
894
+ "properties": {
895
+ "query": {"type": "string", "description": "Search query text"},
896
+ "user_id": {"type": "string", "description": "User ID for the search session"}
897
+ },
898
+ "required": ["query", "user_id"],
899
+ "additionalProperties": False,
900
+ }
901
+
902
+ async def execute(self, **params) -> Dict[str, Any]:
903
+ try:
904
+ # your tool logic
905
+ result = "Your tool results"
906
+
907
+ return {
908
+ "status": "success",
909
+ "result": result,
910
+ }
911
+ except Exception as e:
912
+ return {
913
+ "status": "error",
914
+ "message": f"Error: {str(e)}",
915
+ }
916
+
917
+ config = {
918
+ "openai": {
919
+ "api_key": "your-openai-api-key",
920
+ },
921
+ "agents": [
922
+ {
923
+ "name": "research_specialist",
924
+ "instructions": "You are an expert researcher who synthesizes complex information clearly.",
925
+ "specialization": "Research and knowledge synthesis",
926
+ },
927
+ {
928
+ "name": "customer_support",
929
+ "instructions": "You provide friendly, helpful customer support responses.",
930
+ "specialization": "Customer inquiries",
931
+ }
932
+ ],
933
+ }
934
+
935
+ solana_agent = SolanaAgent(config=config)
936
+
937
+ test_tool = TestTool()
938
+
939
+ solana_agent.register_tool("customer_support", test_tool)
940
+
941
+ async for response in solana_agent.process("user123", "What are the latest AI developments?"):
942
+ print(response, end="")
943
+ ```
944
+
945
+ ## Autonomous Operation & Event-Driven Agents
946
+
947
+ While Solana Agent facilitates request-response interactions, the underlying architecture supports building autonomous agents. You can achieve autonomy by orchestrating calls based on external triggers rather than direct user input.
948
+
949
+ **Key Concepts:**
950
+
951
+ * **External Triggers:** Use schedulers like cron, message queues (RabbitMQ, Kafka), monitoring systems, webhooks, or other event sources to initiate agent actions.
952
+ * **Programmatic Calls:** Instead of a user typing a message, your triggering system calls with a specific message (acting as instructions or data for the task) and potentially a dedicated user representing the autonomous process.
953
+ * **Tool-Centric Tasks:** Autonomous agents often focus on executing specific tools. The prompt can instruct the agent to use a particular tool with given parameters derived from the triggering event.
954
+ * **Example Scenario:** An agent could be triggered hourly by a scheduler. The `message` could be "Check the SOL balance for wallet X using the `solana` tool." The agent executes the tool, and the result could be logged or trigger another tool (e.g., using `mcp` to send an alert if the balance is low).
955
+
956
+ By combining Solana Agent's agent definitions, tool integration, and routing with external orchestration, you can create sophisticated autonomous systems.
957
+
958
+ ## Advanced Customization
959
+
960
+ ### Runtime Prompt Injection
961
+
962
+ ```python
963
+ from solana_agent import SolanaAgent
964
+
965
+ config = {
966
+ "openai": {
967
+ "api_key": "your-openai-api-key",
968
+ },
969
+ "agents": [
970
+ {
971
+ "name": "customer_support",
972
+ "instructions": "You provide friendly, helpful customer support responses.",
973
+ "specialization": "Customer inquiries",
974
+ }
975
+ ],
976
+ }
977
+
978
+ solana_agent = SolanaAgent(config=config)
979
+
980
+ async for response in solana_agent.process("user123", "How do replace the latch on my dishwasher?", "This is my corporate appliance fixing FAQ"):
981
+ print(response, end="")
982
+ ```
983
+
984
+ ### Custom Routing
985
+
986
+ In advanced cases like implementing a ticketing system on-top of Solana Agent - you can use your own router.
987
+
988
+ ```python
989
+ from solana_agent import SolanaAgent
990
+ from solana_agent.interfaces.services.routing import RoutingService as RoutingServiceInterface
991
+
992
+ config = {
993
+ "openai": {
994
+ "api_key": "your-openai-api-key",
995
+ },
996
+ "agents": [
997
+ {
998
+ "name": "research_specialist",
999
+ "instructions": "You are an expert researcher who synthesizes complex information clearly.",
1000
+ "specialization": "Research and knowledge synthesis",
1001
+ },
1002
+ {
1003
+ "name": "customer_support",
1004
+ "instructions": "You provide friendly, helpful customer support responses.",
1005
+ "specialization": "Customer inquiries",
1006
+ }
1007
+ ],
1008
+ }
1009
+
1010
+ class Router(RoutingServiceInterface)
1011
+ def __init__(self):
1012
+ # your router initialization - delete the following pass
1013
+ pass
1014
+
1015
+ async def route_query(self, query: str) -> str:
1016
+ # a simple example to route always to customer_support agent
1017
+ return "customer_support"
1018
+
1019
+ router = Router()
1020
+
1021
+ solana_agent = SolanaAgent(config=config)
1022
+
1023
+ async for response in solana_agent.process("user123", "What are the latest AI developments?", router=router):
1024
+ print(response, end="")
1025
+ ```
1026
+
1027
+ ## API Documentation
1028
+
1029
+ The official up-to-date documentation site
1030
+
1031
+ [Solana Agent Documentation Site](https://docs.solana-agent.com)
1032
+
1033
+ ## Official Tools
1034
+
1035
+ The official collection of tools in one plugin
1036
+
1037
+ [Solana Agent Kit](https://github.com/truemagic-coder/solana-agent-kit)
1038
+
1039
+ ## Example App
1040
+
1041
+ The official example app written in FastAPI and Next.js
1042
+
1043
+ [Solana Agent Example App](https://github.com/truemagic-coder/solana-agent-app)
1044
+
1045
+ ## Demo App
1046
+
1047
+ The official demo app written in FastAPI and Next.js
1048
+
1049
+ [Solana Agent Demo App](https://demo.solana-agent.com)
1050
+
1051
+ ## Agent Framework Comparisons
1052
+
1053
+ [Compare Python Agent Frameworks](https://github.com/truemagic-coder/solana-agent/wiki/Agent-Framework-Comparisons)
1054
+
1055
+ ## Contributing
1056
+
1057
+ If you have a question, feedback, or feature request - please open a GitHub discussion.
1058
+
1059
+ If you find a bug - please open a GitHub issue.
1060
+
1061
+ We are currently accepting PRs if approved in discussions. Make sure all tests pass and the README & docs are updated.
1062
+
1063
+ To run the documentation site locally run `make livehtml` in the root directory.
1064
+
1065
+ To run the test suite locally run `poetry run pytest --cov=solana_agent --cov-report=html` in the root directory.
1066
+
1067
+ ## License
1068
+
1069
+ This project is licensed under the MIT License - see the LICENSE file for details.
1070
+