@axiom-lattice/gateway 2.1.11 → 2.1.13
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/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +16 -0
- package/README.md +53 -0
- package/dist/index.js +798 -68
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +794 -64
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/config.ts +124 -0
- package/src/controllers/assistant.ts +274 -3
- package/src/controllers/config.ts +126 -0
- package/src/controllers/models.ts +152 -0
- package/src/controllers/threads.ts +189 -0
- package/src/routes/index.ts +80 -1
- package/src/schemas/index.ts +74 -0
- package/src/services/supabase.ts +44 -10
- package/src/stores/assistant_store.ts +82 -0
- package/src/stores/thread_store.ts +115 -0
- package/src/types/index.ts +14 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { FastifyRequest, FastifyReply } from "fastify";
|
|
2
|
+
import { threadStore } from "../stores/thread_store";
|
|
3
|
+
import { Thread, CreateThreadRequest } from "../types";
|
|
4
|
+
import { randomUUID } from "crypto";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Thread Controller
|
|
8
|
+
* Handles thread-related CRUD operations for a specific assistant
|
|
9
|
+
* All operations are scoped to an assistant ID
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Thread list response interface
|
|
14
|
+
*/
|
|
15
|
+
interface ThreadListResponse {
|
|
16
|
+
success: boolean;
|
|
17
|
+
message: string;
|
|
18
|
+
data: {
|
|
19
|
+
records: Thread[];
|
|
20
|
+
total: number;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Thread response interface
|
|
26
|
+
*/
|
|
27
|
+
interface ThreadResponse {
|
|
28
|
+
success: boolean;
|
|
29
|
+
message: string;
|
|
30
|
+
data?: Thread;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Thread update request body interface
|
|
35
|
+
*/
|
|
36
|
+
interface ThreadUpdateBody {
|
|
37
|
+
metadata?: Record<string, any>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get list of all threads for a specific assistant
|
|
42
|
+
*/
|
|
43
|
+
export async function getThreadList(
|
|
44
|
+
request: FastifyRequest<{ Params: { assistantId: string } }>,
|
|
45
|
+
reply: FastifyReply
|
|
46
|
+
): Promise<ThreadListResponse> {
|
|
47
|
+
const { assistantId } = request.params;
|
|
48
|
+
|
|
49
|
+
const threads = threadStore.getThreadsByAssistantId(assistantId);
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
success: true,
|
|
53
|
+
message: "Successfully retrieved thread list",
|
|
54
|
+
data: {
|
|
55
|
+
records: threads,
|
|
56
|
+
total: threads.length,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Get a single thread by ID for a specific assistant
|
|
63
|
+
*/
|
|
64
|
+
export async function getThread(
|
|
65
|
+
request: FastifyRequest<{
|
|
66
|
+
Params: { assistantId: string; threadId: string };
|
|
67
|
+
}>,
|
|
68
|
+
reply: FastifyReply
|
|
69
|
+
): Promise<ThreadResponse> {
|
|
70
|
+
const { assistantId, threadId } = request.params;
|
|
71
|
+
|
|
72
|
+
const thread = threadStore.getThreadById(assistantId, threadId);
|
|
73
|
+
|
|
74
|
+
if (!thread) {
|
|
75
|
+
return reply.status(404).send({
|
|
76
|
+
success: false,
|
|
77
|
+
message: "Thread not found",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
success: true,
|
|
83
|
+
message: "Successfully retrieved thread",
|
|
84
|
+
data: thread,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Create a new thread for an assistant
|
|
90
|
+
*/
|
|
91
|
+
export async function createThread(
|
|
92
|
+
request: FastifyRequest<{
|
|
93
|
+
Params: { assistantId: string };
|
|
94
|
+
Body: CreateThreadRequest;
|
|
95
|
+
}>,
|
|
96
|
+
reply: FastifyReply
|
|
97
|
+
): Promise<ThreadResponse> {
|
|
98
|
+
const { assistantId } = request.params;
|
|
99
|
+
const data = request.body;
|
|
100
|
+
|
|
101
|
+
// Generate thread ID if not provided
|
|
102
|
+
const threadId = randomUUID();
|
|
103
|
+
|
|
104
|
+
// Create thread
|
|
105
|
+
const newThread = threadStore.createThread(assistantId, threadId, data);
|
|
106
|
+
|
|
107
|
+
return reply.status(201).send({
|
|
108
|
+
success: true,
|
|
109
|
+
message: "Successfully created thread",
|
|
110
|
+
data: newThread,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Update an existing thread by ID
|
|
116
|
+
*/
|
|
117
|
+
export async function updateThread(
|
|
118
|
+
request: FastifyRequest<{
|
|
119
|
+
Params: { assistantId: string; threadId: string };
|
|
120
|
+
Body: ThreadUpdateBody;
|
|
121
|
+
}>,
|
|
122
|
+
reply: FastifyReply
|
|
123
|
+
): Promise<ThreadResponse> {
|
|
124
|
+
const { assistantId, threadId } = request.params;
|
|
125
|
+
const updates = request.body;
|
|
126
|
+
|
|
127
|
+
// Check if thread exists
|
|
128
|
+
if (!threadStore.hasThread(assistantId, threadId)) {
|
|
129
|
+
return reply.status(404).send({
|
|
130
|
+
success: false,
|
|
131
|
+
message: "Thread not found",
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Update thread
|
|
136
|
+
const updatedThread = threadStore.updateThread(
|
|
137
|
+
assistantId,
|
|
138
|
+
threadId,
|
|
139
|
+
updates
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
if (!updatedThread) {
|
|
143
|
+
return reply.status(500).send({
|
|
144
|
+
success: false,
|
|
145
|
+
message: "Failed to update thread",
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
success: true,
|
|
151
|
+
message: "Successfully updated thread",
|
|
152
|
+
data: updatedThread,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Delete a thread by ID
|
|
158
|
+
*/
|
|
159
|
+
export async function deleteThread(
|
|
160
|
+
request: FastifyRequest<{
|
|
161
|
+
Params: { assistantId: string; threadId: string };
|
|
162
|
+
}>,
|
|
163
|
+
reply: FastifyReply
|
|
164
|
+
): Promise<{ success: boolean; message: string }> {
|
|
165
|
+
const { assistantId, threadId } = request.params;
|
|
166
|
+
|
|
167
|
+
// Check if thread exists
|
|
168
|
+
if (!threadStore.hasThread(assistantId, threadId)) {
|
|
169
|
+
return reply.status(404).send({
|
|
170
|
+
success: false,
|
|
171
|
+
message: "Thread not found",
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Delete the thread
|
|
176
|
+
const deleted = threadStore.deleteThread(assistantId, threadId);
|
|
177
|
+
|
|
178
|
+
if (!deleted) {
|
|
179
|
+
return reply.status(500).send({
|
|
180
|
+
success: false,
|
|
181
|
+
message: "Failed to delete thread",
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
success: true,
|
|
187
|
+
message: "Successfully deleted thread",
|
|
188
|
+
};
|
|
189
|
+
}
|
package/src/routes/index.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { FastifyInstance } from "fastify";
|
|
2
|
-
|
|
2
|
+
import * as assistantController from "../controllers/assistant";
|
|
3
3
|
import * as runController from "../controllers/run";
|
|
4
4
|
import * as memoryController from "../controllers/memory";
|
|
5
5
|
import * as graphController from "../controllers/assistant";
|
|
6
6
|
import * as agentTaskController from "../controllers/agent_task";
|
|
7
|
+
import * as threadsController from "../controllers/threads";
|
|
8
|
+
import * as configController from "../controllers/config";
|
|
9
|
+
import * as modelsController from "../controllers/models";
|
|
7
10
|
import {
|
|
8
11
|
createRunSchema,
|
|
9
12
|
getAllMemoryItemsSchema,
|
|
@@ -15,6 +18,8 @@ import {
|
|
|
15
18
|
getAgentGraphSchema,
|
|
16
19
|
resumeStreamSchema,
|
|
17
20
|
triggerAgentTaskSchema,
|
|
21
|
+
updateConfigSchema,
|
|
22
|
+
getConfigSchema,
|
|
18
23
|
} from "../schemas";
|
|
19
24
|
|
|
20
25
|
export const registerLatticeRoutes = (app: FastifyInstance): void => {
|
|
@@ -90,6 +95,26 @@ export const registerLatticeRoutes = (app: FastifyInstance): void => {
|
|
|
90
95
|
memoryController.clearMemory
|
|
91
96
|
);
|
|
92
97
|
|
|
98
|
+
// Assistant CRUD routes
|
|
99
|
+
app.get("/api/assistants", assistantController.getAssistantList);
|
|
100
|
+
|
|
101
|
+
app.get<{
|
|
102
|
+
Params: { id: string };
|
|
103
|
+
}>("/api/assistants/:id", assistantController.getAssistant);
|
|
104
|
+
|
|
105
|
+
app.post<{
|
|
106
|
+
Body: any;
|
|
107
|
+
}>("/api/assistants", assistantController.createAssistant);
|
|
108
|
+
|
|
109
|
+
app.put<{
|
|
110
|
+
Params: { id: string };
|
|
111
|
+
Body: any;
|
|
112
|
+
}>("/api/assistants/:id", assistantController.updateAssistant);
|
|
113
|
+
|
|
114
|
+
app.delete<{
|
|
115
|
+
Params: { id: string };
|
|
116
|
+
}>("/api/assistants/:id", assistantController.deleteAssistant);
|
|
117
|
+
|
|
93
118
|
// 图表路由
|
|
94
119
|
app.get<{
|
|
95
120
|
Params: { assistantId: string };
|
|
@@ -107,4 +132,58 @@ export const registerLatticeRoutes = (app: FastifyInstance): void => {
|
|
|
107
132
|
{ schema: triggerAgentTaskSchema },
|
|
108
133
|
agentTaskController.triggerAgentTask
|
|
109
134
|
);
|
|
135
|
+
|
|
136
|
+
// Thread CRUD routes for a specific assistant
|
|
137
|
+
app.get<{
|
|
138
|
+
Params: { assistantId: string };
|
|
139
|
+
}>("/api/assistants/:assistantId/threads", threadsController.getThreadList);
|
|
140
|
+
|
|
141
|
+
app.get<{
|
|
142
|
+
Params: { assistantId: string; threadId: string };
|
|
143
|
+
}>(
|
|
144
|
+
"/api/assistants/:assistantId/threads/:threadId",
|
|
145
|
+
threadsController.getThread
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
app.post<{
|
|
149
|
+
Params: { assistantId: string };
|
|
150
|
+
Body: any;
|
|
151
|
+
}>("/api/assistants/:assistantId/threads", threadsController.createThread);
|
|
152
|
+
|
|
153
|
+
app.put<{
|
|
154
|
+
Params: { assistantId: string; threadId: string };
|
|
155
|
+
Body: any;
|
|
156
|
+
}>(
|
|
157
|
+
"/api/assistants/:assistantId/threads/:threadId",
|
|
158
|
+
threadsController.updateThread
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
app.delete<{
|
|
162
|
+
Params: { assistantId: string; threadId: string };
|
|
163
|
+
}>(
|
|
164
|
+
"/api/assistants/:assistantId/threads/:threadId",
|
|
165
|
+
threadsController.deleteThread
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
// Configuration routes
|
|
169
|
+
app.get(
|
|
170
|
+
"/api/config",
|
|
171
|
+
{ schema: getConfigSchema },
|
|
172
|
+
configController.getConfig
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
app.put<{
|
|
176
|
+
Body: { config: Record<string, any> };
|
|
177
|
+
}>(
|
|
178
|
+
"/api/config",
|
|
179
|
+
{ schema: updateConfigSchema },
|
|
180
|
+
configController.updateConfig
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
// Models routes
|
|
184
|
+
app.get("/api/models", modelsController.getModels);
|
|
185
|
+
|
|
186
|
+
app.put<{
|
|
187
|
+
Body: { models: any[] };
|
|
188
|
+
}>("/api/models", modelsController.updateModels);
|
|
110
189
|
};
|
package/src/schemas/index.ts
CHANGED
|
@@ -245,3 +245,77 @@ export const triggerAgentTaskSchema: FastifySchema = {
|
|
|
245
245
|
},
|
|
246
246
|
},
|
|
247
247
|
};
|
|
248
|
+
|
|
249
|
+
// Configuration Schemas
|
|
250
|
+
export const updateConfigSchema: FastifySchema = {
|
|
251
|
+
description: "Update gateway configuration",
|
|
252
|
+
tags: ["Configuration"],
|
|
253
|
+
summary: "Update Configuration",
|
|
254
|
+
body: {
|
|
255
|
+
type: "object",
|
|
256
|
+
properties: {
|
|
257
|
+
config: {
|
|
258
|
+
type: "object",
|
|
259
|
+
description: "Configuration object to update",
|
|
260
|
+
properties: {
|
|
261
|
+
port: { type: "number", description: "Server port" },
|
|
262
|
+
queueServiceType: {
|
|
263
|
+
type: "string",
|
|
264
|
+
enum: ["memory", "redis"],
|
|
265
|
+
description: "Queue service type",
|
|
266
|
+
},
|
|
267
|
+
redisUrl: { type: "string", description: "Redis URL" },
|
|
268
|
+
redisPassword: { type: "string", description: "Redis password" },
|
|
269
|
+
queueName: { type: "string", description: "Queue name" },
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
required: ["config"],
|
|
274
|
+
},
|
|
275
|
+
response: {
|
|
276
|
+
200: {
|
|
277
|
+
type: "object",
|
|
278
|
+
properties: {
|
|
279
|
+
success: { type: "boolean" },
|
|
280
|
+
message: { type: "string" },
|
|
281
|
+
data: { type: "object" },
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
400: {
|
|
285
|
+
type: "object",
|
|
286
|
+
properties: {
|
|
287
|
+
success: { type: "boolean" },
|
|
288
|
+
error: { type: "string" },
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
500: {
|
|
292
|
+
type: "object",
|
|
293
|
+
properties: {
|
|
294
|
+
success: { type: "boolean" },
|
|
295
|
+
error: { type: "string" },
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
export const getConfigSchema: FastifySchema = {
|
|
302
|
+
description: "Get current gateway configuration",
|
|
303
|
+
tags: ["Configuration"],
|
|
304
|
+
summary: "Get Configuration",
|
|
305
|
+
response: {
|
|
306
|
+
200: {
|
|
307
|
+
type: "object",
|
|
308
|
+
properties: {
|
|
309
|
+
success: { type: "boolean" },
|
|
310
|
+
data: { type: "object" },
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
500: {
|
|
314
|
+
type: "object",
|
|
315
|
+
properties: {
|
|
316
|
+
success: { type: "boolean" },
|
|
317
|
+
error: { type: "string" },
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
};
|
package/src/services/supabase.ts
CHANGED
|
@@ -1,15 +1,36 @@
|
|
|
1
|
-
import { createClient } from "@supabase/supabase-js";
|
|
2
|
-
import { config } from "../config";
|
|
1
|
+
import { createClient, SupabaseClient } from "@supabase/supabase-js";
|
|
3
2
|
// import { Database } from "@/types/database.types";
|
|
4
3
|
// import { Database as PgmqPublic } from "@/types/pgmq_public.types";
|
|
5
|
-
// 创建Supabase客户端
|
|
6
|
-
const supabaseClient = createClient(config.supabase.url, config.supabase.key);
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Get Supabase client
|
|
7
|
+
* This function reads from environment variables directly
|
|
8
|
+
*/
|
|
9
|
+
const getSupabaseClient = (): SupabaseClient => {
|
|
10
|
+
const url = process.env.SUPABASE_URL;
|
|
11
|
+
const key = process.env.SUPABASE_KEY;
|
|
12
|
+
if (!url || !key) {
|
|
13
|
+
throw new Error("Supabase URL and Key must be configured");
|
|
14
|
+
}
|
|
15
|
+
return createClient(url, key);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Default export - creates client using current config
|
|
19
|
+
// Note: Since config uses getters, this will read the latest config values
|
|
20
|
+
export default getSupabaseClient();
|
|
9
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Create a Supabase client with tenant headers
|
|
24
|
+
* This function reads from environment variables directly
|
|
25
|
+
*/
|
|
10
26
|
export const createSupabaseClient = (headers: Record<string, string>) => {
|
|
11
27
|
const currentTenantId = headers["x-tenant-id"];
|
|
12
|
-
|
|
28
|
+
const url = process.env.SUPABASE_URL;
|
|
29
|
+
const key = process.env.SUPABASE_KEY;
|
|
30
|
+
if (!url || !key) {
|
|
31
|
+
throw new Error("Supabase URL and Key must be configured");
|
|
32
|
+
}
|
|
33
|
+
return createClient(url, key, {
|
|
13
34
|
global: {
|
|
14
35
|
fetch: async (input, init) => {
|
|
15
36
|
const headers = new Headers(init?.headers);
|
|
@@ -20,7 +41,20 @@ export const createSupabaseClient = (headers: Record<string, string>) => {
|
|
|
20
41
|
});
|
|
21
42
|
};
|
|
22
43
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Get Supabase queue client
|
|
46
|
+
* This function reads from environment variables directly
|
|
47
|
+
*/
|
|
48
|
+
export const getSupabaseQueueClient = (): SupabaseClient => {
|
|
49
|
+
const url = process.env.SUPABASE_URL;
|
|
50
|
+
const key = process.env.SUPABASE_KEY;
|
|
51
|
+
if (!url || !key) {
|
|
52
|
+
throw new Error("Supabase URL and Key must be configured");
|
|
53
|
+
}
|
|
54
|
+
return createClient(url, key);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// For backward compatibility, export a client that reads config dynamically
|
|
58
|
+
// Note: This creates a new client each time, but Supabase clients are lightweight
|
|
59
|
+
// and this ensures we always use the latest config
|
|
60
|
+
export const supabaseQueueClient = getSupabaseQueueClient();
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Assistant, CreateAssistantRequest } from "../types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* In-memory store for assistants
|
|
5
|
+
* Provides CRUD operations for assistant data
|
|
6
|
+
*/
|
|
7
|
+
class AssistantStore {
|
|
8
|
+
private assistants: Map<string, Assistant> = new Map();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get all assistants
|
|
12
|
+
*/
|
|
13
|
+
getAllAssistants(): Assistant[] {
|
|
14
|
+
return Array.from(this.assistants.values());
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get assistant by ID
|
|
19
|
+
*/
|
|
20
|
+
getAssistantById(id: string): Assistant | undefined {
|
|
21
|
+
return this.assistants.get(id);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Create a new assistant
|
|
26
|
+
*/
|
|
27
|
+
createAssistant(
|
|
28
|
+
id: string,
|
|
29
|
+
data: CreateAssistantRequest
|
|
30
|
+
): Assistant {
|
|
31
|
+
const now = new Date();
|
|
32
|
+
const assistant: Assistant = {
|
|
33
|
+
id,
|
|
34
|
+
name: data.name,
|
|
35
|
+
description: data.description,
|
|
36
|
+
graphDefinition: data.graphDefinition,
|
|
37
|
+
createdAt: now,
|
|
38
|
+
updatedAt: now,
|
|
39
|
+
};
|
|
40
|
+
this.assistants.set(id, assistant);
|
|
41
|
+
return assistant;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Update an existing assistant
|
|
46
|
+
*/
|
|
47
|
+
updateAssistant(
|
|
48
|
+
id: string,
|
|
49
|
+
updates: Partial<CreateAssistantRequest>
|
|
50
|
+
): Assistant | null {
|
|
51
|
+
const existing = this.assistants.get(id);
|
|
52
|
+
if (!existing) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const updated: Assistant = {
|
|
57
|
+
...existing,
|
|
58
|
+
...updates,
|
|
59
|
+
updatedAt: new Date(),
|
|
60
|
+
};
|
|
61
|
+
this.assistants.set(id, updated);
|
|
62
|
+
return updated;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Delete an assistant by ID
|
|
67
|
+
*/
|
|
68
|
+
deleteAssistant(id: string): boolean {
|
|
69
|
+
return this.assistants.delete(id);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Check if assistant exists
|
|
74
|
+
*/
|
|
75
|
+
hasAssistant(id: string): boolean {
|
|
76
|
+
return this.assistants.has(id);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Export singleton instance
|
|
81
|
+
export const assistantStore = new AssistantStore();
|
|
82
|
+
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Thread, CreateThreadRequest } from "../types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* In-memory store for threads
|
|
5
|
+
* Provides CRUD operations for thread data
|
|
6
|
+
* Threads are organized by assistant ID
|
|
7
|
+
*/
|
|
8
|
+
class ThreadStore {
|
|
9
|
+
// Map<assistantId, Map<threadId, Thread>>
|
|
10
|
+
private threads: Map<string, Map<string, Thread>> = new Map();
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get all threads for a specific assistant
|
|
14
|
+
*/
|
|
15
|
+
getThreadsByAssistantId(assistantId: string): Thread[] {
|
|
16
|
+
const assistantThreads = this.threads.get(assistantId);
|
|
17
|
+
if (!assistantThreads) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
return Array.from(assistantThreads.values());
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get a thread by ID for a specific assistant
|
|
25
|
+
*/
|
|
26
|
+
getThreadById(assistantId: string, threadId: string): Thread | undefined {
|
|
27
|
+
const assistantThreads = this.threads.get(assistantId);
|
|
28
|
+
if (!assistantThreads) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
return assistantThreads.get(threadId);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create a new thread for an assistant
|
|
36
|
+
*/
|
|
37
|
+
createThread(
|
|
38
|
+
assistantId: string,
|
|
39
|
+
threadId: string,
|
|
40
|
+
data: CreateThreadRequest
|
|
41
|
+
): Thread {
|
|
42
|
+
const now = new Date();
|
|
43
|
+
const thread: Thread = {
|
|
44
|
+
id: threadId,
|
|
45
|
+
assistantId,
|
|
46
|
+
metadata: data.metadata || {},
|
|
47
|
+
createdAt: now,
|
|
48
|
+
updatedAt: now,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Initialize assistant's thread map if it doesn't exist
|
|
52
|
+
if (!this.threads.has(assistantId)) {
|
|
53
|
+
this.threads.set(assistantId, new Map());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const assistantThreads = this.threads.get(assistantId)!;
|
|
57
|
+
assistantThreads.set(threadId, thread);
|
|
58
|
+
return thread;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Update an existing thread
|
|
63
|
+
*/
|
|
64
|
+
updateThread(
|
|
65
|
+
assistantId: string,
|
|
66
|
+
threadId: string,
|
|
67
|
+
updates: Partial<CreateThreadRequest>
|
|
68
|
+
): Thread | null {
|
|
69
|
+
const assistantThreads = this.threads.get(assistantId);
|
|
70
|
+
if (!assistantThreads) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const existing = assistantThreads.get(threadId);
|
|
75
|
+
if (!existing) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const updated: Thread = {
|
|
80
|
+
...existing,
|
|
81
|
+
metadata: {
|
|
82
|
+
...existing.metadata,
|
|
83
|
+
...(updates.metadata || {}),
|
|
84
|
+
},
|
|
85
|
+
updatedAt: new Date(),
|
|
86
|
+
};
|
|
87
|
+
assistantThreads.set(threadId, updated);
|
|
88
|
+
return updated;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Delete a thread by ID
|
|
93
|
+
*/
|
|
94
|
+
deleteThread(assistantId: string, threadId: string): boolean {
|
|
95
|
+
const assistantThreads = this.threads.get(assistantId);
|
|
96
|
+
if (!assistantThreads) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
return assistantThreads.delete(threadId);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Check if thread exists
|
|
104
|
+
*/
|
|
105
|
+
hasThread(assistantId: string, threadId: string): boolean {
|
|
106
|
+
const assistantThreads = this.threads.get(assistantId);
|
|
107
|
+
if (!assistantThreads) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
return assistantThreads.has(threadId);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Export singleton instance
|
|
115
|
+
export const threadStore = new ThreadStore();
|
package/src/types/index.ts
CHANGED
|
@@ -121,3 +121,17 @@ export interface ServiceResponse<T = any> {
|
|
|
121
121
|
data?: T;
|
|
122
122
|
error?: string;
|
|
123
123
|
}
|
|
124
|
+
|
|
125
|
+
// Thread type
|
|
126
|
+
export interface Thread {
|
|
127
|
+
id: string;
|
|
128
|
+
assistantId: string;
|
|
129
|
+
metadata?: Record<string, any>;
|
|
130
|
+
createdAt: Date;
|
|
131
|
+
updatedAt: Date;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Create thread request type
|
|
135
|
+
export interface CreateThreadRequest {
|
|
136
|
+
metadata?: Record<string, any>;
|
|
137
|
+
}
|