agstack 1.21.0__tar.gz → 1.22.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.21.0 → agstack-1.22.0}/PKG-INFO +3 -1
- {agstack-1.21.0 → agstack-1.22.0}/agstack/config/manager.py +47 -11
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/agent.py +5 -3
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/tool.py +10 -2
- {agstack-1.21.0 → agstack-1.22.0}/agstack.egg-info/PKG-INFO +3 -1
- {agstack-1.21.0 → agstack-1.22.0}/agstack.egg-info/requires.txt +3 -0
- {agstack-1.21.0 → agstack-1.22.0}/pyproject.toml +2 -1
- {agstack-1.21.0 → agstack-1.22.0}/LICENSE +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/README.md +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/__init__.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/cache/__init__.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/cache/base.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/cache/memory.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/cache/redis.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/config/__init__.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/config/logger.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/config/types.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/contexts.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/decorators.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/events.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/exceptions.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/fastapi/__init__.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/fastapi/exception.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/fastapi/middleware.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/fastapi/offline.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/fastapi/sse.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/infra/db/__init__.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/infra/es/__init__.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/infra/kg/__init__.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/infra/mq/__init__.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/__init__.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/client.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/__init__.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/context.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/event.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/exceptions.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/factory.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/flow.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/loader.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/nodes/__init__.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/nodes/agent_node.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/nodes/base.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/nodes/detect_node.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/nodes/echo_node.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/nodes/llm_chat_node.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/nodes/llm_embed_node.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/nodes/llm_rerank_node.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/nodes/python_node.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/nodes/subflow_node.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/nodes/switch_node.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/nodes/tool_node.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/records.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/registry.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/sandbox.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/state.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/flow/trace.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/prompts.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/llm/token.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/messagebus/__init__.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/messagebus/base.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/messagebus/memory.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/messagebus/redis.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/schema.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/security/__init__.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/security/casbin.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/security/crypt.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack/status.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack.egg-info/SOURCES.txt +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack.egg-info/dependency_links.txt +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/agstack.egg-info/top_level.txt +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/setup.cfg +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/tests/test_cache_memory.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/tests/test_cache_redis.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/tests/test_flow_io.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/tests/test_flow_switch_subflow.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/tests/test_messagebus_memory.py +0 -0
- {agstack-1.21.0 → agstack-1.22.0}/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.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>
|
|
@@ -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
|
|
@@ -245,13 +245,13 @@ class Agent:
|
|
|
245
245
|
context.add_message(
|
|
246
246
|
self.name,
|
|
247
247
|
"tool",
|
|
248
|
-
content=json.dumps({"error": error_msg}),
|
|
248
|
+
content=json.dumps({"error": error_msg}, ensure_ascii=False),
|
|
249
249
|
tool_call_id=tool_call["id"],
|
|
250
250
|
)
|
|
251
251
|
# AG-UI: TOOL_CALL_RESULT (错误)
|
|
252
252
|
yield event.tool_call_result(
|
|
253
253
|
tool_call_id=tool_call["id"],
|
|
254
|
-
content=json.dumps({"error": error_msg}),
|
|
254
|
+
content=json.dumps({"error": error_msg}, ensure_ascii=False),
|
|
255
255
|
)
|
|
256
256
|
continue
|
|
257
257
|
|
|
@@ -288,7 +288,9 @@ class Agent:
|
|
|
288
288
|
|
|
289
289
|
# 使用 result.content 作为 LLM 上下文(Tool 已计算好)
|
|
290
290
|
result_content = result.content or (
|
|
291
|
-
json.dumps(result.result
|
|
291
|
+
json.dumps(result.result, ensure_ascii=False)
|
|
292
|
+
if result.success
|
|
293
|
+
else json.dumps({"error": result.error}, ensure_ascii=False)
|
|
292
294
|
)
|
|
293
295
|
context.add_message(
|
|
294
296
|
self.name,
|
|
@@ -93,9 +93,17 @@ class Tool:
|
|
|
93
93
|
try:
|
|
94
94
|
result.content = self.result_formatter(result)
|
|
95
95
|
except Exception:
|
|
96
|
-
result.content =
|
|
96
|
+
result.content = (
|
|
97
|
+
json.dumps(result.result, ensure_ascii=False)
|
|
98
|
+
if result.success
|
|
99
|
+
else json.dumps({"error": result.error}, ensure_ascii=False)
|
|
100
|
+
)
|
|
97
101
|
else:
|
|
98
|
-
result.content =
|
|
102
|
+
result.content = (
|
|
103
|
+
json.dumps(result.result, ensure_ascii=False)
|
|
104
|
+
if result.success
|
|
105
|
+
else json.dumps({"error": result.error}, ensure_ascii=False)
|
|
106
|
+
)
|
|
99
107
|
|
|
100
108
|
# 生成面向用户的摘要
|
|
101
109
|
if self.summary_fn:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agstack
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.22.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>
|
|
@@ -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.0"
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|