nyxa-ai 0.0.1__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 (115) hide show
  1. nyxa_ai-0.0.1/LICENSE +21 -0
  2. nyxa_ai-0.0.1/PKG-INFO +372 -0
  3. nyxa_ai-0.0.1/README.md +337 -0
  4. nyxa_ai-0.0.1/pyproject.toml +50 -0
  5. nyxa_ai-0.0.1/setup.cfg +4 -0
  6. nyxa_ai-0.0.1/src/nyxa_ai/__init__.py +499 -0
  7. nyxa_ai-0.0.1/src/nyxa_ai/_shared.py +117 -0
  8. nyxa_ai-0.0.1/src/nyxa_ai/agent.py +1749 -0
  9. nyxa_ai-0.0.1/src/nyxa_ai/approvals/__init__.py +57 -0
  10. nyxa_ai-0.0.1/src/nyxa_ai/approvals/db.py +88 -0
  11. nyxa_ai-0.0.1/src/nyxa_ai/approvals/decisions.py +102 -0
  12. nyxa_ai-0.0.1/src/nyxa_ai/approvals/memory.py +64 -0
  13. nyxa_ai-0.0.1/src/nyxa_ai/approvals/resume.py +159 -0
  14. nyxa_ai-0.0.1/src/nyxa_ai/approvals/store.py +109 -0
  15. nyxa_ai-0.0.1/src/nyxa_ai/attachments.py +334 -0
  16. nyxa_ai-0.0.1/src/nyxa_ai/chat.py +310 -0
  17. nyxa_ai-0.0.1/src/nyxa_ai/classify.py +665 -0
  18. nyxa_ai-0.0.1/src/nyxa_ai/commands.py +204 -0
  19. nyxa_ai-0.0.1/src/nyxa_ai/conformance.py +74 -0
  20. nyxa_ai-0.0.1/src/nyxa_ai/conversations/__init__.py +131 -0
  21. nyxa_ai-0.0.1/src/nyxa_ai/conversations/db.py +170 -0
  22. nyxa_ai-0.0.1/src/nyxa_ai/conversations/memory.py +126 -0
  23. nyxa_ai-0.0.1/src/nyxa_ai/conversations/store.py +198 -0
  24. nyxa_ai-0.0.1/src/nyxa_ai/engine.py +417 -0
  25. nyxa_ai-0.0.1/src/nyxa_ai/engines/__init__.py +10 -0
  26. nyxa_ai-0.0.1/src/nyxa_ai/engines/openai_responses.py +47 -0
  27. nyxa_ai-0.0.1/src/nyxa_ai/engines/pydantic.py +1566 -0
  28. nyxa_ai-0.0.1/src/nyxa_ai/errors.py +196 -0
  29. nyxa_ai-0.0.1/src/nyxa_ai/evals.py +127 -0
  30. nyxa_ai-0.0.1/src/nyxa_ai/events.py +751 -0
  31. nyxa_ai-0.0.1/src/nyxa_ai/file_storage.py +301 -0
  32. nyxa_ai-0.0.1/src/nyxa_ai/files.py +179 -0
  33. nyxa_ai-0.0.1/src/nyxa_ai/generators.py +119 -0
  34. nyxa_ai-0.0.1/src/nyxa_ai/kit.py +36 -0
  35. nyxa_ai-0.0.1/src/nyxa_ai/locator.py +84 -0
  36. nyxa_ai-0.0.1/src/nyxa_ai/manager.py +750 -0
  37. nyxa_ai-0.0.1/src/nyxa_ai/media/__init__.py +60 -0
  38. nyxa_ai-0.0.1/src/nyxa_ai/media/audio.py +134 -0
  39. nyxa_ai-0.0.1/src/nyxa_ai/media/base.py +181 -0
  40. nyxa_ai-0.0.1/src/nyxa_ai/media/drivers.py +144 -0
  41. nyxa_ai-0.0.1/src/nyxa_ai/media/fake.py +209 -0
  42. nyxa_ai-0.0.1/src/nyxa_ai/media/image.py +184 -0
  43. nyxa_ai-0.0.1/src/nyxa_ai/media/responses.py +144 -0
  44. nyxa_ai-0.0.1/src/nyxa_ai/media/specs.py +55 -0
  45. nyxa_ai-0.0.1/src/nyxa_ai/media/transcription.py +163 -0
  46. nyxa_ai-0.0.1/src/nyxa_ai/media/types.py +225 -0
  47. nyxa_ai-0.0.1/src/nyxa_ai/media/vendors.py +530 -0
  48. nyxa_ai-0.0.1/src/nyxa_ai/messages.py +275 -0
  49. nyxa_ai-0.0.1/src/nyxa_ai/migrations/20261101000001_create_agent_conversations.py +40 -0
  50. nyxa_ai-0.0.1/src/nyxa_ai/migrations/20261101000002_create_agent_approvals.py +31 -0
  51. nyxa_ai-0.0.1/src/nyxa_ai/provider.py +138 -0
  52. nyxa_ai-0.0.1/src/nyxa_ai/providers.py +221 -0
  53. nyxa_ai-0.0.1/src/nyxa_ai/py.typed +0 -0
  54. nyxa_ai-0.0.1/src/nyxa_ai/queueing.py +480 -0
  55. nyxa_ai-0.0.1/src/nyxa_ai/rag/__init__.py +41 -0
  56. nyxa_ai-0.0.1/src/nyxa_ai/rag/documents.py +146 -0
  57. nyxa_ai-0.0.1/src/nyxa_ai/rag/embeddings.py +1021 -0
  58. nyxa_ai-0.0.1/src/nyxa_ai/rag/search.py +102 -0
  59. nyxa_ai-0.0.1/src/nyxa_ai/rag/stores.py +340 -0
  60. nyxa_ai-0.0.1/src/nyxa_ai/rerank.py +421 -0
  61. nyxa_ai-0.0.1/src/nyxa_ai/response.py +79 -0
  62. nyxa_ai-0.0.1/src/nyxa_ai/skills.py +200 -0
  63. nyxa_ai-0.0.1/src/nyxa_ai/ssrf.py +51 -0
  64. nyxa_ai-0.0.1/src/nyxa_ai/stores.py +403 -0
  65. nyxa_ai-0.0.1/src/nyxa_ai/streaming.py +379 -0
  66. nyxa_ai-0.0.1/src/nyxa_ai/stubs/agent.ai.stub +13 -0
  67. nyxa_ai-0.0.1/src/nyxa_ai/stubs/agent.conversational.stub +18 -0
  68. nyxa_ai-0.0.1/src/nyxa_ai/stubs/agent.structured.stub +25 -0
  69. nyxa_ai-0.0.1/src/nyxa_ai/stubs/agent.stub +22 -0
  70. nyxa_ai-0.0.1/src/nyxa_ai/stubs/config_ai.stub +47 -0
  71. nyxa_ai-0.0.1/src/nyxa_ai/stubs/pyproject.ai.stub +12 -0
  72. nyxa_ai-0.0.1/src/nyxa_ai/stubs/routes.ai.stub +20 -0
  73. nyxa_ai-0.0.1/src/nyxa_ai/stubs/smoke_test_ai.stub +37 -0
  74. nyxa_ai-0.0.1/src/nyxa_ai/stubs/test.agent.stub +20 -0
  75. nyxa_ai-0.0.1/src/nyxa_ai/stubs/test.tool.stub +28 -0
  76. nyxa_ai-0.0.1/src/nyxa_ai/stubs/tool.stub +27 -0
  77. nyxa_ai-0.0.1/src/nyxa_ai/testing.py +276 -0
  78. nyxa_ai-0.0.1/src/nyxa_ai/tool.py +626 -0
  79. nyxa_ai-0.0.1/src/nyxa_ai.egg-info/PKG-INFO +372 -0
  80. nyxa_ai-0.0.1/src/nyxa_ai.egg-info/SOURCES.txt +113 -0
  81. nyxa_ai-0.0.1/src/nyxa_ai.egg-info/dependency_links.txt +1 -0
  82. nyxa_ai-0.0.1/src/nyxa_ai.egg-info/entry_points.txt +8 -0
  83. nyxa_ai-0.0.1/src/nyxa_ai.egg-info/requires.txt +32 -0
  84. nyxa_ai-0.0.1/src/nyxa_ai.egg-info/top_level.txt +1 -0
  85. nyxa_ai-0.0.1/tests/test_agent.py +249 -0
  86. nyxa_ai-0.0.1/tests/test_chat.py +76 -0
  87. nyxa_ai-0.0.1/tests/test_classification.py +279 -0
  88. nyxa_ai-0.0.1/tests/test_conversations.py +134 -0
  89. nyxa_ai-0.0.1/tests/test_deprecations.py +71 -0
  90. nyxa_ai-0.0.1/tests/test_depth.py +355 -0
  91. nyxa_ai-0.0.1/tests/test_embeddings.py +421 -0
  92. nyxa_ai-0.0.1/tests/test_evals.py +158 -0
  93. nyxa_ai-0.0.1/tests/test_file_storage.py +129 -0
  94. nyxa_ai-0.0.1/tests/test_files.py +141 -0
  95. nyxa_ai-0.0.1/tests/test_generators.py +114 -0
  96. nyxa_ai-0.0.1/tests/test_hitl.py +148 -0
  97. nyxa_ai-0.0.1/tests/test_knowledge_fakes.py +115 -0
  98. nyxa_ai-0.0.1/tests/test_local_embeddings.py +212 -0
  99. nyxa_ai-0.0.1/tests/test_locator.py +110 -0
  100. nyxa_ai-0.0.1/tests/test_manager.py +144 -0
  101. nyxa_ai-0.0.1/tests/test_mcp_tools.py +167 -0
  102. nyxa_ai-0.0.1/tests/test_media.py +549 -0
  103. nyxa_ai-0.0.1/tests/test_media_queue.py +108 -0
  104. nyxa_ai-0.0.1/tests/test_middleware.py +236 -0
  105. nyxa_ai-0.0.1/tests/test_providers.py +158 -0
  106. nyxa_ai-0.0.1/tests/test_queueing.py +168 -0
  107. nyxa_ai-0.0.1/tests/test_rag.py +171 -0
  108. nyxa_ai-0.0.1/tests/test_reranking.py +272 -0
  109. nyxa_ai-0.0.1/tests/test_skills.py +106 -0
  110. nyxa_ai-0.0.1/tests/test_ssrf_urls.py +31 -0
  111. nyxa_ai-0.0.1/tests/test_stores.py +309 -0
  112. nyxa_ai-0.0.1/tests/test_streaming.py +245 -0
  113. nyxa_ai-0.0.1/tests/test_testing.py +116 -0
  114. nyxa_ai-0.0.1/tests/test_tools.py +276 -0
  115. nyxa_ai-0.0.1/tests/test_typing.py +29 -0
nyxa_ai-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NyxaDev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
nyxa_ai-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,372 @@
1
+ Metadata-Version: 2.4
2
+ Name: nyxa-ai
3
+ Version: 0.0.1
4
+ Summary: Agents, tools, RAG, streaming, and HITL for the Nyxa framework
5
+ Author-email: Al-Amin Islam Nerob <alamin@aincoder.com>
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/NyxaDev/Nyxa
8
+ Requires-Python: >=3.13
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: nyxa>=0.0.1
12
+ Requires-Dist: pydantic-ai-slim<2.0,>=1.0
13
+ Requires-Dist: httpx>=0.27
14
+ Provides-Extra: openai
15
+ Requires-Dist: pydantic-ai-slim[openai]<2.0,>=1.0; extra == "openai"
16
+ Provides-Extra: anthropic
17
+ Requires-Dist: pydantic-ai-slim[anthropic]<2.0,>=1.0; extra == "anthropic"
18
+ Provides-Extra: gemini
19
+ Requires-Dist: pydantic-ai-slim[google]<2.0,>=1.0; extra == "gemini"
20
+ Provides-Extra: mcp
21
+ Requires-Dist: nyxa-mcp>=0.0.1; extra == "mcp"
22
+ Requires-Dist: pydantic-ai-slim[mcp]<2.0,>=1.0; extra == "mcp"
23
+ Provides-Extra: ag-ui
24
+ Requires-Dist: pydantic-ai-slim[ag-ui]<2.0,>=1.0; extra == "ag-ui"
25
+ Provides-Extra: sqlite-vec
26
+ Requires-Dist: sqlite-vec>=0.1; extra == "sqlite-vec"
27
+ Provides-Extra: pgvector
28
+ Requires-Dist: pgvector>=0.3; extra == "pgvector"
29
+ Provides-Extra: local-embeddings
30
+ Requires-Dist: model2vec<1,>=0.10; extra == "local-embeddings"
31
+ Provides-Extra: all
32
+ Requires-Dist: nyxa-ai[ag-ui,anthropic,gemini,mcp,openai]; extra == "all"
33
+ Requires-Dist: nyxa-ai[local-embeddings,pgvector,sqlite-vec]; extra == "all"
34
+ Dynamic: license-file
35
+
36
+ # nyxa-ai
37
+
38
+ AI agents, tools, RAG, streaming, and human-in-the-loop approvals for
39
+ the Nyxa framework — declarative `Agent` classes on a pluggable
40
+ provider layer (pydantic-ai engines), typed tools with approval
41
+ gates, conversations, classification/reranking, hosted file stores,
42
+ media generation, queueing, SSE/AG-UI streaming, and a complete fake
43
+ suite. `import nyxa_ai` is lazy — no engine or provider SDK loads until
44
+ used.
45
+
46
+ ## Features
47
+
48
+ - **Declarative agents** — `class Support(Agent[Answer])`: class attrs
49
+ for `instructions`, `tools`, `output` (pydantic type), `provider`,
50
+ `model`, `temperature`/`top_p`/`max_tokens`, `max_steps`, `timeout`,
51
+ `retries`, `conversational`, `middleware`, `skills`,
52
+ `provider_options`/`model_settings`, prompt caching
53
+ (`cache_instructions`, `cache_tool_definitions`), model tiers
54
+ (`use_cheapest_model`/`use_smartest_model`), and
55
+ `without_broadcasting`. `get_*` hooks supply dynamic values.
56
+ - **Prompting** — `await agent.prompt(text)` → `AgentResponse[T]`
57
+ (`.text`, `.parsed`, `.usage`, steps); `agent.stream(text)` →
58
+ `StreamableAgentResponse` (SSE-renderable from routes, Vercel AI
59
+ SDK v5 + AG-UI protocols, `broadcast_on` channel fan-out);
60
+ `await agent.queue(text)` → `QueuedAgentResponse` with
61
+ `.then`/`.catch`; conversations via `for_user`/`for_participant`/
62
+ `continue_`/`continue_last_conversation`.
63
+ - **Tools** — `Tool` subclasses declare a pydantic `Args` model +
64
+ `handle(args, ctx)`; approval gates via `require_approval()` /
65
+ `needs_approval()` / `Approval`. Built-ins: `web_search`,
66
+ `web_fetch`, `code_execution`, `file_search` (with
67
+ `FileSearchFilter`), `ToolSearch` (strategy-filtered tool sets),
68
+ `mcp_stdio`/`mcp_http` clients and `MCPServerTool` remote wrappers,
69
+ `NativeTool` provider-side tools, `LoadSkill`.
70
+ - **Skills** — `Skill` bundles (`SKILL.md` + files) from dirs,
71
+ objects, or lazy callables; `resolve_skills`; `LoadSkill` tool
72
+ loads them into context.
73
+ - **HITL approvals** — tool calls pause the run into a
74
+ `PendingApprovalStore` (memory or database, TTL'd); resolve with
75
+ `app.ai.approve(run_id)` / `deny(run_id, reason)` /
76
+ `decide(run_id, Decisions)`; `Decisions` per-call approve/reject
77
+ with `approve_remaining`/`reject_remaining`.
78
+ - **Conversations** — `Conversation` records + `ConversationStore`
79
+ protocol (memory + database stores; messages as serialized blobs,
80
+ `group_messages`, `page`); `manager.conversations()`,
81
+ `conversation_messages()`, `pending_approvals_for()`.
82
+ - **Manager** — `app.ai`: `agent(...)`, `summarize`, `classify`,
83
+ `choose`, `rerank`/`rerank_items`, `image`, `audio`,
84
+ `transcription`, `embed`/`embeddings`, `stores`, `engine()`/
85
+ `extend(engine)`, `resolve`/`provider_config`, `approve`/`deny`/
86
+ `decide`, and the fake suite.
87
+ - **Media** — `app.ai.image(prompt)` (`.quality`/`.portrait`/
88
+ `.landscape`/`.square`/`.attachments`), `audio`, `transcription`
89
+ builders → `generate()`/`queue()` → `ImageResponse`/`AudioResponse`/
90
+ `TranscriptionResponse` with `GeneratedImage`/`TranscriptionSegment`/
91
+ usage types.
92
+ - **RAG** — `VectorStore` protocol with `MemoryVectorStore`,
93
+ `SqliteVecStore`, `PgVectorStore` (`vector_store_for(app)`);
94
+ `SimilaritySearch` tool (`using_model(Model, column="embedding")`);
95
+ hosted `FileStorage`/`FileStorageTools` and `stores()` CRUD
96
+ (create/attach/detach/delete) over provider vector stores.
97
+ - **Classification & reranking** — `app.ai.classify(content)` with
98
+ `Boolean`/`Choice`/`Score` question types → `BooleanAnswer`/
99
+ `ChoiceAnswer`/`ScoreAnswer` in `ClassificationResponse`;
100
+ `rerank(documents)` → `RerankResponse`/`RerankResult`/`RerankUsage`;
101
+ `choose` helper.
102
+ - **Chat surface** — `ChatRequest`/`ChatProtocol` parse Vercel AI SDK
103
+ and AG-UI bodies (with pending `Decisions`); `to_ui_messages` /
104
+ `to_client_state` serialize history back for clients.
105
+ - **Queueing** — `InvokeAgent`/`InvokeMedia` jobs run prompts and
106
+ media generation on `nyxa-jobs`; `QueuedAgentResponse`/
107
+ `QueuedMediaResponse` futures; `broadcast_agent_on_queue` streams
108
+ progress on a broadcast channel.
109
+ - **Events** — full lifecycle telemetry: prompting/steps/tool calls/
110
+ approvals/streaming/classify/rerank/media/files/stores/failover —
111
+ all emitted on `app.events`.
112
+ - **Engine seam** — `Engine` protocol with `AgentSpec`, `ToolSpec`,
113
+ `ModelRef`, `EngineResult`, `EngineStream`, `StreamEvent`,
114
+ `StepView`; `manager.extend(engine)` plugs new engines (pydantic-ai
115
+ - OpenAI-responses engines ship).
116
+ - **CLI + kit** — `nyxa add nyxa-ai`, `ai:install`, `make:agent`
117
+ (`--structured/--conversational/--test`), `make:tool` (`--approval`),
118
+ `eval:run`, `eval:gate --min=`, `nyxa utils` embedding-model
119
+ download; `AiKit` scaffolds an `nyxa new` AI app with a `/chat`
120
+ route; `Eval`/`EvalCase`/`EvalResult` drive evals.
121
+ - **Testing** — `MyAgent.fake(responses)` / `app.ai.fake()`,
122
+ `fake_media`, `fake_classification`, `fake_reranking`,
123
+ `fake_files`, `fake_stores`, `prevent_stray_prompts`,
124
+ `assert_queued`, `clear_fakes`.
125
+ - **Errors** — typed failures for stray prompts, decisions mismatch,
126
+ missing keys/extras, provider capability/config, queue unavailable,
127
+ media serialization, skills, tool search, untrusted locators.
128
+
129
+ ## Install
130
+
131
+ ```bash
132
+ nyxa add nyxa-ai # writes config/ai.py
133
+ nyxa add "nyxa-ai[openai]" # or [anthropic] / [gemini] / [mcp] / [ag-ui]
134
+ ```
135
+
136
+ Set provider keys in `config/ai.py` (`ai.providers.<name>.api_key`
137
+ etc.) or env vars.
138
+
139
+ ## Usage
140
+
141
+ ```python
142
+ from nyxa_ai import Agent, Tool, ToolContext
143
+
144
+
145
+ class Weather(Tool):
146
+ class Args(BaseModel):
147
+ city: str
148
+
149
+ async def handle(self, args: Args, ctx: ToolContext) -> str:
150
+ return f"Sunny in {args.city}"
151
+
152
+
153
+ class Assistant(Agent):
154
+ instructions = "You are helpful."
155
+ tools = [Weather]
156
+ conversational = True
157
+
158
+
159
+ agent = Assistant().for_user(user)
160
+ response = await agent.prompt("Weather in Paris?")
161
+ response.text # final text
162
+ response.usage.total_tokens # accounting
163
+ ```
164
+
165
+ Streaming from a route (SSE via the response renderer):
166
+
167
+ ```python
168
+ async def chat(ctx):
169
+ return Assistant().stream("Tell me a story").vercel(5)
170
+ ```
171
+
172
+ ## Public API
173
+
174
+ ### Agents
175
+
176
+ - **`Agent[T]`** — declarative base: `Agent.make(**kwargs)`,
177
+ `await agent.prompt(text, **opts) -> AgentResponse[T]`,
178
+ `agent.stream(text)` / `await agent.queue(text)` /
179
+ `agent.broadcast_on_queue(text, channel)`,
180
+ `agent.for_user(owner)` / `for_participant` / `continue_(id, as_)` /
181
+ `continue_last_conversation(owner)`, `name`, `description`,
182
+ `get_instructions`/`get_tools`/`get_messages`/`get_middleware`/
183
+ `get_skills`, `Agent.fake(responses)`, `Agent.prevent_stray_prompts()`,
184
+ `Agent.clear_fakes()`.
185
+ - **`AnonymousAgent`** — untyped ad-hoc agent (`manager.agent(...)`
186
+ product).
187
+ - **`StepMiddleware`** — `handle(step: StepView, next)` protocol for
188
+ per-step interception.
189
+ - **`ToolDecl`** / **`MiddlewareDecl`** — declaration value types.
190
+
191
+ ### Manager + provider
192
+
193
+ - **`AiManager`** — bound as `app.ai` (see Features → Manager).
194
+ - **`AiProvider`** — binds `app.ai`, publishes `ai.*` config,
195
+ registers the `StreamableAgentResponse` SSE renderer, the five
196
+ commands, the `nyxa utils` embedding action, and `configure()`.
197
+
198
+ ### Responses / streaming / chat
199
+
200
+ - **`AgentResponse[T]`** — `.text`, `.parsed` (structured output),
201
+ `.usage`, steps/records.
202
+ - **`StreamableAgentResponse[T]`** — async-iterates `StreamEvent`s;
203
+ `.vercel(version=5)`, `.ag_ui(thread_id, run_id)`, `.using_protocol`,
204
+ `.broadcast_on(channel)`, `.then(fn)`, `await .result()`,
205
+ `.to_response()` (SSE).
206
+ - **`StreamProtocol`** — encoder protocol for custom wire formats.
207
+ - **`ChatRequest`** / **`ChatProtocol`** — parsed chat body (Vercel /
208
+ AG-UI) incl. `Decisions`.
209
+ - **`to_ui_messages(stored)`** / **`to_client_state(...)`** — history
210
+ serialization for clients.
211
+
212
+ ### Tools
213
+
214
+ - **`Tool`** — subclass with `Args` model; `handle(args, ctx)`,
215
+ `needs_approval(args)`, `require_approval(reason=None)`,
216
+ `without_approval()`, `name`, `tool_spec(ctx)`.
217
+ - **`ToolContext`** — per-run context (`.container`, `.bind(run_ctx)`).
218
+ - **`Approval`** — approval requirement value.
219
+ - **`NativeTool`** — provider-side tool wrapper.
220
+ - **`MCPServerTool`** — adapts a remote MCP tool (`mcp_client()`,
221
+ `name`, `tool_spec`, `handle`).
222
+ - **`ToolSearch`** — `ToolSearch(tools, strategy=None)` — searchable
223
+ tool-set wrapper (raises `ToolSearchUnsupportedError` when the
224
+ provider can't search).
225
+ - **`mcp_stdio(command, args=None, **kw)`** / **`mcp_http(url, **kw)`**
226
+ — MCP client factories.
227
+ - **`web_search` / `web_fetch` / `code_execution` /
228
+ `file_search(vector_store_ids, filters=..., max_results=...)`** —
229
+ built-in native tool factories.
230
+
231
+ ### Engine seam
232
+
233
+ - **`Engine`** — engine protocol (`manager.extend()`).
234
+ - **`AgentSpec`** / **`ToolSpec`** / **`ModelRef`** — resolved agent/
235
+ tool/model references.
236
+ - **`EngineResult`** / **`EngineStream`** / **`StreamEvent`** /
237
+ **`StepView`** — run results, event streams, and the middleware
238
+ step view.
239
+
240
+ ### Messages
241
+
242
+ - **`Message`** / **`StoredMessage`** / **`MessagePage`** — conversation
243
+ units and pagination.
244
+ - **`Usage`** — token accounting.
245
+ - **`StepRecord`** — persisted per-step record.
246
+ - **`PendingApproval`** — an unresolved tool approval in a stored run.
247
+
248
+ ### Conversations + approvals
249
+
250
+ - **`Conversation`** — record with `participant()` owner resolution.
251
+ - **`ConversationStore`** — protocol: `create`/`load`/`latest`/
252
+ `append`/`list`/`messages`/`describe_messages`/
253
+ `conversation_belongs_to`/`pending_approvals_for` (memory + db
254
+ drivers; `ai.conversations.store`).
255
+ - **`PendingRun`** — serialized paused run (`.to_json()`/`.from_json`).
256
+ - **`PendingApprovalStore`** — protocol: `save`/`load`/`delete`/
257
+ `find_for_conversation`/`prune` (`ai.approvals.store`, `ttl`).
258
+ - **`Decision`** — `Decision.approve(args=None)` / `.reject(reason)` /
259
+ `.is_bare_reject`.
260
+ - **`Decisions`** — `Decisions()` → `.approve(id, args)` / `.reject(id,
261
+ reason)` / `.approve_remaining()` / `.reject_remaining()` /
262
+ `.resolve(pending)`.
263
+
264
+ ### Classification + reranking
265
+
266
+ - **`Classification`** — facade over `manager.classify`.
267
+ - **`Boolean` / `Choice` / `Score`** — question types; answers are
268
+ **`BooleanAnswer` / `ChoiceAnswer` / `ScoreAnswer`** in
269
+ **`ClassificationResponse`**.
270
+ - **`RerankResponse` / `RerankResult` / `RerankUsage`** — rerank
271
+ output types.
272
+
273
+ ### Skills + file storage
274
+
275
+ - **`Skill`** — a `SKILL.md` bundle; **`resolve_skills(sources)`**;
276
+ **`LoadSkill`** — the loader tool.
277
+ - **`FileStorage`** / **`FileStorageTools`** — hosted file store
278
+ accessor + its tools.
279
+
280
+ ### Media
281
+
282
+ - **`ImageResponse` / `AudioResponse` / `TranscriptionResponse`** —
283
+ generation results (`generate()`/`queue()`).
284
+ - **`GeneratedImage` / `ImageUsage` / `TranscriptionSegment` /
285
+ `TranscriptionUsage` / `MediaSource`** — value types.
286
+
287
+ ### Queueing
288
+
289
+ - **`InvokeAgent` / `InvokeMedia`** — the queue jobs.
290
+ - **`QueuedAgentResponse` / `QueuedMediaResponse`** — job futures with
291
+ `.then(fn)` / `.catch(fn)`.
292
+
293
+ ### Attachments
294
+
295
+ - **`Attachment`** / **`Image` / `Document` / `Video` / `Audio` /
296
+ `FileRef`** — prompt attachment types.
297
+
298
+ ### Testing
299
+
300
+ - **`AgentFake`** — `Agent.fake()`/`manager.fake()`: canned responses,
301
+ recorded prompts, assertions.
302
+ - **`MediaFake` / `RecordedMediaCall`** — `manager.fake_media()`:
303
+ recorded generate calls.
304
+ - **`ClassificationFake`** — `manager.fake_classification(...)`.
305
+ - **`RerankingFake`** — `manager.fake_reranking(...)`.
306
+ - **`FilesFake`** — `manager.fake_files()`: `upload`/`retrieve`/
307
+ `remove`, `assert_uploaded`/`assert_deleted`/
308
+ `assert_nothing_uploaded`.
309
+ - **`StoresFake`** — `manager.fake_stores()`: `create`/`get`/`delete`/
310
+ `attach`/`detach`/`members`.
311
+
312
+ ### Events (emitted on `app.events`)
313
+
314
+ `AgentPrompting`/`AgentPrompted`, `AgentQueued`,
315
+ `AgentResponseStreamed`, `StartingStep`/`StepCompleted`/`StepFailed`,
316
+ `InvokingTool`/`ToolInvoked`/`ToolFailed`, `ToolCallStarted`/
317
+ `ToolCallFinished`, `ToolApprovalRequested`/`ToolApprovalResolved`,
318
+ `ApprovalRequested`/`ApprovalResolved`, `FailoverTriggered`,
319
+ `Classifying`/`Classified`, `Reranking`/`Reranked`,
320
+ `GeneratingImage`/`ImageGenerated`, `GeneratingAudio`/`AudioGenerated`,
321
+ `GeneratingTranscription`/`TranscriptionGenerated`, `StoringFile`/
322
+ `FileStored`, `AddingFileToStore`/`FileAddedToStore`,
323
+ `RemovingFileFromStore`/`FileRemovedFromStore`, `CreatingStore`/
324
+ `StoreCreated`/`StoreDeleted`, `FileDeleted`.
325
+
326
+ ### Errors
327
+
328
+ `AiError` (base), `AgentOutputError`, `ApprovalError`,
329
+ `ApprovalNotResumableError`, `ConversationError`,
330
+ `ConversationNotFoundError`, `ConversationConflictError`,
331
+ `ConversationOwnershipError`, `DecisionsMismatchError`,
332
+ `MediaSerializationError`, `MissingExtraError`, `MissingKeyError`,
333
+ `ProviderCapabilityError`, `ProviderConfigError`,
334
+ `QueueUnavailableError`, `SkillError`, `StrayPromptError`,
335
+ `ToolSearchUnsupportedError`, `UnknownProviderError`,
336
+ `UntrustedLocatorError`.
337
+
338
+ ## Configuration
339
+
340
+ `nyxa add nyxa-ai` writes `config/ai.py` (the `config` dict's keys
341
+ namespace as `ai.*`):
342
+
343
+ ```python
344
+ config = {
345
+ "default": None, # default provider name
346
+ "providers": {}, # {name: {driver, api_key, models…}}
347
+ "conversations": {"store": "memory"}, # "memory" | "database"
348
+ "approvals": {"store": "memory", "ttl": 3600},
349
+ "embeddings": {"dimensions": None},
350
+ }
351
+ ```
352
+
353
+ Model tiers `models.text.cheapest`/`models.text.smartest` resolve via
354
+ `use_cheapest_model`/`use_smartest_model`.
355
+
356
+ ## Testing
357
+
358
+ ```python
359
+ from nyxa_ai import Agent
360
+
361
+ Assistant.fake(["hello"])
362
+ resp = await Assistant().prompt("hi")
363
+ assert resp.text == "hello"
364
+
365
+ app.ai.prevent_stray_prompts() # any unfaked prompt raises
366
+ app.ai.assert_queued() # a prompt was queued
367
+ app.ai.clear_fakes()
368
+ ```
369
+
370
+ ## License
371
+
372
+ MIT