agstack 1.21.1__tar.gz → 1.22.1__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-1.21.1 → agstack-1.22.1}/PKG-INFO +3 -1
- {agstack-1.21.1 → agstack-1.22.1}/agstack/config/manager.py +47 -11
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/event.py +4 -4
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/flow.py +12 -8
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/nodes/agent_node.py +4 -2
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/nodes/base.py +4 -2
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/nodes/echo_node.py +3 -2
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/nodes/llm_chat_node.py +6 -4
- {agstack-1.21.1 → agstack-1.22.1}/agstack.egg-info/PKG-INFO +3 -1
- {agstack-1.21.1 → agstack-1.22.1}/agstack.egg-info/requires.txt +3 -0
- {agstack-1.21.1 → agstack-1.22.1}/pyproject.toml +2 -1
- {agstack-1.21.1 → agstack-1.22.1}/LICENSE +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/README.md +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/__init__.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/cache/__init__.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/cache/base.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/cache/memory.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/cache/redis.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/config/__init__.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/config/logger.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/config/types.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/contexts.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/decorators.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/events.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/exceptions.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/fastapi/__init__.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/fastapi/exception.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/fastapi/middleware.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/fastapi/offline.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/fastapi/sse.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/infra/db/__init__.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/infra/es/__init__.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/infra/kg/__init__.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/infra/mq/__init__.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/__init__.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/client.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/__init__.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/agent.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/context.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/exceptions.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/factory.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/loader.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/nodes/__init__.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/nodes/detect_node.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/nodes/llm_embed_node.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/nodes/llm_rerank_node.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/nodes/python_node.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/nodes/subflow_node.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/nodes/switch_node.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/nodes/tool_node.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/records.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/registry.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/sandbox.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/state.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/tool.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/flow/trace.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/prompts.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/llm/token.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/messagebus/__init__.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/messagebus/base.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/messagebus/memory.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/messagebus/redis.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/schema.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/security/__init__.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/security/casbin.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/security/crypt.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack/status.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack.egg-info/SOURCES.txt +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack.egg-info/dependency_links.txt +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/agstack.egg-info/top_level.txt +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/setup.cfg +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/tests/test_cache_memory.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/tests/test_cache_redis.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/tests/test_flow_io.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/tests/test_flow_switch_subflow.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/tests/test_messagebus_memory.py +0 -0
- {agstack-1.21.1 → agstack-1.22.1}/tests/test_messagebus_redis.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agstack
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.22.1
|
|
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>
|
|
@@ -43,6 +43,8 @@ Provides-Extra: graph
|
|
|
43
43
|
Requires-Dist: nebula3-python>=3.8.3; extra == "graph"
|
|
44
44
|
Provides-Extra: redis
|
|
45
45
|
Requires-Dist: redis>=5.0; extra == "redis"
|
|
46
|
+
Provides-Extra: yaml
|
|
47
|
+
Requires-Dist: pyyaml>=6.0; extra == "yaml"
|
|
46
48
|
Provides-Extra: std
|
|
47
49
|
Requires-Dist: agstack[mq]; extra == "std"
|
|
48
50
|
Requires-Dist: agstack[db]; extra == "std"
|
|
@@ -10,14 +10,42 @@ from .logger import setup_logger
|
|
|
10
10
|
from .types import AppConfig
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
_CONFIG_CANDIDATES = ("config.toml", "config.yaml", "config.yml")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _find_config_file(approot: Path) -> Path:
|
|
17
|
+
"""按优先级查找配置文件"""
|
|
18
|
+
for name in _CONFIG_CANDIDATES:
|
|
19
|
+
path = approot / name
|
|
20
|
+
if path.exists():
|
|
21
|
+
return path
|
|
22
|
+
return approot / "config.toml"
|
|
23
|
+
|
|
24
|
+
|
|
13
25
|
def _load_config_file(config_path: Path) -> dict[str, Any]:
|
|
14
|
-
"""
|
|
26
|
+
"""加载配置文件(支持 TOML 和 YAML 格式)"""
|
|
15
27
|
if not config_path.exists():
|
|
16
28
|
return {}
|
|
17
29
|
|
|
30
|
+
suffix = config_path.suffix.lower()
|
|
18
31
|
try:
|
|
19
|
-
|
|
20
|
-
|
|
32
|
+
if suffix == ".toml":
|
|
33
|
+
with open(config_path, "rb") as f:
|
|
34
|
+
return tomllib.load(f)
|
|
35
|
+
elif suffix in (".yaml", ".yml"):
|
|
36
|
+
try:
|
|
37
|
+
import yaml
|
|
38
|
+
except ImportError as err:
|
|
39
|
+
raise ImportError(
|
|
40
|
+
f"PyYAML is required to load {config_path}. Install it with: pip install agstack[yaml]"
|
|
41
|
+
) from err
|
|
42
|
+
with open(config_path) as f:
|
|
43
|
+
return yaml.safe_load(f) or {}
|
|
44
|
+
else:
|
|
45
|
+
print(f"Unsupported config format: {suffix}")
|
|
46
|
+
return {}
|
|
47
|
+
except ImportError:
|
|
48
|
+
raise
|
|
21
49
|
except Exception: # noqa
|
|
22
50
|
print(f"Failed to load config file: {config_path}")
|
|
23
51
|
return {}
|
|
@@ -95,37 +123,45 @@ def _determine_log_level(config_data: dict[str, Any]) -> str:
|
|
|
95
123
|
return config_data.get("logger", {}).get("level", "INFO")
|
|
96
124
|
|
|
97
125
|
|
|
98
|
-
def setup_config(appname: str, envprefix: str = "APP") -> AppConfig:
|
|
126
|
+
def setup_config(appname: str, envprefix: str = "APP", config_file: str | Path | None = None) -> AppConfig:
|
|
99
127
|
"""初始化配置
|
|
100
128
|
|
|
101
129
|
Args:
|
|
102
130
|
appname: 应用名称
|
|
103
131
|
envprefix: 环境变量前缀
|
|
132
|
+
config_file: 配置文件路径(支持 .toml / .yaml / .yml),为 None 时自动查找
|
|
104
133
|
|
|
105
134
|
Returns:
|
|
106
135
|
AppConfig: 配置实例
|
|
107
136
|
"""
|
|
108
137
|
approot = Path.cwd()
|
|
109
|
-
config_path = approot / "config.toml"
|
|
110
138
|
|
|
111
|
-
# 1.
|
|
139
|
+
# 1. 确定配置文件路径
|
|
140
|
+
if config_file:
|
|
141
|
+
config_path = Path(config_file)
|
|
142
|
+
if not config_path.is_absolute():
|
|
143
|
+
config_path = approot / config_path
|
|
144
|
+
else:
|
|
145
|
+
config_path = _find_config_file(approot)
|
|
146
|
+
|
|
147
|
+
# 2. 加载配置文件(容错)
|
|
112
148
|
config_data = _load_config_file(config_path)
|
|
113
149
|
|
|
114
|
-
#
|
|
150
|
+
# 3. 加载环境变量覆盖
|
|
115
151
|
env_overrides = _load_env_overrides(envprefix)
|
|
116
152
|
config_data.update(env_overrides)
|
|
117
153
|
|
|
118
|
-
#
|
|
154
|
+
# 4. 设置应用信息
|
|
119
155
|
config_data.update({"appname": appname, "approot": approot})
|
|
120
156
|
|
|
121
|
-
#
|
|
157
|
+
# 5. 确定日志级别(优先级处理)
|
|
122
158
|
log_level = _determine_log_level(config_data)
|
|
123
159
|
config_data.setdefault("logger", {})["level"] = log_level
|
|
124
160
|
|
|
125
|
-
#
|
|
161
|
+
# 6. 初始化日志(使用字典配置)
|
|
126
162
|
setup_logger(appname, **config_data["logger"])
|
|
127
163
|
|
|
128
|
-
#
|
|
164
|
+
# 7. 创建配置实例(最后验证)
|
|
129
165
|
config = AppConfig.model_validate(config_data)
|
|
130
166
|
|
|
131
167
|
return config
|
|
@@ -97,12 +97,12 @@ def run_error(*, message: str, code: str | None = None) -> dict[str, Any]:
|
|
|
97
97
|
# ── Step ──
|
|
98
98
|
|
|
99
99
|
|
|
100
|
-
def step_started(*, step_name: str) -> dict[str, Any]:
|
|
101
|
-
return _ev(EventType.STEP_STARTED, step_name=step_name)
|
|
100
|
+
def step_started(*, step_name: str, step_id: str | None = None) -> dict[str, Any]:
|
|
101
|
+
return _ev(EventType.STEP_STARTED, step_name=step_name, step_id=step_id or str(uuid4()))
|
|
102
102
|
|
|
103
103
|
|
|
104
|
-
def step_finished(*, step_name: str) -> dict[str, Any]:
|
|
105
|
-
return _ev(EventType.STEP_FINISHED, step_name=step_name)
|
|
104
|
+
def step_finished(*, step_name: str, step_id: str) -> dict[str, Any]:
|
|
105
|
+
return _ev(EventType.STEP_FINISHED, step_name=step_name, step_id=step_id)
|
|
106
106
|
|
|
107
107
|
|
|
108
108
|
# ── State ──
|
|
@@ -370,7 +370,8 @@ class Flow:
|
|
|
370
370
|
async def stream(self, context: "FlowContext") -> AsyncIterator[dict[str, Any]]:
|
|
371
371
|
"""流式执行 Flow(输出 AG-UI 标准事件)"""
|
|
372
372
|
context.trace.started_at = time.time()
|
|
373
|
-
|
|
373
|
+
flow_sid = str(uuid4())
|
|
374
|
+
yield event.step_started(step_name=f"flow:{self.name}", step_id=flow_sid)
|
|
374
375
|
|
|
375
376
|
try:
|
|
376
377
|
if not self.edges:
|
|
@@ -386,7 +387,7 @@ class Flow:
|
|
|
386
387
|
context.trace.finished_at = time.time()
|
|
387
388
|
context.trace.total_usage = context.usage
|
|
388
389
|
|
|
389
|
-
yield event.step_finished(step_name=f"flow:{self.name}")
|
|
390
|
+
yield event.step_finished(step_name=f"flow:{self.name}", step_id=flow_sid)
|
|
390
391
|
|
|
391
392
|
async def _stream_sequential(self, context: "FlowContext") -> AsyncIterator[dict[str, Any]]:
|
|
392
393
|
"""顺序流式执行"""
|
|
@@ -437,7 +438,8 @@ class Flow:
|
|
|
437
438
|
context.trace.record_node_start(current_node_id, "message", inputs=msg_config)
|
|
438
439
|
|
|
439
440
|
# message 节点增加 STEP 事件
|
|
440
|
-
|
|
441
|
+
msg_sid = str(uuid4())
|
|
442
|
+
step_evt = event.step_started(step_name=f"message:{current_node_id}", step_id=msg_sid)
|
|
441
443
|
step_evt["_node_id"] = current_node_id
|
|
442
444
|
step_evt["_label"] = msg_config.get("label")
|
|
443
445
|
step_evt["_echo"] = msg_config.get("echo", True)
|
|
@@ -454,7 +456,7 @@ class Flow:
|
|
|
454
456
|
text = template.format_map(_SafeFormatDict(context.variables))
|
|
455
457
|
context.set_output(current_node_id, {"result": text})
|
|
456
458
|
|
|
457
|
-
fin_evt = event.step_finished(step_name=f"message:{current_node_id}")
|
|
459
|
+
fin_evt = event.step_finished(step_name=f"message:{current_node_id}", step_id=msg_sid)
|
|
458
460
|
fin_evt["_node_id"] = current_node_id
|
|
459
461
|
fin_evt["_label"] = msg_config.get("label")
|
|
460
462
|
fin_evt["_echo"] = msg_config.get("echo", True)
|
|
@@ -469,7 +471,8 @@ class Flow:
|
|
|
469
471
|
|
|
470
472
|
context.trace.record_node_start(current_node_id, "parallel", inputs=config)
|
|
471
473
|
|
|
472
|
-
|
|
474
|
+
parallel_sid = str(uuid4())
|
|
475
|
+
step_evt = event.step_started(step_name=f"parallel:{current_node_id}", step_id=parallel_sid)
|
|
473
476
|
step_evt["_node_id"] = current_node_id
|
|
474
477
|
step_evt["_label"] = None
|
|
475
478
|
step_evt["_echo"] = False
|
|
@@ -510,7 +513,7 @@ class Flow:
|
|
|
510
513
|
merged.update(branch_result)
|
|
511
514
|
context.set_output(current_node_id, merged)
|
|
512
515
|
|
|
513
|
-
fin_evt = event.step_finished(step_name=f"parallel:{current_node_id}")
|
|
516
|
+
fin_evt = event.step_finished(step_name=f"parallel:{current_node_id}", step_id=parallel_sid)
|
|
514
517
|
fin_evt["_node_id"] = current_node_id
|
|
515
518
|
fin_evt["_label"] = None
|
|
516
519
|
fin_evt["_echo"] = False
|
|
@@ -533,7 +536,8 @@ class Flow:
|
|
|
533
536
|
|
|
534
537
|
context.trace.record_node_start(current_node_id, "iteration", inputs=config)
|
|
535
538
|
|
|
536
|
-
|
|
539
|
+
iter_sid = str(uuid4())
|
|
540
|
+
step_evt = event.step_started(step_name=f"iteration:{current_node_id}", step_id=iter_sid)
|
|
537
541
|
step_evt["_node_id"] = current_node_id
|
|
538
542
|
step_evt["_label"] = None
|
|
539
543
|
step_evt["_echo"] = False
|
|
@@ -574,7 +578,7 @@ class Flow:
|
|
|
574
578
|
iteration_output = {"results": results}
|
|
575
579
|
context.set_output(current_node_id, iteration_output)
|
|
576
580
|
|
|
577
|
-
fin_evt = event.step_finished(step_name=f"iteration:{current_node_id}")
|
|
581
|
+
fin_evt = event.step_finished(step_name=f"iteration:{current_node_id}", step_id=iter_sid)
|
|
578
582
|
fin_evt["_node_id"] = current_node_id
|
|
579
583
|
fin_evt["_label"] = None
|
|
580
584
|
fin_evt["_echo"] = False
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"""Agent 节点处理器 — 从 flow.py 提取"""
|
|
4
4
|
|
|
5
5
|
from typing import TYPE_CHECKING, Any, AsyncIterator
|
|
6
|
+
from uuid import uuid4
|
|
6
7
|
|
|
7
8
|
from .. import event
|
|
8
9
|
from ..exceptions import FlowError
|
|
@@ -46,8 +47,9 @@ class AgentNodeHandler(NodeHandler):
|
|
|
46
47
|
async def stream(self, node: dict, context: "FlowContext", node_id: str) -> AsyncIterator[dict[str, Any]]:
|
|
47
48
|
config = node.get("config", {})
|
|
48
49
|
step_name = self.get_step_name(node, node_id)
|
|
50
|
+
sid = str(uuid4())
|
|
49
51
|
|
|
50
|
-
yield event.step_started(step_name=step_name)
|
|
52
|
+
yield event.step_started(step_name=step_name, step_id=sid)
|
|
51
53
|
resolved = self.resolve_inputs(config, context)
|
|
52
54
|
ag = self._create_agent(config, context)
|
|
53
55
|
async for evt in ag.stream(context, inputs=resolved):
|
|
@@ -63,4 +65,4 @@ class AgentNodeHandler(NodeHandler):
|
|
|
63
65
|
tool_calls = context.pop_execution_records()
|
|
64
66
|
context.set_variable("_last_node_tool_calls", tool_calls)
|
|
65
67
|
|
|
66
|
-
yield event.step_finished(step_name=step_name)
|
|
68
|
+
yield event.step_finished(step_name=step_name, step_id=sid)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"""NodeHandler 基类 — 所有执行类节点的公共接口"""
|
|
4
4
|
|
|
5
5
|
from typing import TYPE_CHECKING, Any, AsyncIterator
|
|
6
|
+
from uuid import uuid4
|
|
6
7
|
|
|
7
8
|
from .. import event
|
|
8
9
|
|
|
@@ -45,7 +46,8 @@ class NodeHandler:
|
|
|
45
46
|
需要流式输出的节点(如 agent, llm_chat)应覆盖此方法。
|
|
46
47
|
"""
|
|
47
48
|
step_name = self.get_step_name(node, node_id)
|
|
48
|
-
|
|
49
|
+
sid = str(uuid4())
|
|
50
|
+
yield event.step_started(step_name=step_name, step_id=sid)
|
|
49
51
|
result = await self.execute(node, context)
|
|
50
52
|
context.set_output(node_id, result)
|
|
51
|
-
yield event.step_finished(step_name=step_name)
|
|
53
|
+
yield event.step_finished(step_name=step_name, step_id=sid)
|
|
@@ -32,8 +32,9 @@ class EchoNodeHandler(NodeHandler):
|
|
|
32
32
|
async def stream(self, node: dict, context: "FlowContext", node_id: str) -> AsyncIterator[dict[str, Any]]:
|
|
33
33
|
config = node.get("config", {})
|
|
34
34
|
step_name = self.get_step_name(node, node_id)
|
|
35
|
+
sid = str(uuid4())
|
|
35
36
|
|
|
36
|
-
yield event.step_started(step_name=step_name)
|
|
37
|
+
yield event.step_started(step_name=step_name, step_id=sid)
|
|
37
38
|
|
|
38
39
|
resolved = self.resolve_inputs(config, context)
|
|
39
40
|
content = resolved.get("content", "")
|
|
@@ -51,4 +52,4 @@ class EchoNodeHandler(NodeHandler):
|
|
|
51
52
|
yield event.text_message_end(message_id=msg_id)
|
|
52
53
|
|
|
53
54
|
context.set_output(node_id, {"result": content})
|
|
54
|
-
yield event.step_finished(step_name=step_name)
|
|
55
|
+
yield event.step_finished(step_name=step_name, step_id=sid)
|
|
@@ -92,15 +92,17 @@ class LLMChatNodeHandler(NodeHandler):
|
|
|
92
92
|
if not use_stream:
|
|
93
93
|
# 非流式:走默认 execute 路径
|
|
94
94
|
step_name = self.get_step_name(node, node_id)
|
|
95
|
-
|
|
95
|
+
sid = str(uuid4())
|
|
96
|
+
yield event.step_started(step_name=step_name, step_id=sid)
|
|
96
97
|
result = await self.execute(node, context)
|
|
97
98
|
context.set_output(node_id, result)
|
|
98
|
-
yield event.step_finished(step_name=step_name)
|
|
99
|
+
yield event.step_finished(step_name=step_name, step_id=sid)
|
|
99
100
|
return
|
|
100
101
|
|
|
101
102
|
# 流式输出
|
|
102
103
|
step_name = self.get_step_name(node, node_id)
|
|
103
|
-
|
|
104
|
+
sid = str(uuid4())
|
|
105
|
+
yield event.step_started(step_name=step_name, step_id=sid)
|
|
104
106
|
|
|
105
107
|
resolved_inputs = self.resolve_inputs(config, context)
|
|
106
108
|
prompt_text = self._build_prompt(config.get("prompt", ""), resolved_inputs)
|
|
@@ -153,4 +155,4 @@ class LLMChatNodeHandler(NodeHandler):
|
|
|
153
155
|
result_text = "".join(content_parts)
|
|
154
156
|
context.set_output(node_id, {"result": result_text})
|
|
155
157
|
|
|
156
|
-
yield event.step_finished(step_name=step_name)
|
|
158
|
+
yield event.step_finished(step_name=step_name, step_id=sid)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agstack
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.22.1
|
|
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>
|
|
@@ -43,6 +43,8 @@ Provides-Extra: graph
|
|
|
43
43
|
Requires-Dist: nebula3-python>=3.8.3; extra == "graph"
|
|
44
44
|
Provides-Extra: redis
|
|
45
45
|
Requires-Dist: redis>=5.0; extra == "redis"
|
|
46
|
+
Provides-Extra: yaml
|
|
47
|
+
Requires-Dist: pyyaml>=6.0; extra == "yaml"
|
|
46
48
|
Provides-Extra: std
|
|
47
49
|
Requires-Dist: agstack[mq]; extra == "std"
|
|
48
50
|
Requires-Dist: agstack[db]; extra == "std"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "agstack"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.22.1"
|
|
4
4
|
description = "Production-ready toolkit for building FastAPI and LLM applications"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -60,6 +60,7 @@ db = ["asyncpg>=0.30.0"]
|
|
|
60
60
|
es = ["elasticsearch[async]>=9.3.0"]
|
|
61
61
|
graph = ["nebula3-python>=3.8.3"]
|
|
62
62
|
redis = ["redis>=5.0"]
|
|
63
|
+
yaml = ["pyyaml>=6.0"]
|
|
63
64
|
std = ["agstack[mq]", "agstack[db]"]
|
|
64
65
|
pro = ["agstack[std]", "agstack[es]"]
|
|
65
66
|
ent = ["agstack[pro]", "agstack[graph]"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|