@axiom-lattice/gateway 3.0.2 → 3.0.3
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.
- package/dist/index.js +31 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +31 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -6
- package/.eslintrc.json +0 -22
- package/.turbo/turbo-build.log +0 -46
- package/AGENTS.md +0 -112
- package/CHANGELOG.md +0 -1190
- package/LOGGER_CONFIG.md +0 -135
- package/RESUME_STREAM_CONTENT_BASED.md +0 -326
- package/RESUME_STREAM_README.md +0 -388
- package/jest.config.js +0 -72
- package/public/sdk/README.md +0 -695
- package/public/sdk/dashboard-engine-skill.md +0 -1122
- package/public/sdk/dashboard-single-file-spec.md +0 -357
- package/public/sdk/data-query-sdk-skill.md +0 -307
- package/public/sdk/data-query-sdk.d.ts +0 -252
- package/public/sdk/data-query-sdk.js +0 -970
- package/public/sdk/occupancy-dashboard.html +0 -363
- package/public/sdk/test-dashboard.html +0 -690
- package/scripts/seed-lark-installation.ts +0 -54
- package/src/__tests__/__mocks__/e2b.ts +0 -1
- package/src/__tests__/a2a.test.ts +0 -428
- package/src/__tests__/channel-installations.test.ts +0 -199
- package/src/__tests__/data-query.test.ts +0 -77
- package/src/__tests__/sandbox-provider-registration.test.ts +0 -74
- package/src/__tests__/setup.ts +0 -5
- package/src/__tests__/workspace.test.ts +0 -400
- package/src/channels/__tests__/routes.test.ts +0 -50
- package/src/channels/lark/LarkChannelAdapter.ts +0 -217
- package/src/channels/lark/README.md +0 -187
- package/src/channels/lark/__tests__/controller.test.ts +0 -136
- package/src/channels/lark/__tests__/mapping-service.test.ts +0 -118
- package/src/channels/lark/__tests__/parser.test.ts +0 -72
- package/src/channels/lark/__tests__/sender.test.ts +0 -37
- package/src/channels/lark/__tests__/verification.test.ts +0 -157
- package/src/channels/lark/controller.ts +0 -48
- package/src/channels/lark/mapping-service.ts +0 -138
- package/src/channels/lark/parser.ts +0 -68
- package/src/channels/lark/routes.ts +0 -22
- package/src/channels/lark/sender.ts +0 -58
- package/src/channels/lark/types.ts +0 -20
- package/src/channels/lark/verification.ts +0 -32
- package/src/channels/registry.ts +0 -20
- package/src/channels/routes.ts +0 -30
- package/src/channels/wechat/WechatChannelAdapter.ts +0 -294
- package/src/channels/wechat/__tests__/context-store.test.ts +0 -148
- package/src/channels/wechat/context-store.ts +0 -54
- package/src/channels/wechat/controller.ts +0 -59
- package/src/channels/wechat/routes.ts +0 -7
- package/src/channels/wechat/types.ts +0 -62
- package/src/channels/wechat/wechat-client.ts +0 -162
- package/src/config/local-a2a-templates.ts +0 -59
- package/src/config.ts +0 -124
- package/src/controllers/__tests__/assistant-local-a2a.test.ts +0 -147
- package/src/controllers/__tests__/local-a2a-templates.test.ts +0 -112
- package/src/controllers/__tests__/mime.test.ts +0 -74
- package/src/controllers/__tests__/resources.test.ts +0 -122
- package/src/controllers/__tests__/run.test.ts +0 -115
- package/src/controllers/__tests__/tasks.test.ts +0 -215
- package/src/controllers/__tests__/workflow-tracking.test.ts +0 -113
- package/src/controllers/agent_task.ts +0 -72
- package/src/controllers/assistant.ts +0 -490
- package/src/controllers/auth.ts +0 -524
- package/src/controllers/channel-bindings.ts +0 -135
- package/src/controllers/channel-installations.ts +0 -409
- package/src/controllers/collections.ts +0 -176
- package/src/controllers/config.ts +0 -126
- package/src/controllers/connections.ts +0 -181
- package/src/controllers/data-query.ts +0 -236
- package/src/controllers/database-configs.ts +0 -440
- package/src/controllers/embeddings.ts +0 -22
- package/src/controllers/entries.ts +0 -167
- package/src/controllers/eval.ts +0 -513
- package/src/controllers/export-import.ts +0 -166
- package/src/controllers/health.ts +0 -36
- package/src/controllers/local-a2a-templates.ts +0 -18
- package/src/controllers/local-a2a.ts +0 -149
- package/src/controllers/mcp-configs.ts +0 -673
- package/src/controllers/memory.ts +0 -257
- package/src/controllers/menu-items.ts +0 -114
- package/src/controllers/metrics-configs.ts +0 -1061
- package/src/controllers/middleware-types.ts +0 -15
- package/src/controllers/models.ts +0 -199
- package/src/controllers/personal-assistant.ts +0 -191
- package/src/controllers/resources.ts +0 -477
- package/src/controllers/run.ts +0 -338
- package/src/controllers/sandbox.ts +0 -255
- package/src/controllers/schedules.ts +0 -336
- package/src/controllers/skills.ts +0 -256
- package/src/controllers/tasks.ts +0 -213
- package/src/controllers/tenants.ts +0 -121
- package/src/controllers/thread_status.ts +0 -66
- package/src/controllers/threads.ts +0 -260
- package/src/controllers/tools.ts +0 -139
- package/src/controllers/users.ts +0 -135
- package/src/controllers/workflow-tracking.ts +0 -693
- package/src/controllers/workspace.ts +0 -879
- package/src/export_registrations/a2a-api-key.registration.ts +0 -89
- package/src/export_registrations/agent.registration.ts +0 -80
- package/src/export_registrations/binding.registration.ts +0 -106
- package/src/export_registrations/channel-installation.registration.ts +0 -88
- package/src/export_registrations/collection.registration.ts +0 -85
- package/src/export_registrations/connection.registration.ts +0 -97
- package/src/export_registrations/database-config.registration.ts +0 -94
- package/src/export_registrations/eval.registration.ts +0 -334
- package/src/export_registrations/index.ts +0 -31
- package/src/export_registrations/mcp-config.registration.ts +0 -97
- package/src/export_registrations/menu.registration.ts +0 -91
- package/src/export_registrations/metrics-config.registration.ts +0 -94
- package/src/export_registrations/skill.registration.ts +0 -88
- package/src/export_registrations/task.registration.ts +0 -99
- package/src/index.ts +0 -497
- package/src/logger/Logger.ts +0 -186
- package/src/router/MessageContext.ts +0 -14
- package/src/router/MessageRouter.ts +0 -490
- package/src/router/middlewares/auditLogger.ts +0 -34
- package/src/router/middlewares/deduplication.ts +0 -38
- package/src/router/middlewares/index.ts +0 -3
- package/src/router/middlewares/rateLimit.ts +0 -46
- package/src/routes/__tests__/a2a-test-connection.test.ts +0 -177
- package/src/routes/a2a-bridge.ts +0 -266
- package/src/routes/a2a-test-connection.ts +0 -126
- package/src/routes/a2a.ts +0 -851
- package/src/routes/channel-bindings.ts +0 -11
- package/src/routes/channel-installations.ts +0 -33
- package/src/routes/index.ts +0 -640
- package/src/routes/menu-items.ts +0 -10
- package/src/routes/resource-routes.ts +0 -35
- package/src/routes/stt.ts +0 -102
- package/src/schemas/data-query.ts +0 -69
- package/src/schemas/index.ts +0 -852
- package/src/services/ExportImportService.ts +0 -296
- package/src/services/__tests__/ExportImportService.test.ts +0 -130
- package/src/services/__tests__/eval-runner.test.ts +0 -131
- package/src/services/__tests__/local-a2a.test.ts +0 -124
- package/src/services/agent_task_consumer.ts +0 -348
- package/src/services/collection_service.ts +0 -258
- package/src/services/eval-runner.ts +0 -283
- package/src/services/local-a2a.ts +0 -354
- package/src/services/queue_service.ts +0 -104
- package/src/services/sandbox_service.ts +0 -223
- package/src/services/skill_service.ts +0 -97
- package/src/services/supabase.ts +0 -60
- package/src/swagger.ts +0 -77
- package/src/types/index.ts +0 -118
- package/src/types/koa.d.ts +0 -7
- package/src/utils/__tests__/local-a2a-runtime.test.ts +0 -77
- package/src/utils/__tests__/path-containment.test.ts +0 -35
- package/src/utils/a2a-url.ts +0 -20
- package/src/utils/local-a2a-runtime.ts +0 -107
- package/src/utils/mime.ts +0 -44
- package/src/utils/path-containment.ts +0 -38
- package/tsconfig.json +0 -26
|
@@ -1,490 +0,0 @@
|
|
|
1
|
-
import { FastifyRequest, FastifyReply } from "fastify";
|
|
2
|
-
import { agentInstanceManager, getStoreLattice } from "@axiom-lattice/core";
|
|
3
|
-
import type {
|
|
4
|
-
Assistant,
|
|
5
|
-
CreateAssistantRequest,
|
|
6
|
-
} from "@axiom-lattice/protocols";
|
|
7
|
-
import { AgentType } from "@axiom-lattice/protocols";
|
|
8
|
-
import type { A2ARemoteAgentConfig } from "@axiom-lattice/protocols";
|
|
9
|
-
import { randomUUID } from "crypto";
|
|
10
|
-
import type { AgentConfig } from "@axiom-lattice/core";
|
|
11
|
-
import { agentLatticeManager, eventBus } from "@axiom-lattice/core";
|
|
12
|
-
import { localA2AService } from "../services/local-a2a";
|
|
13
|
-
import { normalizeA2AAgentCardUrl } from "../utils/a2a-url";
|
|
14
|
-
import {
|
|
15
|
-
getAgentCardPort,
|
|
16
|
-
validateLocalRuntimeCommand,
|
|
17
|
-
validateLocalRuntimePort,
|
|
18
|
-
} from "../utils/local-a2a-runtime";
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Assistant Controller
|
|
22
|
-
* Handles assistant-related CRUD operations
|
|
23
|
-
* Merges code-configured agents (from @axiom-lattice/core) with in-memory stored assistants
|
|
24
|
-
* GET operations return both code-configured and stored assistants
|
|
25
|
-
* CUD operations only work on stored assistants
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Get tenant ID from authenticated user context
|
|
30
|
-
* Falls back to request headers for backward compatibility
|
|
31
|
-
*/
|
|
32
|
-
function getTenantId(request: FastifyRequest): string {
|
|
33
|
-
// First try to get from authenticated user context
|
|
34
|
-
const userTenantId = (request as any).user?.tenantId;
|
|
35
|
-
if (userTenantId) {
|
|
36
|
-
return userTenantId;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Fallback to request headers for backward compatibility
|
|
40
|
-
return (request.headers["x-tenant-id"] as string) || "default";
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function getUserId(request: FastifyRequest): string | undefined {
|
|
44
|
-
const userId = (request as any).user?.id;
|
|
45
|
-
if (userId) return userId;
|
|
46
|
-
return (request.headers["x-user-id"] as string) || undefined;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Convert AgentConfig to Assistant format
|
|
51
|
-
*/
|
|
52
|
-
function convertAgentConfigToAssistant(config: AgentConfig): Assistant {
|
|
53
|
-
return {
|
|
54
|
-
id: config.key,
|
|
55
|
-
tenantId: "default", // Code-configured agents belong to default tenant
|
|
56
|
-
name: config.name,
|
|
57
|
-
description: config.description,
|
|
58
|
-
graphDefinition: config, // Store the full config as graphDefinition
|
|
59
|
-
createdAt: new Date(0), // Code-configured agents have no creation date
|
|
60
|
-
updatedAt: new Date(0), // Code-configured agents have no update date
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Assistant list response interface
|
|
66
|
-
*/
|
|
67
|
-
interface AssistantListResponse {
|
|
68
|
-
success: boolean;
|
|
69
|
-
message: string;
|
|
70
|
-
data: {
|
|
71
|
-
records: Assistant[];
|
|
72
|
-
total: number;
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Assistant response interface
|
|
78
|
-
*/
|
|
79
|
-
interface AssistantResponse {
|
|
80
|
-
success: boolean;
|
|
81
|
-
message: string;
|
|
82
|
-
data?: Assistant;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Assistant update request body interface
|
|
87
|
-
*/
|
|
88
|
-
interface AssistantUpdateBody {
|
|
89
|
-
name?: string;
|
|
90
|
-
description?: string;
|
|
91
|
-
graphDefinition?: any;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Get list of all assistants
|
|
96
|
-
* Merges code-configured agents with stored assistants
|
|
97
|
-
*/
|
|
98
|
-
export async function getAssistantList(
|
|
99
|
-
request: FastifyRequest,
|
|
100
|
-
reply: FastifyReply
|
|
101
|
-
): Promise<AssistantListResponse> {
|
|
102
|
-
const tenantId = getTenantId(request);
|
|
103
|
-
|
|
104
|
-
// Get code-configured agents for the tenant
|
|
105
|
-
const agentConfigs = await agentLatticeManager.getAllAgentConfigsByTenant(tenantId);
|
|
106
|
-
const codeConfiguredAssistants = agentConfigs.map(
|
|
107
|
-
convertAgentConfigToAssistant
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
// Get stored assistants for the tenant
|
|
111
|
-
const storeLattice = getStoreLattice("default", "assistant");
|
|
112
|
-
const assistantStore = storeLattice.store;
|
|
113
|
-
const storedAssistants = await assistantStore.getAllAssistants(tenantId);
|
|
114
|
-
|
|
115
|
-
// Merge both sources, stored assistants take precedence if ID conflicts
|
|
116
|
-
const assistantMap = new Map<string, Assistant>();
|
|
117
|
-
|
|
118
|
-
// First add code-configured agents
|
|
119
|
-
codeConfiguredAssistants.forEach((assistant) => {
|
|
120
|
-
assistantMap.set(assistant.id, assistant);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// Then add stored assistants (overwrite if ID exists)
|
|
124
|
-
storedAssistants.forEach((assistant) => {
|
|
125
|
-
assistantMap.set(assistant.id, assistant);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
const allAssistants = Array.from(assistantMap.values());
|
|
129
|
-
|
|
130
|
-
// Filter: exclude personal assistants owned by other users
|
|
131
|
-
const userId = getUserId(request);
|
|
132
|
-
const filtered = allAssistants.filter((a) => {
|
|
133
|
-
if (!a.ownerUserId) return true;
|
|
134
|
-
return a.ownerUserId === userId;
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
success: true,
|
|
139
|
-
message: "Successfully retrieved assistant list",
|
|
140
|
-
data: {
|
|
141
|
-
records: filtered,
|
|
142
|
-
total: filtered.length,
|
|
143
|
-
},
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Get a single assistant by ID
|
|
149
|
-
* Checks both code-configured agents and stored assistants
|
|
150
|
-
*/
|
|
151
|
-
export async function getAssistant(
|
|
152
|
-
request: FastifyRequest<{ Params: { id: string } }>,
|
|
153
|
-
reply: FastifyReply
|
|
154
|
-
): Promise<AssistantResponse> {
|
|
155
|
-
const { id } = request.params;
|
|
156
|
-
const tenantId = getTenantId(request);
|
|
157
|
-
|
|
158
|
-
// First check stored assistants
|
|
159
|
-
const storeLattice = getStoreLattice("default", "assistant");
|
|
160
|
-
const assistantStore = storeLattice.store;
|
|
161
|
-
let assistant = await assistantStore.getAssistantById(tenantId, id);
|
|
162
|
-
|
|
163
|
-
// If not found in store, check code-configured agents for the tenant
|
|
164
|
-
if (!assistant) {
|
|
165
|
-
const agentConfig = await agentLatticeManager.getAgentConfigWithTenant(tenantId, id);
|
|
166
|
-
if (agentConfig) {
|
|
167
|
-
assistant = convertAgentConfigToAssistant(agentConfig);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (!assistant) {
|
|
172
|
-
return reply.status(404).send({
|
|
173
|
-
success: false,
|
|
174
|
-
message: "Assistant not found",
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return {
|
|
179
|
-
success: true,
|
|
180
|
-
message: "Successfully retrieved assistant",
|
|
181
|
-
data: assistant,
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Upsert assistant - create if not exists in store, update if exists
|
|
187
|
-
*/
|
|
188
|
-
async function upsertAssistant(
|
|
189
|
-
tenantId: string,
|
|
190
|
-
id: string,
|
|
191
|
-
data: CreateAssistantRequest | AssistantUpdateBody,
|
|
192
|
-
reply: FastifyReply,
|
|
193
|
-
requireFields: boolean = false
|
|
194
|
-
): Promise<AssistantResponse> {
|
|
195
|
-
const storeLattice = getStoreLattice("default", "assistant");
|
|
196
|
-
const assistantStore = storeLattice.store;
|
|
197
|
-
|
|
198
|
-
const exists = await assistantStore.hasAssistant(tenantId, id);
|
|
199
|
-
|
|
200
|
-
let assistant: Assistant | null;
|
|
201
|
-
if (exists) {
|
|
202
|
-
assistant = await assistantStore.updateAssistant(tenantId, id, data);
|
|
203
|
-
if (!assistant) {
|
|
204
|
-
return reply.status(500).send({
|
|
205
|
-
success: false,
|
|
206
|
-
message: "Failed to update assistant",
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
eventBus.publish("assistant:updated", { id: assistant.id, name: assistant.name, tenantId });
|
|
210
|
-
return {
|
|
211
|
-
success: true,
|
|
212
|
-
message: "Updated assistant",
|
|
213
|
-
data: assistant,
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (requireFields) {
|
|
218
|
-
const createData = data as CreateAssistantRequest;
|
|
219
|
-
if (!createData.name || !createData.graphDefinition) {
|
|
220
|
-
return reply.status(400).send({
|
|
221
|
-
success: false,
|
|
222
|
-
message: "name and graphDefinition are required",
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
assistant = await assistantStore.createAssistant(tenantId, id, data as CreateAssistantRequest);
|
|
228
|
-
eventBus.publish("assistant:created", { id: assistant.id, name: assistant.name, tenantId });
|
|
229
|
-
return reply.status(201).send({
|
|
230
|
-
success: true,
|
|
231
|
-
message: "Created assistant",
|
|
232
|
-
data: assistant,
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Create a new assistant
|
|
238
|
-
*/
|
|
239
|
-
export async function createAssistant(
|
|
240
|
-
request: FastifyRequest<{ Body: CreateAssistantRequest & { id?: string } }>,
|
|
241
|
-
reply: FastifyReply
|
|
242
|
-
): Promise<AssistantResponse> {
|
|
243
|
-
const tenantId = getTenantId(request);
|
|
244
|
-
const data = request.body;
|
|
245
|
-
|
|
246
|
-
if (!data.name || !data.graphDefinition) {
|
|
247
|
-
return reply.status(400).send({
|
|
248
|
-
success: false,
|
|
249
|
-
message: "name and graphDefinition are required",
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const id = data.id ?? randomUUID();
|
|
254
|
-
|
|
255
|
-
// A2A_REMOTE: validate agentCardUrl, check localRuntime conflicts
|
|
256
|
-
if (
|
|
257
|
-
data.graphDefinition &&
|
|
258
|
-
(data.graphDefinition as AgentConfig).type === AgentType.A2A_REMOTE
|
|
259
|
-
) {
|
|
260
|
-
const a2aConfig = data.graphDefinition as A2ARemoteAgentConfig;
|
|
261
|
-
const warnings: string[] = [];
|
|
262
|
-
const isLocalManaged = !!a2aConfig.localRuntime;
|
|
263
|
-
a2aConfig.agentCardUrl = normalizeA2AAgentCardUrl(
|
|
264
|
-
a2aConfig.agentCardUrl,
|
|
265
|
-
isLocalManaged ? "http://" : "https://",
|
|
266
|
-
);
|
|
267
|
-
|
|
268
|
-
if (a2aConfig.localRuntime) {
|
|
269
|
-
const commandValidation = validateLocalRuntimeCommand(
|
|
270
|
-
a2aConfig.localRuntime,
|
|
271
|
-
);
|
|
272
|
-
if (!commandValidation.ok) {
|
|
273
|
-
return reply.status(400).send({
|
|
274
|
-
success: false,
|
|
275
|
-
message: commandValidation.error,
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
a2aConfig.localRuntime.command.executable =
|
|
279
|
-
a2aConfig.localRuntime.command.executable.trim();
|
|
280
|
-
|
|
281
|
-
a2aConfig.localRuntime.agentCardUrl = normalizeA2AAgentCardUrl(
|
|
282
|
-
a2aConfig.localRuntime.agentCardUrl || a2aConfig.agentCardUrl,
|
|
283
|
-
"http://",
|
|
284
|
-
);
|
|
285
|
-
a2aConfig.agentCardUrl = a2aConfig.localRuntime.agentCardUrl;
|
|
286
|
-
|
|
287
|
-
const portValidation = validateLocalRuntimePort(
|
|
288
|
-
a2aConfig.localRuntime,
|
|
289
|
-
a2aConfig.agentCardUrl,
|
|
290
|
-
);
|
|
291
|
-
if (!portValidation.ok) {
|
|
292
|
-
return reply.status(400).send({
|
|
293
|
-
success: false,
|
|
294
|
-
message: portValidation.error,
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (a2aConfig.localRuntime) {
|
|
300
|
-
const existingAssistants = await getStoreLattice("default", "assistant").store.getAllAssistants(tenantId);
|
|
301
|
-
const targetPort = getAgentCardPort(a2aConfig.localRuntime.agentCardUrl);
|
|
302
|
-
const duplicate = existingAssistants.find((a) => {
|
|
303
|
-
if (a.id === id) return false;
|
|
304
|
-
const gd = a.graphDefinition && typeof a.graphDefinition === "object"
|
|
305
|
-
? a.graphDefinition
|
|
306
|
-
: undefined;
|
|
307
|
-
if (!gd || (gd as { type?: unknown }).type !== AgentType.A2A_REMOTE) return false;
|
|
308
|
-
const lr = (gd as A2ARemoteAgentConfig).localRuntime;
|
|
309
|
-
if (!lr) return false;
|
|
310
|
-
const existingAgentCardUrl = normalizeA2AAgentCardUrl(lr.agentCardUrl, "http://");
|
|
311
|
-
const existingPort = getAgentCardPort(existingAgentCardUrl);
|
|
312
|
-
if (targetPort !== null && existingPort !== null) {
|
|
313
|
-
return existingPort === targetPort;
|
|
314
|
-
}
|
|
315
|
-
return existingAgentCardUrl === a2aConfig.localRuntime!.agentCardUrl;
|
|
316
|
-
});
|
|
317
|
-
if (duplicate) {
|
|
318
|
-
const conflictDetail = targetPort === null
|
|
319
|
-
? `agentCardUrl "${a2aConfig.localRuntime.agentCardUrl}"`
|
|
320
|
-
: `port ${targetPort}`;
|
|
321
|
-
return reply.status(409).send({
|
|
322
|
-
success: false,
|
|
323
|
-
message: `A local managed A2A assistant using ${conflictDetail} already exists: "${duplicate.name}". Each local managed A2A assistant needs a unique port.`,
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// Validate agentCardUrl reachability (non-blocking)
|
|
329
|
-
try {
|
|
330
|
-
const resp = await fetch(a2aConfig.agentCardUrl, {
|
|
331
|
-
signal: AbortSignal.timeout(5000),
|
|
332
|
-
});
|
|
333
|
-
if (!resp.ok) {
|
|
334
|
-
warnings.push(`agentCardUrl returned HTTP ${resp.status}`);
|
|
335
|
-
}
|
|
336
|
-
} catch {
|
|
337
|
-
warnings.push(`agentCardUrl is not reachable: ${a2aConfig.agentCardUrl}`);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
if (warnings.length > 0) {
|
|
341
|
-
console.warn(`[createAssistant] A2A warnings for ${a2aConfig.agentCardUrl}:`, warnings);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
return upsertAssistant(tenantId, id, data, reply, true);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Update an existing assistant by ID
|
|
350
|
-
*/
|
|
351
|
-
export async function updateAssistant(
|
|
352
|
-
request: FastifyRequest<{
|
|
353
|
-
Params: { id: string };
|
|
354
|
-
Body: AssistantUpdateBody;
|
|
355
|
-
}>,
|
|
356
|
-
reply: FastifyReply
|
|
357
|
-
): Promise<AssistantResponse> {
|
|
358
|
-
const tenantId = getTenantId(request);
|
|
359
|
-
const { id } = request.params;
|
|
360
|
-
const updates = request.body;
|
|
361
|
-
|
|
362
|
-
return upsertAssistant(tenantId, id, updates, reply, false);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Delete an assistant by ID
|
|
367
|
-
* For stored assistants: deletes from store
|
|
368
|
-
* For local A2A agents: stops provider, unregisters from lattice, then deletes from store
|
|
369
|
-
* For code-configured assistants: only deletes from store if exists (code registration remains)
|
|
370
|
-
*/
|
|
371
|
-
export async function deleteAssistant(
|
|
372
|
-
request: FastifyRequest<{ Params: { id: string } }>,
|
|
373
|
-
reply: FastifyReply
|
|
374
|
-
): Promise<{ success: boolean; message: string }> {
|
|
375
|
-
const tenantId = getTenantId(request);
|
|
376
|
-
const { id } = request.params;
|
|
377
|
-
|
|
378
|
-
const storeLattice = getStoreLattice("default", "assistant");
|
|
379
|
-
const assistantStore = storeLattice.store;
|
|
380
|
-
|
|
381
|
-
const storedAssistant = await assistantStore.getAssistantById(tenantId, id);
|
|
382
|
-
const graphDefinition = storedAssistant?.graphDefinition;
|
|
383
|
-
const hasLocalRuntime =
|
|
384
|
-
graphDefinition && typeof graphDefinition === "object"
|
|
385
|
-
? !!(graphDefinition as A2ARemoteAgentConfig).localRuntime
|
|
386
|
-
: false;
|
|
387
|
-
|
|
388
|
-
if (storedAssistant && hasLocalRuntime) {
|
|
389
|
-
localA2AService.removeState(id);
|
|
390
|
-
const deleted = await assistantStore.deleteAssistant(tenantId, id);
|
|
391
|
-
if (!deleted) {
|
|
392
|
-
return reply.status(500).send({
|
|
393
|
-
success: false,
|
|
394
|
-
message: "Failed to delete assistant",
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
eventBus.publish("assistant:deleted", { id, tenantId });
|
|
398
|
-
return {
|
|
399
|
-
success: true,
|
|
400
|
-
message: "Deleted local A2A assistant",
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
const agentConfig = await agentLatticeManager.getAgentConfigWithTenant(tenantId, id);
|
|
405
|
-
const isCodeConfigured = !!agentConfig;
|
|
406
|
-
|
|
407
|
-
if (isCodeConfigured) {
|
|
408
|
-
if (!storedAssistant) {
|
|
409
|
-
return reply.status(404).send({
|
|
410
|
-
success: false,
|
|
411
|
-
message: "Assistant not found (code-configured assistants cannot be deleted from code, only from store)",
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
await assistantStore.deleteAssistant(tenantId, id);
|
|
415
|
-
eventBus.publish("assistant:deleted", { id, tenantId });
|
|
416
|
-
return {
|
|
417
|
-
success: true,
|
|
418
|
-
message: "Deleted assistant from store (code-configured registration remains)",
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
if (!storedAssistant) {
|
|
423
|
-
return reply.status(404).send({
|
|
424
|
-
success: false,
|
|
425
|
-
message: "Assistant not found",
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const deleted = await assistantStore.deleteAssistant(tenantId, id);
|
|
430
|
-
|
|
431
|
-
if (!deleted) {
|
|
432
|
-
return reply.status(500).send({
|
|
433
|
-
success: false,
|
|
434
|
-
message: "Failed to delete assistant",
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
eventBus.publish("assistant:deleted", { id, tenantId });
|
|
439
|
-
|
|
440
|
-
// Clean up UserTenantLink metadata if this was a personal assistant
|
|
441
|
-
const userId = getUserId(request);
|
|
442
|
-
if (userId) {
|
|
443
|
-
try {
|
|
444
|
-
const linkStore = getStoreLattice("default", "userTenantLink").store;
|
|
445
|
-
const link = await linkStore.getLink(userId, tenantId);
|
|
446
|
-
const meta = (link?.metadata || {}) as Record<string, unknown>;
|
|
447
|
-
if (meta.personalAssistantId === id) {
|
|
448
|
-
delete meta.personalAssistantId;
|
|
449
|
-
delete meta.personalProjectId;
|
|
450
|
-
delete meta.personalWorkspaceId;
|
|
451
|
-
await linkStore.updateLink(userId, tenantId, { metadata: meta } as any);
|
|
452
|
-
}
|
|
453
|
-
} catch { /* best effort */ }
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
return {
|
|
457
|
-
success: true,
|
|
458
|
-
message: "Successfully deleted assistant",
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* Get agent graph visualization
|
|
464
|
-
*/
|
|
465
|
-
export const getAgentGraph = async (
|
|
466
|
-
request: FastifyRequest<{
|
|
467
|
-
Params: { assistantId: string };
|
|
468
|
-
}>,
|
|
469
|
-
reply: FastifyReply
|
|
470
|
-
) => {
|
|
471
|
-
try {
|
|
472
|
-
const { assistantId } = request.params;
|
|
473
|
-
const tenant_id = getTenantId(request);
|
|
474
|
-
|
|
475
|
-
const agent = agentInstanceManager.getAgent({ assistant_id: assistantId, tenant_id, thread_id: '' })
|
|
476
|
-
|
|
477
|
-
// Call drawing service to get image data
|
|
478
|
-
const imageData = await agent.get_draw_graph()
|
|
479
|
-
|
|
480
|
-
// Set response header and return image data
|
|
481
|
-
reply.header("Content-Type", "application/json").send({
|
|
482
|
-
image: imageData,
|
|
483
|
-
});
|
|
484
|
-
} catch (error: any) {
|
|
485
|
-
reply.status(500).send({
|
|
486
|
-
success: false,
|
|
487
|
-
error: error.message || "Failed to get agent graph",
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
};
|