|
|
@@ -1,11 +1,13 @@
|
|
|
import type { AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from "axios";
|
|
|
import type {
|
|
|
AgentDefinition,
|
|
|
+ AgentConfig,
|
|
|
AgentRun,
|
|
|
- AgentVersion,
|
|
|
+ ApiResponse,
|
|
|
ApiKeyCreateResponse,
|
|
|
ApiKeyResponse,
|
|
|
AppResponse,
|
|
|
+ AuthMeData,
|
|
|
DiscoverModelsResponse,
|
|
|
DownstreamServiceHealth,
|
|
|
ExecutionLog,
|
|
|
@@ -14,7 +16,7 @@ import type {
|
|
|
KnowledgeBase,
|
|
|
KnowledgeChunk,
|
|
|
KnowledgeDocument,
|
|
|
- LoginResponse,
|
|
|
+ LoginData,
|
|
|
MemoryItem,
|
|
|
MemorySearchResult,
|
|
|
MemoryStatus,
|
|
|
@@ -40,12 +42,19 @@ import type {
|
|
|
WorkflowRun,
|
|
|
} from "@/types";
|
|
|
|
|
|
-export const mockMode = import.meta.env.VITE_USE_MOCKS !== "false";
|
|
|
+export const mockMode = import.meta.env.VITE_USE_MOCKS === "true";
|
|
|
|
|
|
const now = new Date();
|
|
|
const iso = (offsetMinutes = 0) => new Date(now.getTime() + offsetMinutes * 60_000).toISOString();
|
|
|
const id = (prefix: string) => `${prefix}_${Math.random().toString(36).slice(2, 10)}`;
|
|
|
const hashText = (value: string) => Array.from(value).reduce((hash, token, index) => ((hash << 5) - hash + token.length + index) | 0, 0);
|
|
|
+const identityResponse = <T>(data: T): ApiResponse<T> => ({
|
|
|
+ success: true,
|
|
|
+ data,
|
|
|
+ error: null,
|
|
|
+ requestId: id("req"),
|
|
|
+ serverTime: iso(),
|
|
|
+});
|
|
|
|
|
|
const apps: AppResponse[] = [
|
|
|
{
|
|
|
@@ -87,12 +96,10 @@ const agents: AgentDefinition[] = [
|
|
|
},
|
|
|
];
|
|
|
|
|
|
-const agentVersions: AgentVersion[] = [
|
|
|
+const agentConfigs: AgentConfig[] = [
|
|
|
{
|
|
|
id: "agv_support_2",
|
|
|
agent_id: "agent_support",
|
|
|
- version_no: 2,
|
|
|
- status: "published",
|
|
|
role: "assistant",
|
|
|
goal: "Resolve customer requests with context.",
|
|
|
system_prompt: "You are a concise operations assistant.",
|
|
|
@@ -101,7 +108,6 @@ const agentVersions: AgentVersion[] = [
|
|
|
runtime_policy_json: {},
|
|
|
tool_refs_json: [{ tool_id: "tool_mcp_database" }],
|
|
|
skill_refs_json: [],
|
|
|
- published_time: iso(-1100),
|
|
|
created_time: iso(-1500),
|
|
|
},
|
|
|
];
|
|
|
@@ -839,6 +845,10 @@ const toolCredentials: ToolCredential[] = [
|
|
|
},
|
|
|
];
|
|
|
|
|
|
+const mockCredentialSecrets = new Map<string, JSONObject>(
|
|
|
+ toolCredentials.map((item) => [item.id, { mocked: true, credentialId: item.id }]),
|
|
|
+);
|
|
|
+
|
|
|
const knowledgeBases: KnowledgeBase[] = [
|
|
|
{
|
|
|
id: "kb_product",
|
|
|
@@ -980,12 +990,12 @@ const apiKeys: ApiKeyResponse[] = [
|
|
|
const demoUser = {
|
|
|
id: "demo-user",
|
|
|
username: "demo-user",
|
|
|
- display_name: "Demo User",
|
|
|
+ displayName: "Demo User",
|
|
|
email: "demo@example.com",
|
|
|
- status: "active" as const,
|
|
|
- metadata_json: {},
|
|
|
- last_login_time: iso(-5),
|
|
|
- created_time: iso(-5000),
|
|
|
+ metadata: {},
|
|
|
+ lastLoginTime: iso(-5),
|
|
|
+ createdTime: iso(-5000),
|
|
|
+ updatedTime: iso(-10),
|
|
|
};
|
|
|
|
|
|
const services: DownstreamServiceHealth[] = [
|
|
|
@@ -996,7 +1006,7 @@ const services: DownstreamServiceHealth[] = [
|
|
|
"tool-service",
|
|
|
"knowledge-service",
|
|
|
"team-service",
|
|
|
- "auth-service",
|
|
|
+ "identity-service",
|
|
|
].map((service) => ({ service, status: "ok", url: `mock://${service}`, http_status: 200, error_message: null }));
|
|
|
|
|
|
const modelProviders: ModelProvider[] = [
|
|
|
@@ -1088,16 +1098,84 @@ function route(config: AxiosRequestConfig): unknown {
|
|
|
|
|
|
if (url === "/services/health") return { service: "api-gateway", status: "ok", downstream_services: services } satisfies GatewayServicesHealth;
|
|
|
|
|
|
- if (url === "/auth/login" && method === "post") {
|
|
|
- return {
|
|
|
- access_token: "mock-access-token",
|
|
|
- token_type: "bearer",
|
|
|
- expires_time: iso(480),
|
|
|
+ if (url === "/identity/auth/login" && method === "post") {
|
|
|
+ return identityResponse({
|
|
|
+ accessToken: "mock-access-token",
|
|
|
+ tokenType: "bearer",
|
|
|
+ expiresTime: iso(480),
|
|
|
user: {
|
|
|
...demoUser,
|
|
|
username: String(payload.username ?? "demo-user"),
|
|
|
},
|
|
|
- } satisfies LoginResponse;
|
|
|
+ } satisfies LoginData);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (url === "/identity/auth/logout" && method === "post") {
|
|
|
+ return identityResponse({ ok: true });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (url === "/identity/auth/me" && method === "post") {
|
|
|
+ return identityResponse({
|
|
|
+ user: demoUser,
|
|
|
+ roles: [
|
|
|
+ {
|
|
|
+ id: "role_admin",
|
|
|
+ name: "Administrator",
|
|
|
+ description: "Full platform operator",
|
|
|
+ permissionBindingCount: 2,
|
|
|
+ createdTime: iso(-6000),
|
|
|
+ updatedTime: iso(-5000),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ permissions: ["agents:*", "knowledge:*"],
|
|
|
+ } satisfies AuthMeData);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (url === "/identity/auth/tokens/verify" && method === "post") {
|
|
|
+ return identityResponse({
|
|
|
+ active: true,
|
|
|
+ userId: demoUser.id,
|
|
|
+ username: demoUser.username,
|
|
|
+ expiresTime: iso(480),
|
|
|
+ reason: null,
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (url === "/identity/users/list" && method === "post") {
|
|
|
+ return identityResponse({
|
|
|
+ items: [demoUser],
|
|
|
+ total: 1,
|
|
|
+ page: Number(payload.page ?? 1),
|
|
|
+ pageSize: Number(payload.pageSize ?? 20),
|
|
|
+ hasMore: false,
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (url === "/identity/roles/list" && method === "post") {
|
|
|
+ return identityResponse({
|
|
|
+ items: [
|
|
|
+ {
|
|
|
+ id: "role_admin",
|
|
|
+ name: "Administrator",
|
|
|
+ description: "Full platform operator",
|
|
|
+ permissionBindingCount: 2,
|
|
|
+ createdTime: iso(-6000),
|
|
|
+ updatedTime: iso(-5000),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ total: 1,
|
|
|
+ page: Number(payload.page ?? 1),
|
|
|
+ pageSize: Number(payload.pageSize ?? 20),
|
|
|
+ hasMore: false,
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (url === "/identity/permissions/check" && method === "post") {
|
|
|
+ return identityResponse({
|
|
|
+ allowed: true,
|
|
|
+ reason: "matched",
|
|
|
+ matchedRoleIds: ["role_admin"],
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
if (url === "/api-keys" && method === "get") return apiKeys;
|
|
|
@@ -1139,27 +1217,24 @@ function route(config: AxiosRequestConfig): unknown {
|
|
|
agents.unshift(created);
|
|
|
return created;
|
|
|
}
|
|
|
- if (url === "/agents/versions" && method === "post") {
|
|
|
- const created: AgentVersion = {
|
|
|
+ if (url === "/agents/configs/create" && method === "post") {
|
|
|
+ const created: AgentConfig = {
|
|
|
id: id("agv"),
|
|
|
agent_id: String(payload.agent_id),
|
|
|
- version_no: agentVersions.filter((v) => v.agent_id === payload.agent_id).length + 1,
|
|
|
- status: (payload.status as AgentVersion["status"]) ?? "draft",
|
|
|
role: String(payload.role ?? "assistant"),
|
|
|
goal: (payload.goal as string | null) ?? null,
|
|
|
system_prompt: String(payload.system_prompt ?? ""),
|
|
|
- model_config_json: (payload.model_config_json as JSONObject) ?? {},
|
|
|
- memory_policy_json: (payload.memory_policy_json as JSONObject) ?? {},
|
|
|
- runtime_policy_json: (payload.runtime_policy_json as JSONObject) ?? {},
|
|
|
- tool_refs_json: (payload.tool_refs_json as JSONObject[]) ?? [],
|
|
|
- skill_refs_json: (payload.skill_refs_json as JSONObject[]) ?? [],
|
|
|
- published_time: null,
|
|
|
+ model_config_json: (payload.model_config as JSONObject) ?? {},
|
|
|
+ memory_policy_json: (payload.memory_policy as JSONObject) ?? {},
|
|
|
+ runtime_policy_json: (payload.runtime_policy as JSONObject) ?? {},
|
|
|
+ tool_refs_json: (payload.tool_refs as JSONObject[]) ?? [],
|
|
|
+ skill_refs_json: (payload.skill_refs as JSONObject[]) ?? [],
|
|
|
created_time: iso(),
|
|
|
};
|
|
|
- agentVersions.unshift(created);
|
|
|
+ agentConfigs.unshift(created);
|
|
|
return created;
|
|
|
}
|
|
|
- if (url === "/agents/versions" && method === "get") return agentVersions.filter((item) => item.agent_id === params.agent_id);
|
|
|
+ if (url === "/agents/configs/list" && method === "post") return agentConfigs.filter((item) => item.agent_id === payload.agent_id);
|
|
|
if (url === "/agents/runs") return params.agent_id ? agentRuns.filter((item) => item.agent_id === params.agent_id) : agentRuns;
|
|
|
|
|
|
if (url === "/skills" && method === "get") return skills;
|
|
|
@@ -1390,51 +1465,233 @@ function route(config: AxiosRequestConfig): unknown {
|
|
|
} satisfies ModelTestResponse;
|
|
|
}
|
|
|
|
|
|
- if (url === "/tools" && method === "get") return tools;
|
|
|
- if (url === "/tools" && method === "post") {
|
|
|
+ if (url === "/tools/list" && method === "post") {
|
|
|
+ const keyword = String(payload.keyword ?? "").toLowerCase().trim();
|
|
|
+ const filtered = tools.filter((item) => {
|
|
|
+ const haystack = `${item.name} ${item.tool_type} ${item.description ?? ""}`.toLowerCase();
|
|
|
+ return !keyword || haystack.includes(keyword);
|
|
|
+ });
|
|
|
+ const page = Number(payload.page ?? 1);
|
|
|
+ const pageSize = Number(payload.pageSize ?? 200);
|
|
|
+ const start = (page - 1) * pageSize;
|
|
|
+ return identityResponse({
|
|
|
+ items: filtered.slice(start, start + pageSize).map(toToolDto),
|
|
|
+ total: filtered.length,
|
|
|
+ page,
|
|
|
+ pageSize,
|
|
|
+ hasMore: page * pageSize < filtered.length,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (url === "/tools/detail" && method === "post") {
|
|
|
+ const target = tools.find((item) => item.id === payload.toolId);
|
|
|
+ return identityResponse(toToolDto(target ?? tools[0]));
|
|
|
+ }
|
|
|
+ if (url === "/tools/create" && method === "post") {
|
|
|
const created: ToolDefinition = {
|
|
|
id: id("tool"),
|
|
|
- plugin_id: (payload.plugin_id as string | null) ?? null,
|
|
|
+ plugin_id: (payload.pluginId as string | null) ?? null,
|
|
|
name: String(payload.name ?? "New Tool"),
|
|
|
- tool_type: String(payload.tool_type ?? "http"),
|
|
|
+ tool_type: String(payload.toolType ?? "http"),
|
|
|
description: (payload.description as string | null) ?? null,
|
|
|
created_time: iso(),
|
|
|
};
|
|
|
tools.unshift(created);
|
|
|
- return created;
|
|
|
+ return identityResponse(toToolDto(created));
|
|
|
+ }
|
|
|
+ if (url === "/tools/update" && method === "post") {
|
|
|
+ const target = tools.find((item) => item.id === payload.toolId);
|
|
|
+ if (target) {
|
|
|
+ if (typeof payload.name === "string") target.name = payload.name;
|
|
|
+ if (typeof payload.toolType === "string") target.tool_type = payload.toolType;
|
|
|
+ if ("description" in payload) target.description = (payload.description as string | null) ?? null;
|
|
|
+ if ("pluginId" in payload) target.plugin_id = (payload.pluginId as string | null) ?? null;
|
|
|
+ }
|
|
|
+ return identityResponse(toToolDto(target ?? tools[0]));
|
|
|
+ }
|
|
|
+ if (url === "/tools/delete" && method === "post") {
|
|
|
+ const index = tools.findIndex((item) => item.id === payload.toolId);
|
|
|
+ if (index >= 0) tools.splice(index, 1);
|
|
|
+ return identityResponse({ deleted: index >= 0, toolId: payload.toolId ?? null });
|
|
|
+ }
|
|
|
+ if (url === "/tools/connections/list" && method === "post") {
|
|
|
+ const filtered = payload.toolId
|
|
|
+ ? toolVersions.filter((item) => item.tool_id === payload.toolId)
|
|
|
+ : toolVersions;
|
|
|
+ const page = Number(payload.page ?? 1);
|
|
|
+ const pageSize = Number(payload.pageSize ?? 500);
|
|
|
+ const start = (page - 1) * pageSize;
|
|
|
+ return identityResponse({
|
|
|
+ items: filtered.slice(start, start + pageSize).map(toToolVersionDto),
|
|
|
+ total: filtered.length,
|
|
|
+ page,
|
|
|
+ pageSize,
|
|
|
+ hasMore: page * pageSize < filtered.length,
|
|
|
+ });
|
|
|
}
|
|
|
- if (url === "/tools/versions" && method === "get") return params.tool_id ? toolVersions.filter((item) => item.tool_id === params.tool_id) : toolVersions;
|
|
|
- if (url === "/tools/versions" && method === "post") {
|
|
|
- const versionNo = toolVersions.filter((item) => item.tool_id === payload.tool_id).length + 1;
|
|
|
+ if (url === "/tools/connections/detail" && method === "post") {
|
|
|
+ const target = toolVersions.find((item) => item.id === payload.connectionId);
|
|
|
+ return identityResponse(toToolVersionDto(target ?? toolVersions[0]));
|
|
|
+ }
|
|
|
+ if (url === "/tools/connections/create" && method === "post") {
|
|
|
+ const toolId = String(payload.toolId);
|
|
|
+ const versionNo = toolVersions.filter((item) => item.tool_id === toolId).length + 1;
|
|
|
const created: ToolVersion = {
|
|
|
id: id("tv"),
|
|
|
- tool_id: String(payload.tool_id),
|
|
|
+ tool_id: toolId,
|
|
|
version_no: versionNo,
|
|
|
- input_schema_json: (payload.input_schema_json as Record<string, never>) ?? {},
|
|
|
- output_schema_json: (payload.output_schema_json as Record<string, never>) ?? {},
|
|
|
- invoke_config_json: (payload.invoke_config_json as Record<string, never>) ?? {},
|
|
|
- timeout_ms: Number(payload.timeout_ms ?? 5000),
|
|
|
- retry_policy_json: (payload.retry_policy_json as Record<string, never>) ?? {},
|
|
|
+ input_schema_json: (payload.inputSchema as Record<string, never>) ?? {},
|
|
|
+ output_schema_json: (payload.outputSchema as Record<string, never>) ?? {},
|
|
|
+ invoke_config_json: (payload.invokeConfig as Record<string, never>) ?? {},
|
|
|
+ timeout_ms: Number(payload.timeoutMs ?? 5000),
|
|
|
+ retry_policy_json: (payload.retryPolicy as Record<string, never>) ?? {},
|
|
|
created_time: iso(),
|
|
|
};
|
|
|
toolVersions.unshift(created);
|
|
|
- return created;
|
|
|
+ return identityResponse(toToolVersionDto(created));
|
|
|
+ }
|
|
|
+ if (url === "/tools/connections/update" && method === "post") {
|
|
|
+ const target = toolVersions.find((item) => item.id === payload.connectionId);
|
|
|
+ if (target) {
|
|
|
+ if ("inputSchema" in payload) target.input_schema_json = (payload.inputSchema as Record<string, never>) ?? {};
|
|
|
+ if ("outputSchema" in payload) target.output_schema_json = (payload.outputSchema as Record<string, never>) ?? {};
|
|
|
+ if ("invokeConfig" in payload) target.invoke_config_json = (payload.invokeConfig as Record<string, never>) ?? {};
|
|
|
+ if ("timeoutMs" in payload) target.timeout_ms = Number(payload.timeoutMs ?? 0) || null;
|
|
|
+ if ("retryPolicy" in payload) target.retry_policy_json = (payload.retryPolicy as Record<string, never>) ?? {};
|
|
|
+ }
|
|
|
+ return identityResponse(toToolVersionDto(target ?? toolVersions[0]));
|
|
|
+ }
|
|
|
+ if (url === "/tools/connections/delete" && method === "post") {
|
|
|
+ const index = toolVersions.findIndex((item) => item.id === payload.connectionId);
|
|
|
+ if (index >= 0) toolVersions.splice(index, 1);
|
|
|
+ return identityResponse({ deleted: index >= 0, connectionId: payload.connectionId ?? null });
|
|
|
+ }
|
|
|
+ if (url === "/tools/mcp/connect" && method === "post") {
|
|
|
+ const serverName = getMcpServerName((payload.config as JSONObject) ?? {}, payload.name);
|
|
|
+ const normalizedConfig = normalizeMcpConfig((payload.config as JSONObject) ?? {}, serverName);
|
|
|
+ const createdTool: ToolDefinition = {
|
|
|
+ id: id("tool"),
|
|
|
+ plugin_id: null,
|
|
|
+ name: String(payload.name ?? serverName),
|
|
|
+ tool_type: "mcp",
|
|
|
+ description: `MCP SSE server: ${String(normalizedConfig.url ?? "")}`,
|
|
|
+ created_time: iso(),
|
|
|
+ };
|
|
|
+ tools.unshift(createdTool);
|
|
|
+ const createdConnection: ToolVersion = {
|
|
|
+ id: id("tv"),
|
|
|
+ tool_id: createdTool.id,
|
|
|
+ version_no: 1,
|
|
|
+ input_schema_json: {},
|
|
|
+ output_schema_json: {},
|
|
|
+ invoke_config_json: normalizedConfig,
|
|
|
+ timeout_ms: Number(normalizedConfig.timeout ?? normalizedConfig.timeout_seconds ?? 0) * 1000 || null,
|
|
|
+ retry_policy_json: { max_attempts: 1 },
|
|
|
+ created_time: iso(),
|
|
|
+ };
|
|
|
+ toolVersions.unshift(createdConnection);
|
|
|
+ return identityResponse({
|
|
|
+ tool: toToolDto(createdTool),
|
|
|
+ connection: toToolVersionDto(createdConnection),
|
|
|
+ discoveredTools: extractMcpTools(normalizedConfig),
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (url === "/tools/bindings/list" && method === "post") {
|
|
|
+ const filtered = payload.appId
|
|
|
+ ? toolBindings.filter((item) => item.app_id === payload.appId)
|
|
|
+ : toolBindings;
|
|
|
+ const page = Number(payload.page ?? 1);
|
|
|
+ const pageSize = Number(payload.pageSize ?? 500);
|
|
|
+ const start = (page - 1) * pageSize;
|
|
|
+ return identityResponse({
|
|
|
+ items: filtered.slice(start, start + pageSize).map(toToolBindingDto),
|
|
|
+ total: filtered.length,
|
|
|
+ page,
|
|
|
+ pageSize,
|
|
|
+ hasMore: page * pageSize < filtered.length,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (url === "/tools/bindings/detail" && method === "post") {
|
|
|
+ const target = toolBindings.find((item) => item.id === payload.bindingId);
|
|
|
+ return identityResponse(toToolBindingDto(target ?? toolBindings[0]));
|
|
|
+ }
|
|
|
+ if (url === "/tools/bindings/create" && method === "post") {
|
|
|
+ const created: ToolBinding = {
|
|
|
+ id: id("tb"),
|
|
|
+ app_id: String(payload.appId),
|
|
|
+ tool_version_id: String(payload.toolVersionId),
|
|
|
+ credential_id: (payload.credentialId as string | null) ?? null,
|
|
|
+ binding_scope: String(payload.bindingScope ?? "app"),
|
|
|
+ config_json: (payload.configJson as Record<string, never>) ?? {},
|
|
|
+ created_time: iso(),
|
|
|
+ };
|
|
|
+ toolBindings.unshift(created);
|
|
|
+ return identityResponse(toToolBindingDto(created));
|
|
|
+ }
|
|
|
+ if (url === "/tools/bindings/update" && method === "post") {
|
|
|
+ const target = toolBindings.find((item) => item.id === payload.bindingId);
|
|
|
+ if (target) {
|
|
|
+ if ("credentialId" in payload) target.credential_id = (payload.credentialId as string | null) ?? null;
|
|
|
+ if (typeof payload.bindingScope === "string") target.binding_scope = payload.bindingScope;
|
|
|
+ if ("configJson" in payload) target.config_json = (payload.configJson as Record<string, never>) ?? {};
|
|
|
+ }
|
|
|
+ return identityResponse(toToolBindingDto(target ?? toolBindings[0]));
|
|
|
+ }
|
|
|
+ if (url === "/tools/bindings/delete" && method === "post") {
|
|
|
+ const index = toolBindings.findIndex((item) => item.id === payload.bindingId);
|
|
|
+ if (index >= 0) toolBindings.splice(index, 1);
|
|
|
+ return identityResponse({ deleted: index >= 0, bindingId: payload.bindingId ?? null });
|
|
|
}
|
|
|
- if (url === "/tools/bindings") return params.app_id ? toolBindings.filter((item) => item.app_id === params.app_id) : toolBindings;
|
|
|
- if (url === "/tools/credentials" && method === "get") return toolCredentials;
|
|
|
- if (url === "/tools/credentials" && method === "post") {
|
|
|
- const secret = JSON.stringify(payload.secret_json ?? {});
|
|
|
+ if (url === "/tools/credentials/list" && method === "post") {
|
|
|
+ const page = Number(payload.page ?? 1);
|
|
|
+ const pageSize = Number(payload.pageSize ?? 500);
|
|
|
+ const start = (page - 1) * pageSize;
|
|
|
+ return identityResponse({
|
|
|
+ items: toolCredentials.slice(start, start + pageSize).map(toToolCredentialDto),
|
|
|
+ total: toolCredentials.length,
|
|
|
+ page,
|
|
|
+ pageSize,
|
|
|
+ hasMore: page * pageSize < toolCredentials.length,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (url === "/tools/credentials/detail" && method === "post") {
|
|
|
+ const target = toolCredentials.find((item) => item.id === payload.credentialId);
|
|
|
+ return identityResponse(toToolCredentialDto(target ?? toolCredentials[0]));
|
|
|
+ }
|
|
|
+ if (url === "/tools/credentials/create" && method === "post") {
|
|
|
+ const secret = JSON.stringify(payload.secretJson ?? {});
|
|
|
const created: ToolCredential = {
|
|
|
id: id("tc"),
|
|
|
name: String(payload.name ?? "New Credential"),
|
|
|
- credential_type: String(payload.credential_type ?? "api_key"),
|
|
|
+ credential_type: String(payload.credentialType ?? "api_key"),
|
|
|
secret_fingerprint: `sha256:${Math.abs(hashText(secret)).toString(16).slice(0, 10)}`,
|
|
|
encryption_algorithm: "mock",
|
|
|
- metadata_json: (payload.metadata_json as Record<string, never>) ?? {},
|
|
|
+ metadata_json: (payload.metadataJson as Record<string, never>) ?? {},
|
|
|
created_time: iso(),
|
|
|
};
|
|
|
toolCredentials.unshift(created);
|
|
|
- return created;
|
|
|
+ mockCredentialSecrets.set(created.id, (payload.secretJson as JSONObject) ?? {});
|
|
|
+ return identityResponse(toToolCredentialDto(created));
|
|
|
+ }
|
|
|
+ if (url === "/tools/credentials/update" && method === "post") {
|
|
|
+ const target = toolCredentials.find((item) => item.id === payload.credentialId);
|
|
|
+ if (target) {
|
|
|
+ if (typeof payload.name === "string") target.name = payload.name;
|
|
|
+ if ("metadataJson" in payload) target.metadata_json = (payload.metadataJson as Record<string, never>) ?? {};
|
|
|
+ }
|
|
|
+ return identityResponse(toToolCredentialDto(target ?? toolCredentials[0]));
|
|
|
+ }
|
|
|
+ if (url === "/tools/credentials/delete" && method === "post") {
|
|
|
+ const index = toolCredentials.findIndex((item) => item.id === payload.credentialId);
|
|
|
+ if (index >= 0) toolCredentials.splice(index, 1);
|
|
|
+ mockCredentialSecrets.delete(String(payload.credentialId ?? ""));
|
|
|
+ return identityResponse({ deleted: index >= 0, credentialId: payload.credentialId ?? null });
|
|
|
+ }
|
|
|
+ if (url === "/tools/credentials/reveal" && method === "post") {
|
|
|
+ const target = toolCredentials.find((item) => item.id === payload.credentialId);
|
|
|
+ return identityResponse({
|
|
|
+ credential: toToolCredentialDto(target ?? toolCredentials[0]),
|
|
|
+ secretJson: mockCredentialSecrets.get(String(payload.credentialId ?? "")) ?? {},
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
if (url === "/knowledge/bases" && method === "get") return knowledgeBases;
|
|
|
@@ -1672,6 +1929,93 @@ function normalize(url?: string) {
|
|
|
return path.startsWith("/gateway") ? path.slice("/gateway".length) || "/" : path;
|
|
|
}
|
|
|
|
|
|
+function toToolDto(item?: ToolDefinition) {
|
|
|
+ return {
|
|
|
+ id: item?.id ?? "",
|
|
|
+ pluginId: item?.plugin_id ?? null,
|
|
|
+ name: item?.name ?? "",
|
|
|
+ toolType: item?.tool_type ?? "mcp",
|
|
|
+ description: item?.description ?? null,
|
|
|
+ createdTime: item?.created_time ?? iso(),
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+function toToolVersionDto(item?: ToolVersion) {
|
|
|
+ return {
|
|
|
+ id: item?.id ?? "",
|
|
|
+ toolId: item?.tool_id ?? "",
|
|
|
+ versionNo: item?.version_no ?? 1,
|
|
|
+ inputSchema: item?.input_schema_json ?? {},
|
|
|
+ outputSchema: item?.output_schema_json ?? {},
|
|
|
+ invokeConfig: item?.invoke_config_json ?? {},
|
|
|
+ timeoutMs: item?.timeout_ms ?? null,
|
|
|
+ retryPolicy: item?.retry_policy_json ?? {},
|
|
|
+ createdTime: item?.created_time ?? iso(),
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+function toToolBindingDto(item?: ToolBinding) {
|
|
|
+ return {
|
|
|
+ id: item?.id ?? "",
|
|
|
+ appId: item?.app_id ?? "",
|
|
|
+ toolVersionId: item?.tool_version_id ?? "",
|
|
|
+ credentialId: item?.credential_id ?? null,
|
|
|
+ bindingScope: item?.binding_scope ?? "app",
|
|
|
+ configJson: item?.config_json ?? {},
|
|
|
+ createdTime: item?.created_time ?? iso(),
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+function toToolCredentialDto(item?: ToolCredential) {
|
|
|
+ return {
|
|
|
+ id: item?.id ?? "",
|
|
|
+ name: item?.name ?? "",
|
|
|
+ credentialType: item?.credential_type ?? "api_key",
|
|
|
+ secretFingerprint: item?.secret_fingerprint ?? "",
|
|
|
+ encryptionAlgorithm: item?.encryption_algorithm ?? "mock",
|
|
|
+ metadataJson: item?.metadata_json ?? {},
|
|
|
+ createdTime: item?.created_time ?? iso(),
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+function getMcpServerName(config: JSONObject, fallback: unknown): string {
|
|
|
+ if (typeof fallback === "string" && fallback.trim()) return fallback.trim();
|
|
|
+ const keys = Object.keys(config);
|
|
|
+ const onlyKey = keys[0];
|
|
|
+ if (onlyKey && keys.length === 1 && typeof config[onlyKey] === "object") return onlyKey;
|
|
|
+ const serverName = config.server_name ?? config.serverName;
|
|
|
+ return typeof serverName === "string" && serverName.trim() ? serverName.trim() : "mcp_server";
|
|
|
+}
|
|
|
+
|
|
|
+function normalizeMcpConfig(config: JSONObject, serverName: string): JSONObject {
|
|
|
+ const nested = config[serverName];
|
|
|
+ const source = nested && typeof nested === "object" && !Array.isArray(nested)
|
|
|
+ ? nested as JSONObject
|
|
|
+ : config;
|
|
|
+ return {
|
|
|
+ ...source,
|
|
|
+ server_name: typeof source.server_name === "string" ? source.server_name : serverName,
|
|
|
+ transport: typeof source.transport === "string" ? source.transport : "sse",
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+function extractMcpTools(config: JSONObject) {
|
|
|
+ const rawTools = config.mcp_tools ?? config.tools;
|
|
|
+ if (!Array.isArray(rawTools)) return [];
|
|
|
+ return rawTools
|
|
|
+ .filter((item): item is JSONObject => Boolean(item) && typeof item === "object" && !Array.isArray(item))
|
|
|
+ .filter((item) => typeof item.name === "string")
|
|
|
+ .map((item) => ({
|
|
|
+ name: String(item.name),
|
|
|
+ description: typeof item.description === "string" ? item.description : null,
|
|
|
+ inputSchema: item.inputSchema && typeof item.inputSchema === "object" && !Array.isArray(item.inputSchema)
|
|
|
+ ? item.inputSchema as JSONObject
|
|
|
+ : item.input_schema && typeof item.input_schema === "object" && !Array.isArray(item.input_schema)
|
|
|
+ ? item.input_schema as JSONObject
|
|
|
+ : null,
|
|
|
+ }));
|
|
|
+}
|
|
|
+
|
|
|
function mockSearch(knowledgeBaseId: string, query: string, topK: number): SearchResult[] {
|
|
|
const baseDocuments = knowledgeDocuments.filter((item) => item.knowledge_base_id === knowledgeBaseId && item.status === "indexed");
|
|
|
const fallbackDocument = baseDocuments[0] ?? knowledgeDocuments[0] ?? {
|