agstack 2.4.0__tar.gz → 3.0.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.
- {agstack-2.4.0 → agstack-3.0.0}/PKG-INFO +6 -9
- {agstack-2.4.0 → agstack-3.0.0}/README.md +5 -8
- agstack-3.0.0/agstack/genai/__init__.py +10 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/agent.py +61 -1
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/nodes/detect_node.py +1 -1
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/nodes/echo_node.py +3 -3
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/nodes/llm_chat_node.py +1 -1
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/nodes/llm_embed_node.py +1 -1
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/nodes/llm_rerank_node.py +1 -1
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/registry.py +1 -1
- agstack-3.0.0/agstack/genai/harness/__init__.py +120 -0
- agstack-3.0.0/agstack/genai/harness/context.py +411 -0
- agstack-3.0.0/agstack/genai/harness/overflow.py +130 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/harness/ports.py +2 -2
- {agstack-2.4.0/agstack → agstack-3.0.0/agstack/genai}/llm/client.py +3 -3
- {agstack-2.4.0/agstack → agstack-3.0.0/agstack/genai}/llm/hooks.py +2 -2
- {agstack-2.4.0 → agstack-3.0.0}/agstack.egg-info/PKG-INFO +6 -9
- agstack-3.0.0/agstack.egg-info/SOURCES.txt +102 -0
- {agstack-2.4.0 → agstack-3.0.0}/pyproject.toml +1 -1
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_agent_guards.py +14 -14
- agstack-3.0.0/tests/test_agent_overflow.py +203 -0
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_agent_parallel_tools.py +9 -9
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_agent_request_overrides.py +6 -6
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_flow_cancellation.py +9 -9
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_flow_error_semantics.py +16 -16
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_flow_io.py +30 -30
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_flow_iterator.py +11 -11
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_flow_switch_subflow.py +8 -8
- agstack-3.0.0/tests/test_harness_context.py +224 -0
- agstack-2.4.0/tests/test_harness_events_projection_tokens.py → agstack-3.0.0/tests/test_harness_events_projection_metering.py +5 -5
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_harness_ports_truncation.py +4 -4
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_harness_spill.py +3 -3
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_llm_call_hooks.py +3 -3
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_llm_usage_callback.py +2 -2
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_tool_hooks.py +6 -6
- agstack-2.4.0/agstack/llm/harness/__init__.py +0 -71
- agstack-2.4.0/agstack.egg-info/SOURCES.txt +0 -97
- {agstack-2.4.0 → agstack-3.0.0}/LICENSE +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/__init__.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/cache/__init__.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/cache/base.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/cache/memory.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/cache/redis.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/config/__init__.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/config/logger.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/config/manager.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/config/types.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/contexts.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/decorators.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/events.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/exceptions.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/fastapi/__init__.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/fastapi/exception.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/fastapi/middleware.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/fastapi/offline.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/fastapi/sse.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/__init__.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/context.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/event.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/exceptions.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/factory.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/flow.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/guards.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/loader.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/nodes/__init__.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/nodes/agent_node.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/nodes/base.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/nodes/iterator_node.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/nodes/python_node.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/nodes/subflow_node.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/nodes/switch_node.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/nodes/tool_node.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/records.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/sandbox.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/state.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/tool.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/flow/trace.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/harness/events.py +0 -0
- /agstack-2.4.0/agstack/llm/harness/tokens.py → /agstack-3.0.0/agstack/genai/harness/metering.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/harness/projection.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/harness/spill.py +0 -0
- {agstack-2.4.0/agstack/llm → agstack-3.0.0/agstack/genai}/harness/truncation.py +0 -0
- {agstack-2.4.0/agstack → agstack-3.0.0/agstack/genai}/llm/__init__.py +0 -0
- {agstack-2.4.0/agstack → agstack-3.0.0/agstack/genai}/llm/prompts.py +0 -0
- {agstack-2.4.0/agstack → agstack-3.0.0/agstack/genai}/llm/token.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/infra/db/__init__.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/infra/es/__init__.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/infra/kg/__init__.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/infra/mq/__init__.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/messagebus/__init__.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/messagebus/base.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/messagebus/memory.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/messagebus/redis.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/schema.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/security/__init__.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/security/casbin.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/security/crypt.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack/status.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack.egg-info/dependency_links.txt +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack.egg-info/requires.txt +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/agstack.egg-info/top_level.txt +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/setup.cfg +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_cache_memory.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_cache_redis.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_messagebus_memory.py +0 -0
- {agstack-2.4.0 → agstack-3.0.0}/tests/test_messagebus_redis.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agstack
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: Production-ready toolkit for building FastAPI and LLM applications
|
|
5
5
|
Author-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
|
|
6
6
|
Maintainer-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
|
|
@@ -86,7 +86,7 @@ pip install agstack
|
|
|
86
86
|
### Basic Usage
|
|
87
87
|
|
|
88
88
|
```python
|
|
89
|
-
from agstack.
|
|
89
|
+
from agstack.genai.flow import (
|
|
90
90
|
Tool,
|
|
91
91
|
FlowContext,
|
|
92
92
|
registry,
|
|
@@ -130,13 +130,10 @@ agstack/
|
|
|
130
130
|
├── schema.py # Base Pydantic models
|
|
131
131
|
├── registry.py # Global component registry
|
|
132
132
|
├── exceptions.py # Exception hierarchy
|
|
133
|
-
├──
|
|
134
|
-
│ ├──
|
|
135
|
-
│
|
|
136
|
-
│
|
|
137
|
-
│ ├── tool.py # Tool definition
|
|
138
|
-
│ ├── flow.py # Flow orchestration
|
|
139
|
-
│ └── ...
|
|
133
|
+
├── genai/ # Generative AI, three one-way layers
|
|
134
|
+
│ ├── llm/ # Model access: client, call hooks, prompts, token counting
|
|
135
|
+
│ ├── flow/ # Flow execution framework (agent / tool / flow / nodes / guards)
|
|
136
|
+
│ └── harness/ # Runtime: ports, events, projection, metering, overflow, context, spill
|
|
140
137
|
├── fastapi/ # FastAPI integration
|
|
141
138
|
├── infra/ # Infrastructure components
|
|
142
139
|
│ ├── db/ # Database
|
|
@@ -28,7 +28,7 @@ pip install agstack
|
|
|
28
28
|
### Basic Usage
|
|
29
29
|
|
|
30
30
|
```python
|
|
31
|
-
from agstack.
|
|
31
|
+
from agstack.genai.flow import (
|
|
32
32
|
Tool,
|
|
33
33
|
FlowContext,
|
|
34
34
|
registry,
|
|
@@ -72,13 +72,10 @@ agstack/
|
|
|
72
72
|
├── schema.py # Base Pydantic models
|
|
73
73
|
├── registry.py # Global component registry
|
|
74
74
|
├── exceptions.py # Exception hierarchy
|
|
75
|
-
├──
|
|
76
|
-
│ ├──
|
|
77
|
-
│
|
|
78
|
-
│
|
|
79
|
-
│ ├── tool.py # Tool definition
|
|
80
|
-
│ ├── flow.py # Flow orchestration
|
|
81
|
-
│ └── ...
|
|
75
|
+
├── genai/ # Generative AI, three one-way layers
|
|
76
|
+
│ ├── llm/ # Model access: client, call hooks, prompts, token counting
|
|
77
|
+
│ ├── flow/ # Flow execution framework (agent / tool / flow / nodes / guards)
|
|
78
|
+
│ └── harness/ # Runtime: ports, events, projection, metering, overflow, context, spill
|
|
82
79
|
├── fastapi/ # FastAPI integration
|
|
83
80
|
├── infra/ # Infrastructure components
|
|
84
81
|
│ ├── db/ # Database
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Copyright (c) 2020-2026 XtraVisions, All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""agstack.genai——生成式 AI 三层(3.0)
|
|
4
|
+
|
|
5
|
+
- :mod:`.llm`:模型接入(client / hooks / prompts / token),不依赖另外两层;
|
|
6
|
+
- :mod:`.flow`:编排(Agent / Tool / Flow / nodes / guards),依赖 llm;
|
|
7
|
+
- :mod:`.harness`:运行时纪律(ports / events / projection / metering / context / overflow / spill),依赖 llm 与 flow。
|
|
8
|
+
|
|
9
|
+
依赖单向、不成环;应用对本包的依赖应集中在一处适配层。
|
|
10
|
+
"""
|
|
@@ -7,7 +7,8 @@ import json
|
|
|
7
7
|
from typing import TYPE_CHECKING, Any, AsyncIterator
|
|
8
8
|
from uuid import uuid4
|
|
9
9
|
|
|
10
|
-
from ..
|
|
10
|
+
from ..harness.overflow import OverflowPolicy, classify_overflow, usage_tokens
|
|
11
|
+
from ..llm.client import get_llm_client
|
|
11
12
|
from . import event
|
|
12
13
|
from .context import Usage
|
|
13
14
|
from .event import EventType
|
|
@@ -22,6 +23,9 @@ if TYPE_CHECKING:
|
|
|
22
23
|
class Agent:
|
|
23
24
|
"""Agent 定义"""
|
|
24
25
|
|
|
26
|
+
#: 上下文溢出恢复策略(harness.overflow;None 不恢复)。子类可按类属性给缺省,构造参数 ``overflow`` 覆盖
|
|
27
|
+
overflow: OverflowPolicy | None = None
|
|
28
|
+
|
|
25
29
|
def __init__(
|
|
26
30
|
self,
|
|
27
31
|
name: str,
|
|
@@ -37,6 +41,7 @@ class Agent:
|
|
|
37
41
|
retry_empty_response: bool = False,
|
|
38
42
|
label: str | None = None,
|
|
39
43
|
echo: bool = False,
|
|
44
|
+
overflow: OverflowPolicy | None = None,
|
|
40
45
|
):
|
|
41
46
|
"""初始化 Agent
|
|
42
47
|
|
|
@@ -52,6 +57,7 @@ class Agent:
|
|
|
52
57
|
以 ``request_overrides(..., retry=True)`` 的覆盖参数重试一次
|
|
53
58
|
:param label: 面向用户的展示名称(控制 STEP 进度事件可见性)
|
|
54
59
|
:param echo: 是否转发 TEXT_MESSAGE 给用户
|
|
60
|
+
:param overflow: 上下文溢出恢复策略(三态判定命中后调 ``compact`` 压缩并同轮重发一次,见 harness.overflow)
|
|
55
61
|
"""
|
|
56
62
|
self.name = name
|
|
57
63
|
self.instructions = instructions or f"You are {name}, a helpful AI assistant."
|
|
@@ -65,6 +71,8 @@ class Agent:
|
|
|
65
71
|
self.retry_empty_response = retry_empty_response
|
|
66
72
|
self.label = label
|
|
67
73
|
self.echo = echo
|
|
74
|
+
if overflow is not None:
|
|
75
|
+
self.overflow = overflow
|
|
68
76
|
|
|
69
77
|
def get_system_message(self) -> dict[str, Any]:
|
|
70
78
|
"""获取系统消息"""
|
|
@@ -102,6 +110,25 @@ class Agent:
|
|
|
102
110
|
return tool
|
|
103
111
|
return None
|
|
104
112
|
|
|
113
|
+
# ── 溢出恢复(机制;策略在 self.overflow) ──
|
|
114
|
+
|
|
115
|
+
def _max_recoveries(self) -> int:
|
|
116
|
+
return self.overflow.max_recoveries if self.overflow is not None else 0
|
|
117
|
+
|
|
118
|
+
def _overflow_kind(self, context: "FlowContext", *, error: BaseException | None = None, **usage: Any) -> str | None:
|
|
119
|
+
if self.overflow is None:
|
|
120
|
+
return None
|
|
121
|
+
if error is not None:
|
|
122
|
+
return classify_overflow(error=error)
|
|
123
|
+
return classify_overflow(context_length=self.overflow.window(context), **usage)
|
|
124
|
+
|
|
125
|
+
async def _compact_overflow(self, context: "FlowContext", kind: str) -> bool:
|
|
126
|
+
assert self.overflow is not None
|
|
127
|
+
try:
|
|
128
|
+
return bool(await self.overflow.compact(context, kind))
|
|
129
|
+
except Exception: # noqa: BLE001 — 压缩失败不替代原错误,按原路报错
|
|
130
|
+
return False
|
|
131
|
+
|
|
105
132
|
def _group_tool_calls(self, tool_calls: list[dict[str, Any]]) -> list[list[dict[str, Any]]]:
|
|
106
133
|
"""按声明分组:连续的 concurrency_safe 调用聚为一组并发执行,其余单独成组串行
|
|
107
134
|
|
|
@@ -290,6 +317,7 @@ class Agent:
|
|
|
290
317
|
|
|
291
318
|
# Agent 循环
|
|
292
319
|
assistant_content = ""
|
|
320
|
+
recoveries = 0 # 溢出恢复次数(每次运行上限 overflow.max_recoveries)
|
|
293
321
|
for turn in range(1, self.max_turns + 1):
|
|
294
322
|
# 协作式取消检查点:不再开始新的 LLM 轮次
|
|
295
323
|
if context.is_cancelled:
|
|
@@ -306,6 +334,8 @@ class Agent:
|
|
|
306
334
|
assistant_content = ""
|
|
307
335
|
tool_calls: list[dict[str, Any]] = []
|
|
308
336
|
tool_calls_buffer: dict[int, dict[str, Any]] = {}
|
|
337
|
+
finish_reason: str | None = None
|
|
338
|
+
turn_usage: Any = None
|
|
309
339
|
|
|
310
340
|
try:
|
|
311
341
|
kwargs: dict[str, Any] = {
|
|
@@ -362,6 +392,7 @@ class Agent:
|
|
|
362
392
|
|
|
363
393
|
# 完成
|
|
364
394
|
if choice.finish_reason:
|
|
395
|
+
finish_reason = choice.finish_reason
|
|
365
396
|
# AG-UI: 工具调用事件
|
|
366
397
|
for tool_call_data in tool_calls_buffer.values():
|
|
367
398
|
tool_calls.append(tool_call_data)
|
|
@@ -383,6 +414,7 @@ class Agent:
|
|
|
383
414
|
|
|
384
415
|
# 更新 usage
|
|
385
416
|
if hasattr(chunk, "usage") and chunk.usage:
|
|
417
|
+
turn_usage = chunk.usage
|
|
386
418
|
context.add_usage(
|
|
387
419
|
Usage(
|
|
388
420
|
prompt_tokens=chunk.usage.prompt_tokens or 0,
|
|
@@ -392,11 +424,39 @@ class Agent:
|
|
|
392
424
|
)
|
|
393
425
|
|
|
394
426
|
except Exception as e:
|
|
427
|
+
# 上下文溢出(后端报错态):尚未放出任何内容时压缩并同轮重发一次(harness.overflow)
|
|
428
|
+
kind = self._overflow_kind(context, error=e) if not assistant_content and not tool_calls else None
|
|
429
|
+
if kind and recoveries < self._max_recoveries():
|
|
430
|
+
recoveries += 1
|
|
431
|
+
yield event.custom(
|
|
432
|
+
name="agent_overflow", value={"agentName": self.name, "kind": kind, "turn": turn}
|
|
433
|
+
)
|
|
434
|
+
if await self._compact_overflow(context, kind):
|
|
435
|
+
messages = [self.get_system_message()] + context.history + context.get_messages(self.name)
|
|
436
|
+
continue
|
|
395
437
|
error_msg = str(e)
|
|
396
438
|
# AG-UI: RUN_ERROR
|
|
397
439
|
yield event.run_error(message=error_msg)
|
|
398
440
|
raise FlowError("AGENT_EXECUTION_FAILED", 500, {"error": error_msg}) from e
|
|
399
441
|
|
|
442
|
+
# 上下文溢出(静默 / length 态):请求成功但输入已撑爆窗口且本次没有产出,同样压缩重发一次
|
|
443
|
+
if not tool_calls and not assistant_content.strip():
|
|
444
|
+
prompt_tokens, completion_tokens = usage_tokens(turn_usage)
|
|
445
|
+
kind = self._overflow_kind(
|
|
446
|
+
context,
|
|
447
|
+
finish_reason=finish_reason,
|
|
448
|
+
prompt_tokens=prompt_tokens,
|
|
449
|
+
completion_tokens=completion_tokens,
|
|
450
|
+
)
|
|
451
|
+
if kind and recoveries < self._max_recoveries():
|
|
452
|
+
recoveries += 1
|
|
453
|
+
yield event.custom(
|
|
454
|
+
name="agent_overflow", value={"agentName": self.name, "kind": kind, "turn": turn}
|
|
455
|
+
)
|
|
456
|
+
if await self._compact_overflow(context, kind):
|
|
457
|
+
messages = [self.get_system_message()] + context.history + context.get_messages(self.name)
|
|
458
|
+
continue
|
|
459
|
+
|
|
400
460
|
if self.retry_empty_response and attempt == 0 and not tool_calls and not assistant_content.strip():
|
|
401
461
|
attempt = 1
|
|
402
462
|
continue
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
from typing import TYPE_CHECKING, Any, AsyncIterator
|
|
6
6
|
from uuid import uuid4
|
|
7
7
|
|
|
8
|
-
from agstack.
|
|
9
|
-
from agstack.
|
|
8
|
+
from agstack.genai.flow import event
|
|
9
|
+
from agstack.genai.flow.nodes.base import NodeHandler
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
if TYPE_CHECKING:
|
|
13
|
-
from agstack.
|
|
13
|
+
from agstack.genai.flow.context import FlowContext
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class EchoNodeHandler(NodeHandler):
|
|
@@ -7,7 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
import copy
|
|
8
8
|
from typing import Any, cast
|
|
9
9
|
|
|
10
|
-
from ..hooks import LLMCallHook, clear_llm_hooks, register_llm_hook
|
|
10
|
+
from ..llm.hooks import LLMCallHook, clear_llm_hooks, register_llm_hook
|
|
11
11
|
from .agent import Agent
|
|
12
12
|
from .tool import Tool, ToolHook, clear_tool_hooks, register_tool_hook
|
|
13
13
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Copyright (c) 2020-2026 XtraVisions, All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""agstack.genai.harness——模型无关、表无关、产品无关的运行时部件
|
|
4
|
+
|
|
5
|
+
- :mod:`.ports`:存储端口声明(SessionLog / SpillStore / UsageSink / KVStore)与 ``register_ports``,
|
|
6
|
+
由应用实现并在进程入口注册;
|
|
7
|
+
- :mod:`.truncation`:工具结果截断设施(保头尾截断、按相关度整条丢弃),策略数值由调用方给;
|
|
8
|
+
- :mod:`.spill`:超长工具结果落盘的 ToolHook(prepend 链头、按内联 token 上限判定、头尾保留 + 固定格式通知、
|
|
9
|
+
存储失败保留内联);
|
|
10
|
+
- :mod:`.events`(2.4):任务事件枢纽 EventHub(序号 / 快照 / 订阅 / 重放,持久化由应用注入)与「flow 事件 → 用户可见
|
|
11
|
+
事件」过滤规则表;
|
|
12
|
+
- :mod:`.projection`(2.4):「日志 → 模型历史」投影引擎(遮蔽过滤 / 事件投影 / 正文改写 / 注记 / 同角色合并,
|
|
13
|
+
规则由应用给);
|
|
14
|
+
- :mod:`.metering`(2.4,原 tokens):估算校准(实报 / 估算钳制)与锚点增量计量;
|
|
15
|
+
- :mod:`.context`(3.0):对话上下文压缩引擎 ContextEngine(预算分层 / 快速路径 / 锚点计量 / 摘要消费与后台刷新 /
|
|
16
|
+
两遍装填),历史来源与摘要存取经 HistorySource / SummaryStore 由应用实现;
|
|
17
|
+
- :mod:`.overflow`(3.0):上下文溢出三态判定与 ``OverflowPolicy``(``Agent.stream`` 命中后调应用的压缩协程并
|
|
18
|
+
同轮重发一次)。
|
|
19
|
+
|
|
20
|
+
LLM 调用钩子 :mod:`agstack.genai.llm.hooks`(F6)留在 llm 包——它织入 LLMClient,client 不能反向依赖 harness——
|
|
21
|
+
这里重导出。Agent 守卫机制(AgentGuards)在 :mod:`agstack.genai.flow.guards`。
|
|
22
|
+
3.0 起 llm / flow / harness 收为 ``agstack.genai`` 三层,``agstack.genai.llm`` 只留模型接入(client / hooks / prompts /
|
|
23
|
+
token);2.x 的 ``agstack.llm`` 系路径不再保留(破坏性变更,随 major)。
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from ..llm.hooks import CallMeta, LLMCallHook, StreamSummary, clear_llm_hooks, register_llm_hook
|
|
27
|
+
from .context import (
|
|
28
|
+
ContextEngine,
|
|
29
|
+
ContextPolicy,
|
|
30
|
+
HistorySource,
|
|
31
|
+
SummaryRecord,
|
|
32
|
+
SummaryStore,
|
|
33
|
+
anchored_history_tokens,
|
|
34
|
+
fill_to_budget,
|
|
35
|
+
messages_tokens,
|
|
36
|
+
schedule_once,
|
|
37
|
+
)
|
|
38
|
+
from .events import EventHub, TaskSnapshot, filter_user_event
|
|
39
|
+
from .metering import CalibratedCounter, anchored_estimate, calibration_from_samples, calibration_sample, clamp_ratio
|
|
40
|
+
from .overflow import (
|
|
41
|
+
OVERFLOW_ERROR,
|
|
42
|
+
OVERFLOW_LENGTH,
|
|
43
|
+
OVERFLOW_RECORD,
|
|
44
|
+
OVERFLOW_SILENT,
|
|
45
|
+
OverflowPolicy,
|
|
46
|
+
classify_overflow,
|
|
47
|
+
usage_tokens,
|
|
48
|
+
)
|
|
49
|
+
from .ports import (
|
|
50
|
+
KVStore,
|
|
51
|
+
LogEvent,
|
|
52
|
+
Ports,
|
|
53
|
+
SessionLog,
|
|
54
|
+
SpillOwner,
|
|
55
|
+
SpillRef,
|
|
56
|
+
SpillSource,
|
|
57
|
+
SpillStore,
|
|
58
|
+
TokenAnchor,
|
|
59
|
+
UsageSink,
|
|
60
|
+
clear_ports,
|
|
61
|
+
get_ports,
|
|
62
|
+
register_ports,
|
|
63
|
+
)
|
|
64
|
+
from .projection import Projection, is_shadowed, merge_consecutive, select_recent
|
|
65
|
+
from .spill import SpillHook, SpillPolicy
|
|
66
|
+
from .truncation import clamp_results, truncate_middle
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
__all__ = [
|
|
70
|
+
"ContextEngine",
|
|
71
|
+
"ContextPolicy",
|
|
72
|
+
"HistorySource",
|
|
73
|
+
"SummaryRecord",
|
|
74
|
+
"SummaryStore",
|
|
75
|
+
"anchored_history_tokens",
|
|
76
|
+
"fill_to_budget",
|
|
77
|
+
"messages_tokens",
|
|
78
|
+
"schedule_once",
|
|
79
|
+
"CallMeta",
|
|
80
|
+
"LLMCallHook",
|
|
81
|
+
"StreamSummary",
|
|
82
|
+
"clear_llm_hooks",
|
|
83
|
+
"register_llm_hook",
|
|
84
|
+
"OVERFLOW_ERROR",
|
|
85
|
+
"OVERFLOW_LENGTH",
|
|
86
|
+
"OVERFLOW_RECORD",
|
|
87
|
+
"OVERFLOW_SILENT",
|
|
88
|
+
"CalibratedCounter",
|
|
89
|
+
"EventHub",
|
|
90
|
+
"OverflowPolicy",
|
|
91
|
+
"Projection",
|
|
92
|
+
"classify_overflow",
|
|
93
|
+
"usage_tokens",
|
|
94
|
+
"TaskSnapshot",
|
|
95
|
+
"anchored_estimate",
|
|
96
|
+
"calibration_from_samples",
|
|
97
|
+
"calibration_sample",
|
|
98
|
+
"clamp_ratio",
|
|
99
|
+
"filter_user_event",
|
|
100
|
+
"is_shadowed",
|
|
101
|
+
"merge_consecutive",
|
|
102
|
+
"select_recent",
|
|
103
|
+
"KVStore",
|
|
104
|
+
"LogEvent",
|
|
105
|
+
"Ports",
|
|
106
|
+
"SessionLog",
|
|
107
|
+
"SpillHook",
|
|
108
|
+
"SpillOwner",
|
|
109
|
+
"SpillPolicy",
|
|
110
|
+
"SpillRef",
|
|
111
|
+
"SpillSource",
|
|
112
|
+
"SpillStore",
|
|
113
|
+
"TokenAnchor",
|
|
114
|
+
"UsageSink",
|
|
115
|
+
"clamp_results",
|
|
116
|
+
"clear_ports",
|
|
117
|
+
"get_ports",
|
|
118
|
+
"register_ports",
|
|
119
|
+
"truncate_middle",
|
|
120
|
+
]
|