agstack 1.15.0__tar.gz → 1.16.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.15.0 → agstack-1.16.1}/PKG-INFO +1 -1
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/flow.py +56 -4
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/nodes/agent_node.py +18 -8
- {agstack-1.15.0 → agstack-1.16.1}/agstack.egg-info/PKG-INFO +1 -1
- {agstack-1.15.0 → agstack-1.16.1}/pyproject.toml +1 -1
- {agstack-1.15.0 → agstack-1.16.1}/LICENSE +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/README.md +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/config/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/config/logger.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/config/manager.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/config/types.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/contexts.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/decorators.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/events.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/exceptions.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/fastapi/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/fastapi/exception.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/fastapi/middleware.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/fastapi/offline.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/fastapi/sse.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/infra/db/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/infra/es/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/infra/kg/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/infra/mq/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/client.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/agent.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/context.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/event.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/exceptions.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/factory.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/loader.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/nodes/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/nodes/base.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/nodes/detect_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/nodes/echo_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/nodes/llm_chat_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/nodes/llm_embed_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/nodes/llm_rerank_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/nodes/python_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/nodes/subflow_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/nodes/switch_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/nodes/tool_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/records.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/registry.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/sandbox.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/state.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/flow/tool.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/prompts.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/llm/token.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/schema.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/security/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/security/casbin.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/security/crypt.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack/status.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack.egg-info/SOURCES.txt +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack.egg-info/dependency_links.txt +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack.egg-info/requires.txt +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/agstack.egg-info/top_level.txt +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/setup.cfg +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/tests/test_flow_io.py +0 -0
- {agstack-1.15.0 → agstack-1.16.1}/tests/test_flow_switch_subflow.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agstack
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.16.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>
|
|
@@ -146,6 +146,34 @@ class Flow:
|
|
|
146
146
|
|
|
147
147
|
# ── 带重试的节点执行(统一走 NodeHandler) ──
|
|
148
148
|
|
|
149
|
+
def _resolve_visibility(self, node_type: str, config: dict) -> tuple[str | None, bool]:
|
|
150
|
+
"""从 node config 和 registry 解析可见性(label, echo)
|
|
151
|
+
|
|
152
|
+
优先级:flow node config > registry 注册属性
|
|
153
|
+
"""
|
|
154
|
+
from .registry import registry
|
|
155
|
+
|
|
156
|
+
label = config.get("label")
|
|
157
|
+
explicit_echo = "echo" in config
|
|
158
|
+
echo = config.get("echo", False)
|
|
159
|
+
|
|
160
|
+
if not explicit_echo and label is None:
|
|
161
|
+
if node_type == "agent":
|
|
162
|
+
agent_name = config.get("agent_name", "")
|
|
163
|
+
label = registry.get_agent_label(agent_name)
|
|
164
|
+
if not label:
|
|
165
|
+
echo = registry.get_agent_echo(agent_name)
|
|
166
|
+
elif node_type == "tool":
|
|
167
|
+
tool_name = config.get("tool_name", "")
|
|
168
|
+
label = registry.get_tool_label(tool_name)
|
|
169
|
+
if not label:
|
|
170
|
+
echo = registry.get_tool_echo(tool_name)
|
|
171
|
+
|
|
172
|
+
if label and not explicit_echo:
|
|
173
|
+
echo = True
|
|
174
|
+
|
|
175
|
+
return label, echo
|
|
176
|
+
|
|
149
177
|
async def _execute_node_with_retry(
|
|
150
178
|
self,
|
|
151
179
|
node: dict,
|
|
@@ -164,6 +192,7 @@ class Flow:
|
|
|
164
192
|
|
|
165
193
|
policy = self._get_retry_policy(node)
|
|
166
194
|
label = handler.get_step_name(node, node_id)
|
|
195
|
+
vis_label, vis_echo = self._resolve_visibility(node_type, node.get("config", {}))
|
|
167
196
|
last_error: Exception | None = None
|
|
168
197
|
|
|
169
198
|
for attempt in range(policy.max_retries + 1):
|
|
@@ -184,6 +213,9 @@ class Flow:
|
|
|
184
213
|
)
|
|
185
214
|
|
|
186
215
|
async for evt in handler.stream(node, context, node_id):
|
|
216
|
+
evt["_node_id"] = node_id
|
|
217
|
+
evt["_label"] = vis_label
|
|
218
|
+
evt["_echo"] = vis_echo
|
|
187
219
|
yield evt
|
|
188
220
|
return
|
|
189
221
|
|
|
@@ -375,14 +407,22 @@ class Flow:
|
|
|
375
407
|
node_type: str = node.get("type", "")
|
|
376
408
|
|
|
377
409
|
if node_type == "message":
|
|
410
|
+
msg_config = node.get("config", {})
|
|
378
411
|
async for evt in self._emit_message(node, context):
|
|
412
|
+
evt["_node_id"] = current_node_id
|
|
413
|
+
evt["_label"] = msg_config.get("label")
|
|
414
|
+
evt["_echo"] = msg_config.get("echo", True)
|
|
379
415
|
yield evt
|
|
380
416
|
current_node_id = self._resolve_next_node(current_node_id, context)
|
|
381
417
|
|
|
382
418
|
elif node_type == "parallel":
|
|
383
419
|
config = node.get("config", {})
|
|
384
420
|
branches = config.get("branches", [])
|
|
385
|
-
|
|
421
|
+
step_evt = event.step_started(step_name=f"parallel:{current_node_id}")
|
|
422
|
+
step_evt["_node_id"] = current_node_id
|
|
423
|
+
step_evt["_label"] = None
|
|
424
|
+
step_evt["_echo"] = False
|
|
425
|
+
yield step_evt
|
|
386
426
|
|
|
387
427
|
async def _exec_branch(branch_id: str) -> None:
|
|
388
428
|
branch_node = self.get_node_config(branch_id)
|
|
@@ -402,7 +442,11 @@ class Flow:
|
|
|
402
442
|
if isinstance(branch_result, dict):
|
|
403
443
|
merged.update(branch_result)
|
|
404
444
|
context.set_output(current_node_id, merged)
|
|
405
|
-
|
|
445
|
+
fin_evt = event.step_finished(step_name=f"parallel:{current_node_id}")
|
|
446
|
+
fin_evt["_node_id"] = current_node_id
|
|
447
|
+
fin_evt["_label"] = None
|
|
448
|
+
fin_evt["_echo"] = False
|
|
449
|
+
yield fin_evt
|
|
406
450
|
current_node_id = self._resolve_next_node(current_node_id, context)
|
|
407
451
|
|
|
408
452
|
elif node_type == "iteration":
|
|
@@ -417,7 +461,11 @@ class Flow:
|
|
|
417
461
|
body_nodes: list[str] = config.get("body", [])
|
|
418
462
|
results: list[Any] = []
|
|
419
463
|
|
|
420
|
-
|
|
464
|
+
step_evt = event.step_started(step_name=f"iteration:{current_node_id}")
|
|
465
|
+
step_evt["_node_id"] = current_node_id
|
|
466
|
+
step_evt["_label"] = None
|
|
467
|
+
step_evt["_echo"] = False
|
|
468
|
+
yield step_evt
|
|
421
469
|
for idx, item in enumerate(items):
|
|
422
470
|
context.set_variable(item_var, item)
|
|
423
471
|
context.set_variable(index_var, idx)
|
|
@@ -434,7 +482,11 @@ class Flow:
|
|
|
434
482
|
results.append(context.outputs.get(body_nodes[-1]))
|
|
435
483
|
|
|
436
484
|
context.set_output(current_node_id, {"results": results})
|
|
437
|
-
|
|
485
|
+
fin_evt = event.step_finished(step_name=f"iteration:{current_node_id}")
|
|
486
|
+
fin_evt["_node_id"] = current_node_id
|
|
487
|
+
fin_evt["_label"] = None
|
|
488
|
+
fin_evt["_echo"] = False
|
|
489
|
+
yield fin_evt
|
|
438
490
|
current_node_id = self._resolve_next_node(current_node_id, context)
|
|
439
491
|
|
|
440
492
|
elif node_type in self._node_handlers:
|
|
@@ -19,13 +19,17 @@ class AgentNodeHandler(NodeHandler):
|
|
|
19
19
|
|
|
20
20
|
node_type = "agent"
|
|
21
21
|
|
|
22
|
-
_NODE_KEYS = frozenset({"agent_name", "inputs"})
|
|
22
|
+
_NODE_KEYS = frozenset({"agent_name", "inputs", "label", "echo"})
|
|
23
23
|
|
|
24
|
-
def _create_agent(self, config: dict):
|
|
24
|
+
def _create_agent(self, config: dict, context: "FlowContext"):
|
|
25
25
|
agent_name = config.get("agent_name")
|
|
26
26
|
if not agent_name:
|
|
27
27
|
raise FlowError("MISSING_AGENT_NAME", 400)
|
|
28
|
-
agent_kwargs = {
|
|
28
|
+
agent_kwargs = {
|
|
29
|
+
k: context.resolve_reference(v) if isinstance(v, str) else v
|
|
30
|
+
for k, v in config.items()
|
|
31
|
+
if k not in self._NODE_KEYS
|
|
32
|
+
}
|
|
29
33
|
agent = registry.create_agent(agent_name, **agent_kwargs)
|
|
30
34
|
if not agent:
|
|
31
35
|
raise FlowError("AGENT_NOT_FOUND", 404, {"agent_name": agent_name})
|
|
@@ -34,8 +38,10 @@ class AgentNodeHandler(NodeHandler):
|
|
|
34
38
|
async def execute(self, node: dict, context: "FlowContext") -> Any:
|
|
35
39
|
config = node.get("config", {})
|
|
36
40
|
resolved = self.resolve_inputs(config, context)
|
|
37
|
-
ag = self._create_agent(config)
|
|
38
|
-
|
|
41
|
+
ag = self._create_agent(config, context)
|
|
42
|
+
result = await ag.run(context, inputs=resolved)
|
|
43
|
+
structured = context.outputs.pop(ag.name, None)
|
|
44
|
+
return structured if structured is not None else result
|
|
39
45
|
|
|
40
46
|
async def stream(self, node: dict, context: "FlowContext", node_id: str) -> AsyncIterator[dict[str, Any]]:
|
|
41
47
|
config = node.get("config", {})
|
|
@@ -43,9 +49,13 @@ class AgentNodeHandler(NodeHandler):
|
|
|
43
49
|
|
|
44
50
|
yield event.step_started(step_name=step_name)
|
|
45
51
|
resolved = self.resolve_inputs(config, context)
|
|
46
|
-
ag = self._create_agent(config)
|
|
52
|
+
ag = self._create_agent(config, context)
|
|
47
53
|
async for evt in ag.stream(context, inputs=resolved):
|
|
48
54
|
yield evt
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
structured = context.outputs.pop(ag.name, None)
|
|
56
|
+
if structured is not None:
|
|
57
|
+
context.set_output(node_id, structured)
|
|
58
|
+
else:
|
|
59
|
+
result = context.get_last_output(ag.name) or ""
|
|
60
|
+
context.set_output(node_id, {"result": result})
|
|
51
61
|
yield event.step_finished(step_name=step_name)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agstack
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.16.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>
|
|
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
|