@treeseed/core 0.4.2 → 0.4.4
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/README.md +7 -1
- package/dist/api/agent-routes.d.ts +13 -0
- package/dist/api/agent-routes.js +402 -0
- package/dist/api/app.d.ts +5 -0
- package/dist/api/app.js +270 -0
- package/dist/api/auth/d1-database.d.ts +3 -0
- package/dist/api/auth/d1-database.js +24 -0
- package/dist/api/auth/d1-provider.d.ts +67 -0
- package/dist/api/auth/d1-provider.js +84 -0
- package/dist/api/auth/d1-store.d.ts +97 -0
- package/dist/api/auth/d1-store.js +631 -0
- package/dist/api/auth/memory-provider.d.ts +73 -0
- package/dist/api/auth/memory-provider.js +239 -0
- package/dist/api/auth/rbac.d.ts +22 -0
- package/dist/api/auth/rbac.js +158 -0
- package/dist/api/auth/tokens.d.ts +18 -0
- package/dist/api/auth/tokens.js +56 -0
- package/dist/api/config.d.ts +2 -0
- package/dist/api/config.js +65 -0
- package/dist/api/gateway.d.ts +5 -0
- package/dist/api/gateway.js +35 -0
- package/dist/api/http.d.ts +24 -0
- package/dist/api/http.js +44 -0
- package/dist/api/index.d.ts +9 -0
- package/dist/api/index.js +18 -0
- package/dist/api/operations-routes.d.ts +6 -0
- package/dist/api/operations-routes.js +34 -0
- package/dist/api/operations.d.ts +3 -0
- package/dist/api/operations.js +26 -0
- package/dist/api/providers.d.ts +2 -0
- package/dist/api/providers.js +61 -0
- package/dist/api/railway.d.ts +45 -0
- package/dist/api/railway.js +69 -0
- package/dist/api/sdk-dispatch.d.ts +14 -0
- package/dist/api/sdk-dispatch.js +145 -0
- package/dist/api/sdk-routes.d.ts +10 -0
- package/dist/api/sdk-routes.js +25 -0
- package/dist/api/server.d.ts +2 -0
- package/dist/api/server.js +10 -0
- package/dist/api/templates.d.ts +3 -0
- package/dist/api/templates.js +31 -0
- package/dist/api/types.d.ts +193 -0
- package/dist/api/types.js +0 -0
- package/dist/api.d.ts +1 -0
- package/dist/api.js +1 -0
- package/dist/dev.d.ts +41 -0
- package/dist/dev.js +189 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +23 -1
- package/dist/platform-resources.d.ts +37 -0
- package/dist/platform-resources.js +133 -0
- package/dist/platform.d.ts +2 -0
- package/dist/platform.js +16 -0
- package/dist/plugin-default.d.ts +1 -0
- package/dist/plugin-default.js +4 -0
- package/dist/railway.d.ts +1 -0
- package/dist/railway.js +4 -0
- package/dist/scripts/build-dist.js +7 -0
- package/dist/scripts/dev-platform.js +24 -0
- package/dist/scripts/workspace-bootstrap.js +0 -1
- package/dist/site-resources.d.ts +1 -29
- package/dist/site-resources.js +7 -120
- package/dist/site.js +3 -1
- package/package.json +37 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @treeseed/core
|
|
2
2
|
|
|
3
|
-
`@treeseed/core` is the Treeseed
|
|
3
|
+
`@treeseed/core` is the Treeseed integrated platform starter for Astro/Starlight sites and Hono API runtimes. It contains the published web runtime, API runtime, integrated local dev orchestration, shared components and styles, the knowledge-factory content model, and the forms stack used by Treeseed tenants.
|
|
4
4
|
|
|
5
5
|
This repository is the package root. Run package commands from [`core`](./), not from the top-level `treeseed` workspace.
|
|
6
6
|
|
|
@@ -54,6 +54,9 @@ This keeps the shared fixture canonical while preserving Core’s package bounda
|
|
|
54
54
|
### Core development
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
|
+
npm run dev
|
|
58
|
+
npm run dev:web
|
|
59
|
+
npm run dev:api
|
|
57
60
|
npm run fixtures:check
|
|
58
61
|
npm run build:dist
|
|
59
62
|
npm run test:unit
|
|
@@ -64,6 +67,9 @@ npm run test:smoke
|
|
|
64
67
|
|
|
65
68
|
What they do:
|
|
66
69
|
|
|
70
|
+
- `dev`: starts the integrated Astro UI and Hono API local runtime from `core`
|
|
71
|
+
- `dev:web`: starts only the Astro UI dev surface through the `core` runtime
|
|
72
|
+
- `dev:api`: starts only the Hono API dev surface through the `core` runtime
|
|
67
73
|
- `fixtures:check`: verifies that the pinned shared fixture is initialized and usable
|
|
68
74
|
- `build:dist`: builds the publishable `dist/` package output
|
|
69
75
|
- `test:unit`: runs package unit tests with Vitest
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Hono } from 'hono';
|
|
2
|
+
import type { AgentSdk } from '@treeseed/sdk';
|
|
3
|
+
import type { GatewayQueueProducer } from './types.ts';
|
|
4
|
+
interface RegisterAgentRoutesOptions {
|
|
5
|
+
sdk: AgentSdk;
|
|
6
|
+
prefix?: string;
|
|
7
|
+
scope?: string | null;
|
|
8
|
+
projectId?: string;
|
|
9
|
+
queueProducer?: GatewayQueueProducer;
|
|
10
|
+
defaultActor?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function registerAgentRoutes(app: Hono<any>, options: RegisterAgentRoutesOptions): void;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { jsonError, requireScope } from "./http.js";
|
|
3
|
+
async function importOptionalAgentRuntime() {
|
|
4
|
+
try {
|
|
5
|
+
const dynamicImport = new Function("specifier", "return import(specifier)");
|
|
6
|
+
return await dynamicImport("@treeseed/agent");
|
|
7
|
+
} catch {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
async function listRegisteredHandlers() {
|
|
12
|
+
const agent = await importOptionalAgentRuntime();
|
|
13
|
+
return agent?.listRegisteredAgentHandlers?.() ?? [];
|
|
14
|
+
}
|
|
15
|
+
function queueEnvelopeForTask(task) {
|
|
16
|
+
return {
|
|
17
|
+
messageId: crypto.randomUUID(),
|
|
18
|
+
taskId: String(task.id ?? ""),
|
|
19
|
+
workDayId: String(task.workDayId ?? task.work_day_id ?? ""),
|
|
20
|
+
agentId: String(task.agentId ?? task.agent_id ?? ""),
|
|
21
|
+
taskType: String(task.type ?? ""),
|
|
22
|
+
idempotencyKey: String(task.idempotencyKey ?? task.idempotency_key ?? ""),
|
|
23
|
+
attempt: Number(task.attemptCount ?? task.attempt_count ?? 0) + 1,
|
|
24
|
+
payloadRef: `d1:tasks/${String(task.id ?? "")}`,
|
|
25
|
+
graphVersion: task.graphVersion !== void 0 && task.graphVersion !== null ? String(task.graphVersion) : task.graph_version !== void 0 && task.graph_version !== null ? String(task.graph_version) : null,
|
|
26
|
+
budgetHint: 1
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function withPrefix(prefix, path) {
|
|
30
|
+
return `${prefix}${path}`.replace(/\/{2,}/g, "/");
|
|
31
|
+
}
|
|
32
|
+
function actor(body, fallback) {
|
|
33
|
+
return String(body.actor ?? fallback);
|
|
34
|
+
}
|
|
35
|
+
async function enqueueTask(options, request) {
|
|
36
|
+
if (!options.queueProducer) {
|
|
37
|
+
throw new Error("Queue producer not configured.");
|
|
38
|
+
}
|
|
39
|
+
const task = await options.sdk.get({ model: "task", id: request.taskId });
|
|
40
|
+
if (!task.payload) {
|
|
41
|
+
throw new Error("Unknown task.");
|
|
42
|
+
}
|
|
43
|
+
await options.queueProducer.enqueue({
|
|
44
|
+
queueName: request.queueName,
|
|
45
|
+
message: queueEnvelopeForTask(task.payload),
|
|
46
|
+
delaySeconds: request.deliveryDelaySeconds ?? 0
|
|
47
|
+
});
|
|
48
|
+
await options.sdk.recordTaskProgress({
|
|
49
|
+
id: request.taskId,
|
|
50
|
+
state: "queued",
|
|
51
|
+
appendEvent: { kind: "queued", data: { queueName: request.queueName ?? null } },
|
|
52
|
+
actor: request.actor
|
|
53
|
+
});
|
|
54
|
+
return { ok: true, taskId: request.taskId, queued: true };
|
|
55
|
+
}
|
|
56
|
+
async function buildTaskContext(sdk, taskId) {
|
|
57
|
+
const context = await sdk.getManagerContext(taskId);
|
|
58
|
+
const task = context.payload.task;
|
|
59
|
+
const agent = task ? (await sdk.get({ model: "agent", slug: String(task.agentId) })).payload : null;
|
|
60
|
+
return {
|
|
61
|
+
...context.payload,
|
|
62
|
+
agent
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function registerAgentRoutes(app, options) {
|
|
66
|
+
const prefix = options.prefix ?? "/agent";
|
|
67
|
+
const defaultActor = options.defaultActor ?? "api";
|
|
68
|
+
app.get(withPrefix(prefix, "/healthz"), async (c) => c.json({
|
|
69
|
+
ok: true,
|
|
70
|
+
service: "treeseed-agent-api",
|
|
71
|
+
handlerCount: (await listRegisteredHandlers()).length
|
|
72
|
+
}));
|
|
73
|
+
app.get(withPrefix(prefix, "/specs"), async (c) => {
|
|
74
|
+
if (options.scope) {
|
|
75
|
+
const unauthorized = requireScope(c, options.scope);
|
|
76
|
+
if (unauthorized) return unauthorized;
|
|
77
|
+
}
|
|
78
|
+
const payload = await options.sdk.listAgentSpecs({ enabled: true });
|
|
79
|
+
return c.json({
|
|
80
|
+
ok: true,
|
|
81
|
+
payload,
|
|
82
|
+
handlers: await listRegisteredHandlers()
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
app.post(withPrefix(prefix, "/workdays/start"), async (c) => {
|
|
86
|
+
if (options.scope) {
|
|
87
|
+
const unauthorized = requireScope(c, options.scope);
|
|
88
|
+
if (unauthorized) return unauthorized;
|
|
89
|
+
}
|
|
90
|
+
const body = await c.req.json().catch(() => ({}));
|
|
91
|
+
const graphRefresh = await options.sdk.refreshGraph();
|
|
92
|
+
const result = await options.sdk.startWorkDay({
|
|
93
|
+
id: typeof body.id === "string" ? body.id : void 0,
|
|
94
|
+
projectId: String(body.projectId ?? options.projectId ?? "treeseed-market"),
|
|
95
|
+
capacityBudget: body.capacityBudget === void 0 ? void 0 : Number(body.capacityBudget),
|
|
96
|
+
graphVersion: typeof body.graphVersion === "string" ? body.graphVersion : graphRefresh.snapshotRoot,
|
|
97
|
+
summary: body.summary ?? { graphRefresh },
|
|
98
|
+
actor: actor(body, defaultActor)
|
|
99
|
+
});
|
|
100
|
+
return c.json(result);
|
|
101
|
+
});
|
|
102
|
+
app.post(withPrefix(prefix, "/workdays/:id/close"), async (c) => {
|
|
103
|
+
if (options.scope) {
|
|
104
|
+
const unauthorized = requireScope(c, options.scope);
|
|
105
|
+
if (unauthorized) return unauthorized;
|
|
106
|
+
}
|
|
107
|
+
const body = await c.req.json().catch(() => ({}));
|
|
108
|
+
const result = await options.sdk.closeWorkDay({
|
|
109
|
+
id: c.req.param("id"),
|
|
110
|
+
state: body.state,
|
|
111
|
+
summary: body.summary ?? null,
|
|
112
|
+
actor: actor(body, defaultActor)
|
|
113
|
+
});
|
|
114
|
+
return result.payload ? c.json(result) : jsonError(c, 404, "Unknown work day.");
|
|
115
|
+
});
|
|
116
|
+
app.post(withPrefix(prefix, "/tasks"), async (c) => {
|
|
117
|
+
if (options.scope) {
|
|
118
|
+
const unauthorized = requireScope(c, options.scope);
|
|
119
|
+
if (unauthorized) return unauthorized;
|
|
120
|
+
}
|
|
121
|
+
const body = await c.req.json().catch(() => ({}));
|
|
122
|
+
const result = await options.sdk.createTask({
|
|
123
|
+
id: typeof body.id === "string" ? body.id : void 0,
|
|
124
|
+
workDayId: String(body.workDayId ?? ""),
|
|
125
|
+
agentId: String(body.agentId ?? ""),
|
|
126
|
+
type: String(body.type ?? ""),
|
|
127
|
+
state: typeof body.state === "string" ? body.state : "pending",
|
|
128
|
+
priority: body.priority === void 0 ? void 0 : Number(body.priority),
|
|
129
|
+
idempotencyKey: String(body.idempotencyKey ?? ""),
|
|
130
|
+
payload: body.payload ?? {},
|
|
131
|
+
payloadHash: typeof body.payloadHash === "string" ? body.payloadHash : null,
|
|
132
|
+
maxAttempts: body.maxAttempts === void 0 ? void 0 : Number(body.maxAttempts),
|
|
133
|
+
availableAt: typeof body.availableAt === "string" ? body.availableAt : void 0,
|
|
134
|
+
graphVersion: typeof body.graphVersion === "string" ? body.graphVersion : null,
|
|
135
|
+
parentTaskId: typeof body.parentTaskId === "string" ? body.parentTaskId : null,
|
|
136
|
+
actor: actor(body, defaultActor)
|
|
137
|
+
});
|
|
138
|
+
return c.json(result);
|
|
139
|
+
});
|
|
140
|
+
app.post(withPrefix(prefix, "/tasks/search"), async (c) => {
|
|
141
|
+
if (options.scope) {
|
|
142
|
+
const unauthorized = requireScope(c, options.scope);
|
|
143
|
+
if (unauthorized) return unauthorized;
|
|
144
|
+
}
|
|
145
|
+
const body = await c.req.json().catch(() => ({}));
|
|
146
|
+
const result = await options.sdk.searchTasks({
|
|
147
|
+
workDayId: typeof body.workDayId === "string" ? body.workDayId : void 0,
|
|
148
|
+
agentId: typeof body.agentId === "string" ? body.agentId : void 0,
|
|
149
|
+
state: Array.isArray(body.state) || typeof body.state === "string" ? body.state : void 0,
|
|
150
|
+
limit: body.limit === void 0 ? void 0 : Number(body.limit)
|
|
151
|
+
});
|
|
152
|
+
return c.json(result);
|
|
153
|
+
});
|
|
154
|
+
app.post(withPrefix(prefix, "/tasks/:id/claim"), async (c) => {
|
|
155
|
+
if (options.scope) {
|
|
156
|
+
const unauthorized = requireScope(c, options.scope);
|
|
157
|
+
if (unauthorized) return unauthorized;
|
|
158
|
+
}
|
|
159
|
+
const body = await c.req.json().catch(() => ({}));
|
|
160
|
+
const result = await options.sdk.claimTask({
|
|
161
|
+
id: c.req.param("id"),
|
|
162
|
+
workerId: String(body.workerId ?? "worker"),
|
|
163
|
+
leaseSeconds: Number(body.leaseSeconds ?? 120),
|
|
164
|
+
actor: actor(body, defaultActor)
|
|
165
|
+
});
|
|
166
|
+
return result.payload ? c.json(result) : jsonError(c, 404, "Unknown task.");
|
|
167
|
+
});
|
|
168
|
+
app.post(withPrefix(prefix, "/tasks/:id/progress"), async (c) => {
|
|
169
|
+
if (options.scope) {
|
|
170
|
+
const unauthorized = requireScope(c, options.scope);
|
|
171
|
+
if (unauthorized) return unauthorized;
|
|
172
|
+
}
|
|
173
|
+
const body = await c.req.json().catch(() => ({}));
|
|
174
|
+
const result = await options.sdk.recordTaskProgress({
|
|
175
|
+
id: c.req.param("id"),
|
|
176
|
+
workerId: typeof body.workerId === "string" ? body.workerId : null,
|
|
177
|
+
state: typeof body.state === "string" ? body.state : void 0,
|
|
178
|
+
appendEvent: body.appendEvent,
|
|
179
|
+
patch: body.patch,
|
|
180
|
+
actor: actor(body, defaultActor)
|
|
181
|
+
});
|
|
182
|
+
return result.payload ? c.json(result) : jsonError(c, 404, "Unknown task.");
|
|
183
|
+
});
|
|
184
|
+
app.post(withPrefix(prefix, "/tasks/:id/complete"), async (c) => {
|
|
185
|
+
if (options.scope) {
|
|
186
|
+
const unauthorized = requireScope(c, options.scope);
|
|
187
|
+
if (unauthorized) return unauthorized;
|
|
188
|
+
}
|
|
189
|
+
const body = await c.req.json().catch(() => ({}));
|
|
190
|
+
const result = await options.sdk.completeTask({
|
|
191
|
+
id: c.req.param("id"),
|
|
192
|
+
output: body.output ?? null,
|
|
193
|
+
outputRef: typeof body.outputRef === "string" ? body.outputRef : null,
|
|
194
|
+
summary: body.summary ?? null,
|
|
195
|
+
actor: actor(body, defaultActor)
|
|
196
|
+
});
|
|
197
|
+
return result.payload ? c.json(result) : jsonError(c, 404, "Unknown task.");
|
|
198
|
+
});
|
|
199
|
+
app.post(withPrefix(prefix, "/tasks/:id/fail"), async (c) => {
|
|
200
|
+
if (options.scope) {
|
|
201
|
+
const unauthorized = requireScope(c, options.scope);
|
|
202
|
+
if (unauthorized) return unauthorized;
|
|
203
|
+
}
|
|
204
|
+
const body = await c.req.json().catch(() => ({}));
|
|
205
|
+
const result = await options.sdk.failTask({
|
|
206
|
+
id: c.req.param("id"),
|
|
207
|
+
errorCode: typeof body.errorCode === "string" ? body.errorCode : null,
|
|
208
|
+
errorMessage: String(body.errorMessage ?? "Task failed"),
|
|
209
|
+
retryable: Boolean(body.retryable),
|
|
210
|
+
nextVisibleAt: typeof body.nextVisibleAt === "string" ? body.nextVisibleAt : null,
|
|
211
|
+
actor: actor(body, defaultActor)
|
|
212
|
+
});
|
|
213
|
+
return result.payload ? c.json(result) : jsonError(c, 404, "Unknown task.");
|
|
214
|
+
});
|
|
215
|
+
app.post(withPrefix(prefix, "/tasks/:id/requeue"), async (c) => {
|
|
216
|
+
if (options.scope) {
|
|
217
|
+
const unauthorized = requireScope(c, options.scope);
|
|
218
|
+
if (unauthorized) return unauthorized;
|
|
219
|
+
}
|
|
220
|
+
const body = await c.req.json().catch(() => ({}));
|
|
221
|
+
try {
|
|
222
|
+
return c.json(await enqueueTask(options, {
|
|
223
|
+
taskId: c.req.param("id"),
|
|
224
|
+
queueName: typeof body.queueName === "string" ? body.queueName : void 0,
|
|
225
|
+
deliveryDelaySeconds: body.delaySeconds === void 0 ? void 0 : Number(body.delaySeconds),
|
|
226
|
+
actor: actor(body, defaultActor)
|
|
227
|
+
}));
|
|
228
|
+
} catch (error) {
|
|
229
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
230
|
+
return jsonError(c, /Unknown task/.test(message) ? 404 : /Queue producer/.test(message) ? 501 : 500, message);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
app.post(withPrefix(prefix, "/tasks/:id/followups"), async (c) => {
|
|
234
|
+
if (options.scope) {
|
|
235
|
+
const unauthorized = requireScope(c, options.scope);
|
|
236
|
+
if (unauthorized) return unauthorized;
|
|
237
|
+
}
|
|
238
|
+
const body = await c.req.json().catch(() => ({}));
|
|
239
|
+
const current = await options.sdk.get({ model: "task", id: c.req.param("id") });
|
|
240
|
+
if (!current.payload) {
|
|
241
|
+
return jsonError(c, 404, "Unknown task.");
|
|
242
|
+
}
|
|
243
|
+
const currentTask = current.payload;
|
|
244
|
+
const followups = Array.isArray(body.followups) ? body.followups : [];
|
|
245
|
+
const created = [];
|
|
246
|
+
for (const followup of followups) {
|
|
247
|
+
created.push(await options.sdk.createTask({
|
|
248
|
+
workDayId: String(followup.workDayId ?? currentTask.workDayId ?? ""),
|
|
249
|
+
agentId: String(followup.agentId ?? currentTask.agentId ?? ""),
|
|
250
|
+
type: String(followup.type ?? "followup"),
|
|
251
|
+
priority: followup.priority === void 0 ? void 0 : Number(followup.priority),
|
|
252
|
+
idempotencyKey: String(followup.idempotencyKey ?? `${c.req.param("id")}:${created.length}`),
|
|
253
|
+
payload: followup.payload ?? {},
|
|
254
|
+
graphVersion: typeof followup.graphVersion === "string" ? followup.graphVersion : null,
|
|
255
|
+
parentTaskId: c.req.param("id"),
|
|
256
|
+
actor: actor(followup, defaultActor)
|
|
257
|
+
}));
|
|
258
|
+
}
|
|
259
|
+
return c.json({ ok: true, payload: created.map((entry) => entry.payload) });
|
|
260
|
+
});
|
|
261
|
+
app.post(withPrefix(prefix, "/queue/enqueue"), async (c) => {
|
|
262
|
+
if (options.scope) {
|
|
263
|
+
const unauthorized = requireScope(c, options.scope);
|
|
264
|
+
if (unauthorized) return unauthorized;
|
|
265
|
+
}
|
|
266
|
+
const body = await c.req.json().catch(() => ({}));
|
|
267
|
+
try {
|
|
268
|
+
return c.json(await enqueueTask(options, {
|
|
269
|
+
taskId: String(body.taskId ?? ""),
|
|
270
|
+
queueName: typeof body.queueName === "string" ? body.queueName : void 0,
|
|
271
|
+
deliveryDelaySeconds: body.deliveryDelaySeconds === void 0 ? void 0 : Number(body.deliveryDelaySeconds),
|
|
272
|
+
actor: actor(body, defaultActor)
|
|
273
|
+
}));
|
|
274
|
+
} catch (error) {
|
|
275
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
276
|
+
return jsonError(c, /Unknown task/.test(message) ? 404 : /Queue producer/.test(message) ? 501 : 500, message);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
app.post(withPrefix(prefix, "/reports"), async (c) => {
|
|
280
|
+
if (options.scope) {
|
|
281
|
+
const unauthorized = requireScope(c, options.scope);
|
|
282
|
+
if (unauthorized) return unauthorized;
|
|
283
|
+
}
|
|
284
|
+
const body = await c.req.json().catch(() => ({}));
|
|
285
|
+
const result = await options.sdk.createReport({
|
|
286
|
+
id: typeof body.id === "string" ? body.id : void 0,
|
|
287
|
+
workDayId: String(body.workDayId ?? ""),
|
|
288
|
+
kind: String(body.kind ?? "workday_summary"),
|
|
289
|
+
body: body.body ?? {},
|
|
290
|
+
renderedRef: typeof body.renderedRef === "string" ? body.renderedRef : null,
|
|
291
|
+
sentAt: typeof body.sentAt === "string" ? body.sentAt : null,
|
|
292
|
+
actor: actor(body, defaultActor)
|
|
293
|
+
});
|
|
294
|
+
return c.json(result);
|
|
295
|
+
});
|
|
296
|
+
app.post(withPrefix(prefix, "/context/resolve-task"), async (c) => {
|
|
297
|
+
if (options.scope) {
|
|
298
|
+
const unauthorized = requireScope(c, options.scope);
|
|
299
|
+
if (unauthorized) return unauthorized;
|
|
300
|
+
}
|
|
301
|
+
const body = await c.req.json().catch(() => ({}));
|
|
302
|
+
return c.json({
|
|
303
|
+
ok: true,
|
|
304
|
+
payload: await buildTaskContext(options.sdk, String(body.taskId ?? ""))
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
app.post(withPrefix(prefix, "/graph/search"), async (c) => {
|
|
308
|
+
if (options.scope) {
|
|
309
|
+
const unauthorized = requireScope(c, options.scope);
|
|
310
|
+
if (unauthorized) return unauthorized;
|
|
311
|
+
}
|
|
312
|
+
const body = await c.req.json().catch(() => ({}));
|
|
313
|
+
const query = String(body.query ?? "");
|
|
314
|
+
const scope = String(body.scope ?? "sections");
|
|
315
|
+
const payload = scope === "files" ? await options.sdk.searchFiles(query, body.options) : scope === "entities" ? await options.sdk.searchEntities(query, body.options) : await options.sdk.searchSections(query, body.options);
|
|
316
|
+
return c.json({ ok: true, payload });
|
|
317
|
+
});
|
|
318
|
+
app.post(withPrefix(prefix, "/graph/subgraph"), async (c) => {
|
|
319
|
+
if (options.scope) {
|
|
320
|
+
const unauthorized = requireScope(c, options.scope);
|
|
321
|
+
if (unauthorized) return unauthorized;
|
|
322
|
+
}
|
|
323
|
+
const body = await c.req.json().catch(() => ({}));
|
|
324
|
+
const payload = await options.sdk.getSubgraph(
|
|
325
|
+
Array.isArray(body.seedIds) ? body.seedIds.map(String) : [],
|
|
326
|
+
body.options
|
|
327
|
+
);
|
|
328
|
+
return c.json({ ok: true, payload });
|
|
329
|
+
});
|
|
330
|
+
app.post(withPrefix(prefix, "/graph/query"), async (c) => {
|
|
331
|
+
if (options.scope) {
|
|
332
|
+
const unauthorized = requireScope(c, options.scope);
|
|
333
|
+
if (unauthorized) return unauthorized;
|
|
334
|
+
}
|
|
335
|
+
const body = await c.req.json().catch(() => ({}));
|
|
336
|
+
const payload = await options.sdk.queryGraph(body);
|
|
337
|
+
if (typeof body.workDayId === "string" && body.workDayId) {
|
|
338
|
+
await options.sdk.create({
|
|
339
|
+
model: "graph_run",
|
|
340
|
+
data: {
|
|
341
|
+
workDayId: body.workDayId,
|
|
342
|
+
corpusHash: String(body.corpusHash ?? "query-graph"),
|
|
343
|
+
graphVersion: String(body.graphVersion ?? ""),
|
|
344
|
+
queryJson: JSON.stringify(body),
|
|
345
|
+
seedIdsJson: JSON.stringify(payload.seedIds),
|
|
346
|
+
selectedNodeIdsJson: JSON.stringify(payload.nodes.map((entry) => entry.node.id)),
|
|
347
|
+
statsJson: JSON.stringify({ nodeCount: payload.nodes.length, edgeCount: payload.edges.length })
|
|
348
|
+
},
|
|
349
|
+
actor: actor(body, defaultActor)
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
return c.json({ ok: true, payload });
|
|
353
|
+
});
|
|
354
|
+
app.post(withPrefix(prefix, "/graph/context-pack"), async (c) => {
|
|
355
|
+
if (options.scope) {
|
|
356
|
+
const unauthorized = requireScope(c, options.scope);
|
|
357
|
+
if (unauthorized) return unauthorized;
|
|
358
|
+
}
|
|
359
|
+
const body = await c.req.json().catch(() => ({}));
|
|
360
|
+
const payload = await options.sdk.buildContextPack(body);
|
|
361
|
+
if (typeof body.workDayId === "string" && body.workDayId) {
|
|
362
|
+
await options.sdk.create({
|
|
363
|
+
model: "graph_run",
|
|
364
|
+
data: {
|
|
365
|
+
workDayId: body.workDayId,
|
|
366
|
+
corpusHash: String(body.corpusHash ?? "context-pack"),
|
|
367
|
+
graphVersion: String(body.graphVersion ?? ""),
|
|
368
|
+
queryJson: JSON.stringify(body),
|
|
369
|
+
seedIdsJson: JSON.stringify(payload.seedIds),
|
|
370
|
+
selectedNodeIdsJson: JSON.stringify(payload.includedNodeIds),
|
|
371
|
+
statsJson: JSON.stringify({
|
|
372
|
+
nodeCount: payload.nodes.length,
|
|
373
|
+
edgeCount: payload.edges.length,
|
|
374
|
+
totalTokenEstimate: payload.totalTokenEstimate
|
|
375
|
+
})
|
|
376
|
+
},
|
|
377
|
+
actor: actor(body, defaultActor)
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
return c.json({ ok: true, payload });
|
|
381
|
+
});
|
|
382
|
+
app.post(withPrefix(prefix, "/graph/parse-dsl"), async (c) => {
|
|
383
|
+
if (options.scope) {
|
|
384
|
+
const unauthorized = requireScope(c, options.scope);
|
|
385
|
+
if (unauthorized) return unauthorized;
|
|
386
|
+
}
|
|
387
|
+
const body = await c.req.json().catch(() => ({}));
|
|
388
|
+
const payload = await options.sdk.parseGraphDsl(String(body.source ?? body.query ?? ""));
|
|
389
|
+
return c.json({ ok: true, payload });
|
|
390
|
+
});
|
|
391
|
+
app.get(withPrefix(prefix, "/graph/node/:id"), async (c) => {
|
|
392
|
+
if (options.scope) {
|
|
393
|
+
const unauthorized = requireScope(c, options.scope);
|
|
394
|
+
if (unauthorized) return unauthorized;
|
|
395
|
+
}
|
|
396
|
+
const payload = await options.sdk.getGraphNode(c.req.param("id"));
|
|
397
|
+
return payload ? c.json({ ok: true, payload }) : jsonError(c, 404, "Unknown graph node.");
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
export {
|
|
401
|
+
registerAgentRoutes
|
|
402
|
+
};
|