aury-agent 0.0.5__py3-none-any.whl → 0.0.7__py3-none-any.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.
- aury/agents/core/base.py +10 -1
- aury/agents/core/context.py +53 -32
- aury/agents/core/event_bus/bus.py +0 -2
- aury/agents/core/factory.py +6 -1
- aury/agents/core/logging.py +24 -1
- aury/agents/core/types/block.py +16 -10
- aury/agents/llm/adapter.py +7 -1
- aury/agents/middleware/base.py +19 -46
- aury/agents/middleware/chain.py +20 -33
- aury/agents/middleware/message.py +6 -11
- aury/agents/middleware/message_container.py +15 -23
- aury/agents/middleware/raw_message.py +6 -5
- aury/agents/middleware/truncation.py +0 -2
- aury/agents/react/agent.py +24 -20
- aury/agents/react/factory.py +13 -1
- aury/agents/react/persistence.py +1 -8
- aury/agents/react/step.py +20 -30
- aury/agents/react/tools.py +53 -15
- aury/agents/tool/builtin/delegate.py +1 -6
- aury/agents/tool/decorator.py +2 -1
- aury/agents/workflow/adapter.py +3 -16
- aury/agents/workflow/executor.py +5 -13
- {aury_agent-0.0.5.dist-info → aury_agent-0.0.7.dist-info}/METADATA +1 -1
- {aury_agent-0.0.5.dist-info → aury_agent-0.0.7.dist-info}/RECORD +26 -26
- {aury_agent-0.0.5.dist-info → aury_agent-0.0.7.dist-info}/WHEEL +0 -0
- {aury_agent-0.0.5.dist-info → aury_agent-0.0.7.dist-info}/entry_points.txt +0 -0
aury/agents/core/base.py
CHANGED
|
@@ -49,8 +49,17 @@ class AgentConfig:
|
|
|
49
49
|
Note: LLM parameters (temperature, max_tokens, timeout, retries) are
|
|
50
50
|
configured on LLMProvider, not here. Tool timeout is configured on
|
|
51
51
|
each tool's ToolConfig, not here.
|
|
52
|
+
|
|
53
|
+
Agent identity fields (for ActorInfo):
|
|
54
|
+
- id: Database ID or unique identifier (e.g. "1", "agent_123")
|
|
55
|
+
- code: Agent code/type (e.g. "super_assistant", "researcher")
|
|
56
|
+
- name: Display name (e.g. "超级助理", "Researcher Agent")
|
|
52
57
|
"""
|
|
53
|
-
|
|
58
|
+
# Agent identity
|
|
59
|
+
id: str | None = None # Database ID
|
|
60
|
+
code: str | None = None # Agent code (used as fallback for id)
|
|
61
|
+
name: str | None = None # Display name
|
|
62
|
+
|
|
54
63
|
max_steps: int = 50
|
|
55
64
|
|
|
56
65
|
# System prompt configuration
|
aury/agents/core/context.py
CHANGED
|
@@ -147,19 +147,31 @@ async def emit(event: "BlockEvent | ActionEvent") -> None:
|
|
|
147
147
|
Use this when you don't have access to InvocationContext,
|
|
148
148
|
e.g., in tool execute() methods.
|
|
149
149
|
|
|
150
|
-
For BlockEvent: automatically fills parent_id from ContextVar if not set.
|
|
151
|
-
ActionEvent does not have parent_id.
|
|
150
|
+
For BlockEvent: automatically fills parent_id and actor from ContextVar if not set.
|
|
151
|
+
ActionEvent does not have parent_id or actor.
|
|
152
152
|
|
|
153
153
|
Args:
|
|
154
154
|
event: BlockEvent or ActionEvent to emit
|
|
155
155
|
"""
|
|
156
156
|
try:
|
|
157
|
+
# Get current context for auto-fill
|
|
158
|
+
ctx = get_current_ctx_or_none()
|
|
159
|
+
|
|
157
160
|
# Auto-fill parent_id from ContextVar if not explicitly set (BlockEvent only)
|
|
158
161
|
if hasattr(event, 'parent_id') and event.parent_id is None:
|
|
159
162
|
from .types.block import BlockKind
|
|
160
163
|
kind = event.kind.value if isinstance(event.kind, BlockKind) else event.kind
|
|
161
164
|
event.parent_id = resolve_parent_id(kind)
|
|
162
165
|
|
|
166
|
+
# Auto-fill actor from context if not explicitly set (BlockEvent only)
|
|
167
|
+
if hasattr(event, 'actor') and event.actor is None and ctx:
|
|
168
|
+
from .types.block import ActorInfo
|
|
169
|
+
event.actor = ActorInfo(
|
|
170
|
+
id=ctx.agent_id,
|
|
171
|
+
role="assistant",
|
|
172
|
+
name=ctx.agent_name,
|
|
173
|
+
)
|
|
174
|
+
|
|
163
175
|
queue = _emit_queue_var.get()
|
|
164
176
|
await queue.put(event)
|
|
165
177
|
# Yield control to event loop to allow consumer to process the queue
|
|
@@ -224,6 +236,7 @@ class InvocationContext:
|
|
|
224
236
|
session: "Session"
|
|
225
237
|
invocation_id: str
|
|
226
238
|
agent_id: str
|
|
239
|
+
agent_name: str | None = None # Agent display name (for ActorInfo)
|
|
227
240
|
|
|
228
241
|
# Backends container (unified backend access)
|
|
229
242
|
backends: "Backends | None" = None
|
|
@@ -272,6 +285,10 @@ class InvocationContext:
|
|
|
272
285
|
config: dict[str, Any] = field(default_factory=dict)
|
|
273
286
|
metadata: dict[str, Any] = field(default_factory=dict)
|
|
274
287
|
|
|
288
|
+
# Block schema versions mapping: kind -> schema_version
|
|
289
|
+
# External can register different schema versions for the same kind
|
|
290
|
+
block_schema_versions: dict[str, str] = field(default_factory=dict)
|
|
291
|
+
|
|
275
292
|
# Depth tracking (for max depth enforcement)
|
|
276
293
|
_depth: int = 0
|
|
277
294
|
|
|
@@ -404,6 +421,7 @@ class InvocationContext:
|
|
|
404
421
|
def create_child(
|
|
405
422
|
self,
|
|
406
423
|
agent_id: str,
|
|
424
|
+
agent_name: str | None = None,
|
|
407
425
|
mode: str = "delegated",
|
|
408
426
|
inherit_config: bool = True,
|
|
409
427
|
llm: "LLMProvider | None" = None,
|
|
@@ -418,6 +436,7 @@ class InvocationContext:
|
|
|
418
436
|
|
|
419
437
|
Args:
|
|
420
438
|
agent_id: Sub-agent ID
|
|
439
|
+
agent_name: Sub-agent display name (optional)
|
|
421
440
|
mode: Execution mode (delegated)
|
|
422
441
|
inherit_config: Whether to copy config
|
|
423
442
|
llm: Override LLM provider (None = inherit from parent)
|
|
@@ -461,6 +480,7 @@ class InvocationContext:
|
|
|
461
480
|
session=self.session,
|
|
462
481
|
invocation_id=generate_id("inv"),
|
|
463
482
|
agent_id=agent_id,
|
|
483
|
+
agent_name=agent_name,
|
|
464
484
|
backends=self.backends, # Inherit backends
|
|
465
485
|
bus=self.bus,
|
|
466
486
|
llm=llm if llm is not None else self.llm,
|
|
@@ -476,6 +496,7 @@ class InvocationContext:
|
|
|
476
496
|
abort_chain=self.abort_chain, # Shared abort_chain
|
|
477
497
|
config=self.config.copy() if inherit_config else {},
|
|
478
498
|
metadata={"parent_block_id": parent_block_id} if parent_block_id else {},
|
|
499
|
+
block_schema_versions=self.block_schema_versions.copy() if inherit_config else {},
|
|
479
500
|
_depth=self._depth + 1,
|
|
480
501
|
)
|
|
481
502
|
|
|
@@ -485,6 +506,7 @@ class InvocationContext:
|
|
|
485
506
|
session=self.session,
|
|
486
507
|
invocation_id=self.invocation_id,
|
|
487
508
|
agent_id=self.agent_id,
|
|
509
|
+
agent_name=self.agent_name,
|
|
488
510
|
backends=self.backends, # Inherit backends
|
|
489
511
|
bus=self.bus,
|
|
490
512
|
llm=self.llm,
|
|
@@ -499,6 +521,7 @@ class InvocationContext:
|
|
|
499
521
|
abort_chain=self.abort_chain,
|
|
500
522
|
config=self.config,
|
|
501
523
|
metadata=self.metadata.copy(),
|
|
524
|
+
block_schema_versions=self.block_schema_versions,
|
|
502
525
|
_depth=self._depth,
|
|
503
526
|
)
|
|
504
527
|
|
|
@@ -574,13 +597,17 @@ class InvocationContext:
|
|
|
574
597
|
- Tool outputs
|
|
575
598
|
- BlockHandle operations
|
|
576
599
|
|
|
577
|
-
The block's session_id, invocation_id,
|
|
578
|
-
Uses ContextVar to find the queue set by
|
|
579
|
-
Parent_id respects the apply_to_kinds filter set
|
|
600
|
+
The block's session_id, invocation_id, parent_id, actor, and schema_version
|
|
601
|
+
are automatically filled. Uses ContextVar to find the queue set by
|
|
602
|
+
BaseAgent.run(). Parent_id respects the apply_to_kinds filter set
|
|
603
|
+
via set_parent_id().
|
|
580
604
|
|
|
581
605
|
Args:
|
|
582
606
|
block: BlockEvent to emit
|
|
583
607
|
"""
|
|
608
|
+
from .types.block import BlockKind, ActorInfo
|
|
609
|
+
kind = block.kind.value if isinstance(block.kind, BlockKind) else block.kind
|
|
610
|
+
|
|
584
611
|
# Fill in IDs if not set
|
|
585
612
|
if not block.session_id:
|
|
586
613
|
block.session_id = self.session_id
|
|
@@ -589,10 +616,21 @@ class InvocationContext:
|
|
|
589
616
|
# Auto-fill parent_id from ContextVar if not explicitly set
|
|
590
617
|
# Uses resolve_parent_id to respect apply_to_kinds filter
|
|
591
618
|
if block.parent_id is None:
|
|
592
|
-
from .types.block import BlockKind
|
|
593
|
-
kind = block.kind.value if isinstance(block.kind, BlockKind) else block.kind
|
|
594
619
|
block.parent_id = resolve_parent_id(kind)
|
|
595
620
|
|
|
621
|
+
# Auto-fill actor if not explicitly set
|
|
622
|
+
# Actor represents the agent that emitted this block
|
|
623
|
+
if block.actor is None:
|
|
624
|
+
block.actor = ActorInfo(
|
|
625
|
+
id=self.agent_id,
|
|
626
|
+
role="assistant",
|
|
627
|
+
name=self.agent_name,
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
# Auto-fill schema_version from config if not explicitly set
|
|
631
|
+
if block.schema_version is None and kind in self.block_schema_versions:
|
|
632
|
+
block.schema_version = self.block_schema_versions[kind]
|
|
633
|
+
|
|
596
634
|
# Put into the current run's queue (via ContextVar)
|
|
597
635
|
try:
|
|
598
636
|
queue = _emit_queue_var.get()
|
|
@@ -639,17 +677,9 @@ class InvocationContext:
|
|
|
639
677
|
**kwargs,
|
|
640
678
|
}
|
|
641
679
|
|
|
642
|
-
# Build context for middleware
|
|
643
|
-
mw_context = {
|
|
644
|
-
"session_id": self.session_id,
|
|
645
|
-
"invocation_id": self.invocation_id,
|
|
646
|
-
"agent_id": self.agent_id,
|
|
647
|
-
"step": self.step,
|
|
648
|
-
}
|
|
649
|
-
|
|
650
680
|
# Process through middleware (on_request)
|
|
651
681
|
if self.middleware:
|
|
652
|
-
processed = await self.middleware.process_request(request
|
|
682
|
+
processed = await self.middleware.process_request(request)
|
|
653
683
|
if processed is None:
|
|
654
684
|
logger.debug("Request blocked by middleware")
|
|
655
685
|
return None
|
|
@@ -658,7 +688,7 @@ class InvocationContext:
|
|
|
658
688
|
try:
|
|
659
689
|
# Call LLM
|
|
660
690
|
if stream:
|
|
661
|
-
return self._stream_llm_with_middleware(provider, request
|
|
691
|
+
return self._stream_llm_with_middleware(provider, request)
|
|
662
692
|
else:
|
|
663
693
|
response = await provider.generate(
|
|
664
694
|
messages=request["messages"],
|
|
@@ -668,7 +698,7 @@ class InvocationContext:
|
|
|
668
698
|
# Process through middleware (on_response)
|
|
669
699
|
if self.middleware:
|
|
670
700
|
response_dict = {"response": response}
|
|
671
|
-
processed = await self.middleware.process_response(response_dict
|
|
701
|
+
processed = await self.middleware.process_response(response_dict)
|
|
672
702
|
if processed is None:
|
|
673
703
|
return None
|
|
674
704
|
response = processed.get("response", response)
|
|
@@ -677,7 +707,7 @@ class InvocationContext:
|
|
|
677
707
|
|
|
678
708
|
except Exception as e:
|
|
679
709
|
if self.middleware:
|
|
680
|
-
processed_error = await self.middleware.process_error(e
|
|
710
|
+
processed_error = await self.middleware.process_error(e)
|
|
681
711
|
if processed_error is None:
|
|
682
712
|
return None
|
|
683
713
|
raise processed_error
|
|
@@ -687,7 +717,6 @@ class InvocationContext:
|
|
|
687
717
|
self,
|
|
688
718
|
provider: "LLMProvider",
|
|
689
719
|
request: dict[str, Any],
|
|
690
|
-
mw_context: dict[str, Any],
|
|
691
720
|
) -> AsyncIterator[Any]:
|
|
692
721
|
"""Stream LLM response with middleware processing."""
|
|
693
722
|
if self.middleware:
|
|
@@ -700,7 +729,7 @@ class InvocationContext:
|
|
|
700
729
|
):
|
|
701
730
|
if self.middleware:
|
|
702
731
|
chunk_dict = {"chunk": chunk}
|
|
703
|
-
processed = await self.middleware.process_stream_chunk(chunk_dict
|
|
732
|
+
processed = await self.middleware.process_stream_chunk(chunk_dict)
|
|
704
733
|
if processed is None:
|
|
705
734
|
continue
|
|
706
735
|
chunk = processed.get("chunk", chunk)
|
|
@@ -708,7 +737,7 @@ class InvocationContext:
|
|
|
708
737
|
|
|
709
738
|
except Exception as e:
|
|
710
739
|
if self.middleware:
|
|
711
|
-
processed_error = await self.middleware.process_error(e
|
|
740
|
+
processed_error = await self.middleware.process_error(e)
|
|
712
741
|
if processed_error is None:
|
|
713
742
|
return
|
|
714
743
|
raise processed_error
|
|
@@ -733,19 +762,11 @@ class InvocationContext:
|
|
|
733
762
|
"""
|
|
734
763
|
from ..middleware import HookAction
|
|
735
764
|
|
|
736
|
-
# Build context for middleware
|
|
737
|
-
mw_context = {
|
|
738
|
-
"session_id": self.session_id,
|
|
739
|
-
"invocation_id": self.invocation_id,
|
|
740
|
-
"agent_id": self.agent_id,
|
|
741
|
-
"step": self.step,
|
|
742
|
-
}
|
|
743
|
-
|
|
744
765
|
current_args = arguments
|
|
745
766
|
|
|
746
767
|
# Process through middleware (on_tool_call)
|
|
747
768
|
if self.middleware:
|
|
748
|
-
result = await self.middleware.process_tool_call(tool, current_args
|
|
769
|
+
result = await self.middleware.process_tool_call(tool, current_args)
|
|
749
770
|
if result.action == HookAction.SKIP:
|
|
750
771
|
logger.debug(f"Tool {tool.name} skipped by middleware")
|
|
751
772
|
from ..tool import ToolResult
|
|
@@ -768,7 +789,7 @@ class InvocationContext:
|
|
|
768
789
|
|
|
769
790
|
# Process through middleware (on_tool_end)
|
|
770
791
|
if self.middleware:
|
|
771
|
-
result = await self.middleware.process_tool_end(tool, tool_result
|
|
792
|
+
result = await self.middleware.process_tool_end(tool, tool_result)
|
|
772
793
|
if result.action == HookAction.RETRY and result.modified_data:
|
|
773
794
|
# Re-execute with modified args
|
|
774
795
|
tool_result = await tool.execute(**result.modified_data)
|
aury/agents/core/factory.py
CHANGED
|
@@ -129,7 +129,12 @@ class AgentFactory:
|
|
|
129
129
|
Agent instance with child context
|
|
130
130
|
"""
|
|
131
131
|
logger.debug(f"AgentFactory.create_subagent: creating subagent, type={agent_type}, mode={mode}, parent_invocation_id={parent_ctx.invocation_id}")
|
|
132
|
-
|
|
132
|
+
|
|
133
|
+
# Get agent name from class if available
|
|
134
|
+
agent_class = self._registry.get(agent_type)
|
|
135
|
+
agent_name = getattr(agent_class, 'name', agent_type) if agent_class else agent_type
|
|
136
|
+
|
|
137
|
+
child_ctx = parent_ctx.create_child(agent_id=agent_type, agent_name=agent_name, mode=mode)
|
|
133
138
|
logger.debug(f"AgentFactory.create_subagent: child context created, child_invocation_id={child_ctx.invocation_id}")
|
|
134
139
|
return self.create(agent_type, child_ctx, config)
|
|
135
140
|
|
aury/agents/core/logging.py
CHANGED
|
@@ -21,7 +21,29 @@ Pre-defined loggers:
|
|
|
21
21
|
- session: aury.agents.session
|
|
22
22
|
"""
|
|
23
23
|
import logging
|
|
24
|
-
from typing import Literal
|
|
24
|
+
from typing import Any, Literal
|
|
25
|
+
|
|
26
|
+
# =============================================================================
|
|
27
|
+
# TRACE Level 支持
|
|
28
|
+
# =============================================================================
|
|
29
|
+
# TRACE (5) < DEBUG (10),用于超细粒度调试
|
|
30
|
+
TRACE = 5
|
|
31
|
+
if logging.getLevelName(TRACE) == "Level 5":
|
|
32
|
+
logging.addLevelName(TRACE, "TRACE")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _ensure_trace_method() -> None:
|
|
36
|
+
"""确保 logging.Logger 有 trace() 方法。"""
|
|
37
|
+
if hasattr(logging.Logger, "trace"):
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
def trace(self: logging.Logger, msg: str, *args: Any, **kwargs: Any) -> None:
|
|
41
|
+
if self.isEnabledFor(TRACE):
|
|
42
|
+
self._log(TRACE, msg, args, **kwargs)
|
|
43
|
+
|
|
44
|
+
logging.Logger.trace = trace # type: ignore[attr-defined]
|
|
45
|
+
|
|
46
|
+
_ensure_trace_method()
|
|
25
47
|
|
|
26
48
|
# Root namespace
|
|
27
49
|
ROOT_NAMESPACE = "aury.agents"
|
|
@@ -79,6 +101,7 @@ LoggerName = Literal[
|
|
|
79
101
|
|
|
80
102
|
|
|
81
103
|
__all__ = [
|
|
104
|
+
"TRACE",
|
|
82
105
|
"get_logger",
|
|
83
106
|
"logger",
|
|
84
107
|
"react_logger",
|
aury/agents/core/types/block.py
CHANGED
|
@@ -110,6 +110,7 @@ class BlockEvent:
|
|
|
110
110
|
op: BlockOp = BlockOp.APPLY
|
|
111
111
|
data: dict[str, Any] | None = None
|
|
112
112
|
branch: str | None = None # For sub-agent isolation (e.g. "agent1.agent2")
|
|
113
|
+
schema_version: str | None = None # Schema version for external rendering/handling
|
|
113
114
|
|
|
114
115
|
# Protocol envelope
|
|
115
116
|
protocol_version: str = "1.0"
|
|
@@ -130,6 +131,7 @@ class BlockEvent:
|
|
|
130
131
|
"op": self.op.value,
|
|
131
132
|
"data": self.data,
|
|
132
133
|
"branch": self.branch,
|
|
134
|
+
"schema_version": self.schema_version,
|
|
133
135
|
"protocol_version": self.protocol_version,
|
|
134
136
|
"event_id": self.event_id,
|
|
135
137
|
"timestamp": self.timestamp,
|
|
@@ -154,6 +156,7 @@ class BlockEvent:
|
|
|
154
156
|
op=BlockOp(data["op"]),
|
|
155
157
|
data=data.get("data"),
|
|
156
158
|
branch=data.get("branch"),
|
|
159
|
+
schema_version=data.get("schema_version"),
|
|
157
160
|
protocol_version=data.get("protocol_version", "1.0"),
|
|
158
161
|
event_id=data.get("event_id", ""),
|
|
159
162
|
timestamp=data.get("timestamp", 0),
|
|
@@ -310,8 +313,7 @@ class PersistedBlock:
|
|
|
310
313
|
# From protocol envelope
|
|
311
314
|
session_id: str = ""
|
|
312
315
|
invocation_id: str = ""
|
|
313
|
-
|
|
314
|
-
actor_role: str = "assistant"
|
|
316
|
+
actor: ActorInfo | None = None
|
|
315
317
|
|
|
316
318
|
# Branch for sub-agent isolation
|
|
317
319
|
branch: str | None = None
|
|
@@ -332,8 +334,7 @@ class PersistedBlock:
|
|
|
332
334
|
"data": self.data,
|
|
333
335
|
"session_id": self.session_id,
|
|
334
336
|
"invocation_id": self.invocation_id,
|
|
335
|
-
"
|
|
336
|
-
"actor_role": self.actor_role,
|
|
337
|
+
"actor": self.actor.to_dict() if self.actor else None,
|
|
337
338
|
"branch": self.branch,
|
|
338
339
|
"created_at": self.created_at.isoformat(),
|
|
339
340
|
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
|
@@ -355,8 +356,7 @@ class PersistedBlock:
|
|
|
355
356
|
data=data.get("data"),
|
|
356
357
|
session_id=data.get("session_id", ""),
|
|
357
358
|
invocation_id=data.get("invocation_id", ""),
|
|
358
|
-
|
|
359
|
-
actor_role=data.get("actor_role", "assistant"),
|
|
359
|
+
actor=ActorInfo.from_dict(data["actor"]) if data.get("actor") else None,
|
|
360
360
|
branch=data.get("branch"),
|
|
361
361
|
created_at=datetime.fromisoformat(data["created_at"]),
|
|
362
362
|
updated_at=datetime.fromisoformat(data["updated_at"]) if data.get("updated_at") else None,
|
|
@@ -395,8 +395,7 @@ class PersistedBlock:
|
|
|
395
395
|
branch=first.branch,
|
|
396
396
|
session_id=first.session_id,
|
|
397
397
|
invocation_id=first.invocation_id,
|
|
398
|
-
|
|
399
|
-
actor_role=first.actor.role if first.actor else "assistant",
|
|
398
|
+
actor=first.actor,
|
|
400
399
|
updated_at=datetime.fromtimestamp(last_timestamp / 1000) if len(events) > 1 else None,
|
|
401
400
|
)
|
|
402
401
|
|
|
@@ -471,8 +470,7 @@ class BlockAggregator:
|
|
|
471
470
|
branch=event.branch,
|
|
472
471
|
session_id=event.session_id,
|
|
473
472
|
invocation_id=event.invocation_id,
|
|
474
|
-
|
|
475
|
-
actor_role=event.actor.role if event.actor else "assistant",
|
|
473
|
+
actor=event.actor,
|
|
476
474
|
)
|
|
477
475
|
self._blocks[block_id] = block
|
|
478
476
|
self._order.append(block_id)
|
|
@@ -533,6 +531,7 @@ class BlockHandle:
|
|
|
533
531
|
parent: "BlockHandle | str | None" = None,
|
|
534
532
|
persistence: Persistence = Persistence.PERSISTENT,
|
|
535
533
|
branch: str | None = None,
|
|
534
|
+
schema_version: str | None = None,
|
|
536
535
|
):
|
|
537
536
|
self.ctx = ctx
|
|
538
537
|
self.kind = kind
|
|
@@ -541,6 +540,8 @@ class BlockHandle:
|
|
|
541
540
|
self.persistence = persistence
|
|
542
541
|
# Use provided branch or get from context
|
|
543
542
|
self.branch = branch or getattr(ctx, 'branch', None)
|
|
543
|
+
# Schema version (None = auto-fill from ctx.block_schema_versions)
|
|
544
|
+
self.schema_version = schema_version
|
|
544
545
|
|
|
545
546
|
async def apply(self, data: dict[str, Any], **kwargs: Any) -> None:
|
|
546
547
|
"""Create or completely replace the Block."""
|
|
@@ -552,6 +553,7 @@ class BlockHandle:
|
|
|
552
553
|
op=BlockOp.APPLY,
|
|
553
554
|
data=data,
|
|
554
555
|
branch=self.branch,
|
|
556
|
+
schema_version=self.schema_version,
|
|
555
557
|
**kwargs,
|
|
556
558
|
))
|
|
557
559
|
|
|
@@ -565,6 +567,7 @@ class BlockHandle:
|
|
|
565
567
|
op=BlockOp.DELTA,
|
|
566
568
|
data=data,
|
|
567
569
|
branch=self.branch,
|
|
570
|
+
schema_version=self.schema_version,
|
|
568
571
|
))
|
|
569
572
|
|
|
570
573
|
async def patch(self, data: dict[str, Any]) -> None:
|
|
@@ -577,6 +580,7 @@ class BlockHandle:
|
|
|
577
580
|
op=BlockOp.PATCH,
|
|
578
581
|
data=data,
|
|
579
582
|
branch=self.branch,
|
|
583
|
+
schema_version=self.schema_version,
|
|
580
584
|
))
|
|
581
585
|
|
|
582
586
|
def child(
|
|
@@ -584,6 +588,7 @@ class BlockHandle:
|
|
|
584
588
|
kind: BlockKind | str,
|
|
585
589
|
block_id: str | None = None,
|
|
586
590
|
persistence: Persistence = Persistence.PERSISTENT,
|
|
591
|
+
schema_version: str | None = None,
|
|
587
592
|
) -> "BlockHandle":
|
|
588
593
|
"""Create a child BlockHandle nested under this Block."""
|
|
589
594
|
return BlockHandle(
|
|
@@ -593,6 +598,7 @@ class BlockHandle:
|
|
|
593
598
|
parent=self,
|
|
594
599
|
persistence=persistence,
|
|
595
600
|
branch=self.branch, # Inherit branch from parent
|
|
601
|
+
schema_version=schema_version, # Child can have different schema_version
|
|
596
602
|
)
|
|
597
603
|
|
|
598
604
|
|
aury/agents/llm/adapter.py
CHANGED
|
@@ -58,6 +58,7 @@ class ModelClientProvider:
|
|
|
58
58
|
api_key: str | None = None,
|
|
59
59
|
base_url: str | None = None,
|
|
60
60
|
capabilities: Capabilities | None = None,
|
|
61
|
+
timeout: float | None = None,
|
|
61
62
|
**kwargs: Any,
|
|
62
63
|
):
|
|
63
64
|
"""Initialize ModelClient provider.
|
|
@@ -68,6 +69,7 @@ class ModelClientProvider:
|
|
|
68
69
|
api_key: API key (optional, uses env if not provided)
|
|
69
70
|
base_url: Base URL override
|
|
70
71
|
capabilities: Model capabilities
|
|
72
|
+
timeout: Request timeout in seconds (None = use provider default, typically 600s)
|
|
71
73
|
**kwargs: Additional ModelClient options
|
|
72
74
|
"""
|
|
73
75
|
if not HAS_MODEL_CLIENT:
|
|
@@ -90,6 +92,8 @@ class ModelClientProvider:
|
|
|
90
92
|
client_kwargs["api_key"] = api_key
|
|
91
93
|
if base_url:
|
|
92
94
|
client_kwargs["base_url"] = base_url
|
|
95
|
+
if timeout is not None:
|
|
96
|
+
client_kwargs["timeout"] = timeout
|
|
93
97
|
|
|
94
98
|
# Pass through additional options
|
|
95
99
|
for key in ("default_max_tokens", "default_temperature", "default_top_p"):
|
|
@@ -381,6 +385,7 @@ class ModelClientProvider:
|
|
|
381
385
|
def create_provider(
|
|
382
386
|
provider: str,
|
|
383
387
|
model: str,
|
|
388
|
+
timeout: float | None = None,
|
|
384
389
|
**kwargs: Any,
|
|
385
390
|
) -> LLMProvider:
|
|
386
391
|
"""Create an LLM provider.
|
|
@@ -388,9 +393,10 @@ def create_provider(
|
|
|
388
393
|
Args:
|
|
389
394
|
provider: Provider name (openai, anthropic, doubao, etc.)
|
|
390
395
|
model: Model name
|
|
396
|
+
timeout: Request timeout in seconds (None = use provider default)
|
|
391
397
|
**kwargs: Additional options
|
|
392
398
|
|
|
393
399
|
Returns:
|
|
394
400
|
LLMProvider instance
|
|
395
401
|
"""
|
|
396
|
-
return ModelClientProvider(provider=provider, model=model, **kwargs)
|
|
402
|
+
return ModelClientProvider(provider=provider, model=model, timeout=timeout, **kwargs)
|