agent-api-server 2.1.7__tar.gz → 2.2.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.
- agent_api_server-2.2.0/PKG-INFO +110 -0
- agent_api_server-2.2.0/README.md +70 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/api/v1/schema.py +15 -1
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/api/v1/thread.py +1 -2
- agent_api_server-2.2.0/agent_api_server/dynamic_llm/model.py +43 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/log/formatters.py +1 -1
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/mcp_convert/mcp_convert.py +56 -64
- agent_api_server-2.2.0/agent_api_server/mcp_interceptor/mcp_intecerpter.py +20 -0
- agent_api_server-2.2.0/agent_api_server/middleware/model.py +59 -0
- agent_api_server-2.2.0/agent_api_server/middleware/schema.py +6 -0
- agent_api_server-2.2.0/agent_api_server/register/__init__.py +0 -0
- agent_api_server-2.2.0/agent_api_server/schema/__init__.py +0 -0
- agent_api_server-2.2.0/agent_api_server/schema/context.py +13 -0
- agent_api_server-2.2.0/agent_api_server/shared/__init__.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/shared/message.py +32 -75
- agent_api_server-2.2.0/pyproject.toml +63 -0
- agent_api_server-2.1.7/PKG-INFO +0 -130
- agent_api_server-2.1.7/README.md +0 -92
- agent_api_server-2.1.7/agent_api_server/shared/decode_token.py +0 -107
- agent_api_server-2.1.7/pyproject.toml +0 -54
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/__init__.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/api/__init__.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/api/v1/__init__.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/api/v1/api.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/api/v1/config.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/api/v1/graph.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/cache/__init__.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/cache/redis_cache.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/callback_handler.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/client/css/styles.css +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/client/favicon.ico +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/client/index.html +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/client/js/app.js +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/client/js/index.umd.js +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/config_center/config_center.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/configs/__init__.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/configs/config.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/dynamic_llm/__init__.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/dynamic_llm/dynamic_llm.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/listener.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/log/__init__.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/log/logging.json +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/mcp_convert/__init__.py +0 -0
- {agent_api_server-2.1.7/agent_api_server/memeory → agent_api_server-2.2.0/agent_api_server/mcp_interceptor}/__init__.py +0 -0
- {agent_api_server-2.1.7/agent_api_server/register → agent_api_server-2.2.0/agent_api_server/memeory}/__init__.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/memeory/postgres.py +0 -0
- {agent_api_server-2.1.7/agent_api_server/shared → agent_api_server-2.2.0/agent_api_server/middleware}/__init__.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/register/register.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/service.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/service_hub/service_hub.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/service_hub/service_hub_test.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/shared/ase.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/shared/base_model.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/shared/common.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/shared/detect_message.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/shared/get_model_info.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/shared/util_func.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/sso_service/__init__.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/sso_service/sdk/__init__.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/sso_service/sdk/client.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/sso_service/sdk/credential.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/sso_service/sdk/encoding.py +0 -0
- {agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/sso_service/sso_service.py +0 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: agent-api-server
|
|
3
|
+
Version: 2.2.0
|
|
4
|
+
Summary: A Langgraph agent API server that implements Langgraph agent's web capabilities and can interact with chatbot
|
|
5
|
+
Keywords: fastapi,langgraph,agent,api-server
|
|
6
|
+
Author: Zijie Zhang
|
|
7
|
+
Author-email: zijie.zhang@advantech.com.cn
|
|
8
|
+
Requires-Python: >=3.11,<3.14
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Framework :: FastAPI
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Dist: aiofiles (>=24.1.0,<25.0.0)
|
|
16
|
+
Requires-Dist: aiohttp (>=3.13.3,<4.0.0)
|
|
17
|
+
Requires-Dist: authlib (>=1.6.5)
|
|
18
|
+
Requires-Dist: cryptography (>=45.0.4,<46.0.0)
|
|
19
|
+
Requires-Dist: fastapi (>=0.117.0,<0.121.2)
|
|
20
|
+
Requires-Dist: fastmcp (>=2.13.0,<3.0.0)
|
|
21
|
+
Requires-Dist: langchain (>=1.2.0,<2.0.0)
|
|
22
|
+
Requires-Dist: langchain-core (>=1.2.5,<2.0.0)
|
|
23
|
+
Requires-Dist: langchain-mcp-adapters (>=0.2.1,<0.3.0)
|
|
24
|
+
Requires-Dist: langgraph (>=1.0.6,<2.0.0)
|
|
25
|
+
Requires-Dist: langgraph-checkpoint (>=4.0.0,<5.0.0)
|
|
26
|
+
Requires-Dist: langgraph-checkpoint-postgres (>=3.0.3,<4.0.0)
|
|
27
|
+
Requires-Dist: llm-sdk (==1.0.1)
|
|
28
|
+
Requires-Dist: model-manage-client (>=0.0.1.8)
|
|
29
|
+
Requires-Dist: nats-py (>=2.11.0,<3.0.0)
|
|
30
|
+
Requires-Dist: psycopg-binary (>=3.2.9,<4.0.0)
|
|
31
|
+
Requires-Dist: psycopg-pool (>=3.2.6,<4.0.0)
|
|
32
|
+
Requires-Dist: pydantic-settings (>=2.9.1,<3.0.0)
|
|
33
|
+
Requires-Dist: redis (>=6.2.0,<7.0.0)
|
|
34
|
+
Requires-Dist: starlette (>=0.49.3,<0.50.0)
|
|
35
|
+
Requires-Dist: tenacity (>=9.1.2,<10.0.0)
|
|
36
|
+
Project-URL: Homepage, https://gitlab.wise-paas.com/openai/agent_api_server
|
|
37
|
+
Project-URL: Repository, https://gitlab.wise-paas.com/openai/agent_api_server
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# agent-api-server
|
|
41
|
+
|
|
42
|
+
`agent-api-server` is a FastAPI-based API server for LangGraph agents. It exposes REST endpoints for thread, schema, graph, and runtime configuration management, and it serves a built-in web client from `/site`.
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- FastAPI application factory for embedding or standalone deployment
|
|
47
|
+
- LangGraph-oriented API routes under `/api/v1`
|
|
48
|
+
- Built-in static client assets bundled in both sdist and wheel artifacts
|
|
49
|
+
- Redis-backed thread storage and PostgreSQL checkpoint integration
|
|
50
|
+
- Optional integration with config center, SSO, MCP, and model management services
|
|
51
|
+
|
|
52
|
+
## Requirements
|
|
53
|
+
|
|
54
|
+
- Python 3.11 to 3.13
|
|
55
|
+
- Redis
|
|
56
|
+
- PostgreSQL
|
|
57
|
+
- Access to all runtime dependencies declared in `pyproject.toml`
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
Install from a package index that provides all required dependencies:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install agent-api-server
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This project depends on `llm-sdk` and `model-manage-client`. If those packages are hosted on a private index in your environment, configure `pip` or Poetry to use that index before installation.
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
The server reads configuration from environment variables. Common settings include:
|
|
72
|
+
|
|
73
|
+
```env
|
|
74
|
+
REDIS_URL=redis://localhost:6379/0
|
|
75
|
+
POSTGRES_URL=postgresql://postgres:postgres@localhost:5432/postgres
|
|
76
|
+
MODEL_MANAGER_SERVICE_URL=http://127.0.0.1:10053
|
|
77
|
+
SERVER_PORT=8080
|
|
78
|
+
SERVER_WORKER_AMOUNT=1
|
|
79
|
+
LOG_LEVEL=INFO
|
|
80
|
+
ENABLE_MCP_SERVER=False
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
See `.env_example` for a more complete example.
|
|
84
|
+
|
|
85
|
+
## Running the server
|
|
86
|
+
|
|
87
|
+
Run the application with Uvicorn:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uvicorn agent_api_server.service:create_fastapi_app --factory --host 0.0.0.0 --port 8080
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
After startup:
|
|
94
|
+
|
|
95
|
+
- API root: `http://127.0.0.1:8080/api/v1`
|
|
96
|
+
- OpenAPI docs: `http://127.0.0.1:8080/docs`
|
|
97
|
+
- Built-in client: `http://127.0.0.1:8080/site`
|
|
98
|
+
|
|
99
|
+
## Build
|
|
100
|
+
|
|
101
|
+
Build source and wheel distributions with Poetry:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
poetry build
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Repository
|
|
108
|
+
|
|
109
|
+
Source repository: <https://gitlab.wise-paas.com/openai/agent_api_server>
|
|
110
|
+
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# agent-api-server
|
|
2
|
+
|
|
3
|
+
`agent-api-server` is a FastAPI-based API server for LangGraph agents. It exposes REST endpoints for thread, schema, graph, and runtime configuration management, and it serves a built-in web client from `/site`.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- FastAPI application factory for embedding or standalone deployment
|
|
8
|
+
- LangGraph-oriented API routes under `/api/v1`
|
|
9
|
+
- Built-in static client assets bundled in both sdist and wheel artifacts
|
|
10
|
+
- Redis-backed thread storage and PostgreSQL checkpoint integration
|
|
11
|
+
- Optional integration with config center, SSO, MCP, and model management services
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- Python 3.11 to 3.13
|
|
16
|
+
- Redis
|
|
17
|
+
- PostgreSQL
|
|
18
|
+
- Access to all runtime dependencies declared in `pyproject.toml`
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
Install from a package index that provides all required dependencies:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install agent-api-server
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This project depends on `llm-sdk` and `model-manage-client`. If those packages are hosted on a private index in your environment, configure `pip` or Poetry to use that index before installation.
|
|
29
|
+
|
|
30
|
+
## Configuration
|
|
31
|
+
|
|
32
|
+
The server reads configuration from environment variables. Common settings include:
|
|
33
|
+
|
|
34
|
+
```env
|
|
35
|
+
REDIS_URL=redis://localhost:6379/0
|
|
36
|
+
POSTGRES_URL=postgresql://postgres:postgres@localhost:5432/postgres
|
|
37
|
+
MODEL_MANAGER_SERVICE_URL=http://127.0.0.1:10053
|
|
38
|
+
SERVER_PORT=8080
|
|
39
|
+
SERVER_WORKER_AMOUNT=1
|
|
40
|
+
LOG_LEVEL=INFO
|
|
41
|
+
ENABLE_MCP_SERVER=False
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
See `.env_example` for a more complete example.
|
|
45
|
+
|
|
46
|
+
## Running the server
|
|
47
|
+
|
|
48
|
+
Run the application with Uvicorn:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
uvicorn agent_api_server.service:create_fastapi_app --factory --host 0.0.0.0 --port 8080
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
After startup:
|
|
55
|
+
|
|
56
|
+
- API root: `http://127.0.0.1:8080/api/v1`
|
|
57
|
+
- OpenAPI docs: `http://127.0.0.1:8080/docs`
|
|
58
|
+
- Built-in client: `http://127.0.0.1:8080/site`
|
|
59
|
+
|
|
60
|
+
## Build
|
|
61
|
+
|
|
62
|
+
Build source and wheel distributions with Poetry:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
poetry build
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Repository
|
|
69
|
+
|
|
70
|
+
Source repository: <https://gitlab.wise-paas.com/openai/agent_api_server>
|
|
@@ -35,8 +35,22 @@ async def get_graph_schema(graph_name: str):
|
|
|
35
35
|
actual_type=type(graph_instance).__name__
|
|
36
36
|
)
|
|
37
37
|
|
|
38
|
+
input_schema = graph_instance.get_input_jsonschema()
|
|
39
|
+
if input_schema:
|
|
40
|
+
if input_schema.get("properties"):
|
|
41
|
+
input_schema["properties"].pop("messages")
|
|
42
|
+
if input_schema.get("required"):
|
|
43
|
+
required_schema = input_schema.get("required")
|
|
44
|
+
|
|
45
|
+
real_required_schema = []
|
|
46
|
+
for _, schema in enumerate(required_schema):
|
|
47
|
+
if schema == "messages":
|
|
48
|
+
continue
|
|
49
|
+
real_required_schema.append(schema)
|
|
50
|
+
input_schema["required"] = real_required_schema
|
|
51
|
+
|
|
38
52
|
return JSONResponse(
|
|
39
|
-
content=
|
|
53
|
+
content=input_schema,
|
|
40
54
|
media_type="application/schema+json",
|
|
41
55
|
)
|
|
42
56
|
except ValueError as ve:
|
|
@@ -276,8 +276,7 @@ async def stream(
|
|
|
276
276
|
404: {"model": error_response, "description": "Thread not found"},
|
|
277
277
|
408: {"model": error_response, "description": "Request timeout"},
|
|
278
278
|
500: {"model": error_response, "description": "Execution failed"}
|
|
279
|
-
}
|
|
280
|
-
deprecated=True
|
|
279
|
+
}
|
|
281
280
|
)
|
|
282
281
|
async def run_thread(
|
|
283
282
|
thread_id: str,
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from langchain_core.language_models import BaseChatModel
|
|
2
|
+
from langchain_openai import ChatOpenAI
|
|
3
|
+
from llm_sdk.llm import ModelInstance
|
|
4
|
+
from llm_sdk.model_providers.base import ConfigType
|
|
5
|
+
from pydantic import SecretStr
|
|
6
|
+
|
|
7
|
+
from agent_api_server.dynamic_llm.dynamic_llm import DynamicLLM
|
|
8
|
+
from agent_api_server.schema.context import Context
|
|
9
|
+
|
|
10
|
+
def get_init_model()->BaseChatModel:
|
|
11
|
+
"""
|
|
12
|
+
Get the initial chat model instance.
|
|
13
|
+
"""
|
|
14
|
+
return ChatOpenAI(
|
|
15
|
+
model="gpt-4o-2024-05-13",
|
|
16
|
+
max_tokens=20000,
|
|
17
|
+
api_key=SecretStr("xxx")
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
def get_chat_model_instance(context: Context)-> ModelInstance:
|
|
21
|
+
""""
|
|
22
|
+
Get the chat model instance for the given context.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
dynamic_llm = DynamicLLM(tool_name="default",config_type=ConfigType.CHAT,use_sys_llm=context.use_system_llm)
|
|
26
|
+
|
|
27
|
+
llm_config = {
|
|
28
|
+
"agent_id":context.graph_name,
|
|
29
|
+
"ts_tenant":context.ts_tenant,
|
|
30
|
+
"provider":context.config.get(dynamic_llm._get_config_key("PROVIDER", context.ts_tenant)),
|
|
31
|
+
"model": context.config.get(dynamic_llm._get_config_key("MODEL", context.ts_tenant)),
|
|
32
|
+
"credentials": context.config.get(dynamic_llm._get_config_key("CREDENTIALS", context.ts_tenant)),
|
|
33
|
+
}
|
|
34
|
+
with dynamic_llm._get_model_instance(llm_config,config={}) as model_instance:
|
|
35
|
+
return model_instance
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_model_credentials(context: Context)-> dict:
|
|
39
|
+
"""
|
|
40
|
+
Get the model credentials for the given context.
|
|
41
|
+
"""
|
|
42
|
+
model_instance = get_chat_model_instance(context)
|
|
43
|
+
return model_instance.unified_credential()
|
|
@@ -90,7 +90,7 @@ class ColorFormatter(logging.Formatter):
|
|
|
90
90
|
|
|
91
91
|
log_template = (
|
|
92
92
|
"{timestamp_color}{timestamp}{reset} "
|
|
93
|
-
"[{level_color}{levelname
|
|
93
|
+
"[{level_color}{levelname}{reset}] "
|
|
94
94
|
"{message} "
|
|
95
95
|
"[{module_color}{module}{reset}] "
|
|
96
96
|
"thread_name={thread_color}{thread}{reset}"
|
{agent_api_server-2.1.7 → agent_api_server-2.2.0}/agent_api_server/mcp_convert/mcp_convert.py
RENAMED
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
import os
|
|
2
1
|
import inspect
|
|
3
2
|
import logging
|
|
4
3
|
import json
|
|
5
4
|
from typing import Dict, Any, Optional, List, Callable, Awaitable
|
|
6
5
|
from functools import wraps, partial
|
|
7
6
|
from datetime import datetime
|
|
8
|
-
|
|
9
|
-
from langfuse.langchain import CallbackHandler
|
|
10
|
-
from agent_api_server.shared.decode_token import decode_jwt
|
|
7
|
+
|
|
11
8
|
from langgraph.config import get_stream_writer
|
|
12
9
|
from langgraph.graph.state import CompiledStateGraph
|
|
13
|
-
from fastmcp import FastMCP,
|
|
10
|
+
from fastmcp import FastMCP,Context
|
|
14
11
|
from mcp import types
|
|
15
12
|
from mcp.types import RequestParams, CallToolResult, TextContent
|
|
13
|
+
|
|
14
|
+
from agent_api_server.schema.context import Context as RuntimeContext
|
|
16
15
|
from agent_api_server.shared.message import handle_stream_event
|
|
17
16
|
from agent_api_server.shared.util_func import load_graph_config, load_graph, get_env
|
|
18
17
|
|
|
@@ -100,12 +99,15 @@ async def _execute_graph_tool(
|
|
|
100
99
|
Execution result dict
|
|
101
100
|
"""
|
|
102
101
|
ctx = Context(fastmcp=mcp)
|
|
102
|
+
|
|
103
103
|
from fastmcp.server.dependencies import get_http_request
|
|
104
104
|
request = get_http_request()
|
|
105
105
|
|
|
106
|
-
use_sys_llm = request.headers.get("UseSysLLM",
|
|
106
|
+
use_sys_llm = request.headers.get("UseSysLLM", None)
|
|
107
107
|
ts_tenant = request.headers.get("TSTenant", "")
|
|
108
108
|
ei_token = request.headers.get("Authorization", "")
|
|
109
|
+
if ei_token.startswith("Bearer "):
|
|
110
|
+
ei_token = ei_token.removeprefix("Bearer ")
|
|
109
111
|
thread_id = request.headers.get('thread_id', '')
|
|
110
112
|
start_time = datetime.now()
|
|
111
113
|
|
|
@@ -113,6 +115,20 @@ async def _execute_graph_tool(
|
|
|
113
115
|
|
|
114
116
|
# Validate input
|
|
115
117
|
schema = graph_instance.get_input_jsonschema()
|
|
118
|
+
if schema:
|
|
119
|
+
if schema.get("properties"):
|
|
120
|
+
if schema["properties"].get("messages"):
|
|
121
|
+
schema["properties"].pop("messages")
|
|
122
|
+
if schema.get("required"):
|
|
123
|
+
required_schema = schema.get("required")
|
|
124
|
+
|
|
125
|
+
real_required_schema = []
|
|
126
|
+
for _, s in enumerate(required_schema):
|
|
127
|
+
if s == "messages":
|
|
128
|
+
continue
|
|
129
|
+
real_required_schema.append(s)
|
|
130
|
+
schema["required"] = real_required_schema
|
|
131
|
+
|
|
116
132
|
input_dict = {}
|
|
117
133
|
validation_errors = []
|
|
118
134
|
|
|
@@ -139,19 +155,6 @@ async def _execute_graph_tool(
|
|
|
139
155
|
thread_id = ctx.session_id
|
|
140
156
|
logger.info(f"execute graph {graph_name} with session id {ctx.session_id}")
|
|
141
157
|
|
|
142
|
-
user_id = None
|
|
143
|
-
if ei_token:
|
|
144
|
-
try:
|
|
145
|
-
header, payload, user_info = decode_jwt(ei_token)
|
|
146
|
-
if user_info and 'id' in user_info:
|
|
147
|
-
user_id = user_info['id']
|
|
148
|
-
logger.info(f"Extracted user_id from token: {user_id}")
|
|
149
|
-
else:
|
|
150
|
-
logger.warning("No user_id found in JWT token")
|
|
151
|
-
except Exception as e:
|
|
152
|
-
logger.warning(f"Failed to decode JWT token: {str(e)}")
|
|
153
|
-
|
|
154
|
-
# Build configurable parameters
|
|
155
158
|
configurable_params = {
|
|
156
159
|
"use_sys_llm": use_sys_llm,
|
|
157
160
|
"thread_id": thread_id,
|
|
@@ -166,53 +169,28 @@ async def _execute_graph_tool(
|
|
|
166
169
|
**configurable_params
|
|
167
170
|
}
|
|
168
171
|
|
|
169
|
-
logger.info(f"finally configurable parameter is {configurable_params}")
|
|
170
|
-
|
|
171
|
-
# Configure Langfuse callbacks if available
|
|
172
|
-
langfuse_keys = [
|
|
173
|
-
os.getenv("LANGFUSE_SECRET_KEY"),
|
|
174
|
-
os.getenv("LANGFUSE_PUBLIC_KEY"),
|
|
175
|
-
os.getenv("LANGFUSE_BASE_URL")
|
|
176
|
-
]
|
|
177
|
-
|
|
178
|
-
callbacks_config = {}
|
|
179
|
-
if all(langfuse_keys):
|
|
180
|
-
langfuse_handler = CallbackHandler()
|
|
181
|
-
callbacks_config = {"callbacks": [langfuse_handler], "run_name": f"{graph_name}_MCP_Call"}
|
|
182
|
-
|
|
183
172
|
chunks = []
|
|
184
|
-
config = {"configurable": configurable_params, **callbacks_config}
|
|
185
173
|
try:
|
|
186
|
-
async
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
subgraphs=True
|
|
207
|
-
):
|
|
208
|
-
async for chunk in handle_stream_event(stream_event):
|
|
209
|
-
yield chunk
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
async for chunk in process_stream():
|
|
213
|
-
ctx.request_context.meta = RequestParams.Meta(progressToken=ctx.request_id)
|
|
214
|
-
await ctx.report_progress(message=chunk, progress=len(chunks))
|
|
215
|
-
chunks.append(chunk)
|
|
174
|
+
async for stream_event in graph_instance.astream(
|
|
175
|
+
input_dict,
|
|
176
|
+
config={
|
|
177
|
+
"configurable": configurable_params
|
|
178
|
+
},
|
|
179
|
+
context=RuntimeContext(
|
|
180
|
+
use_system_llm=configurable_params.get("use_sys_llm"),
|
|
181
|
+
ts_tenant=configurable_params.get("TSTenant"),
|
|
182
|
+
ei_token=configurable_params.get("EIToken"),
|
|
183
|
+
input=input_dict,
|
|
184
|
+
config=configurable_params,
|
|
185
|
+
graph_name=configurable_params.get("graph_name"),
|
|
186
|
+
),
|
|
187
|
+
stream_mode=["updates"],
|
|
188
|
+
subgraphs=True
|
|
189
|
+
):
|
|
190
|
+
async for chunk in handle_stream_event(stream_event):
|
|
191
|
+
ctx.request_context.meta = RequestParams.Meta(progressToken=ctx.request_id)
|
|
192
|
+
await ctx.report_progress(message=chunk, progress=len(chunks))
|
|
193
|
+
chunks.append(chunk)
|
|
216
194
|
|
|
217
195
|
if not chunks:
|
|
218
196
|
raise ValueError("No response from graph execution")
|
|
@@ -251,6 +229,20 @@ def create_tool_from_schema(
|
|
|
251
229
|
func_doc: str = "",
|
|
252
230
|
implementation: Optional[Callable[..., Awaitable[Dict[str, Any]]]] = None
|
|
253
231
|
) -> Callable[..., Awaitable[Dict[str, Any]]]:
|
|
232
|
+
if schema:
|
|
233
|
+
if schema.get("properties"):
|
|
234
|
+
if schema["properties"].get("messages"):
|
|
235
|
+
schema["properties"].pop("messages")
|
|
236
|
+
if schema.get("required"):
|
|
237
|
+
required_schema = schema.get("required")
|
|
238
|
+
|
|
239
|
+
real_required_schema = []
|
|
240
|
+
for _, s in enumerate(required_schema):
|
|
241
|
+
if s == "messages":
|
|
242
|
+
continue
|
|
243
|
+
real_required_schema.append(s)
|
|
244
|
+
schema["required"] = real_required_schema
|
|
245
|
+
|
|
254
246
|
properties = schema.get("properties", {})
|
|
255
247
|
required = schema.get("required", [])
|
|
256
248
|
type_map = {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from langchain_mcp_adapters.interceptors import MCPToolCallRequest
|
|
2
|
+
|
|
3
|
+
async def inject_authorization(
|
|
4
|
+
request: MCPToolCallRequest,
|
|
5
|
+
handler,
|
|
6
|
+
):
|
|
7
|
+
"""Inject user credentials into MCP tool calls."""
|
|
8
|
+
runtime = request.runtime
|
|
9
|
+
authorization = runtime.context.ei_token
|
|
10
|
+
tenant_id = runtime.context.ts_tenant
|
|
11
|
+
|
|
12
|
+
if request.headers:
|
|
13
|
+
headers = {**request.headers, "TSTenant": tenant_id, "Authorization": f"Bearer {authorization}"}
|
|
14
|
+
else:
|
|
15
|
+
headers = {"TSTenant": tenant_id, "Authorization": f"Bearer {authorization}"}
|
|
16
|
+
# Add user context to tool arguments
|
|
17
|
+
modified_request = request.override(
|
|
18
|
+
headers={**headers}
|
|
19
|
+
)
|
|
20
|
+
return await handler(modified_request)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from langchain_core.messages import HumanMessage
|
|
2
|
+
|
|
3
|
+
from agent_api_server.middleware.schema import InputState
|
|
4
|
+
from agent_api_server.schema.context import Context
|
|
5
|
+
from agent_api_server.dynamic_llm.model import get_chat_model_instance
|
|
6
|
+
from langchain.agents.middleware import AgentMiddleware, ModelRequest, ModelResponse, wrap_tool_call
|
|
7
|
+
from typing import Callable
|
|
8
|
+
|
|
9
|
+
class ModelMiddleware(AgentMiddleware[InputState]):
|
|
10
|
+
state_schema = InputState
|
|
11
|
+
|
|
12
|
+
def __init__(self, use_system_llm:bool=False):
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.use_system_llm = use_system_llm
|
|
15
|
+
|
|
16
|
+
async def abefore_agent(self,state: InputState) -> ModelRequest:
|
|
17
|
+
human_message = [HumanMessage(content=state["user_input"])]
|
|
18
|
+
return {
|
|
19
|
+
"messages": [
|
|
20
|
+
*state["messages"],
|
|
21
|
+
*human_message
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async def awrap_model_call(
|
|
26
|
+
self,
|
|
27
|
+
request: ModelRequest,
|
|
28
|
+
handler: Callable[[ModelRequest], ModelResponse],
|
|
29
|
+
) -> ModelResponse:
|
|
30
|
+
context: Context = request.runtime.context
|
|
31
|
+
if context.use_system_llm is None:
|
|
32
|
+
context.use_system_llm = self.use_system_llm
|
|
33
|
+
|
|
34
|
+
model_instance = get_chat_model_instance(context)
|
|
35
|
+
|
|
36
|
+
model_settings = request.model_settings.copy()
|
|
37
|
+
model_settings.pop("cache_control", None)
|
|
38
|
+
|
|
39
|
+
return await handler(request.override(model=model_instance, model_settings=model_settings))
|
|
40
|
+
|
|
41
|
+
class ChangeModel(AgentMiddleware):
|
|
42
|
+
def __init__(self, use_system_llm: bool = False):
|
|
43
|
+
super().__init__()
|
|
44
|
+
self.use_system_llm = use_system_llm
|
|
45
|
+
|
|
46
|
+
async def awrap_model_call(
|
|
47
|
+
self,
|
|
48
|
+
request: ModelRequest,
|
|
49
|
+
handler: Callable[[ModelRequest], ModelResponse],
|
|
50
|
+
) -> ModelResponse:
|
|
51
|
+
context: Context = request.runtime.context
|
|
52
|
+
context.use_system_llm = self.use_system_llm
|
|
53
|
+
|
|
54
|
+
model_instance = get_chat_model_instance(context)
|
|
55
|
+
|
|
56
|
+
model_settings = request.model_settings.copy()
|
|
57
|
+
model_settings.pop("cache_control", None)
|
|
58
|
+
|
|
59
|
+
return await handler(request.override(model=model_instance, model_settings=model_settings))
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
@dataclass
|
|
6
|
+
class Context:
|
|
7
|
+
ts_tenant: str
|
|
8
|
+
use_system_llm: Optional[bool] = None
|
|
9
|
+
input: Optional[dict] = None
|
|
10
|
+
ei_token: Optional[str] = None
|
|
11
|
+
graph_name: Optional[str] = None
|
|
12
|
+
files: Optional[list[dict]] = None
|
|
13
|
+
config: Optional[dict] = None
|
|
File without changes
|