diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..55eb5d3
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,9 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+*.class
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..b221fc0
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 0000000..b2ddf3f
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,17 @@
+
+
+
+
+ mysql.8
+ true
+ com.mysql.cj.jdbc.Driver
+ jdbc:mysql://localhost:3306
+
+
+
+
+
+ $ProjectFileDir$
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..63e9001
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..ea7349c
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..9dc782b
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/disign.md b/disign.md
new file mode 100644
index 0000000..87e1478
--- /dev/null
+++ b/disign.md
@@ -0,0 +1,134 @@
+# enterprise-ai-agent-gateway
+企业级 AI 智能体网关
+
+这份终稿设计书已经为你全面整合完毕。它不仅包含了底层的**数据库模型**和**网关责任链**,还把你刚刚关心的**“前端如何降低脚本编写成本”**的设计思路,以及核心的**系统提示词(System Prompt)**全部固化了进去。
+
+你可以直接将以下全部内容复制,喂给 Antigravity,让它开始生成骨架代码。
+
+***
+
+# 🚀 Enterprise AI Agent Gateway (企业级 AI 智能体网关) - 核心架构与开发设计书
+
+## 1. 架构定位与核心设计理念
+本系统是一个定位于大模型(LLM/AI Agent)与企业老旧业务系统(Legacy Systems)之间的**安全中间件与协议转换枢纽**。
+* **零侵入架构**:老系统无需修改任何代码,通过本网关即可将现有 API 暴露为标准的大模型 Tool Schema。
+* **控制面与数据面分离**:
+ * **控制面 (Control Plane)**:前端可视化配置,业务人员通过“表单填报”或“AI 辅助生成”完成 API 注册与清洗规则设定。
+ * **数据面 (Data Plane)**:纯粹的 Java 高并发执行引擎,负责鉴权、状态挂起(人工审批)、代理调用与底层 GraalVM 极速数据洗涤。
+
+## 2. 技术栈选型
+* **数据面网关核心**:Spring Boot 3.x (WebFlux/纯 WebMVC) + JDK 17/21。
+* **清洗执行引擎**:GraalVM Polyglot (内嵌高安全级别的 JavaScript 运行时沙箱)。
+* **缓存与风控**:Redis (分布式限流、状态机挂起) + Caffeine (本地极速配置缓存)。
+* **控制面后端**:Spring Boot / FastAPI (提供标准的 CRUD 接口)。
+* **前端管理台**:Vue 3 + Element Plus / Ant Design Vue + Monaco Editor。
+* **数据存储**:MySQL 8.0。
+
+---
+
+## 3. 核心数据库实体模型 (MySQL 8.0 DDL 需求)
+
+> **To Antigravity**: 请基于以下实体关系,优先生成 DDL 建表语句以及对应的底层 CRUD 代码(Entity/Mapper/Service)。
+
+### 3.1 `ai_tenant` (租户/AI 助手接入表)
+* `id`: 主键
+* `tenant_name`: 租户/机器人名称(例:“财务客服 Agent”)
+* `app_key`: 网关调用的唯一凭证 (唯一索引)
+* `app_secret`: 签名与加解密密钥
+* `rate_limit_qps`: 该租户的全局 QPS 限制阈值
+* `status`: 状态 (启用/禁用)
+
+### 3.2 `ai_tool_registry` (API 工具注册表)
+* `id`: 主键
+* `tool_name`: 工具标识(英文下划线,符合 LLM 命名规范)
+* `description`: 喂给大模型的详细描述(决定 LLM 是否调用该工具的核心依据)
+* `action_type`: `READ` (默认放行) / `WRITE` (高危,强制触发人工审批)
+* `target_url`: 底层老系统的真实内网 URL
+* `http_method`: GET / POST
+* `request_schema`: 请求参数的标准 JSON Schema (用于 LLM 识别)
+
+### 3.3 `ai_tenant_tool_rel` (权限控制映射表)
+* `tenant_id`: 关联 `ai_tenant.id`
+* `tool_id`: 关联 `ai_tool_registry.id`
+
+### 3.4 `ai_wash_script` (GraalVM 数据清洗脚本表)
+* `tool_id`: 唯一关联 `ai_tool_registry.id`
+* `js_script`: 具体的 JavaScript 源码文本(由控制面生成,供数据面 GraalVM 执行)
+* `version`: 版本号,用于并发控制和缓存刷新
+
+### 3.5 `ai_audit_log` (全链路安全审计日志表)
+* `trace_id`: 全局请求流水号 (UUID)
+* `tenant_id`: 关联的租户 ID
+* `tool_name`: 命中的工具名称
+* `raw_request`: AI 发起的原始 JSON 参数
+* `raw_response`: 老系统返回的巨型原始 JSON (MediumText)
+* `washed_response`: 经过 GraalVM JS 脚本洗涤后的纯净 JSON
+* `cost_time_ms`: 总耗时 (毫秒)
+
+---
+
+## 4. 控制面前端 (Vue 3) 交互设计规范
+
+前端的核心目标是**隐藏 JavaScript 的编写复杂度**。对于清洗规则 (`ai_wash_script`) 的配置页面,需实现以下三层交互降级方案:
+
+1. **AI Copilot 生成(主推)**:页面提供左侧输入“原始 JSON 样例”,上方输入“自然语言提取需求”,点击按钮后,后台调用大模型生成 JS 代码并填充。
+2. **可视化勾选表单(中阶)**:提供“保留字段白名单”、“移除 Null 值”、“拍平数组”等勾选项,前端根据勾选自动拼接为 JS 字符串。
+3. **Monaco Editor 兜底(高阶)**:提供类似 VS Code 的代码编辑框,允许懂代码的开发人员直接修正在线生成的 JavaScript 规则。
+
+---
+
+## 5. 数据面网关 Pipeline (责任链/Filter Chain 设计)
+
+> **To Antigravity**: 在生成网关核心转发逻辑时,请严格按照以下 Filter 顺序构建职责链模式。
+
+1. **Config Watcher (配置加载)**:定时从 MySQL 拉取 `ai_tool_registry`、权限与 `js_script`,加载至 Caffeine 内存。
+2. **Auth & Rate Limiting (鉴权限流)**:校验 `app_key`,拦截非法调用;利用 Redis 执行令牌桶限流。
+3. **Identity OBO (权限穿透)**:若包含终端用户 Token,将该身份附加至 Downstream Header 中。
+4. **HITL Suspender (审批挂起)**:若 `action_type == 'WRITE'`,拦截当前线程,向外部(如企微/钉钉)发送包含审批链接的 Webhook,当前请求挂起等待回调。
+5. **Proxy Execution (代理转发)**:组装参数,向 `target_url` 发起真实的 HTTP 内部请求。
+6. **GraalVM Washing (洗涤瘦身)**:拿到原始大 JSON,在限制了内存与执行时间(如 max 100ms)的 GraalVM 沙箱中执行对应的 `js_script`,返回瘦身结果。
+7. **Async Audit (异步审计)**:无论成功失败,将完整上下文抛入线程池,落库至 `ai_audit_log`。
+
+---
+
+## 6. 核心资产:AI 辅助生成清洗脚本的 System Prompt
+
+> 针对控制面的“AI 自动生成 JS 规则”功能,后端需要内置以下 System Prompt。
+
+```text
+# Role
+你是一个资深的 JavaScript 数据处理专家与大模型工程架构师。
+
+# Objective
+你的任务是根据用户提供的【原始庞大 JSON 样例】和【自然语言提取要求】,编写一段精简、安全、高效的 JavaScript 代码,用于在 GraalVM 环境下对 JSON 进行瘦身清洗。这段清洗后的数据将被直接喂给大模型(LLM)作为上下文。
+
+# Constraints & Rules
+1. 你的输出必须且只能包含一个名为 `wash` 的 JavaScript 函数。
+2. 该函数的入参必须是 `rawJsonString` (字符串类型)。
+3. 该函数的返回值必须是清洗并序列化后的 JSON 字符串,以确保后续直接使用。
+4. 代码必须健壮,需处理常见的空指针(undefined/null)和数组越界异常。
+5. 必须剔除所有无业务价值的字段(如 HTML 标签、内部 traceId、全 null 字段等),最大限度节省 LLM 的 Token。
+6. 不要使用任何外部依赖或 npm 包,只能使用 ES6+ 标准原生语法。
+
+# Output Format Example
+```javascript
+function wash(rawJsonString) {
+ try {
+ const data = JSON.parse(rawJsonString);
+ if (!data || !data.list) return "[]";
+
+ const result = data.list.map(item => ({
+ eventName: item.event_name || '未知',
+ date: item.timestamp ? new Date(item.timestamp).toISOString().split('T')[0] : '',
+ coreProfit: item.financial_data?.net_profit ?? 0
+ }));
+
+ return JSON.stringify(result);
+ } catch (e) {
+ return JSON.stringify({ error: "数据清洗失败" });
+ }
+}
+```
+***
+
+把这份文档丢给 Antigravity 后,你可以直接下达指令:**“请先根据第 3 节生成所有 MySQL 建表语句,然后生成第 5 节的 Filter 责任链代码骨架。”** 期待你的架构早日跑通!
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..ef8ef25
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,99 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.2.4
+
+
+ com.cicc.enterprise
+ ai-agent-gateway
+ 1.0.0-SNAPSHOT
+ ai-agent-gateway
+ Enterprise AI Agent Gateway
+
+
+ 21
+ 23.1.2
+ 3.5.5
+ 2.0.47
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+ com.github.ben-manes.caffeine
+ caffeine
+
+
+ com.baomidou
+ mybatis-plus-spring-boot3-starter
+ ${mybatis-plus.version}
+
+
+ com.mysql
+ mysql-connector-j
+ runtime
+
+
+ com.alibaba.fastjson2
+ fastjson2
+ ${fastjson2.version}
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+ org.graalvm.polyglot
+ polyglot
+ ${graalvm.version}
+
+
+ org.graalvm.polyglot
+ js
+ ${graalvm.version}
+ pom
+
+
+
+
+ com.squareup.okhttp3
+ okhttp
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
diff --git a/src/main/java/com/cicc/enterprise/gateway/GatewayApplication.java b/src/main/java/com/cicc/enterprise/gateway/GatewayApplication.java
new file mode 100644
index 0000000..75a8f29
--- /dev/null
+++ b/src/main/java/com/cicc/enterprise/gateway/GatewayApplication.java
@@ -0,0 +1,13 @@
+package com.cicc.enterprise.gateway;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+
+@SpringBootApplication
+@EnableCaching
+public class GatewayApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(GatewayApplication.class, args);
+ }
+}
diff --git a/src/main/java/com/cicc/enterprise/gateway/config/MybatisPlusConfig.java b/src/main/java/com/cicc/enterprise/gateway/config/MybatisPlusConfig.java
new file mode 100644
index 0000000..d23924a
--- /dev/null
+++ b/src/main/java/com/cicc/enterprise/gateway/config/MybatisPlusConfig.java
@@ -0,0 +1,19 @@
+package com.cicc.enterprise.gateway.config;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@MapperScan("com.cicc.enterprise.gateway.mapper")
+public class MybatisPlusConfig {
+ @Bean
+ public MybatisPlusInterceptor mybatisPlusInterceptor() {
+ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+ interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+ return interceptor;
+ }
+}
diff --git a/src/main/java/com/cicc/enterprise/gateway/config/RedisConfig.java b/src/main/java/com/cicc/enterprise/gateway/config/RedisConfig.java
new file mode 100644
index 0000000..0fe6209
--- /dev/null
+++ b/src/main/java/com/cicc/enterprise/gateway/config/RedisConfig.java
@@ -0,0 +1,23 @@
+package com.cicc.enterprise.gateway.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+@Configuration
+public class RedisConfig {
+ @Bean
+ public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {
+ RedisTemplate template = new RedisTemplate<>();
+ template.setConnectionFactory(connectionFactory);
+ template.setKeySerializer(new StringRedisSerializer());
+ template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
+ template.setHashKeySerializer(new StringRedisSerializer());
+ template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
+ template.afterPropertiesSet();
+ return template;
+ }
+}
diff --git a/src/main/java/com/cicc/enterprise/gateway/controller/ControlPlaneAdminController.java b/src/main/java/com/cicc/enterprise/gateway/controller/ControlPlaneAdminController.java
new file mode 100644
index 0000000..3100b11
--- /dev/null
+++ b/src/main/java/com/cicc/enterprise/gateway/controller/ControlPlaneAdminController.java
@@ -0,0 +1,58 @@
+package com.cicc.enterprise.gateway.controller;
+
+import com.cicc.enterprise.gateway.model.AiToolRegistry;
+import com.cicc.enterprise.gateway.service.AiToolRegistryService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/api/v1/admin")
+@RequiredArgsConstructor
+public class ControlPlaneAdminController {
+
+ private final AiToolRegistryService toolRegistryService;
+
+ // Standard CRUD
+ @GetMapping("/tools")
+ public List listTools() {
+ return toolRegistryService.list();
+ }
+
+ @PostMapping("/tools")
+ public AiToolRegistry createTool(@RequestBody AiToolRegistry tool) {
+ toolRegistryService.save(tool);
+ return tool;
+ }
+
+ // AI Copilot Mock API for Wash Script Generation
+ @PostMapping("/copilot/generate-wash-script")
+ public Map generateWashScript(@RequestBody Map request) {
+ // Extract parameters from request if needed for dynamic prompt building
+ // String rawJsonSample = request.get("rawJsonSample");
+ // String requirement = request.get("requirement");
+ String systemPrompt = """
+ # Role
+ 你是一个资深的 JavaScript 数据处理专家与大模型工程架构师。
+
+ # Objective
+ 根据用户提供的【原始庞大 JSON 样例】和【自然语言提取要求】,编写一段精简、安全、高效的 JavaScript 代码,用于在 GraalVM 环境下对 JSON 进行瘦身清洗。这段清洗后的数据将被直接喂给大模型(LLM)作为上下文。
+
+ # Constraints & Rules
+ 1. 你的输出必须且只能包含一个名为 `wash` 的 JavaScript 函数。
+ 2. 该函数的入参必须是 `rawJsonString` (字符串类型)。
+ 3. 该函数的返回值必须是清洗并序列化后的 JSON 字符串,以确保后续直接使用。
+ ...
+ """;
+
+ Map response = new HashMap<>();
+ response.put("mockedSystemPrompt", systemPrompt);
+ response.put("status", "This endpoint should delegate to an LLM provider to generate the JS string.");
+ response.put("dummyOutput", "function wash(rawJsonString) { return '{}'; }");
+
+ return response;
+ }
+}
diff --git a/src/main/java/com/cicc/enterprise/gateway/controller/GatewayEntryController.java b/src/main/java/com/cicc/enterprise/gateway/controller/GatewayEntryController.java
new file mode 100644
index 0000000..3e1d363
--- /dev/null
+++ b/src/main/java/com/cicc/enterprise/gateway/controller/GatewayEntryController.java
@@ -0,0 +1,65 @@
+package com.cicc.enterprise.gateway.controller;
+
+import com.cicc.enterprise.gateway.filter.core.GatewayContext;
+import com.cicc.enterprise.gateway.filter.core.GatewayFilterExecutor;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+import java.util.UUID;
+
+@Slf4j
+@RestController
+@RequestMapping("/api/v1/gw")
+@RequiredArgsConstructor
+public class GatewayEntryController {
+
+ private final GatewayFilterExecutor filterExecutor;
+
+ @RequestMapping(value = "/invoke/{toolName}", method = {RequestMethod.GET, RequestMethod.POST})
+ public ResponseEntity