agent-framework-core 1.14.0__tar.gz → 1.16.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.
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/PKG-INFO +1 -1
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/__init__.py +4 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/__init__.pyi +4 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_agent_hooks.py +112 -64
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_agents.py +29 -6
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_compaction.py +4 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_evaluation.py +1 -2
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_harness/_agent.py +17 -3
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_harness/_agent.pyi +2 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_harness/_background_agents.py +26 -3
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_harness/_loop.py +169 -119
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_harness/_tool_approval.py +27 -5
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_mcp.py +90 -33
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_middleware.py +65 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_serialization.py +2 -2
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_sessions.py +89 -5
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_settings.py +30 -4
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_skills.py +3 -1
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_tools.py +381 -30
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_types.py +43 -10
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_agent.py +21 -8
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_checkpoint.py +12 -10
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_checkpoint_encoding.py +24 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_edge_runner.py +20 -3
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_events.py +15 -5
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_request_info_mixin.py +369 -369
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_state.py +17 -10
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_typing_utils.py +158 -17
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_workflow.py +3 -1
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/observability.py +759 -123
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/pyproject.toml +1 -1
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/LICENSE +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/README.md +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_clients.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_docstrings.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_feature_stage.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_filesystem.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_harness/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_harness/_file_access.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_harness/_file_memory.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_harness/_memory.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_harness/_mode.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_harness/_todo.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_telemetry.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_agent_executor.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_agent_utils.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_const.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_conversation_history.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_edge.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_executor.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_function_executor.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_functional.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_message_utils.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_model_utils.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_runner.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_runner_context.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_validation.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_viz.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_workflow_builder.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_workflow_context.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_workflows/_workflow_executor.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/a2a/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/a2a/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/ag_ui/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/ag_ui/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/amazon/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/amazon/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/anthropic/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/anthropic/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/azure/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/azure/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/chatkit/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/chatkit/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/declarative/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/declarative/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/devui/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/devui/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/exceptions.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/foundry/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/foundry/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/gemini/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/gemini/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/github/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/github/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/google/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/google/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/hyperlight/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/lab/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/mem0/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/mem0/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/microsoft/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/microsoft/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/mistral/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/mistral/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/monty/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/monty/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/ollama/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/ollama/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/openai/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/openai/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/orchestrations/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/orchestrations/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/py.typed +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/redis/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/redis/__init__.pyi +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/security.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/tools/__init__.py +0 -0
- {agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/tools/__init__.pyi +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-framework-core
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.16.0
|
|
4
4
|
Summary: Microsoft Agent Framework for building AI Agents with Python. This is the core package that has all the core abstractions and implementations.
|
|
5
5
|
Author-email: Microsoft <af-support@microsoft.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -185,6 +185,7 @@ _LAZY_MODULE_EXPORTS: Final[Mapping[str, tuple[str, ...]]] = {
|
|
|
185
185
|
"FunctionMiddleware",
|
|
186
186
|
"FunctionMiddlewareTypes",
|
|
187
187
|
"MiddlewareBundle",
|
|
188
|
+
"MiddlewareFailure",
|
|
188
189
|
"MiddlewareTermination",
|
|
189
190
|
"MiddlewareType",
|
|
190
191
|
"MiddlewareTypes",
|
|
@@ -293,6 +294,7 @@ _LAZY_MODULE_EXPORTS: Final[Mapping[str, tuple[str, ...]]] = {
|
|
|
293
294
|
"InMemoryCheckpointStorage",
|
|
294
295
|
"WorkflowCheckpoint",
|
|
295
296
|
),
|
|
297
|
+
"._workflows._checkpoint_encoding": ("register_checkpoint_type",),
|
|
296
298
|
"._workflows._const": (
|
|
297
299
|
"DEFAULT_MAX_ITERATIONS",
|
|
298
300
|
"INTERNAL_SOURCE_ID",
|
|
@@ -509,6 +511,7 @@ __all__ = [
|
|
|
509
511
|
"MessageInjectionMiddleware",
|
|
510
512
|
"MiddlewareBundle",
|
|
511
513
|
"MiddlewareException",
|
|
514
|
+
"MiddlewareFailure",
|
|
512
515
|
"MiddlewareTermination",
|
|
513
516
|
"MiddlewareType",
|
|
514
517
|
"MiddlewareTypes",
|
|
@@ -631,6 +634,7 @@ __all__ = [
|
|
|
631
634
|
"normalize_tools",
|
|
632
635
|
"prepend_agent_framework_to_user_agent",
|
|
633
636
|
"prepend_instructions_to_messages",
|
|
637
|
+
"register_checkpoint_type",
|
|
634
638
|
"register_state_type",
|
|
635
639
|
"resolve_agent_id",
|
|
636
640
|
"response_handler",
|
|
@@ -144,6 +144,7 @@ from ._middleware import (
|
|
|
144
144
|
FunctionMiddleware,
|
|
145
145
|
FunctionMiddlewareTypes,
|
|
146
146
|
MiddlewareBundle,
|
|
147
|
+
MiddlewareFailure,
|
|
147
148
|
MiddlewareTermination,
|
|
148
149
|
MiddlewareType,
|
|
149
150
|
MiddlewareTypes,
|
|
@@ -259,6 +260,7 @@ from ._workflows._checkpoint import (
|
|
|
259
260
|
InMemoryCheckpointStorage,
|
|
260
261
|
WorkflowCheckpoint,
|
|
261
262
|
)
|
|
263
|
+
from ._workflows._checkpoint_encoding import register_checkpoint_type
|
|
262
264
|
from ._workflows._const import DEFAULT_MAX_ITERATIONS, INTERNAL_SOURCE_ID
|
|
263
265
|
from ._workflows._edge import (
|
|
264
266
|
Case,
|
|
@@ -473,6 +475,7 @@ __all__ = [
|
|
|
473
475
|
"MessageInjectionMiddleware",
|
|
474
476
|
"MiddlewareBundle",
|
|
475
477
|
"MiddlewareException",
|
|
478
|
+
"MiddlewareFailure",
|
|
476
479
|
"MiddlewareTermination",
|
|
477
480
|
"MiddlewareType",
|
|
478
481
|
"MiddlewareTypes",
|
|
@@ -595,6 +598,7 @@ __all__ = [
|
|
|
595
598
|
"normalize_tools",
|
|
596
599
|
"prepend_agent_framework_to_user_agent",
|
|
597
600
|
"prepend_instructions_to_messages",
|
|
601
|
+
"register_checkpoint_type",
|
|
598
602
|
"register_state_type",
|
|
599
603
|
"resolve_agent_id",
|
|
600
604
|
"response_handler",
|
|
@@ -37,7 +37,13 @@ Enforcement semantics (``mode="enforce"``):
|
|
|
37
37
|
not executed (or its result is discarded) and a tool-error payload is surfaced to the
|
|
38
38
|
model so the agent loop can continue, per the spec's block-propagation rules. A
|
|
39
39
|
``host_error:*`` deny at the tool seam additionally halts the run (the enforcement
|
|
40
|
-
layer itself failed, so continuing would be unreliable)
|
|
40
|
+
layer itself failed, so continuing would be unreliable): the run is aborted through
|
|
41
|
+
the function-invocation loop's fail-closed escape
|
|
42
|
+
(:class:`~agent_framework.MiddlewareFailure`) and the
|
|
43
|
+
:class:`agent_hooks.InterceptionBlocked` propagates to the caller, exactly like a
|
|
44
|
+
run-level deny. Other unexpected failures inside the enforcement layer (projection
|
|
45
|
+
bug, emitter fault) abort the run the same way and surface as
|
|
46
|
+
:class:`~agent_framework.MiddlewareFailure`.
|
|
41
47
|
- Framework middleware short-circuits (``MiddlewareTermination``) are guarded: a result
|
|
42
48
|
substituted by another middleware still passes ``output`` / ``post_model_call`` /
|
|
43
49
|
``post_tool_call`` before it egresses or enters the transcript.
|
|
@@ -113,6 +119,7 @@ from ._middleware import (
|
|
|
113
119
|
FunctionInvocationContext,
|
|
114
120
|
FunctionMiddleware,
|
|
115
121
|
MiddlewareBundle,
|
|
122
|
+
MiddlewareFailure,
|
|
116
123
|
MiddlewareTermination,
|
|
117
124
|
)
|
|
118
125
|
from ._serialization import make_json_safe
|
|
@@ -231,7 +238,6 @@ class _RunState:
|
|
|
231
238
|
builder: AgentContextBuilder
|
|
232
239
|
session_scoped: bool
|
|
233
240
|
config: _AgentHooksConfig
|
|
234
|
-
halted: BaseException | None = None
|
|
235
241
|
|
|
236
242
|
|
|
237
243
|
_RUN_STATE: ContextVar[_RunState | None] = ContextVar("agent_framework_agent_hooks_run_state", default=None)
|
|
@@ -895,27 +901,63 @@ def _is_approval_request(result: Any) -> bool:
|
|
|
895
901
|
return isinstance(result, Content) and result.type == "function_approval_request"
|
|
896
902
|
|
|
897
903
|
|
|
898
|
-
def _halt_on_enforcement_failure(
|
|
899
|
-
|
|
900
|
-
) -> NoReturn:
|
|
901
|
-
"""Route an unexpected failure inside the enforcement layer through the fail-closed halt path.
|
|
904
|
+
def _halt_on_enforcement_failure(exc: BaseException, point: str) -> NoReturn:
|
|
905
|
+
"""Abort the run fail-closed on an unexpected failure inside the enforcement layer.
|
|
902
906
|
|
|
903
907
|
The function-invocation loop converts arbitrary exceptions raised by function
|
|
904
908
|
middleware into tool-error results and keeps running; for a failure of the
|
|
905
909
|
enforcement layer itself (projection bug, emitter fault) that would fail open —
|
|
906
910
|
the failure would vanish from the audit trail and the run would continue unguarded.
|
|
907
|
-
|
|
908
|
-
the
|
|
911
|
+
:class:`MiddlewareFailure` is the loop's explicit fail-closed escape: it propagates
|
|
912
|
+
to the caller at the run boundary, with the underlying failure chained as its cause.
|
|
909
913
|
"""
|
|
910
|
-
message = f"agent-hooks {point} enforcement failed: {type(exc).__name__}"
|
|
911
|
-
context.result = {"error": message}
|
|
912
914
|
if isinstance(exc, MiddlewareException):
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
915
|
+
raise MiddlewareFailure(str(exc)) from exc
|
|
916
|
+
raise MiddlewareFailure(f"agent-hooks {point} enforcement failed: {type(exc).__name__}") from exc
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
class _ToolSeamBlockFailure(MiddlewareFailure):
|
|
920
|
+
"""Private tag for this feature's own tool-seam ``host_error`` halts.
|
|
921
|
+
|
|
922
|
+
Only failures raised by :meth:`_AgentHooksFunctionMiddleware._maybe_halt` carry
|
|
923
|
+
this type, which is what authorizes :func:`_reraise_tool_seam_block` to unwrap
|
|
924
|
+
the chained :class:`agent_hooks.InterceptionBlocked` at the run boundary. A plain
|
|
925
|
+
``MiddlewareFailure`` raised by third-party middleware is never unwrapped — even
|
|
926
|
+
when its ``__cause__`` happens to be an ``InterceptionBlocked`` — so untrusted
|
|
927
|
+
code cannot launder a crafted interception record into this feature's deny
|
|
928
|
+
surface.
|
|
929
|
+
"""
|
|
930
|
+
|
|
931
|
+
|
|
932
|
+
def _reraise_tool_seam_block(failure: MiddlewareFailure) -> NoReturn:
|
|
933
|
+
"""Surface a tool-seam ``host_error`` block as the block itself at the run boundary.
|
|
934
|
+
|
|
935
|
+
The tool seam sits behind the function-invocation loop, so its fail-closed halts
|
|
936
|
+
travel as :class:`MiddlewareFailure` (the loop's loud escape) with the triggering
|
|
937
|
+
exception chained as the cause. When the failure is this feature's own tagged
|
|
938
|
+
:class:`_ToolSeamBlockFailure`, re-raise its :class:`agent_hooks.InterceptionBlocked`
|
|
939
|
+
cause so callers see the same deny surface — ``InterceptionBlocked`` carrying the
|
|
940
|
+
interception record — at every seam (run-, model-, and tool-level). Any other
|
|
941
|
+
failure (including a third-party ``MiddlewareFailure`` with a crafted
|
|
942
|
+
``InterceptionBlocked`` cause) propagates exactly as raised.
|
|
943
|
+
"""
|
|
944
|
+
from agent_hooks import InterceptionBlocked
|
|
945
|
+
|
|
946
|
+
block = failure.__cause__
|
|
947
|
+
if isinstance(failure, _ToolSeamBlockFailure) and isinstance(block, InterceptionBlocked):
|
|
948
|
+
# Detach the transport wrapper's back-links (both were set to the block when
|
|
949
|
+
# _maybe_halt raised the wrapper from it) before re-raising: re-raising the
|
|
950
|
+
# block while they are intact would make the two exceptions each other's
|
|
951
|
+
# cause/context — a chain cycle that every consumer walking
|
|
952
|
+
# __cause__/__context__ would have to guard against. The bare raise below
|
|
953
|
+
# records the wrapper as the block's __context__ instead (truthful: the block
|
|
954
|
+
# is re-raised while the wrapper is being handled), keeping both exceptions
|
|
955
|
+
# visible in tracebacks, acyclically.
|
|
956
|
+
failure.__cause__ = None
|
|
957
|
+
if failure.__context__ is block:
|
|
958
|
+
failure.__context__ = None
|
|
959
|
+
raise block
|
|
960
|
+
raise failure
|
|
919
961
|
|
|
920
962
|
|
|
921
963
|
# endregion
|
|
@@ -1025,8 +1067,6 @@ class _AgentHooksAgentMiddleware(_AgentHooksMiddlewareBase, AgentMiddleware):
|
|
|
1025
1067
|
# A middleware short-circuited the run; any substituted result
|
|
1026
1068
|
# still egresses to the caller, so it passes the output point.
|
|
1027
1069
|
termination = exc
|
|
1028
|
-
if state.halted is not None:
|
|
1029
|
-
raise state.halted
|
|
1030
1070
|
result = context.result
|
|
1031
1071
|
if isinstance(result, AgentResponse):
|
|
1032
1072
|
await self._emit_output(state, result)
|
|
@@ -1046,6 +1086,14 @@ class _AgentHooksAgentMiddleware(_AgentHooksMiddlewareBase, AgentMiddleware):
|
|
|
1046
1086
|
shutdown_reason = "error"
|
|
1047
1087
|
context.result = None
|
|
1048
1088
|
raise
|
|
1089
|
+
except MiddlewareFailure as failure:
|
|
1090
|
+
# A fail-closed abort from behind the function-invocation loop: the
|
|
1091
|
+
# gated persistence is dropped and, for a tool-seam host_error block,
|
|
1092
|
+
# the block itself is surfaced (one deny surface at every seam).
|
|
1093
|
+
gate.drop()
|
|
1094
|
+
shutdown_reason = "error"
|
|
1095
|
+
context.result = None
|
|
1096
|
+
_reraise_tool_seam_block(failure)
|
|
1049
1097
|
except asyncio.CancelledError:
|
|
1050
1098
|
shutdown_reason = "cancelled"
|
|
1051
1099
|
raise
|
|
@@ -1093,10 +1141,6 @@ class _AgentHooksAgentMiddleware(_AgentHooksMiddlewareBase, AgentMiddleware):
|
|
|
1093
1141
|
termination = exc
|
|
1094
1142
|
inner = context.result
|
|
1095
1143
|
if inner is None and termination is not None:
|
|
1096
|
-
if state.halted is not None:
|
|
1097
|
-
# The enforcement layer itself failed: strand the deferred
|
|
1098
|
-
# persistence (fail-closed) and surface the halt.
|
|
1099
|
-
raise state.halted
|
|
1100
1144
|
# Terminated without a result: nothing will egress, so the no-egress
|
|
1101
1145
|
# termination is a permitted outcome. Release the persistence the
|
|
1102
1146
|
# drained in-pipeline work deferred — history of model calls that
|
|
@@ -1119,6 +1163,12 @@ class _AgentHooksAgentMiddleware(_AgentHooksMiddlewareBase, AgentMiddleware):
|
|
|
1119
1163
|
# A middleware substituted its own stream: it is guarded, and the
|
|
1120
1164
|
# termination still short-circuits the rest of the pipeline.
|
|
1121
1165
|
raise termination
|
|
1166
|
+
except MiddlewareFailure as failure:
|
|
1167
|
+
# A fail-closed abort during the pipeline descent (e.g. a retry middleware
|
|
1168
|
+
# drained an attempt whose tool seam hit a host_error block): surface the
|
|
1169
|
+
# block itself for tool-seam blocks (one deny surface at every seam). The
|
|
1170
|
+
# deferred persistence is stranded un-flushed — fail-closed.
|
|
1171
|
+
_reraise_tool_seam_block(failure)
|
|
1122
1172
|
except asyncio.CancelledError:
|
|
1123
1173
|
shutdown_reason = "cancelled"
|
|
1124
1174
|
raise
|
|
@@ -1151,6 +1201,14 @@ class _AgentHooksAgentMiddleware(_AgentHooksMiddlewareBase, AgentMiddleware):
|
|
|
1151
1201
|
except asyncio.CancelledError:
|
|
1152
1202
|
await self._emit_shutdown(state, "cancelled")
|
|
1153
1203
|
raise
|
|
1204
|
+
except MiddlewareFailure as failure:
|
|
1205
|
+
# A fail-closed abort from behind the function-invocation loop: close
|
|
1206
|
+
# the trail and, for a tool-seam host_error block, surface the block
|
|
1207
|
+
# itself (one deny surface at every seam). The deferred persistence
|
|
1208
|
+
# is dropped — denied content never becomes durable.
|
|
1209
|
+
gate_handle.drop()
|
|
1210
|
+
await self._emit_shutdown(state, "error")
|
|
1211
|
+
_reraise_tool_seam_block(failure)
|
|
1154
1212
|
except BaseException:
|
|
1155
1213
|
await self._emit_shutdown(state, "error")
|
|
1156
1214
|
raise
|
|
@@ -1164,8 +1222,6 @@ class _AgentHooksAgentMiddleware(_AgentHooksMiddlewareBase, AgentMiddleware):
|
|
|
1164
1222
|
from agent_hooks import InterceptionBlocked
|
|
1165
1223
|
|
|
1166
1224
|
try:
|
|
1167
|
-
if state.halted is not None:
|
|
1168
|
-
raise state.halted
|
|
1169
1225
|
if not isinstance(final, AgentResponse):
|
|
1170
1226
|
raise MiddlewareException(
|
|
1171
1227
|
f"agent-hooks cannot guard a streamed run result of type {type(final).__name__}; "
|
|
@@ -1323,21 +1379,20 @@ class _AgentHooksChatMiddleware(_AgentHooksMiddlewareBase, ChatMiddleware):
|
|
|
1323
1379
|
class _AgentHooksFunctionMiddleware(_AgentHooksMiddlewareBase, FunctionMiddleware):
|
|
1324
1380
|
"""Tool bracket: ``pre_tool_call`` and ``post_tool_call``."""
|
|
1325
1381
|
|
|
1326
|
-
def _block(
|
|
1327
|
-
self, state: _RunState, context: FunctionInvocationContext, exc: InterceptionBlocked, point: str
|
|
1328
|
-
) -> None:
|
|
1382
|
+
def _block(self, context: FunctionInvocationContext, exc: InterceptionBlocked, point: str) -> None:
|
|
1329
1383
|
"""Enforce a tool-seam deny: surface a tool error and, on host errors, halt the run."""
|
|
1330
1384
|
context.result = _blocked_tool_result(point, exc.result)
|
|
1331
|
-
self._maybe_halt(
|
|
1385
|
+
self._maybe_halt(exc, point)
|
|
1332
1386
|
|
|
1333
|
-
def _maybe_halt(self,
|
|
1387
|
+
def _maybe_halt(self, exc: InterceptionBlocked, point: str) -> None:
|
|
1334
1388
|
record: InterceptionRecord = exc.result
|
|
1335
1389
|
if _is_host_error(record):
|
|
1336
1390
|
# The enforcement layer itself failed (interceptor crash/timeout, invalid
|
|
1337
|
-
# context): continuing the loop would run unguarded.
|
|
1338
|
-
# agent middleware re-raises the block
|
|
1339
|
-
|
|
1340
|
-
|
|
1391
|
+
# context): continuing the loop would run unguarded. Abort the run through
|
|
1392
|
+
# the loop's fail-closed escape; the agent middleware re-raises the block
|
|
1393
|
+
# itself to the caller (the private tag is what authorizes the unwrap —
|
|
1394
|
+
# see _reraise_tool_seam_block).
|
|
1395
|
+
raise _ToolSeamBlockFailure(
|
|
1341
1396
|
f"agent-hooks {point} failed closed: {record.verdict.reason}",
|
|
1342
1397
|
) from exc
|
|
1343
1398
|
|
|
@@ -1346,21 +1401,15 @@ class _AgentHooksFunctionMiddleware(_AgentHooksMiddlewareBase, FunctionMiddlewar
|
|
|
1346
1401
|
|
|
1347
1402
|
state = _RUN_STATE.get()
|
|
1348
1403
|
if state is None:
|
|
1349
|
-
# No run state means the bundle's agent middleware never ran
|
|
1350
|
-
#
|
|
1351
|
-
#
|
|
1352
|
-
|
|
1353
|
-
# dispatched and the loop stops.
|
|
1354
|
-
message = _TRIO_REQUIRED_MESSAGE.format(seam="function")
|
|
1355
|
-
context.result = {"error": message}
|
|
1356
|
-
raise MiddlewareTermination(message)
|
|
1404
|
+
# No run state means the bundle's agent middleware never ran (a partial
|
|
1405
|
+
# install the public API makes impossible). The tool must never be
|
|
1406
|
+
# dispatched: abort the run through the loop's fail-closed escape.
|
|
1407
|
+
raise MiddlewareFailure(_TRIO_REQUIRED_MESSAGE.format(seam="function"))
|
|
1357
1408
|
if not self._shares_config(state.config):
|
|
1358
1409
|
# A different bundle owns the innermost run state (stacked bundles):
|
|
1359
|
-
# binding to it would silently misroute emissions.
|
|
1360
|
-
# fail-closed (the loop swallows plain exceptions, so route through the
|
|
1361
|
-
# halt path).
|
|
1410
|
+
# binding to it would silently misroute emissions. Abort fail-closed.
|
|
1362
1411
|
_halt_on_enforcement_failure(
|
|
1363
|
-
|
|
1412
|
+
MiddlewareException(_FOREIGN_TRIO_MESSAGE.format(seam="function")), "pre_tool_call"
|
|
1364
1413
|
)
|
|
1365
1414
|
|
|
1366
1415
|
try:
|
|
@@ -1379,23 +1428,20 @@ class _AgentHooksFunctionMiddleware(_AgentHooksMiddlewareBase, FunctionMiddlewar
|
|
|
1379
1428
|
args = effective
|
|
1380
1429
|
except InterceptionBlocked as exc:
|
|
1381
1430
|
# §6.2: the tool is not dispatched and no post_tool_call is emitted.
|
|
1382
|
-
self._block(
|
|
1431
|
+
self._block(context, exc, "pre_tool_call")
|
|
1383
1432
|
return
|
|
1384
|
-
except (MiddlewareTermination, asyncio.CancelledError):
|
|
1433
|
+
except (MiddlewareTermination, MiddlewareFailure, asyncio.CancelledError):
|
|
1385
1434
|
raise
|
|
1386
1435
|
except BaseException as exc:
|
|
1387
|
-
_halt_on_enforcement_failure(
|
|
1436
|
+
_halt_on_enforcement_failure(exc, "pre_tool_call")
|
|
1388
1437
|
|
|
1389
1438
|
termination: MiddlewareTermination | None = None
|
|
1390
1439
|
try:
|
|
1391
1440
|
await call_next()
|
|
1392
1441
|
except MiddlewareTermination as exc:
|
|
1393
|
-
if state.halted is not None or _is_approval_request(context.result):
|
|
1394
|
-
# Our own halt path, or framework approval control flow (the tool did
|
|
1395
|
-
# not run; an approved replay re-enters through pre_tool_call).
|
|
1396
|
-
raise
|
|
1397
1442
|
# A middleware short-circuited with a substituted result; that result
|
|
1398
|
-
# still enters the transcript, so it is bracketed below
|
|
1443
|
+
# still enters the transcript, so it is bracketed below (approval-request
|
|
1444
|
+
# control flow is passed through un-emitted further down instead).
|
|
1399
1445
|
termination = exc
|
|
1400
1446
|
except asyncio.CancelledError:
|
|
1401
1447
|
raise
|
|
@@ -1411,19 +1457,21 @@ class _AgentHooksFunctionMiddleware(_AgentHooksMiddlewareBase, FunctionMiddlewar
|
|
|
1411
1457
|
except InterceptionBlocked as blocked:
|
|
1412
1458
|
# A policy deny over an already-errored call changes nothing (the
|
|
1413
1459
|
# result is discarded either way); a host error still halts the run.
|
|
1414
|
-
self._maybe_halt(
|
|
1415
|
-
except asyncio.CancelledError:
|
|
1460
|
+
self._maybe_halt(blocked, "post_tool_call")
|
|
1461
|
+
except (MiddlewareTermination, MiddlewareFailure, asyncio.CancelledError):
|
|
1416
1462
|
raise
|
|
1417
1463
|
except BaseException as emit_exc:
|
|
1418
|
-
_halt_on_enforcement_failure(
|
|
1464
|
+
_halt_on_enforcement_failure(emit_exc, "post_tool_call")
|
|
1419
1465
|
raise
|
|
1420
1466
|
|
|
1421
1467
|
if _is_approval_request(context.result):
|
|
1422
|
-
# Framework approval control flow
|
|
1423
|
-
#
|
|
1424
|
-
# no result to bracket — pass the control object through un-emitted
|
|
1425
|
-
#
|
|
1426
|
-
#
|
|
1468
|
+
# Framework approval control flow (a middleware set an approval request,
|
|
1469
|
+
# whether it returned or short-circuited): the tool has not run, so there
|
|
1470
|
+
# is no result to bracket — pass the control object through un-emitted.
|
|
1471
|
+
# The approved replay re-enters through pre_tool_call. A short-circuit is
|
|
1472
|
+
# re-raised so the loop still stops and surfaces the request.
|
|
1473
|
+
if termination is not None:
|
|
1474
|
+
raise termination
|
|
1427
1475
|
return
|
|
1428
1476
|
|
|
1429
1477
|
try:
|
|
@@ -1434,11 +1482,11 @@ class _AgentHooksFunctionMiddleware(_AgentHooksMiddlewareBase, FunctionMiddlewar
|
|
|
1434
1482
|
context.result = _ToolResultCodec.write_back(context.result, value, outcome.target)
|
|
1435
1483
|
except InterceptionBlocked as exc:
|
|
1436
1484
|
# §6.1: the result must be discarded as if the call had errored.
|
|
1437
|
-
self._block(
|
|
1438
|
-
except (MiddlewareTermination, asyncio.CancelledError):
|
|
1485
|
+
self._block(context, exc, "post_tool_call")
|
|
1486
|
+
except (MiddlewareTermination, MiddlewareFailure, asyncio.CancelledError):
|
|
1439
1487
|
raise
|
|
1440
1488
|
except BaseException as exc:
|
|
1441
|
-
_halt_on_enforcement_failure(
|
|
1489
|
+
_halt_on_enforcement_failure(exc, "post_tool_call")
|
|
1442
1490
|
if termination is not None:
|
|
1443
1491
|
raise termination
|
|
1444
1492
|
|
|
@@ -56,6 +56,7 @@ from ._types import (
|
|
|
56
56
|
ChatResponseUpdate,
|
|
57
57
|
Message,
|
|
58
58
|
ResponseStream,
|
|
59
|
+
_append_instructions, # pyright: ignore[reportPrivateUsage]
|
|
59
60
|
_build_agent_response_from_chat_response, # pyright: ignore[reportPrivateUsage]
|
|
60
61
|
map_chat_to_agent_update,
|
|
61
62
|
normalize_messages,
|
|
@@ -84,6 +85,15 @@ if TYPE_CHECKING:
|
|
|
84
85
|
|
|
85
86
|
logger = logging.getLogger("agent_framework")
|
|
86
87
|
|
|
88
|
+
# AgentLoopMiddleware stamps this key into the run options while a loop
|
|
89
|
+
# iteration is running, so providers scoped to the whole user turn
|
|
90
|
+
# (``after_run_once_per_turn``) skip their per-iteration ``after_run`` and only
|
|
91
|
+
# fire once at the loop boundary. It rides the run's options rather than a
|
|
92
|
+
# context variable: options reach only the runs the loop itself drives, so a
|
|
93
|
+
# nested ``agent.run()`` (fresh options, its own session) keeps its own turn,
|
|
94
|
+
# and nothing leaks into the caller's context while a stream is paused.
|
|
95
|
+
_LOOP_ITERATION_TOKEN_KEY = "_agent_loop_iteration" # nosec B105 - a context-options key, not a credential # ruff: ignore[hardcoded-password-string]
|
|
96
|
+
|
|
87
97
|
if TYPE_CHECKING:
|
|
88
98
|
ResponseModelBoundT = TypeVar("ResponseModelBoundT", bound=BaseModel)
|
|
89
99
|
else:
|
|
@@ -159,8 +169,8 @@ def _merge_options(base: dict[str, Any], override: dict[str, Any]) -> dict[str,
|
|
|
159
169
|
# Merge metadata dicts
|
|
160
170
|
result["metadata"] = {**result["metadata"], **value}
|
|
161
171
|
elif key == "instructions" and result.get("instructions"):
|
|
162
|
-
# Concatenate instructions
|
|
163
|
-
result["instructions"] =
|
|
172
|
+
# Concatenate instructions, preserving provider-native structured values
|
|
173
|
+
result["instructions"] = _append_instructions(result["instructions"], value)
|
|
164
174
|
else:
|
|
165
175
|
result[key] = value
|
|
166
176
|
return {key: value for key, value in result.items() if value is not None}
|
|
@@ -545,6 +555,7 @@ class BaseAgent(SerializationMixin):
|
|
|
545
555
|
*,
|
|
546
556
|
session: AgentSession | None,
|
|
547
557
|
context: SessionContext,
|
|
558
|
+
only_per_turn: bool = False,
|
|
548
559
|
) -> None:
|
|
549
560
|
"""Run after_run on all context providers in reverse order.
|
|
550
561
|
|
|
@@ -557,6 +568,10 @@ class BaseAgent(SerializationMixin):
|
|
|
557
568
|
Keyword Args:
|
|
558
569
|
session: The conversation session.
|
|
559
570
|
context: The invocation context with response populated.
|
|
571
|
+
only_per_turn: When True, run only providers that opted into
|
|
572
|
+
once-per-turn semantics (``after_run_once_per_turn``); used by
|
|
573
|
+
AgentLoopMiddleware when a loop ends. When False, those
|
|
574
|
+
providers are skipped while a loop iteration is in progress.
|
|
560
575
|
"""
|
|
561
576
|
if _defer_run_persistence(partial(self._run_after_providers, session=session, context=context)):
|
|
562
577
|
return
|
|
@@ -570,9 +585,17 @@ class BaseAgent(SerializationMixin):
|
|
|
570
585
|
per_service_call_history_required = self.require_per_service_call_history_persistence and any(
|
|
571
586
|
isinstance(provider, HistoryProvider) for provider in self.context_providers
|
|
572
587
|
)
|
|
588
|
+
# The loop stamps the runs it drives via their options; anything else
|
|
589
|
+
# (nested run, caller-side run while a stream is paused) is its own turn.
|
|
590
|
+
in_loop_iteration = context.options.get(_LOOP_ITERATION_TOKEN_KEY) is not None
|
|
573
591
|
for provider in reversed(self.context_providers):
|
|
574
592
|
if per_service_call_history_required and isinstance(provider, HistoryProvider):
|
|
575
593
|
continue
|
|
594
|
+
once_per_turn = getattr(provider, "after_run_once_per_turn", False)
|
|
595
|
+
if only_per_turn and not once_per_turn:
|
|
596
|
+
continue
|
|
597
|
+
if in_loop_iteration and once_per_turn:
|
|
598
|
+
continue
|
|
576
599
|
if provider_session is None:
|
|
577
600
|
raise RuntimeError("Provider session must be available when context providers are configured.")
|
|
578
601
|
await provider.after_run(
|
|
@@ -1489,6 +1512,9 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]):
|
|
|
1489
1512
|
# _merge_options strips unset (None) options, so e.g. an unset `store` is not forwarded
|
|
1490
1513
|
# and the service decides its own default.
|
|
1491
1514
|
co = _merge_options(chat_options, run_opts)
|
|
1515
|
+
# The loop marker must remain on SessionContext.options for after_run provider
|
|
1516
|
+
# scoping, but it is framework-private metadata and must not reach the client.
|
|
1517
|
+
co.pop(_LOOP_ITERATION_TOKEN_KEY, None)
|
|
1492
1518
|
|
|
1493
1519
|
# Build session_messages from session context: context messages + input messages
|
|
1494
1520
|
session_messages: list[Message] = session_context.get_messages(include_input=True)
|
|
@@ -1623,10 +1649,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]):
|
|
|
1623
1649
|
# Merge provider-contributed instructions into chat_options
|
|
1624
1650
|
if session_context.instructions:
|
|
1625
1651
|
combined_instructions = "\n".join(session_context.instructions)
|
|
1626
|
-
|
|
1627
|
-
chat_options["instructions"] = f"{chat_options['instructions']}\n{combined_instructions}"
|
|
1628
|
-
else:
|
|
1629
|
-
chat_options["instructions"] = combined_instructions
|
|
1652
|
+
chat_options["instructions"] = _append_instructions(chat_options.get("instructions"), combined_instructions)
|
|
1630
1653
|
|
|
1631
1654
|
return session_context, chat_options
|
|
1632
1655
|
|
|
@@ -1529,6 +1529,10 @@ class CompactionProvider(ContextProvider):
|
|
|
1529
1529
|
await agent.run("Hello", session=session)
|
|
1530
1530
|
"""
|
|
1531
1531
|
|
|
1532
|
+
# Compacting persisted history mid-task rewrites the transcript the loop
|
|
1533
|
+
# still works from, so defer it to the end of the user turn.
|
|
1534
|
+
after_run_once_per_turn = True
|
|
1535
|
+
|
|
1532
1536
|
def __init__(
|
|
1533
1537
|
self,
|
|
1534
1538
|
*,
|
|
@@ -797,8 +797,7 @@ class AgentEvalConverter:
|
|
|
797
797
|
"tool_call_id": c.call_id or "",
|
|
798
798
|
"name": c.name or "",
|
|
799
799
|
}
|
|
800
|
-
if args
|
|
801
|
-
tc["arguments"] = args
|
|
800
|
+
tc["arguments"] = args if args is not None else {}
|
|
802
801
|
content_items.append(tc)
|
|
803
802
|
elif c.type == "function_result":
|
|
804
803
|
result_val = c.result
|
{agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_harness/_agent.py
RENAMED
|
@@ -24,7 +24,7 @@ from .._sessions import ContextProvider, HistoryProvider, InMemoryHistoryProvide
|
|
|
24
24
|
from .._skills import SkillsProvider
|
|
25
25
|
from .._telemetry import FeatureIndex, mark_feature_used
|
|
26
26
|
from .._types import ChatOptions
|
|
27
|
-
from ._background_agents import BackgroundAgentsProvider
|
|
27
|
+
from ._background_agents import DEFAULT_BACKGROUND_AGENTS_WAIT_TIMEOUT_SECONDS, BackgroundAgentsProvider
|
|
28
28
|
from ._file_access import AgentFileStore, FileAccessProvider, FileSystemAgentFileStore
|
|
29
29
|
from ._file_memory import FileMemoryProvider
|
|
30
30
|
from ._loop import DEFAULT_MAX_ITERATIONS, AgentLoopMiddleware
|
|
@@ -160,6 +160,7 @@ def _assemble_context_providers(
|
|
|
160
160
|
skills_paths: str | Path | Sequence[str | Path] | None,
|
|
161
161
|
background_agents: Sequence[SupportsAgentRun] | None,
|
|
162
162
|
background_agents_instructions: str | None,
|
|
163
|
+
background_agents_wait_timeout_seconds: int,
|
|
163
164
|
shell_context_provider: ContextProvider | None,
|
|
164
165
|
extra_context_providers: Sequence[ContextProvider] | None,
|
|
165
166
|
) -> list[ContextProvider]:
|
|
@@ -205,7 +206,13 @@ def _assemble_context_providers(
|
|
|
205
206
|
|
|
206
207
|
# Background agents are opt-in: only added when agents are provided.
|
|
207
208
|
if background_agents:
|
|
208
|
-
providers.append(
|
|
209
|
+
providers.append(
|
|
210
|
+
BackgroundAgentsProvider(
|
|
211
|
+
background_agents,
|
|
212
|
+
instructions=background_agents_instructions,
|
|
213
|
+
wait_timeout_seconds=background_agents_wait_timeout_seconds,
|
|
214
|
+
)
|
|
215
|
+
)
|
|
209
216
|
|
|
210
217
|
# Shell environment provider is opt-in: only added when a shell tool was wired.
|
|
211
218
|
if shell_context_provider is not None:
|
|
@@ -329,6 +336,7 @@ def create_harness_agent(
|
|
|
329
336
|
skills_paths: str | Path | Sequence[str | Path] | None = None,
|
|
330
337
|
background_agents: Sequence[SupportsAgentRun] | None = None,
|
|
331
338
|
background_agents_instructions: str | None = None,
|
|
339
|
+
background_agents_wait_timeout_seconds: int = DEFAULT_BACKGROUND_AGENTS_WAIT_TIMEOUT_SECONDS,
|
|
332
340
|
shell_executor: ShellExecutor | None = None,
|
|
333
341
|
shell_environment_provider_options: ShellEnvironmentProviderOptions | None = None,
|
|
334
342
|
disable_web_search: bool = False,
|
|
@@ -478,6 +486,10 @@ def create_harness_agent(
|
|
|
478
486
|
background_agents_instructions: Optional instruction override for the
|
|
479
487
|
``BackgroundAgentsProvider``. May include ``{background_agents}`` placeholder
|
|
480
488
|
which will be replaced with the agent listing.
|
|
489
|
+
background_agents_wait_timeout_seconds: Maximum seconds the background-agent wait
|
|
490
|
+
tool blocks for a task to complete. Must be a positive integer.
|
|
491
|
+
Defaults to 300 seconds. On expiry, the tool returns normally and leaves the
|
|
492
|
+
background tasks running. Only used when ``background_agents`` is provided.
|
|
481
493
|
shell_executor: Optional shell tool that enables shell command execution. When
|
|
482
494
|
provided, the shell tool and a ``ShellEnvironmentProvider`` are automatically
|
|
483
495
|
added (provided the client supports shell tools; otherwise a warning is logged
|
|
@@ -525,7 +537,8 @@ def create_harness_agent(
|
|
|
525
537
|
Raises:
|
|
526
538
|
ValueError: If max_context_window_tokens is provided and <= 0, or
|
|
527
539
|
max_output_tokens is provided and <= 0, or max_output_tokens >=
|
|
528
|
-
max_context_window_tokens when both are provided
|
|
540
|
+
max_context_window_tokens when both are provided, or
|
|
541
|
+
background_agents_wait_timeout_seconds is invalid when background agents are provided.
|
|
529
542
|
"""
|
|
530
543
|
if max_context_window_tokens is not None and max_context_window_tokens <= 0:
|
|
531
544
|
raise ValueError("max_context_window_tokens must be positive.")
|
|
@@ -601,6 +614,7 @@ def create_harness_agent(
|
|
|
601
614
|
skills_paths=skills_paths,
|
|
602
615
|
background_agents=background_agents,
|
|
603
616
|
background_agents_instructions=background_agents_instructions,
|
|
617
|
+
background_agents_wait_timeout_seconds=background_agents_wait_timeout_seconds,
|
|
604
618
|
shell_context_provider=shell_provider,
|
|
605
619
|
extra_context_providers=context_providers,
|
|
606
620
|
)
|
{agent_framework_core-1.14.0 → agent_framework_core-1.16.0}/agent_framework/_harness/_agent.pyi
RENAMED
|
@@ -14,6 +14,7 @@ from .._sessions import ContextProvider, HistoryProvider
|
|
|
14
14
|
from .._skills import SkillsProvider
|
|
15
15
|
from .._tools import ToolTypes
|
|
16
16
|
from .._types import ChatOptions
|
|
17
|
+
from ._background_agents import DEFAULT_BACKGROUND_AGENTS_WAIT_TIMEOUT_SECONDS
|
|
17
18
|
from ._file_access import AgentFileStore
|
|
18
19
|
from ._loop import DEFAULT_MAX_ITERATIONS, NextMessageCallable, ShouldContinueCallable
|
|
19
20
|
from ._mode import AgentModeProvider
|
|
@@ -77,6 +78,7 @@ def create_harness_agent(
|
|
|
77
78
|
skills_paths: str | Path | Sequence[str | Path] | None = None,
|
|
78
79
|
background_agents: Sequence[SupportsAgentRun] | None = None,
|
|
79
80
|
background_agents_instructions: str | None = None,
|
|
81
|
+
background_agents_wait_timeout_seconds: int = DEFAULT_BACKGROUND_AGENTS_WAIT_TIMEOUT_SECONDS,
|
|
80
82
|
shell_executor: _ShellExecutorLike | None = None,
|
|
81
83
|
shell_environment_provider_options: _ShellEnvironmentProviderOptionsLike | None = None,
|
|
82
84
|
disable_web_search: bool = False,
|