elidia-agent-cli 0.4.0__tar.gz → 0.4.2__tar.gz

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 (137) hide show
  1. {elidia_agent_cli-0.4.0/elidia_agent_cli.egg-info → elidia_agent_cli-0.4.2}/PKG-INFO +72 -6
  2. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/README.md +71 -5
  3. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/agent/loop.py +403 -4
  4. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/api/client.py +46 -3
  5. elidia_agent_cli-0.4.2/elidia/attachments.py +186 -0
  6. elidia_agent_cli-0.4.2/elidia/cli/banner.py +398 -0
  7. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/cli/repl.py +213 -31
  8. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/config/defaults.py +1 -1
  9. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/daemon/ipc.py +16 -3
  10. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/daemon/worker.py +189 -1
  11. elidia_agent_cli-0.4.2/elidia/memory/knowledge_graph.py +286 -0
  12. elidia_agent_cli-0.4.2/elidia/memory/output_evaluator.py +155 -0
  13. elidia_agent_cli-0.4.2/elidia/memory/pattern_learner.py +205 -0
  14. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/models/router.py +38 -6
  15. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/modes/classifier.py +8 -1
  16. elidia_agent_cli-0.4.2/elidia/orchestration/__init__.py +7 -0
  17. elidia_agent_cli-0.4.2/elidia/orchestration/deep_evaluator.py +223 -0
  18. elidia_agent_cli-0.4.2/elidia/orchestration/project_planner.py +323 -0
  19. elidia_agent_cli-0.4.2/elidia/orchestration/sprint_executor.py +204 -0
  20. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/research/orchestrator.py +24 -9
  21. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2/elidia_agent_cli.egg-info}/PKG-INFO +72 -6
  22. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia_agent_cli.egg-info/SOURCES.txt +9 -0
  23. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/pyproject.toml +1 -1
  24. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/CHANGELOG.md +0 -0
  25. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/LICENSE +0 -0
  26. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/MANIFEST.in +0 -0
  27. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/ARCHITECTURE_FLOWCHARTS.md +0 -0
  28. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/AUDIT_REPORT_v0.1.0.md +0 -0
  29. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/api/commands.md +0 -0
  30. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/architecture/modules.md +0 -0
  31. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/architecture/overview.md +0 -0
  32. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/getting-started/configuration.md +0 -0
  33. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/getting-started/installation.md +0 -0
  34. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/getting-started/quickstart.md +0 -0
  35. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/guide/chat-modes.md +0 -0
  36. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/guide/creative.md +0 -0
  37. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/guide/models.md +0 -0
  38. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/guide/research.md +0 -0
  39. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/guide/themes.md +0 -0
  40. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/guide/tools-mcp.md +0 -0
  41. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/guide/workflows.md +0 -0
  42. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/docs/index.md +0 -0
  43. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/__init__.py +0 -0
  44. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/__main__.py +0 -0
  45. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/agent/__init__.py +0 -0
  46. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/agent/personas.py +0 -0
  47. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/agent/portal.py +0 -0
  48. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/api/__init__.py +0 -0
  49. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/api/streaming.py +0 -0
  50. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/auth/__init__.py +0 -0
  51. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/auth/keychain.py +0 -0
  52. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/cache/__init__.py +0 -0
  53. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/cache/lru.py +0 -0
  54. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/cli/__init__.py +0 -0
  55. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/cli/commands.py +0 -0
  56. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/cli/main.py +0 -0
  57. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/cli/pager.py +0 -0
  58. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/cli/progress.py +0 -0
  59. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/cli/renderer.py +0 -0
  60. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/cli/themes.py +0 -0
  61. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/config/__init__.py +0 -0
  62. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/config/rules.py +0 -0
  63. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/config/settings.py +0 -0
  64. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/creative/__init__.py +0 -0
  65. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/creative/audio.py +0 -0
  66. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/creative/display.py +0 -0
  67. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/creative/image.py +0 -0
  68. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/creative/local.py +0 -0
  69. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/creative/video.py +0 -0
  70. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/daemon/__init__.py +0 -0
  71. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/daemon/config.py +0 -0
  72. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/daemon/manager.py +0 -0
  73. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/daemon/process.py +0 -0
  74. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/db/__init__.py +0 -0
  75. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/db/database.py +0 -0
  76. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/mcp/__init__.py +0 -0
  77. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/mcp/client.py +0 -0
  78. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/mcp/config.py +0 -0
  79. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/mcp/registry.py +0 -0
  80. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/mcp/types.py +0 -0
  81. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/memory/__init__.py +0 -0
  82. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/memory/auto.py +0 -0
  83. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/memory/compaction.py +0 -0
  84. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/memory/embeddings.py +0 -0
  85. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/memory/outcomes.py +0 -0
  86. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/memory/patterns.py +0 -0
  87. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/memory/store.py +0 -0
  88. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/models/__init__.py +0 -0
  89. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/models/adaptive.py +0 -0
  90. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/models/local.py +0 -0
  91. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/modes/__init__.py +0 -0
  92. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/modes/autonomous.py +0 -0
  93. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/modes/budget.py +0 -0
  94. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/modes/consensus.py +0 -0
  95. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/modes/deep_think.py +0 -0
  96. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/modes/swarm.py +0 -0
  97. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/modes/thinking.py +0 -0
  98. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/permissions/__init__.py +0 -0
  99. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/permissions/audit.py +0 -0
  100. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/permissions/manager.py +0 -0
  101. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/permissions/trust.py +0 -0
  102. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/rag/__init__.py +0 -0
  103. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/rag/chunker.py +0 -0
  104. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/rag/engine.py +0 -0
  105. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/rag/ingest.py +0 -0
  106. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/rag/portal_bridge.py +0 -0
  107. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/rag/watcher.py +0 -0
  108. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/research/__init__.py +0 -0
  109. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/research/export.py +0 -0
  110. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/research/sources.py +0 -0
  111. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/session/__init__.py +0 -0
  112. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/session/history.py +0 -0
  113. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/session/manager.py +0 -0
  114. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/__init__.py +0 -0
  115. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/base.py +0 -0
  116. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/browser.py +0 -0
  117. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/calendar.py +0 -0
  118. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/database.py +0 -0
  119. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/email.py +0 -0
  120. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/fetch.py +0 -0
  121. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/filesystem.py +0 -0
  122. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/git.py +0 -0
  123. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/office.py +0 -0
  124. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/rag.py +0 -0
  125. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/search.py +0 -0
  126. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/terminal.py +0 -0
  127. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/tools/tool_router.py +0 -0
  128. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/widgets/__init__.py +0 -0
  129. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/widgets/protocol.py +0 -0
  130. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/widgets/renderer.py +0 -0
  131. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/workflow/__init__.py +0 -0
  132. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia/workflow/engine.py +0 -0
  133. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia_agent_cli.egg-info/dependency_links.txt +0 -0
  134. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia_agent_cli.egg-info/entry_points.txt +0 -0
  135. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia_agent_cli.egg-info/requires.txt +0 -0
  136. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/elidia_agent_cli.egg-info/top_level.txt +0 -0
  137. {elidia_agent_cli-0.4.0 → elidia_agent_cli-0.4.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: elidia-agent-cli
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: Elidia Agent CLI — Universal AI Agent for your terminal
5
5
  Author-email: Elidia Technology Pvt Ltd <support@aiutils.io>
6
6
  License-Expression: LicenseRef-Proprietary
@@ -171,18 +171,84 @@ pip install elidia_agent_cli-0.3.0-py3-none-any.whl
171
171
  ## Quick Start
172
172
 
173
173
  ### 1. Authenticate
174
-
175
174
  ```bash
176
175
  elidia auth login
177
176
  ```
178
-
179
- You'll be prompted for your AiUtils Developer API key (`ak-dev-...`).
177
+ Enter your AiUtils Developer API key (`ak-dev-...`). Get one at [developer.aiutils.io](https://developer.aiutils.io).
180
178
 
181
179
  ### 2. Start chatting
180
+ ```bash
181
+ elidia ask "Write a Python function to reverse a string"
182
+ elidia # Interactive REPL
183
+ ```
182
184
 
185
+ ## All Commands
186
+
187
+ | Command | Description |
188
+ |---|---|
189
+ | `elidia ask <msg>` | One-shot message (supports `--model`, `--mode`, `--file`, `--image`) |
190
+ | `elidia` | Interactive REPL with 27 slash commands |
191
+ | `elidia auth login/logout/status` | Manage API key |
192
+ | `elidia auth email-login/email-logout/email-status` | Email credentials |
193
+ | `elidia config show` | View current configuration |
194
+ | `elidia config set <section.field> <value>` | Persist preferences (e.g., `models.default gpt-4o`) |
195
+ | `elidia daemon start/stop/restart/status/init` | Background daemon (24/7 agent) |
196
+ | `elidia mcp list/health` | MCP server management |
197
+ | `elidia models` | List all 30+ available LLMs |
198
+ | `elidia models --local` | List local Ollama models |
199
+ | `elidia rag ingest/search/list/clear` | Local RAG document store |
200
+ | `elidia session list/new/delete` | Session management |
201
+ | `elidia version` | Show version |
202
+ | `elidia workflow run <file>` | Execute YAML workflow |
203
+
204
+ ## Available Models
205
+
206
+ ### Language Models (LLMs) — `elidia models`
207
+ 30+ models via AiUtils API: Claude (Opus 4.8, Sonnet 4-6), GPT (4o, 5.5), Gemini (2.5 Pro/Flash), DeepSeek (V4, Reasoner), Llama (4, 3.3), Qwen (3, 2.5), Mistral, and more.
208
+
209
+ ### Creative Models — available through chat
210
+ | Category | Count | Example |
211
+ |---|---|---|
212
+ | Image Generation | 500+ | Flux, SDXL, DALL-E, Midjourney |
213
+ | Video Generation | 500+ | Runway, Pika, Kling, Sora |
214
+ | Audio/Music | 100+ | ElevenLabs, MusicGen, Whisper |
215
+ | 3D Generation | 20+ | TripoSR, Zero123++, Stable3D |
216
+
217
+ ### Local Models — `elidia models --local`
218
+ Ollama models running on your machine. Zero API cost, works offline.
183
219
  ```bash
184
- # Interactive REPL
185
- elidia chat
220
+ ollama pull qwen3:1.7b
221
+ elidia models --local
222
+ ```
223
+
224
+ ## Working Modes
225
+
226
+ | Mode | Use for |
227
+ |---|---|
228
+ | `chat` | General conversation, creative work |
229
+ | `code` | Software development, debugging |
230
+ | `research` | Deep research with web search + RAG |
231
+ | `think` | Extended chain-of-thought reasoning |
232
+ | `create` | Content generation (books, scripts, ads) |
233
+
234
+ Set via `--mode` flag, `/mode` in REPL, or mode selector in Desktop.
235
+
236
+ **Advanced execution strategies (REPL):**
237
+ | Command | Description |
238
+ |---|---|
239
+ | `/research <topic>` | 3-agent research pipeline (plan → search → synthesize) |
240
+ | `/think <problem>` | Deep reasoning with chain-of-thought |
241
+ | `/budget` | Show session cost |
242
+ | `/persona <slug>` | Switch domain persona (coder, doctor, lawyer, marketer, etc.) |
243
+
244
+ ## MCP Servers — `elidia mcp`
245
+
246
+ Connect to any MCP server to extend capabilities:
247
+ ```bash
248
+ elidia mcp list # Show connected servers
249
+ elidia mcp health # Check server status
250
+ ```
251
+ Configure in `~/.elidia/mcp.json`. Connect databases, APIs, GitHub, Slack, Jira, and more.
186
252
 
187
253
  # One-shot query
188
254
  elidia chat "Explain async/await in Python"
@@ -111,18 +111,84 @@ pip install elidia_agent_cli-0.3.0-py3-none-any.whl
111
111
  ## Quick Start
112
112
 
113
113
  ### 1. Authenticate
114
-
115
114
  ```bash
116
115
  elidia auth login
117
116
  ```
118
-
119
- You'll be prompted for your AiUtils Developer API key (`ak-dev-...`).
117
+ Enter your AiUtils Developer API key (`ak-dev-...`). Get one at [developer.aiutils.io](https://developer.aiutils.io).
120
118
 
121
119
  ### 2. Start chatting
120
+ ```bash
121
+ elidia ask "Write a Python function to reverse a string"
122
+ elidia # Interactive REPL
123
+ ```
122
124
 
125
+ ## All Commands
126
+
127
+ | Command | Description |
128
+ |---|---|
129
+ | `elidia ask <msg>` | One-shot message (supports `--model`, `--mode`, `--file`, `--image`) |
130
+ | `elidia` | Interactive REPL with 27 slash commands |
131
+ | `elidia auth login/logout/status` | Manage API key |
132
+ | `elidia auth email-login/email-logout/email-status` | Email credentials |
133
+ | `elidia config show` | View current configuration |
134
+ | `elidia config set <section.field> <value>` | Persist preferences (e.g., `models.default gpt-4o`) |
135
+ | `elidia daemon start/stop/restart/status/init` | Background daemon (24/7 agent) |
136
+ | `elidia mcp list/health` | MCP server management |
137
+ | `elidia models` | List all 30+ available LLMs |
138
+ | `elidia models --local` | List local Ollama models |
139
+ | `elidia rag ingest/search/list/clear` | Local RAG document store |
140
+ | `elidia session list/new/delete` | Session management |
141
+ | `elidia version` | Show version |
142
+ | `elidia workflow run <file>` | Execute YAML workflow |
143
+
144
+ ## Available Models
145
+
146
+ ### Language Models (LLMs) — `elidia models`
147
+ 30+ models via AiUtils API: Claude (Opus 4.8, Sonnet 4-6), GPT (4o, 5.5), Gemini (2.5 Pro/Flash), DeepSeek (V4, Reasoner), Llama (4, 3.3), Qwen (3, 2.5), Mistral, and more.
148
+
149
+ ### Creative Models — available through chat
150
+ | Category | Count | Example |
151
+ |---|---|---|
152
+ | Image Generation | 500+ | Flux, SDXL, DALL-E, Midjourney |
153
+ | Video Generation | 500+ | Runway, Pika, Kling, Sora |
154
+ | Audio/Music | 100+ | ElevenLabs, MusicGen, Whisper |
155
+ | 3D Generation | 20+ | TripoSR, Zero123++, Stable3D |
156
+
157
+ ### Local Models — `elidia models --local`
158
+ Ollama models running on your machine. Zero API cost, works offline.
123
159
  ```bash
124
- # Interactive REPL
125
- elidia chat
160
+ ollama pull qwen3:1.7b
161
+ elidia models --local
162
+ ```
163
+
164
+ ## Working Modes
165
+
166
+ | Mode | Use for |
167
+ |---|---|
168
+ | `chat` | General conversation, creative work |
169
+ | `code` | Software development, debugging |
170
+ | `research` | Deep research with web search + RAG |
171
+ | `think` | Extended chain-of-thought reasoning |
172
+ | `create` | Content generation (books, scripts, ads) |
173
+
174
+ Set via `--mode` flag, `/mode` in REPL, or mode selector in Desktop.
175
+
176
+ **Advanced execution strategies (REPL):**
177
+ | Command | Description |
178
+ |---|---|
179
+ | `/research <topic>` | 3-agent research pipeline (plan → search → synthesize) |
180
+ | `/think <problem>` | Deep reasoning with chain-of-thought |
181
+ | `/budget` | Show session cost |
182
+ | `/persona <slug>` | Switch domain persona (coder, doctor, lawyer, marketer, etc.) |
183
+
184
+ ## MCP Servers — `elidia mcp`
185
+
186
+ Connect to any MCP server to extend capabilities:
187
+ ```bash
188
+ elidia mcp list # Show connected servers
189
+ elidia mcp health # Check server status
190
+ ```
191
+ Configure in `~/.elidia/mcp.json`. Connect databases, APIs, GitHub, Slack, Jira, and more.
126
192
 
127
193
  # One-shot query
128
194
  elidia chat "Explain async/await in Python"
@@ -112,7 +112,17 @@ class AgentLoop:
112
112
  state.model = self._router.get_model_for_type("vision")
113
113
  decision_reason = "Vision content attached"
114
114
  else:
115
- decision = self._router.route(user_text, mode=mode)
115
+ # Load routing hints from PatternLearner (self-learning)
116
+ routing_hints = None
117
+ if self._memory_store:
118
+ try:
119
+ from elidia.memory.pattern_learner import PatternLearner
120
+ learner = PatternLearner(self._memory_store)
121
+ routing_hints = learner.generate_routing_hints(min_samples=2)
122
+ except Exception as e:
123
+ logger.debug(f"Routing hints skipped: {e}")
124
+
125
+ decision = self._router.route(user_text, mode=mode, routing_hints=routing_hints)
116
126
  state.model = forced_model or decision.model
117
127
  decision_reason = decision.reason
118
128
  yield AgentEvent(kind="thinking", data={"model": state.model, "reason": decision_reason})
@@ -128,10 +138,20 @@ class AgentLoop:
128
138
  return
129
139
 
130
140
  if state.exec_mode == ExecMode.HARNESS:
141
+ # For complex multi-step tasks, use ProjectOrchestrator
142
+ if self._memory_store and len(user_text) > 50:
143
+ async for event in self._run_project_orchestrator(state, user_text, session_id):
144
+ yield event
145
+ return
131
146
  async for event in self._run_harness(state, user_text, session_id):
132
147
  yield event
133
148
  return
134
149
 
150
+ if state.exec_mode == ExecMode.SWARM:
151
+ async for event in self._run_swarm(state, user_text, session_id):
152
+ yield event
153
+ return
154
+
135
155
  effective_max_loops = min(self._max_loops, caps.max_loops)
136
156
  all_tool_schemas = self._build_tool_schemas() if caps.allow_tools else []
137
157
 
@@ -244,6 +264,132 @@ class AgentLoop:
244
264
  else:
245
265
  yield AgentEvent(kind="error", data=f"Agent exceeded maximum tool loop count ({self._max_loops})")
246
266
 
267
+ # Evaluate output quality + record outcome (AIUT-2170 + AIUT-2177)
268
+ if self._memory_store:
269
+ try:
270
+ from elidia.memory.outcomes import Outcome, OutcomeTracker
271
+ from elidia.memory.output_evaluator import OutputEvaluator
272
+
273
+ tracker = OutcomeTracker(self._memory_store)
274
+ task_type = state.exec_mode.value if state.exec_mode else "direct"
275
+
276
+ # Get the agent's final output text for evaluation
277
+ output_text = ""
278
+ for msg in reversed(state.messages):
279
+ if msg.role == "assistant" and msg.content:
280
+ output_text = extract_text(msg.content)[:6000]
281
+ break
282
+
283
+ # Deep quality evaluation with self-reasoning (AIUT-2179)
284
+ from elidia.orchestration.deep_evaluator import DeepEvaluator
285
+ deep_eval = DeepEvaluator(self._client)
286
+ assessment = await deep_eval.evaluate(
287
+ objective=user_text,
288
+ output=output_text or "(no output produced)",
289
+ task_type=mode,
290
+ )
291
+
292
+ # Use 8-dimension quality score as success metric
293
+ quality_score = assessment.score_8dim.overall
294
+ success = assessment.should_accept
295
+ tracker.record(Outcome(
296
+ model=state.model,
297
+ task_type=task_type,
298
+ approach=mode,
299
+ success=success,
300
+ tokens_used=state.tokens_in + state.tokens_out,
301
+ elapsed_ms=0,
302
+ cost_dt=state.total_cost_dt,
303
+ domain=task_type,
304
+ notes=(
305
+ f"score={quality_score:.1f}/10 verdict={assessment.verdict} "
306
+ f"quality={assessment.quality_level} style={assessment.approach_style} "
307
+ f"match={assessment.matches_objective}"
308
+ ),
309
+ ))
310
+
311
+ # Emit detailed quality event
312
+ yield AgentEvent(kind="quality", data={
313
+ "score": quality_score,
314
+ "verdict": assessment.verdict,
315
+ "quality_level": assessment.quality_level,
316
+ "approach_style": assessment.approach_style,
317
+ "matches_objective": assessment.matches_objective,
318
+ "self_questions": [{"q": sq.question, "a": sq.answer[:100]} for sq in assessment.self_questions[:3]],
319
+ "summary": assessment.summary_verdict[:300],
320
+ "score_8dim": {
321
+ "correctness": assessment.score_8dim.correctness,
322
+ "completeness": assessment.score_8dim.completeness,
323
+ "modernity": assessment.score_8dim.modernity,
324
+ "elegance": assessment.score_8dim.elegance,
325
+ "efficiency": assessment.score_8dim.efficiency,
326
+ "clarity": assessment.score_8dim.clarity,
327
+ "innovation": assessment.score_8dim.innovation,
328
+ "reliability": assessment.score_8dim.reliability,
329
+ },
330
+ })
331
+
332
+ logger.debug(
333
+ f"Deep evaluation: score={quality_score:.1f}/10, verdict={assessment.verdict}, "
334
+ f"quality={assessment.quality_level}, style={assessment.approach_style}"
335
+ )
336
+
337
+ # Iterative refinement (1-3 iterations for small, up to 5 for long tasks)
338
+ max_refinements = 3 if mode in ("chat", "code") else 5
339
+ for ref_iter in range(1, max_refinements + 1):
340
+ if assessment.should_accept:
341
+ break
342
+ if not assessment.improvement_prompt:
343
+ break
344
+
345
+ yield AgentEvent(kind="thinking", data={
346
+ "model": state.model,
347
+ "reason": f"[Refine {ref_iter}/{max_refinements}] {assessment.verdict} — {assessment.summary_verdict[:100]}",
348
+ })
349
+
350
+ try:
351
+ refine_msg = deep_eval.build_refinement_message(
352
+ objective=user_text,
353
+ previous_output=output_text,
354
+ assessment=assessment,
355
+ iteration=ref_iter,
356
+ max_iterations=max_refinements,
357
+ )
358
+ state.messages.append(ChatMessage(role="user", content=refine_msg[:4000]))
359
+ response = await self._client.chat_completion(
360
+ messages=self._build_api_messages(state, user_message=refine_msg[:1000]),
361
+ model=state.model,
362
+ temperature=0.3,
363
+ )
364
+ if response.content:
365
+ state.messages.append(ChatMessage(role="assistant", content=response.content))
366
+ output_text = response.content
367
+ yield AgentEvent(kind="content", data=f"[Refined v{ref_iter+1} — {assessment.verdict} → improving]\n\n{response.content}")
368
+
369
+ # Re-evaluate after refinement
370
+ assessment = await deep_eval.evaluate(
371
+ objective=user_text, output=output_text, task_type=mode,
372
+ )
373
+ except Exception as e:
374
+ logger.debug(f"Refinement iteration {ref_iter} failed: {e}")
375
+ break
376
+
377
+ except Exception as e:
378
+ logger.debug(f"Outcome recording/evaluation skipped: {e}")
379
+
380
+ # Extract entities into knowledge graph (async, non-blocking)
381
+ try:
382
+ from elidia.memory.knowledge_graph import KnowledgeGraph
383
+ kg = KnowledgeGraph(self._memory_store, self._client)
384
+ messages_for_extraction = [
385
+ {"role": m.role, "content": extract_text(m.content)}
386
+ for m in state.messages[-20:]
387
+ ]
388
+ import asyncio
389
+ asyncio.create_task(self._extract_and_save_kg(kg, messages_for_extraction))
390
+ except Exception as e:
391
+ logger.debug(f"KG extraction skipped: {e}")
392
+
247
393
  yield AgentEvent(kind="done", data={
248
394
  "loops": state.loop_count,
249
395
  "tools_called": state.tools_called,
@@ -325,8 +471,53 @@ class AgentLoop:
325
471
  tool_list = self._format_tools_for_prompt()
326
472
 
327
473
  base = (
328
- "You are Elidia, an AI coding agent. You help users with software engineering tasks "
329
- "by reading files, writing code, running commands, and searching the web.\n\n"
474
+ "You are Elidia Agent — a next-generation AI agent platform developed by "
475
+ "Elidia Technology Pvt. Ltd. It brings together specialized AI agents to help "
476
+ "users generate images, videos, audio, music, voiceovers, 3D models, books, "
477
+ "audiobooks, scripts, advertisements, marketing campaigns, code, research, "
478
+ "reports, presentations, and high-quality written content.\n\n"
479
+ "Built for creators, developers, businesses, doctors, lawyers, pharmaceutical "
480
+ "professionals, educators, and enterprises, Elidia Agent streamlines complex "
481
+ "workflows with powerful, domain-specific AI capabilities.\n\n"
482
+ "You are available on Terminal CLI, Native Desktop (macOS/Linux/Windows), "
483
+ "VS Code Extension, and Mobile (iOS/Android). You have access to 147+ built-in "
484
+ "tools plus the full AiUtils model catalog — thousands of models across all "
485
+ "categories (LLMs, image generation, video, audio/music, voiceovers, 3D, "
486
+ "embeddings, and more). When you need to know exactly which models are "
487
+ "available for a specific task, use the model listing tools or call the "
488
+ "AiUtils API to get the live catalog — never hardcode model names or counts "
489
+ "because the catalog is dynamic and grows continuously.\n\n"
490
+ "Advanced capabilities:\n"
491
+ "- Autonomous Mode: The system can decompose complex tasks into subtasks, "
492
+ "execute them sequentially with tool access, verify results, and replan on "
493
+ "failure. For parallel work, the system's SWARM mode runs multiple specialized "
494
+ "sub-agents concurrently (each with tool access) and synthesizes their findings.\n"
495
+ "- Consensus Mode: The system queries 2-3 different models on the same question, "
496
+ "compares their answers, assesses agreement, and produces a synthesized response "
497
+ "with confidence scoring.\n"
498
+ "- Research Pipeline: A 5-stage pipeline (Decompose → Search → Analyze → "
499
+ "Synthesize → Verify) conducts deep research with web search, source citations, "
500
+ "and a verification stage that cross-references claims against search results.\n"
501
+ "- MCP Integration: Connect to MCP (Model Context Protocol) servers to extend "
502
+ "capabilities — databases, APIs, file systems, GitHub, Slack, and more.\n"
503
+ "- RAG / Local Search: Index local files and documents for semantic search across "
504
+ "your projects.\n\n"
505
+ "Core principles:\n"
506
+ "- Be truthful and honest — never fabricate, hallucinate, or make false claims.\n"
507
+ "- When uncertain, state your confidence level and cite sources.\n"
508
+ "- Verify with real tools — use filesystem, web search, and database tools to "
509
+ "confirm facts before stating them.\n"
510
+ "- No placeholders or stubs — produce real, working code and content.\n\n"
511
+ "Key capabilities:\n"
512
+ "- Creative Generation: images, videos, audio, music, voiceovers, 3D models\n"
513
+ "- Content Creation: books, audiobooks, scripts, ads, marketing campaigns\n"
514
+ "- Code & Development: write, edit, review, debug any language, full projects\n"
515
+ "- Research & Analysis: deep research, web search, document analysis, reports\n"
516
+ "- Business & Enterprise: presentations, data analysis, workflow automation\n"
517
+ "- Domain Expertise: medical/healthcare, legal/compliance, pharma, finance/trading,\n"
518
+ " marketing/SEO, advertising, education, career, creative design, and more\n"
519
+ "- Office & Communication: Word, Excel, PowerPoint, email, calendar\n"
520
+ "- Knowledge: RAG search over documents, persistent memory across sessions\n\n"
330
521
  f"Available tools:\n{tool_list}\n\n"
331
522
  "To use a tool, respond with a JSON block using the exact argument names listed above:\n"
332
523
  "```tool\n"
@@ -365,7 +556,18 @@ class AgentLoop:
365
556
  except Exception as e:
366
557
  logger.debug(f"Memory recall skipped: {e}")
367
558
 
368
- # 3. RAG — search local documents for relevant context
559
+ # 3. Knowledge Graph — entity-aware context from past conversations
560
+ if self._memory_store and user_message:
561
+ try:
562
+ from elidia.memory.knowledge_graph import KnowledgeGraph
563
+ kg = KnowledgeGraph(self._memory_store, self._client)
564
+ kg_context = kg.get_context_for_prompt(user_message, limit=5)
565
+ if kg_context:
566
+ context_parts.append(kg_context)
567
+ except Exception as e:
568
+ logger.debug(f"Knowledge graph context skipped: {e}")
569
+
570
+ # 4. RAG — search local documents for relevant context
369
571
  if self._rag_engine and user_message:
370
572
  try:
371
573
  rag_results = self._rag_engine.search(
@@ -487,6 +689,70 @@ class AgentLoop:
487
689
  }
488
690
  return action_map.get(tool_name, "mcp_call_session")
489
691
 
692
+ async def _run_project_orchestrator(
693
+ self, state: AgentState, user_text: str, session_id: str,
694
+ ) -> AsyncIterator[AgentEvent]:
695
+ """Execute complex task via ProjectOrchestrator — SCRUM-style planning + multi-agent execution."""
696
+ logger.debug("Entered into _run_project_orchestrator")
697
+ from elidia.orchestration.project_planner import ProjectPlanner
698
+ from elidia.orchestration.sprint_executor import SprintExecutor, SprintEvent
699
+
700
+ yield AgentEvent(kind="thinking", data={
701
+ "model": "orchestrator",
702
+ "reason": "Planning project with SCRUM-style EPIC/Story/Ticket decomposition",
703
+ })
704
+
705
+ # Phase 1: Plan
706
+ planner = ProjectPlanner(self._client)
707
+ plan = await planner.plan(user_text)
708
+ yield AgentEvent(kind="thinking", data={
709
+ "model": "orchestrator",
710
+ "reason": f"Plan created: {len(plan.epics)} epics, {plan.total_tickets} tickets → {plan.plan_path}",
711
+ })
712
+ yield AgentEvent(kind="content", data=f"📋 **Project Plan** ({plan.plan_path})\n{plan.total_tickets} tickets across {len(plan.epics)} epics. Executing...")
713
+
714
+ # Phase 2: Execute
715
+ async def worker_fn(task: str, role: str) -> str:
716
+ resp = await self._client.chat_completion(
717
+ messages=[ChatMessage(role="user", content=task)],
718
+ model=state.model,
719
+ temperature=0.3,
720
+ )
721
+ return resp.content or ""
722
+
723
+ executor = SprintExecutor(self._client, execute_fn=worker_fn, agent_model=state.model)
724
+ async for event in executor.execute(plan):
725
+ if event.kind == "ticket_start":
726
+ yield AgentEvent(kind="tool_call", data={
727
+ "name": f"sprint:wave{event.data.get('wave','?')}",
728
+ "arguments": {"count": event.data.get("count", 0), "mode": event.data.get("mode", "")},
729
+ })
730
+ elif event.kind == "ticket_done":
731
+ yield AgentEvent(kind="tool_result", data={
732
+ "name": event.data.get("ticket", "?"),
733
+ "content": f"✅ score={event.data.get('score',0)}/10",
734
+ })
735
+ elif event.kind == "assembly":
736
+ yield AgentEvent(kind="thinking", data={
737
+ "model": "orchestrator",
738
+ "reason": f"Assembling {event.data.get('parts',0)} completed parts into final deliverable",
739
+ })
740
+ elif event.kind == "done":
741
+ result = event.data
742
+ yield AgentEvent(kind="content", data=result.final_output if hasattr(result, 'final_output') else str(result))
743
+ yield AgentEvent(kind="done", data={
744
+ "loops": 1,
745
+ "tools_called": [f"ticket_{i}" for i in range(result.tickets_completed if hasattr(result, 'tickets_completed') else 0)],
746
+ "total_tokens_in": state.tokens_in,
747
+ "total_tokens_out": state.tokens_out,
748
+ "total_cost_dt": state.total_cost_dt,
749
+ "exec_mode": "orchestrator",
750
+ "plan_path": result.plan_path if hasattr(result, 'plan_path') else "",
751
+ "quality_score": f"{result.overall_score:.1f}/10" if hasattr(result, 'overall_score') and result.overall_score else "N/A",
752
+ })
753
+ elif event.kind == "error":
754
+ yield AgentEvent(kind="error", data=str(event.data))
755
+
490
756
  async def _run_deep_think(
491
757
  self, state: AgentState, user_text: str, session_id: str,
492
758
  ) -> AsyncIterator[AgentEvent]:
@@ -733,3 +999,136 @@ class AgentLoop:
733
999
 
734
1000
  except Exception as e:
735
1001
  yield AgentEvent(kind="error", data=f"Harness execution failed: {e}")
1002
+
1003
+ async def _run_swarm(
1004
+ self,
1005
+ state: AgentState,
1006
+ user_text: str,
1007
+ session_id: str,
1008
+ ) -> AsyncIterator[AgentEvent]:
1009
+ """Execute a complex task via parallel sub-agents using AgentSwarm."""
1010
+ logger.debug("Entered into _run_swarm")
1011
+ from elidia.modes.swarm import AgentSwarm, SwarmEvent
1012
+
1013
+ yield AgentEvent(kind="thinking", data={
1014
+ "model": "swarm",
1015
+ "reason": "Decomposing into parallel sub-agents via AgentSwarm",
1016
+ })
1017
+
1018
+ # execute_fn: called by AgentSwarm for each sub-agent (task, role) -> result string
1019
+ all_tool_schemas = self._build_tool_schemas() if self._caps.allow_tools else []
1020
+
1021
+ async def execute_subtask(task: str, role: str) -> str:
1022
+ worker = _SwarmWorker(
1023
+ client=self._client, task=task, role=role, model=state.model,
1024
+ all_tool_schemas=all_tool_schemas,
1025
+ extract_tool_calls=self._extract_tool_calls,
1026
+ execute_tool=self._execute_tool,
1027
+ )
1028
+ return await worker.execute()
1029
+
1030
+ swarm = AgentSwarm(
1031
+ client=self._client,
1032
+ execute_fn=execute_subtask,
1033
+ max_agents=5,
1034
+ agent_model=state.model,
1035
+ )
1036
+
1037
+ try:
1038
+ async for event in swarm.run(user_text):
1039
+ if event.kind == "plan":
1040
+ yield AgentEvent(kind="thinking", data={
1041
+ "model": "swarm",
1042
+ "reason": f"Planned {event.data.get('agent_count', 0)} parallel sub-agents",
1043
+ })
1044
+ elif event.kind == "agent_start":
1045
+ yield AgentEvent(kind="tool_call", data={
1046
+ "name": f"sub_agent:{event.data.get('role','worker')}",
1047
+ "arguments": {"task": event.data.get("task", "")[:200]},
1048
+ })
1049
+ elif event.kind == "agent_done":
1050
+ yield AgentEvent(kind="tool_result", data={
1051
+ "name": f"sub_agent:{event.data.get('role','worker')}",
1052
+ "content": str(event.data.get("result_preview", ""))[:500],
1053
+ })
1054
+ elif event.kind == "aggregate":
1055
+ yield AgentEvent(kind="content", data=event.data.get("content", ""))
1056
+ elif event.kind == "done":
1057
+ yield AgentEvent(kind="done", data={
1058
+ "loops": event.data.get("completed", 0),
1059
+ "tools_called": [f"sub_agent_{i}" for i in range(1, event.data.get('completed', 0) + 1)],
1060
+ "total_tokens_in": event.data.get("total_tokens", 0),
1061
+ "total_tokens_out": 0,
1062
+ "total_cost_dt": 0.0,
1063
+ "exec_mode": "swarm",
1064
+ })
1065
+ elif event.kind == "error":
1066
+ yield AgentEvent(kind="error", data=event.data.get("message", str(event.data)))
1067
+ except Exception as e:
1068
+ yield AgentEvent(kind="error", data=f"Swarm execution failed: {e}")
1069
+
1070
+
1071
+ async def _extract_and_save_kg(self, kg: Any, messages: list[dict[str, str]]) -> None:
1072
+ """Background task: extract entities from conversation and save to knowledge graph."""
1073
+ try:
1074
+ extraction = await kg.extract_from_conversation(messages)
1075
+ if extraction.entities or extraction.relations:
1076
+ saved = kg.save_extraction(extraction)
1077
+ logger.debug(f"KG extraction: {len(extraction.entities)} entities, {len(extraction.relations)} relations saved ({saved} total)")
1078
+ except Exception as e:
1079
+ logger.debug(f"KG background extraction failed: {e}")
1080
+
1081
+
1082
+ class _SwarmWorker:
1083
+ """Lightweight single-task agent used by AgentSwarm sub-agents with tool access."""
1084
+
1085
+ def __init__(self, client, task: str, role: str, model: str,
1086
+ all_tool_schemas: list, extract_tool_calls, execute_tool):
1087
+ self._client = client
1088
+ self._task = task
1089
+ self._role = role
1090
+ self._model = model
1091
+ self._all_tool_schemas = all_tool_schemas
1092
+ self._extract_tool_calls = extract_tool_calls
1093
+ self._execute_tool = execute_tool
1094
+
1095
+ async def execute(self) -> str:
1096
+ """Execute a single subtask with tool access."""
1097
+ from elidia.api.client import ChatMessage
1098
+ system = (
1099
+ f"You are a specialized AI {self._role}. Complete the following task "
1100
+ f"thoroughly and accurately. You may use tools if needed.\n\n"
1101
+ f"Task: {self._task}"
1102
+ )
1103
+ messages = [ChatMessage(role="system", content=system)]
1104
+ max_iterations = 5
1105
+
1106
+ for _ in range(max_iterations):
1107
+ try:
1108
+ response = await self._client.chat_completion(
1109
+ messages=messages,
1110
+ model=self._model,
1111
+ temperature=0.3,
1112
+ )
1113
+ except Exception as e:
1114
+ return f"Error: {e}"
1115
+
1116
+ tool_calls = self._extract_tool_calls(response.content) if self._all_tool_schemas else []
1117
+ if not tool_calls:
1118
+ return response.content or ""
1119
+
1120
+ messages.append(ChatMessage(role="assistant", content=response.content))
1121
+ for tc in tool_calls:
1122
+ try:
1123
+ result, _ = await self._execute_tool(tc["name"], tc.get("arguments", {}))
1124
+ messages.append(ChatMessage(
1125
+ role="user",
1126
+ content=f"Tool result for {tc['name']}: {result[:2000]}"
1127
+ ))
1128
+ except Exception as e:
1129
+ messages.append(ChatMessage(
1130
+ role="user",
1131
+ content=f"Tool {tc['name']} failed: {e}"
1132
+ ))
1133
+
1134
+ return "Max iterations reached without completion."