@waynesutton/agent-memory 0.0.1
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/.claude/settings.json +9 -0
- package/.claude/settings.local.json +7 -0
- package/AGENTS.md +113 -0
- package/CLAUDE.md +79 -0
- package/README.md +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +192 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/parsers/claude-code.d.ts +3 -0
- package/dist/cli/parsers/claude-code.d.ts.map +1 -0
- package/dist/cli/parsers/claude-code.js +75 -0
- package/dist/cli/parsers/claude-code.js.map +1 -0
- package/dist/cli/parsers/codex.d.ts +3 -0
- package/dist/cli/parsers/codex.d.ts.map +1 -0
- package/dist/cli/parsers/codex.js +42 -0
- package/dist/cli/parsers/codex.js.map +1 -0
- package/dist/cli/parsers/conductor.d.ts +3 -0
- package/dist/cli/parsers/conductor.d.ts.map +1 -0
- package/dist/cli/parsers/conductor.js +43 -0
- package/dist/cli/parsers/conductor.js.map +1 -0
- package/dist/cli/parsers/cursor.d.ts +3 -0
- package/dist/cli/parsers/cursor.d.ts.map +1 -0
- package/dist/cli/parsers/cursor.js +50 -0
- package/dist/cli/parsers/cursor.js.map +1 -0
- package/dist/cli/parsers/index.d.ts +12 -0
- package/dist/cli/parsers/index.d.ts.map +1 -0
- package/dist/cli/parsers/index.js +27 -0
- package/dist/cli/parsers/index.js.map +1 -0
- package/dist/cli/parsers/opencode.d.ts +3 -0
- package/dist/cli/parsers/opencode.d.ts.map +1 -0
- package/dist/cli/parsers/opencode.js +72 -0
- package/dist/cli/parsers/opencode.js.map +1 -0
- package/dist/cli/parsers/parsers.test.d.ts +2 -0
- package/dist/cli/parsers/parsers.test.d.ts.map +1 -0
- package/dist/cli/parsers/parsers.test.js +151 -0
- package/dist/cli/parsers/parsers.test.js.map +1 -0
- package/dist/cli/parsers/pi.d.ts +3 -0
- package/dist/cli/parsers/pi.d.ts.map +1 -0
- package/dist/cli/parsers/pi.js +43 -0
- package/dist/cli/parsers/pi.js.map +1 -0
- package/dist/cli/parsers/types.d.ts +25 -0
- package/dist/cli/parsers/types.d.ts.map +1 -0
- package/dist/cli/parsers/types.js +2 -0
- package/dist/cli/parsers/types.js.map +1 -0
- package/dist/cli/parsers/vscode-copilot.d.ts +3 -0
- package/dist/cli/parsers/vscode-copilot.d.ts.map +1 -0
- package/dist/cli/parsers/vscode-copilot.js +69 -0
- package/dist/cli/parsers/vscode-copilot.js.map +1 -0
- package/dist/cli/parsers/zed.d.ts +3 -0
- package/dist/cli/parsers/zed.d.ts.map +1 -0
- package/dist/cli/parsers/zed.js +43 -0
- package/dist/cli/parsers/zed.js.map +1 -0
- package/dist/cli/sync.d.ts +21 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +78 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/cli/type-extractor.d.ts +25 -0
- package/dist/cli/type-extractor.d.ts.map +1 -0
- package/dist/cli/type-extractor.js +254 -0
- package/dist/cli/type-extractor.js.map +1 -0
- package/dist/cli/type-extractor.test.d.ts +2 -0
- package/dist/cli/type-extractor.test.d.ts.map +1 -0
- package/dist/cli/type-extractor.test.js +173 -0
- package/dist/cli/type-extractor.test.js.map +1 -0
- package/dist/client/http.d.ts +44 -0
- package/dist/client/http.d.ts.map +1 -0
- package/dist/client/http.js +311 -0
- package/dist/client/http.js.map +1 -0
- package/dist/client/index.d.ts +158 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +256 -0
- package/dist/client/index.js.map +1 -0
- package/dist/component/_generated/api.d.ts +12 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +13 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +18 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +42 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +39 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/actions.d.ts +42 -0
- package/dist/component/actions.d.ts.map +1 -0
- package/dist/component/actions.js +405 -0
- package/dist/component/actions.js.map +1 -0
- package/dist/component/apiKeyMutations.d.ts +29 -0
- package/dist/component/apiKeyMutations.d.ts.map +1 -0
- package/dist/component/apiKeyMutations.js +149 -0
- package/dist/component/apiKeyMutations.js.map +1 -0
- package/dist/component/apiKeyQueries.d.ts +37 -0
- package/dist/component/apiKeyQueries.d.ts.map +1 -0
- package/dist/component/apiKeyQueries.js +127 -0
- package/dist/component/apiKeyQueries.js.map +1 -0
- package/dist/component/checksum.d.ts +6 -0
- package/dist/component/checksum.d.ts.map +1 -0
- package/dist/component/checksum.js +14 -0
- package/dist/component/checksum.js.map +1 -0
- package/dist/component/checksum.test.d.ts +2 -0
- package/dist/component/checksum.test.d.ts.map +1 -0
- package/dist/component/checksum.test.js +27 -0
- package/dist/component/checksum.test.js.map +1 -0
- package/dist/component/convex.config.d.ts +3 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +4 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/cronActions.d.ts +3 -0
- package/dist/component/cronActions.d.ts.map +1 -0
- package/dist/component/cronActions.js +38 -0
- package/dist/component/cronActions.js.map +1 -0
- package/dist/component/cronQueries.d.ts +6 -0
- package/dist/component/cronQueries.d.ts.map +1 -0
- package/dist/component/cronQueries.js +38 -0
- package/dist/component/cronQueries.js.map +1 -0
- package/dist/component/crons.d.ts +3 -0
- package/dist/component/crons.d.ts.map +1 -0
- package/dist/component/crons.js +18 -0
- package/dist/component/crons.js.map +1 -0
- package/dist/component/format.d.ts +11 -0
- package/dist/component/format.d.ts.map +1 -0
- package/dist/component/format.js +175 -0
- package/dist/component/format.js.map +1 -0
- package/dist/component/format.test.d.ts +2 -0
- package/dist/component/format.test.d.ts.map +1 -0
- package/dist/component/format.test.js +118 -0
- package/dist/component/format.test.js.map +1 -0
- package/dist/component/mutations.d.ts +158 -0
- package/dist/component/mutations.d.ts.map +1 -0
- package/dist/component/mutations.js +745 -0
- package/dist/component/mutations.js.map +1 -0
- package/dist/component/queries.d.ts +94 -0
- package/dist/component/queries.d.ts.map +1 -0
- package/dist/component/queries.js +574 -0
- package/dist/component/queries.js.map +1 -0
- package/dist/component/schema.d.ts +278 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +161 -0
- package/dist/component/schema.js.map +1 -0
- package/dist/mcp/server.d.ts +11 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +571 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/shared.d.ts +126 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +67 -0
- package/dist/shared.js.map +1 -0
- package/dist/test.d.ts +23 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +21 -0
- package/dist/test.js.map +1 -0
- package/eslint.config.js +15 -0
- package/example/convex/convex.config.ts +7 -0
- package/example/convex/memory.ts +129 -0
- package/llms.md +175 -0
- package/llms.txt +126 -0
- package/package.json +72 -0
- package/prds/API-REFERENCE.md +935 -0
- package/prds/README.md +988 -0
- package/prds/SETUP.md +682 -0
- package/src/cli/index.ts +254 -0
- package/src/cli/parsers/claude-code.ts +80 -0
- package/src/cli/parsers/codex.ts +45 -0
- package/src/cli/parsers/conductor.ts +47 -0
- package/src/cli/parsers/cursor.ts +55 -0
- package/src/cli/parsers/index.ts +30 -0
- package/src/cli/parsers/opencode.ts +84 -0
- package/src/cli/parsers/parsers.test.ts +201 -0
- package/src/cli/parsers/pi.ts +47 -0
- package/src/cli/parsers/types.ts +26 -0
- package/src/cli/parsers/vscode-copilot.ts +78 -0
- package/src/cli/parsers/zed.ts +47 -0
- package/src/cli/sync.ts +110 -0
- package/src/cli/type-extractor.test.ts +241 -0
- package/src/cli/type-extractor.ts +331 -0
- package/src/client/http.ts +415 -0
- package/src/client/index.ts +519 -0
- package/src/component/_generated/api.ts +14 -0
- package/src/component/_generated/dataModel.ts +20 -0
- package/src/component/_generated/server.ts +64 -0
- package/src/component/actions.ts +558 -0
- package/src/component/apiKeyMutations.ts +175 -0
- package/src/component/apiKeyQueries.ts +156 -0
- package/src/component/checksum.test.ts +31 -0
- package/src/component/checksum.ts +13 -0
- package/src/component/convex.config.ts +5 -0
- package/src/component/cronActions.ts +52 -0
- package/src/component/cronQueries.ts +42 -0
- package/src/component/crons.ts +34 -0
- package/src/component/format.test.ts +133 -0
- package/src/component/format.ts +232 -0
- package/src/component/mutations.ts +824 -0
- package/src/component/queries.ts +684 -0
- package/src/component/schema.ts +207 -0
- package/src/mcp/server.ts +695 -0
- package/src/shared.ts +251 -0
- package/src/test.ts +32 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
import { httpActionGeneric, type HttpRouter } from "convex/server";
|
|
2
|
+
import type { api } from "../component/_generated/api.js";
|
|
3
|
+
|
|
4
|
+
// Use the generic httpAction since this is a component (no app-specific data model)
|
|
5
|
+
const httpAction = httpActionGeneric;
|
|
6
|
+
|
|
7
|
+
// ── Types ───────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
type ComponentApi = typeof api;
|
|
10
|
+
|
|
11
|
+
export interface MemoryHttpApiConfig {
|
|
12
|
+
/** Allowed CORS origins. Defaults to ["*"]. */
|
|
13
|
+
corsOrigins?: string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface ValidKey {
|
|
17
|
+
valid: true;
|
|
18
|
+
keyHash: string;
|
|
19
|
+
projectId: string;
|
|
20
|
+
permissions: string[];
|
|
21
|
+
rateLimit: { requestsPerWindow: number; windowMs: number };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ── Helpers ─────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
function corsHeaders(origins: string[]): Record<string, string> {
|
|
27
|
+
return {
|
|
28
|
+
"Access-Control-Allow-Origin": origins.includes("*") ? "*" : origins[0],
|
|
29
|
+
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
|
30
|
+
"Access-Control-Allow-Headers": "Authorization, Content-Type",
|
|
31
|
+
"Access-Control-Max-Age": "86400",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function jsonResponse(
|
|
36
|
+
data: unknown,
|
|
37
|
+
status: number,
|
|
38
|
+
cors: Record<string, string>,
|
|
39
|
+
): Response {
|
|
40
|
+
return new Response(JSON.stringify(data), {
|
|
41
|
+
status,
|
|
42
|
+
headers: { "Content-Type": "application/json", ...cors },
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function errorResponse(
|
|
47
|
+
message: string,
|
|
48
|
+
status: number,
|
|
49
|
+
cors: Record<string, string>,
|
|
50
|
+
extra?: Record<string, unknown>,
|
|
51
|
+
): Response {
|
|
52
|
+
return jsonResponse({ error: message, ...extra }, status, cors);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ── MemoryHttpApi ───────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Generates read-only HTTP endpoint handlers that a Convex app mounts
|
|
59
|
+
* on its own `httpRouter`. Each request is authenticated via an API key
|
|
60
|
+
* (Bearer token) and rate-limited using the component's built-in
|
|
61
|
+
* fixed-window token bucket.
|
|
62
|
+
*
|
|
63
|
+
* Usage in the consuming app's `convex/http.ts`:
|
|
64
|
+
*
|
|
65
|
+
* ```typescript
|
|
66
|
+
* import { httpRouter } from "convex/server";
|
|
67
|
+
* import { MemoryHttpApi } from "@waynesutton/agent-memory/http";
|
|
68
|
+
* import { components } from "./_generated/api";
|
|
69
|
+
*
|
|
70
|
+
* const http = httpRouter();
|
|
71
|
+
* const memoryApi = new MemoryHttpApi(components.agentMemory);
|
|
72
|
+
* memoryApi.mount(http, "/api/memory");
|
|
73
|
+
* export default http;
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export class MemoryHttpApi {
|
|
77
|
+
private component: ComponentApi;
|
|
78
|
+
private cors: Record<string, string>;
|
|
79
|
+
|
|
80
|
+
constructor(component: ComponentApi, config?: MemoryHttpApiConfig) {
|
|
81
|
+
this.component = component;
|
|
82
|
+
this.cors = corsHeaders(config?.corsOrigins ?? ["*"]);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ── Auth + rate-limit middleware ─────────────────────────────────
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Validates the Bearer token, checks rate limits, and returns the
|
|
89
|
+
* validated key info. Returns an error Response if auth or rate
|
|
90
|
+
* limiting fails.
|
|
91
|
+
*/
|
|
92
|
+
private async authenticate(
|
|
93
|
+
ctx: { runQuery: any; runMutation: any },
|
|
94
|
+
request: Request,
|
|
95
|
+
requiredPermission: string,
|
|
96
|
+
): Promise<ValidKey | Response> {
|
|
97
|
+
const authHeader = request.headers.get("Authorization");
|
|
98
|
+
if (!authHeader?.startsWith("Bearer ")) {
|
|
99
|
+
return errorResponse(
|
|
100
|
+
"Missing or invalid Authorization header. Expected: Bearer am_<key>",
|
|
101
|
+
401,
|
|
102
|
+
this.cors,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const key = authHeader.slice(7);
|
|
107
|
+
const validation = await ctx.runQuery(
|
|
108
|
+
this.component.apiKeyQueries.validateApiKey,
|
|
109
|
+
{ key },
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
if (!validation.valid) {
|
|
113
|
+
return errorResponse(validation.reason, 401, this.cors);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Check permission
|
|
117
|
+
if (!validation.permissions.includes(requiredPermission)) {
|
|
118
|
+
return errorResponse(
|
|
119
|
+
`API key does not have "${requiredPermission}" permission`,
|
|
120
|
+
403,
|
|
121
|
+
this.cors,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Consume rate limit
|
|
126
|
+
const rateResult = await ctx.runMutation(
|
|
127
|
+
this.component.apiKeyMutations.consumeRateLimit,
|
|
128
|
+
{
|
|
129
|
+
keyHash: validation.keyHash,
|
|
130
|
+
requestsPerWindow: validation.rateLimit.requestsPerWindow,
|
|
131
|
+
windowMs: validation.rateLimit.windowMs,
|
|
132
|
+
},
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
if (!rateResult.allowed) {
|
|
136
|
+
return errorResponse("Rate limit exceeded", 429, this.cors, {
|
|
137
|
+
retryAfterMs: rateResult.retryAfterMs,
|
|
138
|
+
"Retry-After": String(Math.ceil(rateResult.retryAfterMs / 1000)),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Fire-and-forget: update lastUsedAt
|
|
143
|
+
ctx
|
|
144
|
+
.runMutation(this.component.apiKeyQueries.updateKeyLastUsed, {
|
|
145
|
+
keyHash: validation.keyHash,
|
|
146
|
+
})
|
|
147
|
+
.catch(() => {});
|
|
148
|
+
|
|
149
|
+
return validation as ValidKey;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ── Route mounting ──────────────────────────────────────────────
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Registers all read-only memory API routes on the given httpRouter
|
|
156
|
+
* under the specified prefix (e.g. "/api/memory").
|
|
157
|
+
*/
|
|
158
|
+
mount(http: HttpRouter, prefix: string): void {
|
|
159
|
+
const p = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
|
|
160
|
+
|
|
161
|
+
// CORS preflight for all routes
|
|
162
|
+
const optionsHandler = httpAction(async () => {
|
|
163
|
+
return new Response(null, { status: 204, headers: this.cors });
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// ── GET /list ────────────────────────────────────────────────
|
|
167
|
+
http.route({
|
|
168
|
+
path: `${p}/list`,
|
|
169
|
+
method: "GET",
|
|
170
|
+
handler: httpAction(async (ctx, request) => {
|
|
171
|
+
const auth = await this.authenticate(ctx, request, "list");
|
|
172
|
+
if (auth instanceof Response) return auth;
|
|
173
|
+
|
|
174
|
+
const url = new URL(request.url);
|
|
175
|
+
const result = await ctx.runQuery(this.component.queries.list, {
|
|
176
|
+
projectId: auth.projectId,
|
|
177
|
+
memoryType: url.searchParams.get("memoryType") ?? undefined,
|
|
178
|
+
scope: (url.searchParams.get("scope") as any) ?? undefined,
|
|
179
|
+
agentId: url.searchParams.get("agentId") ?? undefined,
|
|
180
|
+
sessionId: url.searchParams.get("sessionId") ?? undefined,
|
|
181
|
+
source: url.searchParams.get("source") ?? undefined,
|
|
182
|
+
tags: url.searchParams.get("tags")
|
|
183
|
+
? url.searchParams.get("tags")!.split(",")
|
|
184
|
+
: undefined,
|
|
185
|
+
archived: url.searchParams.get("archived") === "true"
|
|
186
|
+
? true
|
|
187
|
+
: undefined,
|
|
188
|
+
minPriority: url.searchParams.get("minPriority")
|
|
189
|
+
? Number(url.searchParams.get("minPriority"))
|
|
190
|
+
: undefined,
|
|
191
|
+
limit: url.searchParams.get("limit")
|
|
192
|
+
? Number(url.searchParams.get("limit"))
|
|
193
|
+
: undefined,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
return jsonResponse(result, 200, this.cors);
|
|
197
|
+
}),
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
http.route({
|
|
201
|
+
path: `${p}/list`,
|
|
202
|
+
method: "OPTIONS",
|
|
203
|
+
handler: optionsHandler,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// ── GET /get?id=<memoryId> ──────────────────────────────────
|
|
207
|
+
http.route({
|
|
208
|
+
path: `${p}/get`,
|
|
209
|
+
method: "GET",
|
|
210
|
+
handler: httpAction(async (ctx, request) => {
|
|
211
|
+
const auth = await this.authenticate(ctx, request, "get");
|
|
212
|
+
if (auth instanceof Response) return auth;
|
|
213
|
+
|
|
214
|
+
const url = new URL(request.url);
|
|
215
|
+
const memoryId = url.searchParams.get("id");
|
|
216
|
+
if (!memoryId) {
|
|
217
|
+
return errorResponse("Missing required query param: id", 400, this.cors);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const result = await ctx.runQuery(this.component.queries.get, {
|
|
221
|
+
memoryId,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
if (!result) {
|
|
225
|
+
return errorResponse("Memory not found", 404, this.cors);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return jsonResponse(result, 200, this.cors);
|
|
229
|
+
}),
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
http.route({
|
|
233
|
+
path: `${p}/get`,
|
|
234
|
+
method: "OPTIONS",
|
|
235
|
+
handler: optionsHandler,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// ── GET /search?q=<query> ───────────────────────────────────
|
|
239
|
+
http.route({
|
|
240
|
+
path: `${p}/search`,
|
|
241
|
+
method: "GET",
|
|
242
|
+
handler: httpAction(async (ctx, request) => {
|
|
243
|
+
const auth = await this.authenticate(ctx, request, "search");
|
|
244
|
+
if (auth instanceof Response) return auth;
|
|
245
|
+
|
|
246
|
+
const url = new URL(request.url);
|
|
247
|
+
const query = url.searchParams.get("q");
|
|
248
|
+
if (!query) {
|
|
249
|
+
return errorResponse("Missing required query param: q", 400, this.cors);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const result = await ctx.runQuery(this.component.queries.search, {
|
|
253
|
+
projectId: auth.projectId,
|
|
254
|
+
query,
|
|
255
|
+
memoryType: url.searchParams.get("memoryType") ?? undefined,
|
|
256
|
+
scope: (url.searchParams.get("scope") as any) ?? undefined,
|
|
257
|
+
limit: url.searchParams.get("limit")
|
|
258
|
+
? Number(url.searchParams.get("limit"))
|
|
259
|
+
: undefined,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
return jsonResponse(result, 200, this.cors);
|
|
263
|
+
}),
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
http.route({
|
|
267
|
+
path: `${p}/search`,
|
|
268
|
+
method: "OPTIONS",
|
|
269
|
+
handler: optionsHandler,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// ── GET /context ────────────────────────────────────────────
|
|
273
|
+
http.route({
|
|
274
|
+
path: `${p}/context`,
|
|
275
|
+
method: "GET",
|
|
276
|
+
handler: httpAction(async (ctx, request) => {
|
|
277
|
+
const auth = await this.authenticate(ctx, request, "context");
|
|
278
|
+
if (auth instanceof Response) return auth;
|
|
279
|
+
|
|
280
|
+
const url = new URL(request.url);
|
|
281
|
+
const result = await ctx.runQuery(
|
|
282
|
+
this.component.queries.getContextBundle,
|
|
283
|
+
{
|
|
284
|
+
projectId: auth.projectId,
|
|
285
|
+
scope: (url.searchParams.get("scope") as any) ?? "project",
|
|
286
|
+
userId: url.searchParams.get("userId") ?? undefined,
|
|
287
|
+
agentId: url.searchParams.get("agentId") ?? undefined,
|
|
288
|
+
activePaths: url.searchParams.get("activePaths")
|
|
289
|
+
? url.searchParams.get("activePaths")!.split(",")
|
|
290
|
+
: undefined,
|
|
291
|
+
maxTokens: url.searchParams.get("maxTokens")
|
|
292
|
+
? Number(url.searchParams.get("maxTokens"))
|
|
293
|
+
: undefined,
|
|
294
|
+
},
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
return jsonResponse(result, 200, this.cors);
|
|
298
|
+
}),
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
http.route({
|
|
302
|
+
path: `${p}/context`,
|
|
303
|
+
method: "OPTIONS",
|
|
304
|
+
handler: optionsHandler,
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// ── GET /export?format=<format> ─────────────────────────────
|
|
308
|
+
http.route({
|
|
309
|
+
path: `${p}/export`,
|
|
310
|
+
method: "GET",
|
|
311
|
+
handler: httpAction(async (ctx, request) => {
|
|
312
|
+
const auth = await this.authenticate(ctx, request, "export");
|
|
313
|
+
if (auth instanceof Response) return auth;
|
|
314
|
+
|
|
315
|
+
const url = new URL(request.url);
|
|
316
|
+
const format = url.searchParams.get("format");
|
|
317
|
+
if (!format) {
|
|
318
|
+
return errorResponse(
|
|
319
|
+
"Missing required query param: format",
|
|
320
|
+
400,
|
|
321
|
+
this.cors,
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const result = await ctx.runQuery(
|
|
326
|
+
this.component.queries.exportForTool,
|
|
327
|
+
{
|
|
328
|
+
projectId: auth.projectId,
|
|
329
|
+
format,
|
|
330
|
+
scope: (url.searchParams.get("scope") as any) ?? undefined,
|
|
331
|
+
userId: url.searchParams.get("userId") ?? undefined,
|
|
332
|
+
since: url.searchParams.get("since")
|
|
333
|
+
? Number(url.searchParams.get("since"))
|
|
334
|
+
: undefined,
|
|
335
|
+
},
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
return jsonResponse(result, 200, this.cors);
|
|
339
|
+
}),
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
http.route({
|
|
343
|
+
path: `${p}/export`,
|
|
344
|
+
method: "OPTIONS",
|
|
345
|
+
handler: optionsHandler,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// ── GET /history?id=<memoryId> ──────────────────────────────
|
|
349
|
+
http.route({
|
|
350
|
+
path: `${p}/history`,
|
|
351
|
+
method: "GET",
|
|
352
|
+
handler: httpAction(async (ctx, request) => {
|
|
353
|
+
const auth = await this.authenticate(ctx, request, "history");
|
|
354
|
+
if (auth instanceof Response) return auth;
|
|
355
|
+
|
|
356
|
+
const url = new URL(request.url);
|
|
357
|
+
const memoryId = url.searchParams.get("id");
|
|
358
|
+
if (!memoryId) {
|
|
359
|
+
return errorResponse("Missing required query param: id", 400, this.cors);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const result = await ctx.runQuery(this.component.queries.history, {
|
|
363
|
+
memoryId,
|
|
364
|
+
limit: url.searchParams.get("limit")
|
|
365
|
+
? Number(url.searchParams.get("limit"))
|
|
366
|
+
: undefined,
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
return jsonResponse(result, 200, this.cors);
|
|
370
|
+
}),
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
http.route({
|
|
374
|
+
path: `${p}/history`,
|
|
375
|
+
method: "OPTIONS",
|
|
376
|
+
handler: optionsHandler,
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// ── GET /relations?id=<memoryId> ────────────────────────────
|
|
380
|
+
http.route({
|
|
381
|
+
path: `${p}/relations`,
|
|
382
|
+
method: "GET",
|
|
383
|
+
handler: httpAction(async (ctx, request) => {
|
|
384
|
+
const auth = await this.authenticate(ctx, request, "relations");
|
|
385
|
+
if (auth instanceof Response) return auth;
|
|
386
|
+
|
|
387
|
+
const url = new URL(request.url);
|
|
388
|
+
const memoryId = url.searchParams.get("id");
|
|
389
|
+
if (!memoryId) {
|
|
390
|
+
return errorResponse("Missing required query param: id", 400, this.cors);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const result = await ctx.runQuery(
|
|
394
|
+
this.component.queries.getRelations,
|
|
395
|
+
{
|
|
396
|
+
memoryId,
|
|
397
|
+
direction: (url.searchParams.get("direction") as any) ?? undefined,
|
|
398
|
+
relationship: url.searchParams.get("relationship") ?? undefined,
|
|
399
|
+
limit: url.searchParams.get("limit")
|
|
400
|
+
? Number(url.searchParams.get("limit"))
|
|
401
|
+
: undefined,
|
|
402
|
+
},
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
return jsonResponse(result, 200, this.cors);
|
|
406
|
+
}),
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
http.route({
|
|
410
|
+
path: `${p}/relations`,
|
|
411
|
+
method: "OPTIONS",
|
|
412
|
+
handler: optionsHandler,
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
}
|