agstack 1.15.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.
- {agstack-1.15.0 → agstack-1.16.0}/PKG-INFO +1 -1
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/flow.py +55 -4
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/nodes/agent_node.py +18 -8
- {agstack-1.15.0 → agstack-1.16.0}/agstack.egg-info/PKG-INFO +1 -1
- {agstack-1.15.0 → agstack-1.16.0}/pyproject.toml +1 -1
- {agstack-1.15.0 → agstack-1.16.0}/LICENSE +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/README.md +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/config/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/config/logger.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/config/manager.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/config/types.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/contexts.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/decorators.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/events.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/exceptions.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/fastapi/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/fastapi/exception.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/fastapi/middleware.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/fastapi/offline.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/fastapi/sse.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/infra/db/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/infra/es/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/infra/kg/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/infra/mq/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/client.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/agent.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/context.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/event.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/exceptions.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/factory.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/loader.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/nodes/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/nodes/base.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/nodes/detect_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/nodes/echo_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/nodes/llm_chat_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/nodes/llm_embed_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/nodes/llm_rerank_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/nodes/python_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/nodes/subflow_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/nodes/switch_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/nodes/tool_node.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/records.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/registry.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/sandbox.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/state.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/flow/tool.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/prompts.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/llm/token.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/schema.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/security/__init__.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/security/casbin.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/security/crypt.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack/status.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack.egg-info/SOURCES.txt +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack.egg-info/dependency_links.txt +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack.egg-info/requires.txt +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/agstack.egg-info/top_level.txt +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/setup.cfg +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/tests/test_flow_io.py +0 -0
- {agstack-1.15.0 → agstack-1.16.0}/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.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>
|
|
@@ -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
|
|
|
@@ -376,13 +408,20 @@ class Flow:
|
|
|
376
408
|
|
|
377
409
|
if node_type == "message":
|
|
378
410
|
async for evt in self._emit_message(node, context):
|
|
411
|
+
evt["_node_id"] = current_node_id
|
|
412
|
+
evt["_label"] = None
|
|
413
|
+
evt["_echo"] = False
|
|
379
414
|
yield evt
|
|
380
415
|
current_node_id = self._resolve_next_node(current_node_id, context)
|
|
381
416
|
|
|
382
417
|
elif node_type == "parallel":
|
|
383
418
|
config = node.get("config", {})
|
|
384
419
|
branches = config.get("branches", [])
|
|
385
|
-
|
|
420
|
+
step_evt = event.step_started(step_name=f"parallel:{current_node_id}")
|
|
421
|
+
step_evt["_node_id"] = current_node_id
|
|
422
|
+
step_evt["_label"] = None
|
|
423
|
+
step_evt["_echo"] = False
|
|
424
|
+
yield step_evt
|
|
386
425
|
|
|
387
426
|
async def _exec_branch(branch_id: str) -> None:
|
|
388
427
|
branch_node = self.get_node_config(branch_id)
|
|
@@ -402,7 +441,11 @@ class Flow:
|
|
|
402
441
|
if isinstance(branch_result, dict):
|
|
403
442
|
merged.update(branch_result)
|
|
404
443
|
context.set_output(current_node_id, merged)
|
|
405
|
-
|
|
444
|
+
fin_evt = event.step_finished(step_name=f"parallel:{current_node_id}")
|
|
445
|
+
fin_evt["_node_id"] = current_node_id
|
|
446
|
+
fin_evt["_label"] = None
|
|
447
|
+
fin_evt["_echo"] = False
|
|
448
|
+
yield fin_evt
|
|
406
449
|
current_node_id = self._resolve_next_node(current_node_id, context)
|
|
407
450
|
|
|
408
451
|
elif node_type == "iteration":
|
|
@@ -417,7 +460,11 @@ class Flow:
|
|
|
417
460
|
body_nodes: list[str] = config.get("body", [])
|
|
418
461
|
results: list[Any] = []
|
|
419
462
|
|
|
420
|
-
|
|
463
|
+
step_evt = event.step_started(step_name=f"iteration:{current_node_id}")
|
|
464
|
+
step_evt["_node_id"] = current_node_id
|
|
465
|
+
step_evt["_label"] = None
|
|
466
|
+
step_evt["_echo"] = False
|
|
467
|
+
yield step_evt
|
|
421
468
|
for idx, item in enumerate(items):
|
|
422
469
|
context.set_variable(item_var, item)
|
|
423
470
|
context.set_variable(index_var, idx)
|
|
@@ -434,7 +481,11 @@ class Flow:
|
|
|
434
481
|
results.append(context.outputs.get(body_nodes[-1]))
|
|
435
482
|
|
|
436
483
|
context.set_output(current_node_id, {"results": results})
|
|
437
|
-
|
|
484
|
+
fin_evt = event.step_finished(step_name=f"iteration:{current_node_id}")
|
|
485
|
+
fin_evt["_node_id"] = current_node_id
|
|
486
|
+
fin_evt["_label"] = None
|
|
487
|
+
fin_evt["_echo"] = False
|
|
488
|
+
yield fin_evt
|
|
438
489
|
current_node_id = self._resolve_next_node(current_node_id, context)
|
|
439
490
|
|
|
440
491
|
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.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>
|
|
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
|