pyagentic-core 2.1.0__tar.gz → 2.1.0a2__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.
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/PKG-INFO +1 -1
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_base/_agent/_agent.py +58 -92
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic_core.egg-info/PKG-INFO +1 -1
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyproject.toml +1 -1
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/LICENSE +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/README.md +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/__init__.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_base/__init__.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_base/_agent/__init__.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_base/_agent/_agent_linking.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_base/_agent/_agent_state.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_base/_exceptions.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_base/_info.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_base/_metaclasses.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_base/_ref.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_base/_spec.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_base/_state.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_base/_tool.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_base/_validation.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_utils/_typing.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/_utils/_warnings.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/llm/__init__.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/llm/_anthropic.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/llm/_gemini.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/llm/_mock.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/llm/_openai.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/llm/_openaiv1.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/llm/_provider.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/logging.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/models/llm.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/models/response.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/models/tracing.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/policies/__init__.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/policies/_events.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/policies/_policy.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/tracing/__init__.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/tracing/_basic.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/tracing/_langfuse.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/tracing/_tracer.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic/updates.py +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic_core.egg-info/SOURCES.txt +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic_core.egg-info/dependency_links.txt +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic_core.egg-info/requires.txt +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic_core.egg-info/top_level.txt +0 -0
- {pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/setup.cfg +0 -0
|
@@ -126,6 +126,8 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
126
126
|
api_key (str, optional): API key matching the model provider
|
|
127
127
|
provider (LLMProvider, optional): Pre-configured provider instance. Overrides
|
|
128
128
|
`model` and `api_key` if provided.
|
|
129
|
+
emitter (Callable, optional): Callback function to receive real-time updates
|
|
130
|
+
about the agent's execution (useful for WebSocket streaming)
|
|
129
131
|
tracer (AgentTracer, optional): Tracer instance for observability. Defaults
|
|
130
132
|
to BasicTracer if not provided.
|
|
131
133
|
max_call_depth (int): Maximum number of tool calling loops per run. Defaults to 1.
|
|
@@ -175,6 +177,7 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
175
177
|
model: str = None
|
|
176
178
|
api_key: str = None
|
|
177
179
|
provider: LLMProvider = None
|
|
180
|
+
emitter: Callable[[Any], str] = None
|
|
178
181
|
tracer: AgentTracer = None
|
|
179
182
|
max_call_depth: int = 1
|
|
180
183
|
|
|
@@ -311,6 +314,8 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
311
314
|
except Exception as e:
|
|
312
315
|
# Handle inference errors gracefully
|
|
313
316
|
logger.exception(e)
|
|
317
|
+
if self.emitter:
|
|
318
|
+
await _safe_run(self.emitter, EmitUpdate(status=Status.ERROR))
|
|
314
319
|
# Add error message to conversation history
|
|
315
320
|
self.state._messages.append(
|
|
316
321
|
Message(role="assistant", content="Failed to generate a response")
|
|
@@ -397,15 +402,37 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
397
402
|
# Handle validation errors for tool arguments
|
|
398
403
|
result = f"Function Args were invalid: {str(e)}"
|
|
399
404
|
compiled_args = {}
|
|
400
|
-
self.
|
|
401
|
-
|
|
405
|
+
if self.emitter:
|
|
406
|
+
self.tracer.record_exception(str(e))
|
|
407
|
+
logger.exception(e)
|
|
408
|
+
if self.emitter:
|
|
409
|
+
await _safe_run(
|
|
410
|
+
self.emitter,
|
|
411
|
+
ToolUpdate(
|
|
412
|
+
status=Status.ERROR, tool_call=tool_call.name, tool_args=kwargs
|
|
413
|
+
),
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
# Execute the tool, emitting status updates
|
|
402
417
|
try:
|
|
418
|
+
if self.emitter:
|
|
419
|
+
await _safe_run(
|
|
420
|
+
self.emitter,
|
|
421
|
+
ToolUpdate(
|
|
422
|
+
status=Status.PROCESSING, tool_call=tool_call.name, tool_args=kwargs
|
|
423
|
+
),
|
|
424
|
+
)
|
|
403
425
|
if compiled_args:
|
|
404
426
|
result = await _safe_run(handler, **compiled_args)
|
|
405
427
|
self.tracer.set_attributes(result=result)
|
|
406
428
|
except TypeError as e:
|
|
407
429
|
self.tracer.record_exception(str(e))
|
|
408
430
|
logger.exception(e)
|
|
431
|
+
if self.emitter:
|
|
432
|
+
await _safe_run(
|
|
433
|
+
self.emitter,
|
|
434
|
+
ToolUpdate(status=Status.ERROR, tool_call=tool_call.name, tool_args=kwargs),
|
|
435
|
+
)
|
|
409
436
|
raise InvalidToolDefinition(
|
|
410
437
|
tool_name=tool_call.name,
|
|
411
438
|
message=f"Tool must have a serializable return type; {tool_def.return_type} failed to be casted to a string.",
|
|
@@ -415,6 +442,11 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
415
442
|
self.tracer.record_exception(str(e))
|
|
416
443
|
logger.exception(e)
|
|
417
444
|
result = f"Tool `{tool_call.name}` failed: {e}. Please kindly state to the user that is failed, provide state, and ask if they want to try again." # noqa E501
|
|
445
|
+
if self.emitter:
|
|
446
|
+
await _safe_run(
|
|
447
|
+
self.emitter,
|
|
448
|
+
ToolUpdate(status=Status.ERROR, tool_call=tool_call.name, tool_args=kwargs),
|
|
449
|
+
)
|
|
418
450
|
|
|
419
451
|
stringified_result = (
|
|
420
452
|
result.model_dump_json(indent=2)
|
|
@@ -460,12 +492,10 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
460
492
|
self, input_: str
|
|
461
493
|
) -> AsyncGenerator[Union[ToolResponse, AgentResponse, LLMResponse]]:
|
|
462
494
|
"""
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
complete result.
|
|
495
|
+
Main execution loop for the agent. Processes user input through multiple rounds
|
|
496
|
+
of LLM inference and tool/agent calls until completion or max_call_depth reached.
|
|
466
497
|
|
|
467
|
-
|
|
468
|
-
control over agent execution. The agent follows an agentic loop pattern:
|
|
498
|
+
The agent follows an agentic loop pattern:
|
|
469
499
|
1. Send user input and conversation history to the LLM
|
|
470
500
|
2. LLM decides to either call tools or respond with final output
|
|
471
501
|
3. If tools are called, execute them and feed results back to LLM
|
|
@@ -474,23 +504,19 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
474
504
|
Args:
|
|
475
505
|
input_ (str): The user input/query for the agent to process
|
|
476
506
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
-
|
|
480
|
-
-
|
|
481
|
-
-
|
|
507
|
+
Returns:
|
|
508
|
+
AgentResponse: Structured response containing:
|
|
509
|
+
- final_output: The final text or structured output from the LLM
|
|
510
|
+
- state: Current agent state after execution
|
|
511
|
+
- tool_responses: List of all tool calls and their outputs
|
|
512
|
+
- provider_info: Information about the LLM provider used
|
|
482
513
|
|
|
483
514
|
Example:
|
|
484
515
|
```python
|
|
485
516
|
agent = MyAgent(model="openai::gpt-4o", api_key=API_KEY)
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
print(f"LLM thinking: {response.text}")
|
|
490
|
-
elif isinstance(response, ToolResponse):
|
|
491
|
-
print(f"Tool executed: {response.output}")
|
|
492
|
-
elif isinstance(response, AgentResponse):
|
|
493
|
-
print(f"Final: {response.final_output}")
|
|
517
|
+
response = await agent.run("What's the weather in San Francisco?")
|
|
518
|
+
print(response.final_output) # LLM's final answer
|
|
519
|
+
print(response.tool_responses) # Tools that were called
|
|
494
520
|
```
|
|
495
521
|
"""
|
|
496
522
|
async with self.tracer.agent(
|
|
@@ -512,6 +538,10 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
512
538
|
agent_responses: list = []
|
|
513
539
|
processed_call_ids: set[str] = set()
|
|
514
540
|
|
|
541
|
+
# Emit initial status
|
|
542
|
+
if self.emitter:
|
|
543
|
+
await _safe_run(self.emitter, EmitUpdate(status=Status.GENERATING))
|
|
544
|
+
|
|
515
545
|
# Main agentic loop: LLM -> Tools -> LLM -> ...
|
|
516
546
|
depth = 0
|
|
517
547
|
final_ai_output: str | None = None
|
|
@@ -554,6 +584,12 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
554
584
|
response = await self._process_llm_inference()
|
|
555
585
|
final_ai_output = response.parsed if response.parsed else response.text
|
|
556
586
|
|
|
587
|
+
# Emit final success status
|
|
588
|
+
if self.emitter:
|
|
589
|
+
await _safe_run(
|
|
590
|
+
self.emitter, AiUpdate(status=Status.SUCCEDED, message=final_ai_output)
|
|
591
|
+
)
|
|
592
|
+
|
|
557
593
|
# Build the structured response
|
|
558
594
|
response_fields = {
|
|
559
595
|
"final_output": final_ai_output,
|
|
@@ -571,32 +607,6 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
571
607
|
yield response
|
|
572
608
|
|
|
573
609
|
async def run(self, input_: str) -> AgentResponse:
|
|
574
|
-
"""
|
|
575
|
-
Executes the agent with a message string and returns the final result.
|
|
576
|
-
|
|
577
|
-
This method consumes the entire step() generator and returns only the final
|
|
578
|
-
AgentResponse. Use this when you don't need intermediate streaming responses
|
|
579
|
-
and just want the final output.
|
|
580
|
-
|
|
581
|
-
Args:
|
|
582
|
-
input_ (str): The user input/query for the agent to process
|
|
583
|
-
|
|
584
|
-
Returns:
|
|
585
|
-
AgentResponse: Structured response containing:
|
|
586
|
-
- final_output: The final text or structured output from the LLM
|
|
587
|
-
- state: Current agent state after execution
|
|
588
|
-
- tool_responses: List of all tool calls and their outputs
|
|
589
|
-
- agent_responses: List of linked agent calls (if any)
|
|
590
|
-
- provider_info: Information about the LLM provider used
|
|
591
|
-
|
|
592
|
-
Example:
|
|
593
|
-
```python
|
|
594
|
-
agent = MyAgent(model="openai::gpt-4o", api_key=API_KEY)
|
|
595
|
-
response = await agent.run("What's the weather in San Francisco?")
|
|
596
|
-
print(response.final_output) # LLM's final answer
|
|
597
|
-
print(response.tool_responses) # Tools that were called
|
|
598
|
-
```
|
|
599
|
-
"""
|
|
600
610
|
final_response = None
|
|
601
611
|
async for res in self.step(input_):
|
|
602
612
|
final_response = res
|
|
@@ -604,57 +614,13 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
604
614
|
|
|
605
615
|
async def __call__(self, user_input: str) -> BaseModel:
|
|
606
616
|
"""
|
|
607
|
-
|
|
608
|
-
structured, typed parameters that match your agent's purpose.
|
|
609
|
-
|
|
610
|
-
When this agent is linked to another agent, the parameters of this method become
|
|
611
|
-
the tool parameters that the LLM sees. This enables type-safe, structured agent
|
|
612
|
-
composition in multi-agent systems.
|
|
613
|
-
|
|
614
|
-
The default implementation accepts a single user_input string and forwards it to
|
|
615
|
-
run(). Override to provide a custom interface:
|
|
617
|
+
Allows the agent to be called directly as a function.
|
|
616
618
|
|
|
617
619
|
Args:
|
|
618
|
-
user_input (str): The user input to process
|
|
620
|
+
user_input (str): The user input to process
|
|
619
621
|
|
|
620
622
|
Returns:
|
|
621
623
|
AgentResponse: The agent's response
|
|
622
|
-
|
|
623
|
-
Example (Default Usage):
|
|
624
|
-
```python
|
|
625
|
-
agent = MyAgent(model="openai::gpt-4o", api_key=API_KEY)
|
|
626
|
-
response = await agent("What's the weather?")
|
|
627
|
-
```
|
|
628
|
-
|
|
629
|
-
Example (Custom Implementation):
|
|
630
|
-
```python
|
|
631
|
-
class CoursePlannerAgent(BaseAgent):
|
|
632
|
-
__system_message__ = "You design course curricula"
|
|
633
|
-
__description__ = "Creates structured course plans"
|
|
634
|
-
|
|
635
|
-
async def __call__(
|
|
636
|
-
self,
|
|
637
|
-
goal: str,
|
|
638
|
-
experience: str,
|
|
639
|
-
context: Optional[str] = None
|
|
640
|
-
) -> CoursePlan:
|
|
641
|
-
# Build structured prompt from parameters
|
|
642
|
-
prompt = f"Goal: {goal}\\nExperience: {experience}"
|
|
643
|
-
if context:
|
|
644
|
-
prompt += f"\\nContext: {context}"
|
|
645
|
-
return await self.run(prompt)
|
|
646
|
-
|
|
647
|
-
# Call with structured parameters
|
|
648
|
-
planner = CoursePlannerAgent(model="openai::gpt-4o", api_key=API_KEY)
|
|
649
|
-
course = await planner(
|
|
650
|
-
goal="Learn ML",
|
|
651
|
-
experience="Python beginner",
|
|
652
|
-
context="Prefer hands-on projects"
|
|
653
|
-
)
|
|
654
|
-
|
|
655
|
-
# When linked to another agent, the LLM sees:
|
|
656
|
-
# Tool: planner(goal: str, experience: str, context: Optional[str])
|
|
657
|
-
```
|
|
658
624
|
"""
|
|
659
625
|
return await self.run(input_=user_input)
|
|
660
626
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyagentic_core-2.1.0 → pyagentic_core-2.1.0a2}/pyagentic_core.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|