forge-ai-runtime 0.7.0__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.
- forge_ai_runtime-0.7.0/LICENSE +0 -0
- forge_ai_runtime-0.7.0/MANIFEST.in +13 -0
- forge_ai_runtime-0.7.0/PKG-INFO +351 -0
- forge_ai_runtime-0.7.0/README.md +332 -0
- forge_ai_runtime-0.7.0/ai_runtime/__init__.py +100 -0
- forge_ai_runtime-0.7.0/ai_runtime/adapters/__init__.py +0 -0
- forge_ai_runtime-0.7.0/ai_runtime/adapters/litellm/__init__.py +0 -0
- forge_ai_runtime-0.7.0/ai_runtime/adapters/litellm/response_adapter.py +58 -0
- forge_ai_runtime-0.7.0/ai_runtime/agents/__init__.py +12 -0
- forge_ai_runtime-0.7.0/ai_runtime/agents/agent.py +62 -0
- forge_ai_runtime-0.7.0/ai_runtime/agents/config_files.py +39 -0
- forge_ai_runtime-0.7.0/ai_runtime/agents/runner.py +177 -0
- forge_ai_runtime-0.7.0/ai_runtime/agents/subagent.py +31 -0
- forge_ai_runtime-0.7.0/ai_runtime/cli.py +81 -0
- forge_ai_runtime-0.7.0/ai_runtime/commands/__init__.py +5 -0
- forge_ai_runtime-0.7.0/ai_runtime/commands/registry.py +62 -0
- forge_ai_runtime-0.7.0/ai_runtime/compat.py +32 -0
- forge_ai_runtime-0.7.0/ai_runtime/context/__init__.py +15 -0
- forge_ai_runtime-0.7.0/ai_runtime/context/window.py +110 -0
- forge_ai_runtime-0.7.0/ai_runtime/conversation/__init__.py +5 -0
- forge_ai_runtime-0.7.0/ai_runtime/conversation/conversation.py +33 -0
- forge_ai_runtime-0.7.0/ai_runtime/conversation/enums.py +8 -0
- forge_ai_runtime-0.7.0/ai_runtime/conversation/message.py +75 -0
- forge_ai_runtime-0.7.0/ai_runtime/conversation/request.py +38 -0
- forge_ai_runtime-0.7.0/ai_runtime/conversation/response.py +32 -0
- forge_ai_runtime-0.7.0/ai_runtime/conversation/usage.py +9 -0
- forge_ai_runtime-0.7.0/ai_runtime/eventing/__init__.py +1 -0
- forge_ai_runtime-0.7.0/ai_runtime/eventing/bus.py +34 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/__init__.py +8 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/background.py +90 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/context.py +92 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/engine.py +195 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/event_processor.py +88 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/hooks.py +79 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/mode.py +8 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/pipeline/__init__.py +13 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/pipeline/compaction_stage.py +60 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/pipeline/llm_stage.py +51 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/pipeline/memory_consolidation_stage.py +76 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/pipeline/pipeline.py +39 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/pipeline/planner_stage.py +132 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/pipeline/request_builder_stage.py +28 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/pipeline/stage.py +20 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/pipeline/supervisor_stage.py +89 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/pipeline/tool_loop_stage.py +242 -0
- forge_ai_runtime-0.7.0/ai_runtime/execution/plan.py +39 -0
- forge_ai_runtime-0.7.0/ai_runtime/mcp/__init__.py +13 -0
- forge_ai_runtime-0.7.0/ai_runtime/mcp/adapter.py +48 -0
- forge_ai_runtime-0.7.0/ai_runtime/mcp/client.py +110 -0
- forge_ai_runtime-0.7.0/ai_runtime/memory/__init__.py +12 -0
- forge_ai_runtime-0.7.0/ai_runtime/memory/conversation_memory.py +42 -0
- forge_ai_runtime-0.7.0/ai_runtime/memory/semantic.py +55 -0
- forge_ai_runtime-0.7.0/ai_runtime/memory/store.py +48 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/__init__.py +17 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/base.py +89 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/capabilities.py +22 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/config.py +68 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/default_registry.py +41 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/enums.py +9 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/exceptions.py +54 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/litellm_exception_mapper.py +49 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/litellm_mapper.py +104 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/litellm_provider.py +158 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/litellm_stream_parser.py +100 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/provider.py +35 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/provider_info.py +18 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/registry.py +78 -0
- forge_ai_runtime-0.7.0/ai_runtime/providers/sdk_info.py +7 -0
- forge_ai_runtime-0.7.0/ai_runtime/rag/__init__.py +12 -0
- forge_ai_runtime-0.7.0/ai_runtime/rag/document.py +13 -0
- forge_ai_runtime-0.7.0/ai_runtime/rag/retriever.py +41 -0
- forge_ai_runtime-0.7.0/ai_runtime/rag/vector_store.py +90 -0
- forge_ai_runtime-0.7.0/ai_runtime/runtime.py +81 -0
- forge_ai_runtime-0.7.0/ai_runtime/server/__init__.py +13 -0
- forge_ai_runtime-0.7.0/ai_runtime/server/agent_server.py +111 -0
- forge_ai_runtime-0.7.0/ai_runtime/server/protocol.py +54 -0
- forge_ai_runtime-0.7.0/ai_runtime/session/__init__.py +1 -0
- forge_ai_runtime-0.7.0/ai_runtime/session/session.py +31 -0
- forge_ai_runtime-0.7.0/ai_runtime/skills/__init__.py +10 -0
- forge_ai_runtime-0.7.0/ai_runtime/skills/registry.py +48 -0
- forge_ai_runtime-0.7.0/ai_runtime/skills/skill.py +26 -0
- forge_ai_runtime-0.7.0/ai_runtime/streaming/__init__.py +25 -0
- forge_ai_runtime-0.7.0/ai_runtime/streaming/completed.py +19 -0
- forge_ai_runtime-0.7.0/ai_runtime/streaming/enums.py +13 -0
- forge_ai_runtime-0.7.0/ai_runtime/streaming/error.py +16 -0
- forge_ai_runtime-0.7.0/ai_runtime/streaming/event.py +18 -0
- forge_ai_runtime-0.7.0/ai_runtime/streaming/factory.py +42 -0
- forge_ai_runtime-0.7.0/ai_runtime/streaming/finish_reason.py +9 -0
- forge_ai_runtime-0.7.0/ai_runtime/streaming/permission.py +23 -0
- forge_ai_runtime-0.7.0/ai_runtime/streaming/text.py +18 -0
- forge_ai_runtime-0.7.0/ai_runtime/streaming/thinking.py +18 -0
- forge_ai_runtime-0.7.0/ai_runtime/streaming/tool_call.py +21 -0
- forge_ai_runtime-0.7.0/ai_runtime/streaming/tool_result.py +29 -0
- forge_ai_runtime-0.7.0/ai_runtime/streaming/usage.py +19 -0
- forge_ai_runtime-0.7.0/ai_runtime/tools/__init__.py +26 -0
- forge_ai_runtime-0.7.0/ai_runtime/tools/adapters/function_adapter.py +26 -0
- forge_ai_runtime-0.7.0/ai_runtime/tools/builtin/__init__.py +31 -0
- forge_ai_runtime-0.7.0/ai_runtime/tools/builtin/file_tools.py +135 -0
- forge_ai_runtime-0.7.0/ai_runtime/tools/builtin/shell_tool.py +45 -0
- forge_ai_runtime-0.7.0/ai_runtime/tools/checkpoints.py +50 -0
- forge_ai_runtime-0.7.0/ai_runtime/tools/executor.py +47 -0
- forge_ai_runtime-0.7.0/ai_runtime/tools/guarded_executor.py +63 -0
- forge_ai_runtime-0.7.0/ai_runtime/tools/permissions.py +77 -0
- forge_ai_runtime-0.7.0/ai_runtime/tools/registry.py +23 -0
- forge_ai_runtime-0.7.0/ai_runtime/tools/tool.py +27 -0
- forge_ai_runtime-0.7.0/ai_runtime/version.py +1 -0
- forge_ai_runtime-0.7.0/ai_runtime/workspace/__init__.py +5 -0
- forge_ai_runtime-0.7.0/ai_runtime/workspace/project.py +51 -0
- forge_ai_runtime-0.7.0/forge_ai_runtime.egg-info/PKG-INFO +351 -0
- forge_ai_runtime-0.7.0/forge_ai_runtime.egg-info/SOURCES.txt +114 -0
- forge_ai_runtime-0.7.0/forge_ai_runtime.egg-info/dependency_links.txt +1 -0
- forge_ai_runtime-0.7.0/forge_ai_runtime.egg-info/entry_points.txt +2 -0
- forge_ai_runtime-0.7.0/forge_ai_runtime.egg-info/requires.txt +9 -0
- forge_ai_runtime-0.7.0/forge_ai_runtime.egg-info/top_level.txt +1 -0
- forge_ai_runtime-0.7.0/pyproject.toml +35 -0
- forge_ai_runtime-0.7.0/setup.cfg +4 -0
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Only ship the ai_runtime library. Explicitly exclude the web app and
|
|
2
|
+
# other non-library directories so `pip install forge-ai-runtime` never bundles them.
|
|
3
|
+
recursive-exclude web *
|
|
4
|
+
recursive-exclude tests *
|
|
5
|
+
recursive-exclude docs *
|
|
6
|
+
recursive-exclude venv *
|
|
7
|
+
recursive-exclude .ai-runtime *
|
|
8
|
+
recursive-exclude .vscode *
|
|
9
|
+
recursive-exclude copilot-agentic-research.md
|
|
10
|
+
recursive-exclude CHANGELOG.md
|
|
11
|
+
recursive-exclude PUBLISHING.md
|
|
12
|
+
global-exclude *.pyc
|
|
13
|
+
global-exclude __pycache__
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: forge-ai-runtime
|
|
3
|
+
Version: 0.7.0
|
|
4
|
+
Summary: Provider-agnostic AI Runtime SDK
|
|
5
|
+
Author: Kirit Vaghela
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: litellm>=1.75
|
|
11
|
+
Requires-Dist: pydantic>=2.8.0
|
|
12
|
+
Requires-Dist: httpx>=0.28
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
15
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
16
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
17
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# AI Runtime
|
|
21
|
+
|
|
22
|
+
AI Runtime is a provider-agnostic Python runtime for building AI
|
|
23
|
+
applications and agent workflows.
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- Provider abstraction with a unified LLM contract
|
|
28
|
+
- Built-in default provider registry and plugin discovery
|
|
29
|
+
- Custom provider registration with test doubles
|
|
30
|
+
- Conversation management and session-based execution
|
|
31
|
+
- Streaming responses with event processing
|
|
32
|
+
- Streaming timeout/cancellation boundary handling
|
|
33
|
+
- Automatic tool-calling loop (model requests tools → runtime executes → re-invokes)
|
|
34
|
+
- Capability-gated request mapping (tools, structured output, vision, metadata)
|
|
35
|
+
- Expanded provider contract: chat, stream, embeddings, image, transcription
|
|
36
|
+
- Retries via `ProviderConfig.max_retries` (forwarded to the backend)
|
|
37
|
+
- Uniform events: `chat()` and `stream()` both emit `StreamEvent`s
|
|
38
|
+
- Rich streaming events: text, usage, tool call, tool result, thinking, permission
|
|
39
|
+
- Execution engine and pipeline stages
|
|
40
|
+
- Provider metadata, capabilities, and request mapping
|
|
41
|
+
- Fully tested runtime and provider integration coverage
|
|
42
|
+
|
|
43
|
+
### Agentic capabilities (v0.6.0)
|
|
44
|
+
|
|
45
|
+
`ai_runtime` now closes the gap with agentic coding tools (Claude Code,
|
|
46
|
+
OpenAI Codex, Cursor):
|
|
47
|
+
|
|
48
|
+
- **Plan mode** — `AgentRunner.plan()` / `ExecutionEngine.plan()` produce a
|
|
49
|
+
reviewable `Plan` (read-only, no tools run) before execution.
|
|
50
|
+
- **Sub-agents** — declare `SubAgentSpec`s on an `Agent`; the `SupervisorStage`
|
|
51
|
+
fans them out in parallel with isolated contexts and aggregates results.
|
|
52
|
+
- **Permissions** — `PermissionPolicy` + `GuardedToolExecutor` enforce
|
|
53
|
+
allow/deny/ask rules (glob-matched) over tool calls, mirroring tiered
|
|
54
|
+
permission modes.
|
|
55
|
+
- **Hooks** — `HookRegistry` with `PreToolUse` / `PostToolUse` / `PreLLM` /
|
|
56
|
+
`PostLLM` / `OnPlan` / `OnCompact` / `OnError` lifecycle hooks.
|
|
57
|
+
- **Auto compaction** — `CompactionStage` summarizes or drops old turns when
|
|
58
|
+
the context window exceeds its token budget.
|
|
59
|
+
- **Memory consolidation** — `MemoryConsolidationStage` writes durable
|
|
60
|
+
learnings (`LEARNING: ...`) back to the agent's `MemoryStore`.
|
|
61
|
+
- **MCP client** — `MCPClient` + `StdioTransport` speak JSON-RPC over stdio;
|
|
62
|
+
`register_mcp_tools()` wraps server tools as runtime `Tool`s.
|
|
63
|
+
- **Background tasks** — `BackgroundTaskRegistry` for resumable async tasks
|
|
64
|
+
(à la `codex resume` / Claude `/tasks`).
|
|
65
|
+
- **Skill scoping** — `Skill` gains `paths` / `globs` / `disable_model_invocation`.
|
|
66
|
+
- **Reasoning controls** — `ProviderConfig.reasoning_effort` / `thinking_enabled`
|
|
67
|
+
/ `thinking_budget_tokens`, forwarded when the provider supports reasoning.
|
|
68
|
+
|
|
69
|
+
### Integration surfaces (v0.7.0)
|
|
70
|
+
|
|
71
|
+
To embed `ai_runtime` in a **web app, desktop app, VS Code, or CLI** like
|
|
72
|
+
Claude Code / Codex / Cursor / Copilot, the framework now ships:
|
|
73
|
+
|
|
74
|
+
- **Built-in tools** — `ReadFileTool`, `WriteFileTool`, `EditFileTool`,
|
|
75
|
+
`GlobTool`, `GrepTool`, `BashTool` (scoped to a sandbox root via
|
|
76
|
+
`register_builtin_tools`). These mirror the file/shell/grep primitives of
|
|
77
|
+
the four tools.
|
|
78
|
+
- **Checkpoints / undo** — `CheckpointManager` snapshots files before edits
|
|
79
|
+
so the UI can roll back (à la Cursor/Claude/Copilot checkpoints).
|
|
80
|
+
- **Agent config files** — `load_project_instructions()` discovers
|
|
81
|
+
`.github/copilot-instructions.md`, `AGENTS.md`, `CLAUDE.md`,
|
|
82
|
+
`.cursor/rules` from the project root and folds them into the system prompt.
|
|
83
|
+
- **Transport-agnostic server** — `AgentServer` exposes an `Agent` over a
|
|
84
|
+
JSON-line protocol (`AgentRequest` / `AgentResponse` / `StreamEvent`) via
|
|
85
|
+
`serve_stdio()` (VS Code / CLI) and `serve_http()` (web / desktop).
|
|
86
|
+
- **CLI** — `ai-runtime` console script: `ai-runtime "prompt" --model ...`,
|
|
87
|
+
`--mode plan|stream`, `--serve` (stdio), `--http` (HTTP server), `--yolo`.
|
|
88
|
+
- **Workspace / project** — `Project` scopes memory, tools, permissions, and
|
|
89
|
+
checkpoints to a project root (the unit you mount in a client).
|
|
90
|
+
- **Slash commands** — `CommandRegistry` / `default_commands()`
|
|
91
|
+
(`/compact`, `/context`, `/clear`) mirroring Copilot's `/` menu.
|
|
92
|
+
- **BYO provider** — `ProviderConfig.from_env()` reads `COPILOT_PROVIDER_*`
|
|
93
|
+
vars to point at Ollama / vLLM / any OpenAI-compatible endpoint.
|
|
94
|
+
|
|
95
|
+
### Web application (`web/`)
|
|
96
|
+
|
|
97
|
+
A ready-to-run web UI + REST/WebSocket API that exercises the full framework:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
export AI_RUNTIME_API_KEY=sk-... # or AI_RUNTIME_PROVIDER/AI_RUNTIME_BASE_URL
|
|
101
|
+
./venv/bin/python web/run.py # serves http://127.0.0.1:8787
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Features exposed in the UI:
|
|
105
|
+
- **Streaming chat** (WebSocket streams `StreamEvent`s: text, tool calls, tool
|
|
106
|
+
results, thinking, usage, completion)
|
|
107
|
+
- **Plan mode** (`/api/chat` with `mode: plan` returns a reviewable `Plan`)
|
|
108
|
+
- **Projects** — `Project` scoping with auto-loaded instruction files + sandboxed
|
|
109
|
+
built-in tools (Read/Write/Edit/Glob/Grep/Bash)
|
|
110
|
+
- **Checkpoints / undo** — snapshot + restore files before agent edits
|
|
111
|
+
- **Permissions** — `PermissionPolicy` allow/deny/ask rules per tool + params
|
|
112
|
+
- **Sub-agents** — configure `SubAgentSpec`s; supervisor fans them out
|
|
113
|
+
- **Background tasks** — submit/resume/cancel via `BackgroundTaskRegistry`
|
|
114
|
+
- **Slash commands** — `/compact`, `/context`, `/clear`
|
|
115
|
+
- **MCP** — connect a stdio MCP server and register its tools
|
|
116
|
+
- **Reasoning controls** — `reasoning_effort` / `thinking_enabled` per request
|
|
117
|
+
|
|
118
|
+
See `web/README.md` for the full API reference.
|
|
119
|
+
|
|
120
|
+
## Installation
|
|
121
|
+
|
|
122
|
+
### From PyPI
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pip install ai-runtime
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### From source
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
git clone https://github.com/KiritVaghela/ai-runtime.git
|
|
132
|
+
cd ai-runtime
|
|
133
|
+
pip install -e .
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Quick Start
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
import os
|
|
140
|
+
|
|
141
|
+
from ai_runtime import AgentRuntime
|
|
142
|
+
from ai_runtime.conversation import ChatMessage
|
|
143
|
+
from ai_runtime.providers.enums import ProviderType
|
|
144
|
+
|
|
145
|
+
runtime = AgentRuntime.from_provider(
|
|
146
|
+
provider=ProviderType.GROQ,
|
|
147
|
+
model="groq/llama-3.3-70b-versatile",
|
|
148
|
+
api_key=os.getenv("GROQ_API_KEY"),
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
session = runtime.create_session()
|
|
152
|
+
|
|
153
|
+
response = await session.chat(
|
|
154
|
+
ChatMessage.user("Hello!")
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
print(response.message.content)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Streaming
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
from ai_runtime.conversation import ChatMessage
|
|
164
|
+
from ai_runtime.streaming import TextDeltaEvent
|
|
165
|
+
|
|
166
|
+
async for event in session.stream(
|
|
167
|
+
ChatMessage.user("Write a haiku.")
|
|
168
|
+
):
|
|
169
|
+
if isinstance(event, TextDeltaEvent):
|
|
170
|
+
print(event.delta, end="")
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Streaming with timeout
|
|
174
|
+
|
|
175
|
+
The runtime supports stream timeout propagation through `ChatRequest.timeout`.
|
|
176
|
+
If a provider stream stalls, an `ErrorEvent` is emitted and the stream stops.
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from ai_runtime.conversation import ChatMessage, ChatRequest
|
|
180
|
+
from ai_runtime.streaming import ErrorEvent, TextDeltaEvent
|
|
181
|
+
|
|
182
|
+
request = ChatRequest(
|
|
183
|
+
messages=[ChatMessage.user("Generate a poem.")],
|
|
184
|
+
timeout=10.0,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
async for event in session.stream(request):
|
|
188
|
+
if isinstance(event, TextDeltaEvent):
|
|
189
|
+
print(event.delta, end="")
|
|
190
|
+
elif isinstance(event, ErrorEvent):
|
|
191
|
+
print("\nStream timed out or failed:", event.message)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Provider registry
|
|
195
|
+
|
|
196
|
+
The runtime uses a provider registry so you can register custom providers or
|
|
197
|
+
replace the default provider implementation during tests.
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
from ai_runtime import AgentRuntime
|
|
201
|
+
from ai_runtime.providers import ProviderRegistry
|
|
202
|
+
from ai_runtime.providers.enums import ProviderType
|
|
203
|
+
|
|
204
|
+
registry = ProviderRegistry()
|
|
205
|
+
registry.register(ProviderType.OPENAI, MyCustomProvider)
|
|
206
|
+
|
|
207
|
+
runtime = AgentRuntime.from_provider(
|
|
208
|
+
provider=ProviderType.OPENAI,
|
|
209
|
+
model="gpt-4.1",
|
|
210
|
+
api_key=os.getenv("OPENAI_API_KEY"),
|
|
211
|
+
registry=registry,
|
|
212
|
+
)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Architecture
|
|
216
|
+
|
|
217
|
+
AgentRuntime
|
|
218
|
+
└── Session
|
|
219
|
+
└── ExecutionEngine
|
|
220
|
+
└── ExecutionPipeline
|
|
221
|
+
├── RequestBuilderStage
|
|
222
|
+
├── LLMStage
|
|
223
|
+
└── ToolLoopStage
|
|
224
|
+
└── EventProcessor
|
|
225
|
+
|
|
226
|
+
## Tools
|
|
227
|
+
|
|
228
|
+
Register tools with a `ToolRegistry`, wrap it in a `ToolExecutor`, and attach
|
|
229
|
+
it to the session context. When the model requests a tool, the runtime
|
|
230
|
+
executes it and feeds the result back automatically.
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
from ai_runtime.tools import ToolRegistry, ToolExecutor, FunctionTool
|
|
234
|
+
from ai_runtime.conversation import ChatMessage
|
|
235
|
+
|
|
236
|
+
registry = ToolRegistry()
|
|
237
|
+
registry.register(
|
|
238
|
+
FunctionTool("get_weather", lambda ctx, inp: f"Weather in {inp['city']}: sunny")
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
session.context.tool_executor = ToolExecutor(registry)
|
|
242
|
+
|
|
243
|
+
response = await session.chat(
|
|
244
|
+
ChatMessage.user("What is the weather in Paris?")
|
|
245
|
+
)
|
|
246
|
+
print(response.message.content)
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Agents
|
|
250
|
+
|
|
251
|
+
An `Agent` bundles a provider, system prompt, tools, memory, and skills.
|
|
252
|
+
`AgentRunner` drives execution (including the automatic tool-call loop) and
|
|
253
|
+
persists conversation memory across turns.
|
|
254
|
+
|
|
255
|
+
```python
|
|
256
|
+
from ai_runtime import AgentRuntime, Agent, AgentRunner
|
|
257
|
+
from ai_runtime.tools import ToolRegistry, ToolExecutor, FunctionTool
|
|
258
|
+
|
|
259
|
+
runtime = AgentRuntime.from_provider(
|
|
260
|
+
provider=ProviderType.GROQ,
|
|
261
|
+
model="llama-3.3-70b-versatile",
|
|
262
|
+
api_key=os.getenv("GROQ_API_KEY"),
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
registry = ToolRegistry()
|
|
266
|
+
registry.register(FunctionTool("ping", lambda ctx, inp: "pong"))
|
|
267
|
+
|
|
268
|
+
agent = runtime.create_agent(
|
|
269
|
+
name="helper",
|
|
270
|
+
system_prompt="You are a helpful assistant.",
|
|
271
|
+
tool_registry=registry,
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
runner = AgentRunner(agent)
|
|
275
|
+
response = await runner.run("Ping the tool for me.")
|
|
276
|
+
print(response.message.content)
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Memory, RAG & Skills
|
|
280
|
+
|
|
281
|
+
- `ai_runtime.memory` — `MemoryStore`, `ConversationMemory`, `SemanticMemory`.
|
|
282
|
+
- `ai_runtime.rag` — `Document`, `VectorStore`, `Retriever` for retrieval.
|
|
283
|
+
- `ai_runtime.skills` — `Skill` + `SkillRegistry` for composable behaviors.
|
|
284
|
+
- `ai_runtime.context` — `ContextWindow` for token budgeting/truncation.
|
|
285
|
+
|
|
286
|
+
## Documentation
|
|
287
|
+
|
|
288
|
+
- [Migration Guide](docs/migration_guide.md)
|
|
289
|
+
- [Adapter Tutorial](docs/adapter_tutorial.md)
|
|
290
|
+
- [Examples](docs/examples.md)
|
|
291
|
+
- [Release Checklist](docs/release_checklist.md)
|
|
292
|
+
|
|
293
|
+
See [CHANGELOG.md](CHANGELOG.md) for version history.
|
|
294
|
+
|
|
295
|
+
## Testing
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
pytest
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Current status:
|
|
302
|
+
|
|
303
|
+
- Provider registry with custom provider registration
|
|
304
|
+
- Streaming response support with timeouts and completion events
|
|
305
|
+
- Session-based execution and conversation accumulation
|
|
306
|
+
- Provider integration coverage with test doubles
|
|
307
|
+
|
|
308
|
+
## Roadmap
|
|
309
|
+
|
|
310
|
+
### v0.3.x
|
|
311
|
+
|
|
312
|
+
- Tool registry
|
|
313
|
+
- Tool execution
|
|
314
|
+
- Permission manager
|
|
315
|
+
- Filesystem tools
|
|
316
|
+
- Bash tools
|
|
317
|
+
|
|
318
|
+
### Future
|
|
319
|
+
|
|
320
|
+
- MCP support
|
|
321
|
+
- Multi-agent workflows
|
|
322
|
+
- Desktop and terminal integrations
|
|
323
|
+
- AI Factory integration
|
|
324
|
+
|
|
325
|
+
## Publishing to PyPI
|
|
326
|
+
|
|
327
|
+
1. Update version in `pyproject.toml`.
|
|
328
|
+
2. Build:
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
python -m build
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
3. Check:
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
twine check dist/*
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
4. Upload to TestPyPI:
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
twine upload --repository testpypi dist/*
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
5. Upload to PyPI:
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
twine upload dist/*
|
|
350
|
+
```
|
|
351
|
+
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# AI Runtime
|
|
2
|
+
|
|
3
|
+
AI Runtime is a provider-agnostic Python runtime for building AI
|
|
4
|
+
applications and agent workflows.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- Provider abstraction with a unified LLM contract
|
|
9
|
+
- Built-in default provider registry and plugin discovery
|
|
10
|
+
- Custom provider registration with test doubles
|
|
11
|
+
- Conversation management and session-based execution
|
|
12
|
+
- Streaming responses with event processing
|
|
13
|
+
- Streaming timeout/cancellation boundary handling
|
|
14
|
+
- Automatic tool-calling loop (model requests tools → runtime executes → re-invokes)
|
|
15
|
+
- Capability-gated request mapping (tools, structured output, vision, metadata)
|
|
16
|
+
- Expanded provider contract: chat, stream, embeddings, image, transcription
|
|
17
|
+
- Retries via `ProviderConfig.max_retries` (forwarded to the backend)
|
|
18
|
+
- Uniform events: `chat()` and `stream()` both emit `StreamEvent`s
|
|
19
|
+
- Rich streaming events: text, usage, tool call, tool result, thinking, permission
|
|
20
|
+
- Execution engine and pipeline stages
|
|
21
|
+
- Provider metadata, capabilities, and request mapping
|
|
22
|
+
- Fully tested runtime and provider integration coverage
|
|
23
|
+
|
|
24
|
+
### Agentic capabilities (v0.6.0)
|
|
25
|
+
|
|
26
|
+
`ai_runtime` now closes the gap with agentic coding tools (Claude Code,
|
|
27
|
+
OpenAI Codex, Cursor):
|
|
28
|
+
|
|
29
|
+
- **Plan mode** — `AgentRunner.plan()` / `ExecutionEngine.plan()` produce a
|
|
30
|
+
reviewable `Plan` (read-only, no tools run) before execution.
|
|
31
|
+
- **Sub-agents** — declare `SubAgentSpec`s on an `Agent`; the `SupervisorStage`
|
|
32
|
+
fans them out in parallel with isolated contexts and aggregates results.
|
|
33
|
+
- **Permissions** — `PermissionPolicy` + `GuardedToolExecutor` enforce
|
|
34
|
+
allow/deny/ask rules (glob-matched) over tool calls, mirroring tiered
|
|
35
|
+
permission modes.
|
|
36
|
+
- **Hooks** — `HookRegistry` with `PreToolUse` / `PostToolUse` / `PreLLM` /
|
|
37
|
+
`PostLLM` / `OnPlan` / `OnCompact` / `OnError` lifecycle hooks.
|
|
38
|
+
- **Auto compaction** — `CompactionStage` summarizes or drops old turns when
|
|
39
|
+
the context window exceeds its token budget.
|
|
40
|
+
- **Memory consolidation** — `MemoryConsolidationStage` writes durable
|
|
41
|
+
learnings (`LEARNING: ...`) back to the agent's `MemoryStore`.
|
|
42
|
+
- **MCP client** — `MCPClient` + `StdioTransport` speak JSON-RPC over stdio;
|
|
43
|
+
`register_mcp_tools()` wraps server tools as runtime `Tool`s.
|
|
44
|
+
- **Background tasks** — `BackgroundTaskRegistry` for resumable async tasks
|
|
45
|
+
(à la `codex resume` / Claude `/tasks`).
|
|
46
|
+
- **Skill scoping** — `Skill` gains `paths` / `globs` / `disable_model_invocation`.
|
|
47
|
+
- **Reasoning controls** — `ProviderConfig.reasoning_effort` / `thinking_enabled`
|
|
48
|
+
/ `thinking_budget_tokens`, forwarded when the provider supports reasoning.
|
|
49
|
+
|
|
50
|
+
### Integration surfaces (v0.7.0)
|
|
51
|
+
|
|
52
|
+
To embed `ai_runtime` in a **web app, desktop app, VS Code, or CLI** like
|
|
53
|
+
Claude Code / Codex / Cursor / Copilot, the framework now ships:
|
|
54
|
+
|
|
55
|
+
- **Built-in tools** — `ReadFileTool`, `WriteFileTool`, `EditFileTool`,
|
|
56
|
+
`GlobTool`, `GrepTool`, `BashTool` (scoped to a sandbox root via
|
|
57
|
+
`register_builtin_tools`). These mirror the file/shell/grep primitives of
|
|
58
|
+
the four tools.
|
|
59
|
+
- **Checkpoints / undo** — `CheckpointManager` snapshots files before edits
|
|
60
|
+
so the UI can roll back (à la Cursor/Claude/Copilot checkpoints).
|
|
61
|
+
- **Agent config files** — `load_project_instructions()` discovers
|
|
62
|
+
`.github/copilot-instructions.md`, `AGENTS.md`, `CLAUDE.md`,
|
|
63
|
+
`.cursor/rules` from the project root and folds them into the system prompt.
|
|
64
|
+
- **Transport-agnostic server** — `AgentServer` exposes an `Agent` over a
|
|
65
|
+
JSON-line protocol (`AgentRequest` / `AgentResponse` / `StreamEvent`) via
|
|
66
|
+
`serve_stdio()` (VS Code / CLI) and `serve_http()` (web / desktop).
|
|
67
|
+
- **CLI** — `ai-runtime` console script: `ai-runtime "prompt" --model ...`,
|
|
68
|
+
`--mode plan|stream`, `--serve` (stdio), `--http` (HTTP server), `--yolo`.
|
|
69
|
+
- **Workspace / project** — `Project` scopes memory, tools, permissions, and
|
|
70
|
+
checkpoints to a project root (the unit you mount in a client).
|
|
71
|
+
- **Slash commands** — `CommandRegistry` / `default_commands()`
|
|
72
|
+
(`/compact`, `/context`, `/clear`) mirroring Copilot's `/` menu.
|
|
73
|
+
- **BYO provider** — `ProviderConfig.from_env()` reads `COPILOT_PROVIDER_*`
|
|
74
|
+
vars to point at Ollama / vLLM / any OpenAI-compatible endpoint.
|
|
75
|
+
|
|
76
|
+
### Web application (`web/`)
|
|
77
|
+
|
|
78
|
+
A ready-to-run web UI + REST/WebSocket API that exercises the full framework:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
export AI_RUNTIME_API_KEY=sk-... # or AI_RUNTIME_PROVIDER/AI_RUNTIME_BASE_URL
|
|
82
|
+
./venv/bin/python web/run.py # serves http://127.0.0.1:8787
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Features exposed in the UI:
|
|
86
|
+
- **Streaming chat** (WebSocket streams `StreamEvent`s: text, tool calls, tool
|
|
87
|
+
results, thinking, usage, completion)
|
|
88
|
+
- **Plan mode** (`/api/chat` with `mode: plan` returns a reviewable `Plan`)
|
|
89
|
+
- **Projects** — `Project` scoping with auto-loaded instruction files + sandboxed
|
|
90
|
+
built-in tools (Read/Write/Edit/Glob/Grep/Bash)
|
|
91
|
+
- **Checkpoints / undo** — snapshot + restore files before agent edits
|
|
92
|
+
- **Permissions** — `PermissionPolicy` allow/deny/ask rules per tool + params
|
|
93
|
+
- **Sub-agents** — configure `SubAgentSpec`s; supervisor fans them out
|
|
94
|
+
- **Background tasks** — submit/resume/cancel via `BackgroundTaskRegistry`
|
|
95
|
+
- **Slash commands** — `/compact`, `/context`, `/clear`
|
|
96
|
+
- **MCP** — connect a stdio MCP server and register its tools
|
|
97
|
+
- **Reasoning controls** — `reasoning_effort` / `thinking_enabled` per request
|
|
98
|
+
|
|
99
|
+
See `web/README.md` for the full API reference.
|
|
100
|
+
|
|
101
|
+
## Installation
|
|
102
|
+
|
|
103
|
+
### From PyPI
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
pip install ai-runtime
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### From source
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
git clone https://github.com/KiritVaghela/ai-runtime.git
|
|
113
|
+
cd ai-runtime
|
|
114
|
+
pip install -e .
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Quick Start
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
import os
|
|
121
|
+
|
|
122
|
+
from ai_runtime import AgentRuntime
|
|
123
|
+
from ai_runtime.conversation import ChatMessage
|
|
124
|
+
from ai_runtime.providers.enums import ProviderType
|
|
125
|
+
|
|
126
|
+
runtime = AgentRuntime.from_provider(
|
|
127
|
+
provider=ProviderType.GROQ,
|
|
128
|
+
model="groq/llama-3.3-70b-versatile",
|
|
129
|
+
api_key=os.getenv("GROQ_API_KEY"),
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
session = runtime.create_session()
|
|
133
|
+
|
|
134
|
+
response = await session.chat(
|
|
135
|
+
ChatMessage.user("Hello!")
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
print(response.message.content)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Streaming
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from ai_runtime.conversation import ChatMessage
|
|
145
|
+
from ai_runtime.streaming import TextDeltaEvent
|
|
146
|
+
|
|
147
|
+
async for event in session.stream(
|
|
148
|
+
ChatMessage.user("Write a haiku.")
|
|
149
|
+
):
|
|
150
|
+
if isinstance(event, TextDeltaEvent):
|
|
151
|
+
print(event.delta, end="")
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Streaming with timeout
|
|
155
|
+
|
|
156
|
+
The runtime supports stream timeout propagation through `ChatRequest.timeout`.
|
|
157
|
+
If a provider stream stalls, an `ErrorEvent` is emitted and the stream stops.
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from ai_runtime.conversation import ChatMessage, ChatRequest
|
|
161
|
+
from ai_runtime.streaming import ErrorEvent, TextDeltaEvent
|
|
162
|
+
|
|
163
|
+
request = ChatRequest(
|
|
164
|
+
messages=[ChatMessage.user("Generate a poem.")],
|
|
165
|
+
timeout=10.0,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
async for event in session.stream(request):
|
|
169
|
+
if isinstance(event, TextDeltaEvent):
|
|
170
|
+
print(event.delta, end="")
|
|
171
|
+
elif isinstance(event, ErrorEvent):
|
|
172
|
+
print("\nStream timed out or failed:", event.message)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Provider registry
|
|
176
|
+
|
|
177
|
+
The runtime uses a provider registry so you can register custom providers or
|
|
178
|
+
replace the default provider implementation during tests.
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
from ai_runtime import AgentRuntime
|
|
182
|
+
from ai_runtime.providers import ProviderRegistry
|
|
183
|
+
from ai_runtime.providers.enums import ProviderType
|
|
184
|
+
|
|
185
|
+
registry = ProviderRegistry()
|
|
186
|
+
registry.register(ProviderType.OPENAI, MyCustomProvider)
|
|
187
|
+
|
|
188
|
+
runtime = AgentRuntime.from_provider(
|
|
189
|
+
provider=ProviderType.OPENAI,
|
|
190
|
+
model="gpt-4.1",
|
|
191
|
+
api_key=os.getenv("OPENAI_API_KEY"),
|
|
192
|
+
registry=registry,
|
|
193
|
+
)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Architecture
|
|
197
|
+
|
|
198
|
+
AgentRuntime
|
|
199
|
+
└── Session
|
|
200
|
+
└── ExecutionEngine
|
|
201
|
+
└── ExecutionPipeline
|
|
202
|
+
├── RequestBuilderStage
|
|
203
|
+
├── LLMStage
|
|
204
|
+
└── ToolLoopStage
|
|
205
|
+
└── EventProcessor
|
|
206
|
+
|
|
207
|
+
## Tools
|
|
208
|
+
|
|
209
|
+
Register tools with a `ToolRegistry`, wrap it in a `ToolExecutor`, and attach
|
|
210
|
+
it to the session context. When the model requests a tool, the runtime
|
|
211
|
+
executes it and feeds the result back automatically.
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
from ai_runtime.tools import ToolRegistry, ToolExecutor, FunctionTool
|
|
215
|
+
from ai_runtime.conversation import ChatMessage
|
|
216
|
+
|
|
217
|
+
registry = ToolRegistry()
|
|
218
|
+
registry.register(
|
|
219
|
+
FunctionTool("get_weather", lambda ctx, inp: f"Weather in {inp['city']}: sunny")
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
session.context.tool_executor = ToolExecutor(registry)
|
|
223
|
+
|
|
224
|
+
response = await session.chat(
|
|
225
|
+
ChatMessage.user("What is the weather in Paris?")
|
|
226
|
+
)
|
|
227
|
+
print(response.message.content)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Agents
|
|
231
|
+
|
|
232
|
+
An `Agent` bundles a provider, system prompt, tools, memory, and skills.
|
|
233
|
+
`AgentRunner` drives execution (including the automatic tool-call loop) and
|
|
234
|
+
persists conversation memory across turns.
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
from ai_runtime import AgentRuntime, Agent, AgentRunner
|
|
238
|
+
from ai_runtime.tools import ToolRegistry, ToolExecutor, FunctionTool
|
|
239
|
+
|
|
240
|
+
runtime = AgentRuntime.from_provider(
|
|
241
|
+
provider=ProviderType.GROQ,
|
|
242
|
+
model="llama-3.3-70b-versatile",
|
|
243
|
+
api_key=os.getenv("GROQ_API_KEY"),
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
registry = ToolRegistry()
|
|
247
|
+
registry.register(FunctionTool("ping", lambda ctx, inp: "pong"))
|
|
248
|
+
|
|
249
|
+
agent = runtime.create_agent(
|
|
250
|
+
name="helper",
|
|
251
|
+
system_prompt="You are a helpful assistant.",
|
|
252
|
+
tool_registry=registry,
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
runner = AgentRunner(agent)
|
|
256
|
+
response = await runner.run("Ping the tool for me.")
|
|
257
|
+
print(response.message.content)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Memory, RAG & Skills
|
|
261
|
+
|
|
262
|
+
- `ai_runtime.memory` — `MemoryStore`, `ConversationMemory`, `SemanticMemory`.
|
|
263
|
+
- `ai_runtime.rag` — `Document`, `VectorStore`, `Retriever` for retrieval.
|
|
264
|
+
- `ai_runtime.skills` — `Skill` + `SkillRegistry` for composable behaviors.
|
|
265
|
+
- `ai_runtime.context` — `ContextWindow` for token budgeting/truncation.
|
|
266
|
+
|
|
267
|
+
## Documentation
|
|
268
|
+
|
|
269
|
+
- [Migration Guide](docs/migration_guide.md)
|
|
270
|
+
- [Adapter Tutorial](docs/adapter_tutorial.md)
|
|
271
|
+
- [Examples](docs/examples.md)
|
|
272
|
+
- [Release Checklist](docs/release_checklist.md)
|
|
273
|
+
|
|
274
|
+
See [CHANGELOG.md](CHANGELOG.md) for version history.
|
|
275
|
+
|
|
276
|
+
## Testing
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
pytest
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Current status:
|
|
283
|
+
|
|
284
|
+
- Provider registry with custom provider registration
|
|
285
|
+
- Streaming response support with timeouts and completion events
|
|
286
|
+
- Session-based execution and conversation accumulation
|
|
287
|
+
- Provider integration coverage with test doubles
|
|
288
|
+
|
|
289
|
+
## Roadmap
|
|
290
|
+
|
|
291
|
+
### v0.3.x
|
|
292
|
+
|
|
293
|
+
- Tool registry
|
|
294
|
+
- Tool execution
|
|
295
|
+
- Permission manager
|
|
296
|
+
- Filesystem tools
|
|
297
|
+
- Bash tools
|
|
298
|
+
|
|
299
|
+
### Future
|
|
300
|
+
|
|
301
|
+
- MCP support
|
|
302
|
+
- Multi-agent workflows
|
|
303
|
+
- Desktop and terminal integrations
|
|
304
|
+
- AI Factory integration
|
|
305
|
+
|
|
306
|
+
## Publishing to PyPI
|
|
307
|
+
|
|
308
|
+
1. Update version in `pyproject.toml`.
|
|
309
|
+
2. Build:
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
python -m build
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
3. Check:
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
twine check dist/*
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
4. Upload to TestPyPI:
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
twine upload --repository testpypi dist/*
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
5. Upload to PyPI:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
twine upload dist/*
|
|
331
|
+
```
|
|
332
|
+
|