agnt5 0.2.4__cp39-abi3-macosx_11_0_arm64.whl → 0.2.5__cp39-abi3-macosx_11_0_arm64.whl
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.
Potentially problematic release.
This version of agnt5 might be problematic. Click here for more details.
- agnt5/__init__.py +2 -1
- agnt5/_core.abi3.so +0 -0
- agnt5/agent.py +15 -11
- agnt5/lm.py +39 -11
- agnt5/workflow.py +118 -0
- {agnt5-0.2.4.dist-info → agnt5-0.2.5.dist-info}/METADATA +1 -1
- {agnt5-0.2.4.dist-info → agnt5-0.2.5.dist-info}/RECORD +8 -8
- {agnt5-0.2.4.dist-info → agnt5-0.2.5.dist-info}/WHEEL +0 -0
agnt5/__init__.py
CHANGED
|
@@ -32,7 +32,7 @@ from .tool import Tool, ToolRegistry, tool
|
|
|
32
32
|
from .types import BackoffPolicy, BackoffType, FunctionConfig, RetryPolicy, WorkflowConfig
|
|
33
33
|
from .version import _get_version
|
|
34
34
|
from .worker import Worker
|
|
35
|
-
from .workflow import WorkflowRegistry, workflow
|
|
35
|
+
from .workflow import WorkflowRegistry, chatflow, workflow
|
|
36
36
|
|
|
37
37
|
# Expose simplified language model API (recommended)
|
|
38
38
|
from . import lm
|
|
@@ -57,6 +57,7 @@ __all__ = [
|
|
|
57
57
|
"with_entity_context",
|
|
58
58
|
"create_entity_context",
|
|
59
59
|
"workflow",
|
|
60
|
+
"chatflow",
|
|
60
61
|
"WorkflowRegistry",
|
|
61
62
|
"tool",
|
|
62
63
|
"Tool",
|
agnt5/_core.abi3.so
CHANGED
|
Binary file
|
agnt5/agent.py
CHANGED
|
@@ -377,13 +377,16 @@ class Agent:
|
|
|
377
377
|
if handoff_config.pass_full_history:
|
|
378
378
|
# Get current conversation from the agent's run loop
|
|
379
379
|
# (This will be set when we detect the handoff in run())
|
|
380
|
-
conversation_history = ctx.get("_current_conversation", [])
|
|
380
|
+
conversation_history = getattr(ctx, '_agent_data', {}).get("_current_conversation", [])
|
|
381
|
+
|
|
381
382
|
if conversation_history:
|
|
382
383
|
ctx.logger.info(
|
|
383
384
|
f"Passing {len(conversation_history)} messages to target agent"
|
|
384
385
|
)
|
|
385
386
|
# Store in context for target agent to optionally use
|
|
386
|
-
ctx
|
|
387
|
+
if not hasattr(ctx, '_agent_data'):
|
|
388
|
+
ctx._agent_data = {}
|
|
389
|
+
ctx._agent_data["_handoff_conversation_history"] = conversation_history
|
|
387
390
|
|
|
388
391
|
# Execute target agent with the message and shared context
|
|
389
392
|
result = await target_agent.run(message, context=ctx)
|
|
@@ -398,7 +401,9 @@ class Agent:
|
|
|
398
401
|
"tool_calls": result.tool_calls,
|
|
399
402
|
}
|
|
400
403
|
|
|
401
|
-
ctx
|
|
404
|
+
if not hasattr(ctx, '_agent_data'):
|
|
405
|
+
ctx._agent_data = {}
|
|
406
|
+
ctx._agent_data["_handoff_result"] = handoff_data
|
|
402
407
|
|
|
403
408
|
# Return the handoff data (will be detected in run() loop)
|
|
404
409
|
return handoff_data
|
|
@@ -449,7 +454,6 @@ class Agent:
|
|
|
449
454
|
|
|
450
455
|
context = Context(
|
|
451
456
|
run_id=f"agent-{self.name}-{uuid.uuid4().hex[:8]}",
|
|
452
|
-
component_type="agent",
|
|
453
457
|
)
|
|
454
458
|
|
|
455
459
|
# Create span for agent execution with trace linking
|
|
@@ -471,8 +475,6 @@ class Agent:
|
|
|
471
475
|
|
|
472
476
|
# Reasoning loop
|
|
473
477
|
for iteration in range(self.max_iterations):
|
|
474
|
-
self.logger.info(f"Agent iteration {iteration + 1}/{self.max_iterations}")
|
|
475
|
-
|
|
476
478
|
# Build tool definitions for LLM
|
|
477
479
|
tool_defs = [
|
|
478
480
|
ToolDefinition(
|
|
@@ -517,10 +519,13 @@ class Agent:
|
|
|
517
519
|
|
|
518
520
|
# Check if LLM wants to use tools
|
|
519
521
|
if response.tool_calls:
|
|
520
|
-
self.logger.
|
|
522
|
+
self.logger.debug(f"Agent calling {len(response.tool_calls)} tool(s)")
|
|
521
523
|
|
|
522
524
|
# Store current conversation in context for potential handoffs
|
|
523
|
-
|
|
525
|
+
# Use a simple dict attribute since we don't need full state persistence for this
|
|
526
|
+
if not hasattr(context, '_agent_data'):
|
|
527
|
+
context._agent_data = {}
|
|
528
|
+
context._agent_data["_current_conversation"] = messages
|
|
524
529
|
|
|
525
530
|
# Execute tool calls
|
|
526
531
|
tool_results = []
|
|
@@ -586,13 +591,13 @@ class Agent:
|
|
|
586
591
|
for tr in tool_results
|
|
587
592
|
]
|
|
588
593
|
)
|
|
589
|
-
messages.append(Message.user(f"Tool results:\n{results_text}"))
|
|
594
|
+
messages.append(Message.user(f"Tool results:\n{results_text}\n\nPlease provide your final answer based on these results."))
|
|
590
595
|
|
|
591
596
|
# Continue loop for agent to process results
|
|
592
597
|
|
|
593
598
|
else:
|
|
594
599
|
# No tool calls - agent is done
|
|
595
|
-
self.logger.
|
|
600
|
+
self.logger.debug(f"Agent completed after {iteration + 1} iterations")
|
|
596
601
|
return AgentResult(
|
|
597
602
|
output=response.text,
|
|
598
603
|
tool_calls=all_tool_calls,
|
|
@@ -636,7 +641,6 @@ class Agent:
|
|
|
636
641
|
|
|
637
642
|
context = Context(
|
|
638
643
|
run_id=f"agent-chat-{self.name}-{uuid.uuid4().hex[:8]}",
|
|
639
|
-
component_type="agent",
|
|
640
644
|
)
|
|
641
645
|
|
|
642
646
|
# Add user message
|
agnt5/lm.py
CHANGED
|
@@ -312,11 +312,23 @@ class _LanguageModel:
|
|
|
312
312
|
if request.response_schema is not None:
|
|
313
313
|
kwargs["response_schema_kw"] = request.response_schema
|
|
314
314
|
|
|
315
|
-
#
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
315
|
+
# Pass tools and tool_choice to Rust
|
|
316
|
+
if request.tools:
|
|
317
|
+
# Serialize tools to JSON for Rust
|
|
318
|
+
tools_list = [
|
|
319
|
+
{
|
|
320
|
+
"name": tool.name,
|
|
321
|
+
"description": tool.description,
|
|
322
|
+
"parameters": tool.parameters,
|
|
323
|
+
}
|
|
324
|
+
for tool in request.tools
|
|
325
|
+
]
|
|
326
|
+
tools_json = json.dumps(tools_list)
|
|
327
|
+
kwargs["tools"] = tools_json
|
|
328
|
+
|
|
329
|
+
if request.tool_choice:
|
|
330
|
+
# Serialize tool_choice to JSON for Rust
|
|
331
|
+
kwargs["tool_choice"] = json.dumps(request.tool_choice.value)
|
|
320
332
|
|
|
321
333
|
# Call Rust implementation - it returns a proper Python coroutine now
|
|
322
334
|
# Using pyo3-async-runtimes for truly async HTTP calls without blocking
|
|
@@ -362,11 +374,22 @@ class _LanguageModel:
|
|
|
362
374
|
if request.config.top_p is not None:
|
|
363
375
|
kwargs["top_p"] = request.config.top_p
|
|
364
376
|
|
|
365
|
-
#
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
377
|
+
# Pass tools and tool_choice to Rust
|
|
378
|
+
if request.tools:
|
|
379
|
+
# Serialize tools to JSON for Rust
|
|
380
|
+
tools_list = [
|
|
381
|
+
{
|
|
382
|
+
"name": tool.name,
|
|
383
|
+
"description": tool.description,
|
|
384
|
+
"parameters": tool.parameters,
|
|
385
|
+
}
|
|
386
|
+
for tool in request.tools
|
|
387
|
+
]
|
|
388
|
+
kwargs["tools"] = json.dumps(tools_list)
|
|
389
|
+
|
|
390
|
+
if request.tool_choice:
|
|
391
|
+
# Serialize tool_choice to JSON for Rust
|
|
392
|
+
kwargs["tool_choice"] = json.dumps(request.tool_choice.value)
|
|
370
393
|
|
|
371
394
|
# Call Rust implementation - it returns a proper Python coroutine now
|
|
372
395
|
# Using pyo3-async-runtimes for truly async streaming without blocking
|
|
@@ -416,11 +439,16 @@ class _LanguageModel:
|
|
|
416
439
|
total_tokens=rust_response.usage.total_tokens,
|
|
417
440
|
)
|
|
418
441
|
|
|
442
|
+
# Extract tool_calls from Rust response
|
|
443
|
+
tool_calls = None
|
|
444
|
+
if hasattr(rust_response, 'tool_calls') and rust_response.tool_calls:
|
|
445
|
+
tool_calls = rust_response.tool_calls
|
|
446
|
+
|
|
419
447
|
return GenerateResponse(
|
|
420
448
|
text=rust_response.content,
|
|
421
449
|
usage=usage,
|
|
422
450
|
finish_reason=None, # TODO: Add finish_reason to Rust response
|
|
423
|
-
tool_calls=
|
|
451
|
+
tool_calls=tool_calls,
|
|
424
452
|
_rust_response=rust_response, # Store for .structured_output access
|
|
425
453
|
)
|
|
426
454
|
|
agnt5/workflow.py
CHANGED
|
@@ -565,3 +565,121 @@ def workflow(
|
|
|
565
565
|
return decorator
|
|
566
566
|
else:
|
|
567
567
|
return decorator(_func)
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
def chatflow(
|
|
571
|
+
_func: Optional[Callable[..., Any]] = None,
|
|
572
|
+
*,
|
|
573
|
+
name: Optional[str] = None,
|
|
574
|
+
) -> Callable[..., Any]:
|
|
575
|
+
"""
|
|
576
|
+
Decorator to mark a function as an AGNT5 chat-enabled workflow.
|
|
577
|
+
|
|
578
|
+
Identical to @workflow but adds metadata {"chat": "true"} to indicate
|
|
579
|
+
this workflow is designed for multi-turn conversation scenarios.
|
|
580
|
+
|
|
581
|
+
The platform can use this metadata to:
|
|
582
|
+
- Enable session affinity and sticky routing
|
|
583
|
+
- Apply conversation-specific optimizations
|
|
584
|
+
- Track chat-specific metrics (turn count, conversation length)
|
|
585
|
+
|
|
586
|
+
Args:
|
|
587
|
+
name: Custom workflow name (default: function's __name__)
|
|
588
|
+
|
|
589
|
+
Example:
|
|
590
|
+
@chatflow
|
|
591
|
+
async def customer_support_chat(ctx: WorkflowContext, message: str) -> dict:
|
|
592
|
+
# Initialize conversation state
|
|
593
|
+
if not ctx.state.get("messages"):
|
|
594
|
+
ctx.state.set("messages", [])
|
|
595
|
+
|
|
596
|
+
# Add user message
|
|
597
|
+
messages = ctx.state.get("messages")
|
|
598
|
+
messages.append({"role": "user", "content": message})
|
|
599
|
+
ctx.state.set("messages", messages)
|
|
600
|
+
|
|
601
|
+
# Generate AI response
|
|
602
|
+
response = await ctx.task(generate_response, messages=messages)
|
|
603
|
+
|
|
604
|
+
# Add assistant response
|
|
605
|
+
messages.append({"role": "assistant", "content": response})
|
|
606
|
+
ctx.state.set("messages", messages)
|
|
607
|
+
|
|
608
|
+
return {"response": response, "turn_count": len(messages) // 2}
|
|
609
|
+
"""
|
|
610
|
+
|
|
611
|
+
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
612
|
+
# Get workflow name
|
|
613
|
+
workflow_name = name or func.__name__
|
|
614
|
+
|
|
615
|
+
# Validate function signature
|
|
616
|
+
sig = inspect.signature(func)
|
|
617
|
+
params = list(sig.parameters.values())
|
|
618
|
+
|
|
619
|
+
if not params or params[0].name != "ctx":
|
|
620
|
+
raise ValueError(
|
|
621
|
+
f"Chatflow '{workflow_name}' must have 'ctx: WorkflowContext' as first parameter"
|
|
622
|
+
)
|
|
623
|
+
|
|
624
|
+
# Convert sync to async if needed
|
|
625
|
+
if inspect.iscoroutinefunction(func):
|
|
626
|
+
handler_func = cast(HandlerFunc, func)
|
|
627
|
+
else:
|
|
628
|
+
# Wrap sync function in async
|
|
629
|
+
@functools.wraps(func)
|
|
630
|
+
async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
631
|
+
return func(*args, **kwargs)
|
|
632
|
+
|
|
633
|
+
handler_func = cast(HandlerFunc, async_wrapper)
|
|
634
|
+
|
|
635
|
+
# Extract schemas from type hints
|
|
636
|
+
input_schema, output_schema = extract_function_schemas(func)
|
|
637
|
+
|
|
638
|
+
# Extract metadata (description, etc.)
|
|
639
|
+
metadata = extract_function_metadata(func)
|
|
640
|
+
|
|
641
|
+
# Add chat metadata - THIS IS THE KEY DIFFERENCE FROM @workflow
|
|
642
|
+
metadata["chat"] = "true"
|
|
643
|
+
|
|
644
|
+
# Register as workflow (chatflows are workflows with chat metadata)
|
|
645
|
+
config = WorkflowConfig(
|
|
646
|
+
name=workflow_name,
|
|
647
|
+
handler=handler_func,
|
|
648
|
+
input_schema=input_schema,
|
|
649
|
+
output_schema=output_schema,
|
|
650
|
+
metadata=metadata,
|
|
651
|
+
)
|
|
652
|
+
WorkflowRegistry.register(config)
|
|
653
|
+
|
|
654
|
+
# Create wrapper that provides context
|
|
655
|
+
@functools.wraps(func)
|
|
656
|
+
async def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
657
|
+
# Create WorkflowEntity and WorkflowContext if not provided
|
|
658
|
+
if not args or not isinstance(args[0], WorkflowContext):
|
|
659
|
+
# Auto-create workflow entity and context for direct chatflow calls
|
|
660
|
+
run_id = f"chatflow-{uuid.uuid4().hex[:8]}"
|
|
661
|
+
|
|
662
|
+
# Create WorkflowEntity to manage state
|
|
663
|
+
workflow_entity = WorkflowEntity(run_id=run_id)
|
|
664
|
+
|
|
665
|
+
# Create WorkflowContext that wraps the entity
|
|
666
|
+
ctx = WorkflowContext(
|
|
667
|
+
workflow_entity=workflow_entity,
|
|
668
|
+
run_id=run_id,
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
# Execute chatflow
|
|
672
|
+
return await handler_func(ctx, *args, **kwargs)
|
|
673
|
+
else:
|
|
674
|
+
# WorkflowContext provided - use it
|
|
675
|
+
return await handler_func(*args, **kwargs)
|
|
676
|
+
|
|
677
|
+
# Store config on wrapper for introspection
|
|
678
|
+
wrapper._agnt5_config = config # type: ignore
|
|
679
|
+
return wrapper
|
|
680
|
+
|
|
681
|
+
# Handle both @chatflow and @chatflow(...) syntax
|
|
682
|
+
if _func is None:
|
|
683
|
+
return decorator
|
|
684
|
+
else:
|
|
685
|
+
return decorator(_func)
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
agnt5-0.2.
|
|
2
|
-
agnt5-0.2.
|
|
3
|
-
agnt5/__init__.py,sha256=
|
|
1
|
+
agnt5-0.2.5.dist-info/METADATA,sha256=zHVYaWjmmQbnDeJvr59rQNan70yGDUzjKg4cyPLfGr8,994
|
|
2
|
+
agnt5-0.2.5.dist-info/WHEEL,sha256=vpqC0tRn_8bTHidvtrPbrnFQPZnrhuKzsjDdeKwCd58,102
|
|
3
|
+
agnt5/__init__.py,sha256=XUixnW140lI-_9h1rLtN4jBWXIDL3EgnM7jmiNzGrYk,2037
|
|
4
4
|
agnt5/_compat.py,sha256=BGuy3v5VDOHVa5f3Z-C22iMN19lAt0mPmXwF3qSSWxI,369
|
|
5
|
-
agnt5/_core.abi3.so,sha256=
|
|
5
|
+
agnt5/_core.abi3.so,sha256=HGQaXAplREgIbUBvtNhmrmHyTkDfh3inERsj90LiSVM,11928992
|
|
6
6
|
agnt5/_retry_utils.py,sha256=loHsWY5BR4wZy57IzcDEjQAy88DHVwVIr25Cn1d9GPA,5801
|
|
7
7
|
agnt5/_schema_utils.py,sha256=MR67RW757T4Oq2Jqf4kB61H_b51zwaf3CLWELnkngRo,9572
|
|
8
8
|
agnt5/_telemetry.py,sha256=bIY9AvBRjJBTHoBPbfR6X1OgaiUf-T0vCoi0_snsWXA,5957
|
|
9
|
-
agnt5/agent.py,sha256=
|
|
9
|
+
agnt5/agent.py,sha256=BAhYHKD5YuZXhNZaqeoN7EXKTtzF8OPhCJhpcWQS1YM,27837
|
|
10
10
|
agnt5/client.py,sha256=kXksazgxdVXWaG9OkjJA4cWruNtcS-ENhtnkrIdw-Nk,23212
|
|
11
11
|
agnt5/context.py,sha256=S2OzPkhn_jnqSWfT21mSYOux8vHaLKQxcAvggZDHQek,2378
|
|
12
12
|
agnt5/entity.py,sha256=dhdxXUxED79u3OlX9yw-2TLCC9VqBcJqES2kx-fDChs,19041
|
|
13
13
|
agnt5/exceptions.py,sha256=mZ0q-NK6OKhYxgwBJpIbgpgzk-CJaFIHDbp1EE-pS7I,925
|
|
14
14
|
agnt5/function.py,sha256=f1vaAlJRwuo8cxCOGEd8XPido00mOhlPS8UJJx-6hJI,11041
|
|
15
|
-
agnt5/lm.py,sha256=
|
|
15
|
+
agnt5/lm.py,sha256=1ufT0TGj_Ra1FXCflgxKfMh1qPQ_DV9p7BLlZGWI4m4,22062
|
|
16
16
|
agnt5/tool.py,sha256=uc4L-Q9QyLzQDe-MZKk2Wo3o5e-mK8tfaQwVDgQdouQ,13133
|
|
17
17
|
agnt5/tracing.py,sha256=Mh2-OfnQM61lM_P8gxJstafdsUA8Gxoo1lP-Joxhub8,5980
|
|
18
18
|
agnt5/types.py,sha256=Zb71ZMwvrt1p4SH18cAKunp2y5tao_W5_jGYaPDejQo,2840
|
|
19
19
|
agnt5/version.py,sha256=rOq1mObLihnnKgKqBrwZA0zwOPudEKVFcW1a48ynkqc,573
|
|
20
20
|
agnt5/worker.py,sha256=_BnqqqvQE16FuezFbPda9FoiKAwcezSaxxNjU0rTjhs,33576
|
|
21
|
-
agnt5/workflow.py,sha256=
|
|
22
|
-
agnt5-0.2.
|
|
21
|
+
agnt5/workflow.py,sha256=GGCyt34W1DTSL8zjcj54qI7SA6Fn3HyQZ1XcMTlCMdI,22748
|
|
22
|
+
agnt5-0.2.5.dist-info/RECORD,,
|
|
File without changes
|