+
+
AI 模型配置
+
密钥仅保存在服务器端,浏览器无法读取明文
+
+
+
+ {config?.enabled ? '已启用' : '未启用'}
+
+ {config?.verified && 已验证}
+ {config?.hasApiKey && (
+
+ 密钥: {sourceLabel(config?.keySource || 'none')}
+
+ )}
+
+
+
+
+
+
+ {/* Test result */}
+ {testResult && (
+
+
+
+ {testResult.success ? (
+ testResult.modelAvailable ? (
+ } color="success">
+ 成功
+
+ ) : (
+ } color="warning">
+ 模型未找到
+
+ )
+ ) : (
+ } color="error">
+ 失败
+
+ )}
+
+
+ {testResult.latencyMs != null ? `${testResult.latencyMs} ms` : '-'}
+
+
+ {testResult.modelCount != null ? testResult.modelCount : '-'}
+
+
+ {formatDateTime(testResult.testedAt)}
+
+
+
+
+ )}
+
+ );
+};
+
+export default AiConfigPage;
diff --git a/apps/server/package.json b/apps/server/package.json
index 95526d5..39fbd54 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -8,10 +8,9 @@
"scripts": {
"dev": "SEED_DEV=true nest start --watch -p tsconfig.build.json",
"build": "nest build -p tsconfig.build.json",
- "start:dev": "SEED_DEV=true nest start --watch",
+ "start:dev": "nest start --watch",
"format": "oxfmt",
"start": "nest start",
- "start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
@@ -23,6 +22,7 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
+ "@casl/ability": "^7.0.1",
"@nestjs/common": "^11.0.1",
"@nestjs/config": "^4.0.4",
"@nestjs/core": "^11.0.1",
diff --git a/apps/server/src/agent-tools/agent-tool.executor.spec.ts b/apps/server/src/agent-tools/agent-tool.executor.spec.ts
new file mode 100644
index 0000000..4db5e9a
--- /dev/null
+++ b/apps/server/src/agent-tools/agent-tool.executor.spec.ts
@@ -0,0 +1,678 @@
+import { NotFoundException } from '@nestjs/common';
+import { CaslAbilityFactory } from '../authorization/casl-ability.factory';
+import { AuthorizationService } from '../authorization/authorization.service';
+import { AgentToolRegistry } from './agent-tool.registry';
+import { AgentToolExecutor } from './agent-tool.executor';
+import { AgentToolContextFactory, AgentToolContext } from './agent-tool.types';
+import type { ToolDef, ToolInputResult, ToolDescriptor } from './agent-tool.types';
+import type { AuthenticatedUser } from '../authorization';
+
+// ---------------------------------------------------------------------------
+// Helpers
+// ---------------------------------------------------------------------------
+
+const abilityFactory = new CaslAbilityFactory();
+
+/** Create context via the factory (the ONLY valid path). */
+function makeCtx(user: Partial