pyagentkit 0.1.4__tar.gz → 0.1.6__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.
@@ -0,0 +1,115 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyagentkit
3
+ Version: 0.1.6
4
+ Summary: Agent toolkit for Ollama
5
+ Project-URL: Homepage, https://github.com/TarikEren/pyagentkit
6
+ Project-URL: Issues, https://github.com/TarikEren/pyagentkit/issues
7
+ Author-email: Tarık Eren Tosun <tarikerentosun@outlook.com>
8
+ Maintainer-email: Tarık Eren Tosun <tarikerentosun@outlook.com>
9
+ License-Expression: Apache-2.0
10
+ License-File: LICENSE
11
+ Keywords: agent,agentic,ai,ollama
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Requires-Python: >=3.12
15
+ Requires-Dist: build>=1.4.2
16
+ Requires-Dist: ollama>=0.6.1
17
+ Requires-Dist: pydantic>=2.12.5
18
+ Requires-Dist: twine>=6.2.0
19
+ Description-Content-Type: text/markdown
20
+
21
+ # PyAgentKit
22
+
23
+ A Python library for building tool-calling agents on top of locally-hosted LLMs via [Ollama](https://ollama.com). PyAgentKit gives models that lack native function-calling support the ability to call tools through structured JSON output, retries, dependency injection, and lifecycle hooks.
24
+
25
+ ---
26
+
27
+ ## Features
28
+
29
+ - **Sync and async agents** — `Agent` for synchronous use, `AsyncAgent` for `asyncio`-based workflows
30
+ - **Tool registration** — attach tools at the class level (shared across all instances) or at the instance level (per-agent)
31
+ - **Structured JSON responses** — agents respond in a validated, discriminated-union schema (`final` or `tool_call`)
32
+ - **Pydantic response models** — extend `AgentResponse` to add your own typed fields to every response
33
+ - **Dependency injection** — pass runtime dependencies (database connections, config, etc.) through `AgentDependencies` into tools without polluting tool signatures
34
+ - **Retry logic** — configurable retry budgets separately for tool calls and for response validation failures
35
+ - **Approval gates** — optionally require human confirmation before any tool is executed
36
+ - **Lifecycle hooks** — callbacks for tool calls, retries, successes, and final responses
37
+ - **Agent composition** — expose any agent as a tool that another agent can call via `.as_tool()`
38
+ - **Token usage tracking** — cumulative `TokenUsage` object updated after every LLM call
39
+ - **Message history** — persistent within a session, with optional trimming, save, and load
40
+ - **Thinking support** — pass `think=True` to enable chain-of-thought reasoning on supported models
41
+
42
+ ---
43
+
44
+ ## Requirements
45
+
46
+ - Python 3.12+
47
+ - [Ollama](https://ollama.com) running locally (or at a reachable URL)
48
+ - A model pulled in Ollama (e.g. `ollama pull llama3.2`)
49
+
50
+ ---
51
+
52
+ ## Installation
53
+
54
+ ```bash
55
+ pip install pyagentkit
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Project Structure
61
+
62
+ ```
63
+ src/pyagentkit/
64
+ ├── agent.py # Synchronous Agent class
65
+ ├── async_agent.py # Asynchronous AsyncAgent class
66
+ ├── definitions.py # Pydantic models, type aliases, enums
67
+ └── exceptions.py # Exception hierarchy
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Core Concepts
73
+
74
+ ### Response Schema
75
+
76
+ Every agent responds in one of two JSON shapes, validated via Pydantic:
77
+
78
+ ```json
79
+ // Tool call
80
+ {
81
+ "response": {
82
+ "type": "tool_call",
83
+ "tool_call": { "name": "my_tool", "params": [{ "name": "x", "value": "42" }] }
84
+ },
85
+ "message": "Calling my_tool to get the result"
86
+ }
87
+
88
+ // Final answer
89
+ {
90
+ "response": { "type": "final" },
91
+ "message": "The answer is 42"
92
+ }
93
+ ```
94
+
95
+ ### Exception Hierarchy
96
+
97
+ ```
98
+ PyAgentKitError
99
+ ├── ExceptionAgentError # Recoverable response failure (triggers retry)
100
+ ├── ExceptionAgentFatal # Irrecoverable response failure
101
+ ├── ExceptionToolError # Recoverable tool failure (triggers retry)
102
+ ├── ExceptionToolFatal # Irrecoverable tool failure
103
+ ├── ExceptionToolRetriesExhausted
104
+ ├── ExceptionResponseRetriesExhausted
105
+ ├── ExceptionEnvironmentError # Ollama unreachable or model not found
106
+ ├── ExceptionInvalidTool # Tool missing docstring or malformed
107
+ └── ExceptionFatalError # Wraps any fatal agent or tool exception
108
+ ExceptionUnhandledError # Unhandled runtime exception (not a PyAgentKitError)
109
+ ```
110
+
111
+ ---
112
+
113
+ ## License
114
+
115
+ APACHE 2.0
@@ -0,0 +1,95 @@
1
+ # PyAgentKit
2
+
3
+ A Python library for building tool-calling agents on top of locally-hosted LLMs via [Ollama](https://ollama.com). PyAgentKit gives models that lack native function-calling support the ability to call tools through structured JSON output, retries, dependency injection, and lifecycle hooks.
4
+
5
+ ---
6
+
7
+ ## Features
8
+
9
+ - **Sync and async agents** — `Agent` for synchronous use, `AsyncAgent` for `asyncio`-based workflows
10
+ - **Tool registration** — attach tools at the class level (shared across all instances) or at the instance level (per-agent)
11
+ - **Structured JSON responses** — agents respond in a validated, discriminated-union schema (`final` or `tool_call`)
12
+ - **Pydantic response models** — extend `AgentResponse` to add your own typed fields to every response
13
+ - **Dependency injection** — pass runtime dependencies (database connections, config, etc.) through `AgentDependencies` into tools without polluting tool signatures
14
+ - **Retry logic** — configurable retry budgets separately for tool calls and for response validation failures
15
+ - **Approval gates** — optionally require human confirmation before any tool is executed
16
+ - **Lifecycle hooks** — callbacks for tool calls, retries, successes, and final responses
17
+ - **Agent composition** — expose any agent as a tool that another agent can call via `.as_tool()`
18
+ - **Token usage tracking** — cumulative `TokenUsage` object updated after every LLM call
19
+ - **Message history** — persistent within a session, with optional trimming, save, and load
20
+ - **Thinking support** — pass `think=True` to enable chain-of-thought reasoning on supported models
21
+
22
+ ---
23
+
24
+ ## Requirements
25
+
26
+ - Python 3.12+
27
+ - [Ollama](https://ollama.com) running locally (or at a reachable URL)
28
+ - A model pulled in Ollama (e.g. `ollama pull llama3.2`)
29
+
30
+ ---
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install pyagentkit
36
+ ```
37
+
38
+ ---
39
+
40
+ ## Project Structure
41
+
42
+ ```
43
+ src/pyagentkit/
44
+ ├── agent.py # Synchronous Agent class
45
+ ├── async_agent.py # Asynchronous AsyncAgent class
46
+ ├── definitions.py # Pydantic models, type aliases, enums
47
+ └── exceptions.py # Exception hierarchy
48
+ ```
49
+
50
+ ---
51
+
52
+ ## Core Concepts
53
+
54
+ ### Response Schema
55
+
56
+ Every agent responds in one of two JSON shapes, validated via Pydantic:
57
+
58
+ ```json
59
+ // Tool call
60
+ {
61
+ "response": {
62
+ "type": "tool_call",
63
+ "tool_call": { "name": "my_tool", "params": [{ "name": "x", "value": "42" }] }
64
+ },
65
+ "message": "Calling my_tool to get the result"
66
+ }
67
+
68
+ // Final answer
69
+ {
70
+ "response": { "type": "final" },
71
+ "message": "The answer is 42"
72
+ }
73
+ ```
74
+
75
+ ### Exception Hierarchy
76
+
77
+ ```
78
+ PyAgentKitError
79
+ ├── ExceptionAgentError # Recoverable response failure (triggers retry)
80
+ ├── ExceptionAgentFatal # Irrecoverable response failure
81
+ ├── ExceptionToolError # Recoverable tool failure (triggers retry)
82
+ ├── ExceptionToolFatal # Irrecoverable tool failure
83
+ ├── ExceptionToolRetriesExhausted
84
+ ├── ExceptionResponseRetriesExhausted
85
+ ├── ExceptionEnvironmentError # Ollama unreachable or model not found
86
+ ├── ExceptionInvalidTool # Tool missing docstring or malformed
87
+ └── ExceptionFatalError # Wraps any fatal agent or tool exception
88
+ ExceptionUnhandledError # Unhandled runtime exception (not a PyAgentKitError)
89
+ ```
90
+
91
+ ---
92
+
93
+ ## License
94
+
95
+ APACHE 2.0
@@ -0,0 +1,422 @@
1
+ # PyAgentKit — Usage Guide
2
+
3
+ ---
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Basic Agent](#1-basic-agent)
8
+ 2. [Writing Tools](#2-writing-tools)
9
+ 3. [Instance vs Class Tools](#3-instance-vs-class-tools)
10
+ 4. [Dependencies](#4-dependencies)
11
+ 5. [Custom Response Models](#5-custom-response-models)
12
+ 6. [Async Agent](#6-async-agent)
13
+ 7. [Lifecycle Hooks](#7-lifecycle-hooks)
14
+ 8. [Agent Composition](#8-agent-composition)
15
+ 9. [Message History](#9-message-history)
16
+ 10. [Token Usage](#10-token-usage)
17
+ 11. [Error Handling](#11-error-handling)
18
+ 12. [Configuration Reference](#12-configuration-reference)
19
+
20
+ ---
21
+
22
+ ## 1. Basic Agent
23
+
24
+ ```python
25
+ from pyagentkit import Agent
26
+
27
+ agent = Agent(
28
+ llm_name="llama3.2", # Must be pulled in Ollama
29
+ system_prompt="You are a helpful assistant.",
30
+ agent_name="my-agent",
31
+ )
32
+
33
+ response = agent.handle_response("What is 2 + 2?")
34
+ print(response.message) # "The answer is 4"
35
+ ```
36
+
37
+ `handle_response` blocks until the agent produces a `final` response or exhausts its retries.
38
+
39
+ ---
40
+
41
+ ## 2. Writing Tools
42
+
43
+ A tool is any plain Python function that returns a `ToolResult`. It **must** have a docstring — the docstring is what the agent reads to understand what the tool does.
44
+
45
+ ```python
46
+ from pyagentkit import Agent
47
+ from pyagentkit.definitions import ToolResult, ToolReturnValue
48
+
49
+
50
+ def add_numbers(a: int, b: int) -> ToolResult:
51
+ """Add two integers together and return their sum."""
52
+ total = a + b
53
+ return ToolResult(return_value=ToolReturnValue.success, content=str(total))
54
+
55
+
56
+ def divide(a: float, b: float) -> ToolResult:
57
+ """Divide a by b. Returns an error if b is zero."""
58
+ if b == 0:
59
+ return ToolResult(return_value=ToolReturnValue.error, content="Cannot divide by zero")
60
+ return ToolResult(return_value=ToolReturnValue.success, content=str(a / b))
61
+ ```
62
+
63
+ ### ToolReturnValue options
64
+
65
+ | Value | Effect |
66
+ |-------|--------|
67
+ | `success` | Result appended to history; agent continues |
68
+ | `error` | Error message sent back to agent; counts as a tool retry |
69
+ | `fatal` | Immediately raises `ExceptionFatalError`; no retry |
70
+
71
+ ### Passing tools to an agent
72
+
73
+ ```python
74
+ agent = Agent(
75
+ llm_name="llama3.2",
76
+ tools=[add_numbers, divide], # registered without approval requirement
77
+ )
78
+ ```
79
+
80
+ By default, tools added via the `tools=` constructor parameter require approval (`requires_approval=True`). To skip the prompt, use `add_tool` with `requires_approval=False`:
81
+
82
+ ```python
83
+ agent.add_tool(add_numbers, requires_approval=False)
84
+ ```
85
+
86
+ ---
87
+
88
+ ## 3. Instance vs Class Tools
89
+
90
+ ### Instance tools
91
+
92
+ Registered on a single agent instance. Use `add_tool` or pass `tools=` to the constructor.
93
+
94
+ ```python
95
+ agent = Agent(llm_name="llama3.2")
96
+ agent.add_tool(my_tool, requires_approval=False)
97
+ ```
98
+
99
+ ### Class tools
100
+
101
+ Registered on the class and shared across **all instances** of that subclass.
102
+
103
+ ```python
104
+ class MyAgent(Agent):
105
+ pass
106
+
107
+
108
+ @MyAgent.register_tool(requires_approval=False)
109
+ def get_time() -> ToolResult:
110
+ """Return the current UTC time as an ISO string."""
111
+ from datetime import datetime, timezone
112
+ return ToolResult(
113
+ return_value=ToolReturnValue.success,
114
+ content=datetime.now(timezone.utc).isoformat(),
115
+ )
116
+
117
+
118
+ agent_a = MyAgent(llm_name="llama3.2")
119
+ agent_b = MyAgent(llm_name="llama3.2", agent_name="second")
120
+ # Both agents can call get_time
121
+ ```
122
+
123
+ ---
124
+
125
+ ## 4. Dependencies
126
+
127
+ Use `AgentDependencies` to inject runtime state (database handles, API clients, config) into tools without exposing them in the tool's public signature shown to the LLM.
128
+
129
+ ```python
130
+ from pydantic import Field
131
+ from pyagentkit.definitions import AgentDependencies, ToolResult, ToolReturnValue
132
+
133
+
134
+ class MyDeps(AgentDependencies):
135
+ db_url: str = Field(description="Database connection URL")
136
+ api_key: str = Field(description="External API key")
137
+
138
+
139
+ def fetch_user(deps: MyDeps, user_id: str) -> ToolResult:
140
+ """Fetch a user record from the database by user ID."""
141
+ # deps.db_url and deps.api_key are available here
142
+ # but `deps` is hidden from the LLM's tool signature
143
+ result = f"User {user_id} from {deps.db_url}"
144
+ return ToolResult(return_value=ToolReturnValue.success, content=result)
145
+
146
+
147
+ deps = MyDeps(prompt="Find user 42", db_url="postgresql://...", api_key="sk-...")
148
+
149
+ agent = Agent(llm_name="llama3.2", tools=[fetch_user])
150
+ response = agent.handle_response("Find user 42", deps=deps)
151
+ ```
152
+
153
+ The `deps` first parameter is detected automatically by inspecting whether the first parameter is a subclass of `AgentDependencies`. It is stripped from the tool signature shown to the LLM.
154
+
155
+ ---
156
+
157
+ ## 5. Custom Response Models
158
+
159
+ Extend `AgentResponse` to add typed fields that the agent must populate on every response.
160
+
161
+ ```python
162
+ from pydantic import Field
163
+ from pyagentkit.definitions import AgentResponse
164
+
165
+
166
+ class SentimentResponse(AgentResponse):
167
+ sentiment: str = Field(description="positive, negative, or neutral")
168
+ confidence: float = Field(description="Confidence score between 0 and 1")
169
+
170
+
171
+ agent = Agent(
172
+ llm_name="llama3.2",
173
+ response_model=SentimentResponse,
174
+ system_prompt="You are a sentiment analysis assistant.",
175
+ )
176
+
177
+ response = agent.handle_response("I love this product!")
178
+ print(response.sentiment) # "positive"
179
+ print(response.confidence) # 0.95
180
+ ```
181
+
182
+ The schema examples injected into the system prompt are generated automatically from the model's field annotations, so the LLM always sees the correct shape.
183
+
184
+ ---
185
+
186
+ ## 6. Async Agent
187
+
188
+ Use `AsyncAgent` in `asyncio` contexts. The API mirrors `Agent` except all relevant methods are coroutines and the client is `ollama.AsyncClient`.
189
+
190
+ ```python
191
+ import asyncio
192
+ from pyagentkit import AsyncAgent
193
+ from pyagentkit.definitions import ToolResult, ToolReturnValue
194
+
195
+
196
+ async def get_weather(city: str) -> ToolResult:
197
+ """Return current weather for a given city name."""
198
+ # ... call a weather API ...
199
+ return ToolResult(return_value=ToolReturnValue.success, content=f"Sunny in {city}")
200
+
201
+
202
+ async def main():
203
+ agent = await AsyncAgent.create(
204
+ llm_name="llama3.2",
205
+ tools=[get_weather],
206
+ agent_name="weather-agent",
207
+ )
208
+ response = await agent.handle_response("What is the weather in Istanbul?")
209
+ print(response.message)
210
+ agent.dispose()
211
+
212
+
213
+ asyncio.run(main())
214
+ ```
215
+
216
+ > **Important:** Use `await AsyncAgent.create(...)` instead of `AsyncAgent(...)` directly. The constructor is synchronous but environment verification (`_verify_ollama_environment`) is async and must be awaited via `create`.
217
+
218
+ ---
219
+
220
+ ## 7. Lifecycle Hooks
221
+
222
+ Hooks let you observe and log what the agent is doing without modifying its core logic.
223
+
224
+ ```python
225
+ from pyagentkit.definitions import AgentResponse
226
+
227
+
228
+ def on_tool_call(tool_name: str, params: dict) -> None:
229
+ print(f"[CALL] {tool_name} | params={params}")
230
+
231
+
232
+ def on_tool_retry(tool_name: str, params: dict, error: str) -> None:
233
+ print(f"[RETRY] {tool_name} | error={error}")
234
+
235
+
236
+ def on_tool_success(tool_name: str, params: dict) -> None:
237
+ print(f"[SUCCESS] {tool_name}")
238
+
239
+
240
+ def on_response(response: AgentResponse) -> None:
241
+ print(f"[FINAL] {response.message}")
242
+
243
+
244
+ def on_response_retry(attempt: int, response_str: str, error: str) -> None:
245
+ print(f"[RESP RETRY] attempt={attempt} | error={error}")
246
+
247
+
248
+ agent = Agent(
249
+ llm_name="llama3.2",
250
+ on_tool_call=on_tool_call,
251
+ on_tool_retry=on_tool_retry,
252
+ on_tool_success=on_tool_success,
253
+ on_response=on_response,
254
+ on_response_retry=on_response_retry,
255
+ )
256
+ ```
257
+
258
+ ---
259
+
260
+ ## 8. Agent Composition
261
+
262
+ Any agent can expose itself as a tool for another agent via `.as_tool()`.
263
+
264
+ ```python
265
+ from pyagentkit import Agent
266
+ from pyagentkit.definitions import ToolResult, ToolReturnValue
267
+
268
+
269
+ # Inner specialist agent
270
+ researcher = Agent(
271
+ llm_name="llama3.2",
272
+ agent_name="researcher",
273
+ system_prompt="You are a research specialist. Answer factual questions concisely.",
274
+ )
275
+
276
+ # Outer orchestrator agent
277
+ orchestrator = Agent(
278
+ llm_name="llama3.2",
279
+ agent_name="orchestrator",
280
+ system_prompt="You are an orchestrator. Delegate research tasks to the researcher agent.",
281
+ tools=[researcher.as_tool(description="Ask the researcher agent a factual question.")],
282
+ )
283
+
284
+ response = orchestrator.handle_response("What is the capital of Japan?")
285
+ print(response.message)
286
+ ```
287
+
288
+ `.as_tool()` wraps `handle_response` in a `ToolResult`-returning function and names it after the agent, so the outer agent can discover and call it like any other tool.
289
+
290
+ ---
291
+
292
+ ## 9. Message History
293
+
294
+ History is maintained automatically within a session. Each call to `handle_response` appends to the same history, giving the agent memory of prior turns.
295
+
296
+ ```python
297
+ agent = Agent(llm_name="llama3.2", agent_name="chat-agent")
298
+
299
+ r1 = agent.handle_response("My name is Alice.")
300
+ r2 = agent.handle_response("What is my name?")
301
+ print(r2.message) # "Your name is Alice."
302
+ ```
303
+
304
+ ### Trimming history
305
+
306
+ Set `max_history` to limit how many non-system messages the agent sees. Older messages are dropped automatically. Orphaned assistant messages (those without a preceding user message after trimming) are also removed.
307
+
308
+ ```python
309
+ agent = Agent(llm_name="llama3.2", max_history=20)
310
+ ```
311
+
312
+ ### Saving and loading history
313
+
314
+ ```python
315
+ agent.save_history("history.json")
316
+
317
+ # Later, in a new session:
318
+ agent.load_history("history.json")
319
+ ```
320
+
321
+ ### Clearing history
322
+
323
+ ```python
324
+ agent.clear_history()
325
+ ```
326
+
327
+ ---
328
+
329
+ ## 10. Token Usage
330
+
331
+ `agent.token_usage` is a `TokenUsage` object that accumulates across all `handle_response` calls on an instance.
332
+
333
+ ```python
334
+ response = agent.handle_response("Summarize the water cycle.")
335
+ print(agent.token_usage.prompt_tokens)
336
+ print(agent.token_usage.response_tokens)
337
+ print(agent.token_usage.total_tokens)
338
+ ```
339
+
340
+ ---
341
+
342
+ ## 11. Error Handling
343
+
344
+ ```python
345
+ from pyagentkit.exceptions import (
346
+ ExceptionToolRetriesExhausted,
347
+ ExceptionResponseRetriesExhausted,
348
+ ExceptionFatalError,
349
+ ExceptionEnvironmentError,
350
+ ExceptionUnhandledError,
351
+ )
352
+
353
+ try:
354
+ response = agent.handle_response("Do something complex.")
355
+ except ExceptionEnvironmentError as e:
356
+ print(f"Ollama not reachable or model missing: {e.message}")
357
+ except ExceptionToolRetriesExhausted as e:
358
+ print(f"Tool retries exhausted after {e.retries} attempts")
359
+ except ExceptionResponseRetriesExhausted as e:
360
+ print(f"Response retries exhausted after {e.retries} attempts")
361
+ except ExceptionFatalError as e:
362
+ print(f"Fatal error, cannot recover: {e.message}")
363
+ except ExceptionUnhandledError as e:
364
+ print(f"Unexpected error: {e}")
365
+ ```
366
+
367
+ Inside a tool, signal errors to the agent using return values rather than raising exceptions directly:
368
+
369
+ ```python
370
+ def risky_tool(path: str) -> ToolResult:
371
+ """Read a file from the given path."""
372
+ try:
373
+ with open(path) as f:
374
+ return ToolResult(return_value=ToolReturnValue.success, content=f.read())
375
+ except FileNotFoundError:
376
+ # Recoverable — agent will retry with corrected params
377
+ return ToolResult(return_value=ToolReturnValue.error, content=f"File not found: {path}")
378
+ except PermissionError:
379
+ # Irrecoverable — raises ExceptionFatalError immediately
380
+ return ToolResult(return_value=ToolReturnValue.fatal, content=f"Permission denied: {path}")
381
+ ```
382
+
383
+ ---
384
+
385
+ ## 12. Configuration Reference
386
+
387
+ | Parameter | Type | Default | Description |
388
+ |-----------|------|---------|-------------|
389
+ | `llm_name` | `str` | required | Ollama model name (e.g. `"llama3.2"`) |
390
+ | `agent_name` | `str \| None` | `llm_name` | Unique name for this agent instance |
391
+ | `system_prompt` | `str \| None` | `""` | Base system prompt prepended to all requests |
392
+ | `instructions` | `str \| None` | `""` | Text appended to every user prompt |
393
+ | `response_model` | `Type[AgentResponse]` | `AgentResponse` | Pydantic model for response validation |
394
+ | `tool_retries` | `int` | `3` | Max tool call retries before raising |
395
+ | `response_retries` | `int` | `3` | Max response validation retries before raising |
396
+ | `num_ctx` | `int` | `8192` | Ollama context window size |
397
+ | `temperature` | `float \| None` | `None` | Sampling temperature |
398
+ | `top_p` | `float \| None` | `None` | Nucleus sampling probability |
399
+ | `seed` | `int \| None` | `None` | Random seed for reproducibility |
400
+ | `ollama_url` | `str \| None` | `None` | Custom Ollama host URL; uses default if `None` |
401
+ | `tools` | `list \| None` | `None` | Tool functions to register on init |
402
+ | `max_history` | `int \| None` | `None` | Max non-system messages to retain |
403
+ | `log_level` | `int` | `logging.INFO` | Python logging level |
404
+ | `think` | `bool` | `False` | Enable chain-of-thought on supported models |
405
+ | `on_tool_call` | callable | `None` | Hook called before each tool execution |
406
+ | `on_tool_retry` | callable | `None` | Hook called on tool error/retry |
407
+ | `on_tool_success` | callable | `None` | Hook called on tool success |
408
+ | `on_response` | callable | `None` | Hook called on final response |
409
+ | `on_response_retry` | callable | `None` | Hook called on response validation failure |
410
+
411
+ ### Agent lifecycle
412
+
413
+ ```python
414
+ agent = Agent(llm_name="llama3.2", agent_name="my-agent")
415
+
416
+ # Use the agent ...
417
+
418
+ # When done, unregister and clean up the logger:
419
+ agent.dispose()
420
+ ```
421
+
422
+ Each agent name must be unique within the `Agent` or `AsyncAgent` registry. Calling `dispose()` frees the name so it can be reused.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pyagentkit"
3
- version = "0.1.4"
3
+ version = "0.1.6"
4
4
  description = "Agent toolkit for Ollama"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -0,0 +1,40 @@
1
+ from .agent import Agent
2
+ from .async_agent import AsyncAgent
3
+ from .definitions import (
4
+ ToolResult,
5
+ AgentResponse,
6
+ AgentDependencies,
7
+ ToolReturnValue,
8
+ TokenUsage,
9
+ )
10
+ from .exceptions import (
11
+ ExceptionAgentError,
12
+ ExceptionAgentFatal,
13
+ ExceptionToolError,
14
+ ExceptionToolFatal,
15
+ ExceptionFatalError,
16
+ ExceptionEnvironmentError,
17
+ ExceptionToolRetriesExhausted,
18
+ ExceptionResponseRetriesExhausted,
19
+ )
20
+
21
+ __all__ = [
22
+ # Agents
23
+ "Agent",
24
+ "AsyncAgent",
25
+ # Definitions
26
+ "ToolResult",
27
+ "AgentResponse",
28
+ "AgentDependencies",
29
+ "ToolReturnValue",
30
+ "TokenUsage",
31
+ # Exceptions
32
+ "ExceptionAgentError",
33
+ "ExceptionAgentFatal",
34
+ "ExceptionToolError",
35
+ "ExceptionToolFatal",
36
+ "ExceptionFatalError",
37
+ "ExceptionEnvironmentError",
38
+ "ExceptionToolRetriesExhausted",
39
+ "ExceptionResponseRetriesExhausted",
40
+ ]