@anteros/core 0.0.40 → 0.0.42
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/database/audit.ts +143 -0
- package/database/collection.ts +6 -4
- package/database/deleteLog.ts +98 -0
- package/database/file.ts +7 -6
- package/database/mongodbadapter.ts +420 -185
- package/database/replication.ts +858 -0
- package/database/schema.ts +140 -125
- package/database/tenant.ts +4 -0
- package/database/ttl.ts +68 -0
- package/database/vars.ts +405 -0
- package/database/workflow.ts +466 -240
- package/index.ts +16 -0
- package/lib/agent.ts +1327 -0
- package/lib/agentMemory.ts +586 -0
- package/lib/agents.ts +157 -0
- package/lib/ai.ts +0 -0
- package/lib/api.ts +246 -0
- package/lib/attachment.ts +351 -0
- package/lib/audit.ts +271 -0
- package/lib/auditResult.ts +133 -0
- package/lib/define.ts +62 -1
- package/lib/endpoints.ts +80 -0
- package/lib/files.ts +66 -12
- package/lib/jsonSchema.ts +183 -0
- package/lib/lifecycle.ts +147 -0
- package/lib/load.ts +17 -0
- package/lib/mcp.ts +3 -2
- package/lib/messages.ts +299 -0
- package/lib/providers.ts +867 -0
- package/lib/redact.ts +117 -0
- package/lib/routes.ts +14 -1
- package/lib/scriptWorker.ts +4 -1
- package/lib/scripts.ts +6 -1
- package/lib/sockets.ts +3 -1
- package/lib/workflow.ts +209 -37
- package/lib/zip.ts +109 -0
- package/package.json +1 -1
- package/server/access.ts +96 -0
- package/server/agents.ts +451 -0
- package/server/api.ts +121 -95
- package/server/boot.ts +196 -53
- package/server/flags.ts +136 -0
- package/server/hono.ts +9 -4
- package/server/mcp.ts +17 -63
- package/server/routes.ts +19 -24
- package/tests/agent-memory.test.ts +617 -0
- package/tests/agent-working-memory.test.ts +402 -0
- package/tests/agent.test.ts +1239 -0
- package/tests/agents-api.test.ts +593 -0
- package/tests/api.test.ts +51 -0
- package/tests/attachment.test.ts +241 -0
- package/tests/audit-file.test.ts +296 -0
- package/tests/audit-operations.test.ts +184 -0
- package/tests/audit-redact.test.ts +259 -0
- package/tests/audit-results.test.ts +188 -0
- package/tests/audit-retention-config.test.ts +76 -0
- package/tests/audit-run-action.test.ts +120 -0
- package/tests/audit.test.ts +320 -0
- package/tests/db-cache.test.ts +7 -7
- package/tests/endpoints.test.ts +80 -0
- package/tests/file-collection-replication.test.ts +98 -0
- package/tests/fixtures/agent-tenant/agents/support.agent.ts +9 -0
- package/tests/fixtures/agent-tenant/agents/weather.agent.ts +21 -0
- package/tests/fixtures/agents-api/agents/assistant.agent.ts +46 -0
- package/tests/fixtures/agents-api/agents/plain.agent.ts +23 -0
- package/tests/fixtures/agents-api/agents/private.agent.ts +15 -0
- package/tests/fixtures/agents-api/collections/notes.model.ts +26 -0
- package/tests/fixtures/agents-api/routes/probe.route.ts +21 -0
- package/tests/fixtures/agents-api/services/probe.service.ts +19 -0
- package/tests/fixtures/attachment/data.csv +2 -0
- package/tests/fixtures/fake-provider.ts +128 -0
- package/tests/fixtures/lc-disabled/lifecycle.ts +11 -0
- package/tests/fixtures/lc-hang/lifecycle.ts +13 -0
- package/tests/fixtures/lc-normal/lifecycle.ts +23 -0
- package/tests/fixtures/lc-throw/lifecycle.ts +6 -0
- package/tests/fixtures/repl-only/app.ts +26 -0
- package/tests/fixtures/repl-only/tenant/collections/orders.model.ts +14 -0
- package/tests/fixtures/repl-only/tenant/lifecycle.ts +14 -0
- package/tests/fixtures/repl-only/tenant/scripts/probe.run.ts +8 -0
- package/tests/fixtures/replication-meta/agents/chat.agent.ts +16 -0
- package/tests/fixtures/replication-meta/collections/counters.model.ts +13 -0
- package/tests/fixtures/replication-meta/collections/orders.model.ts +9 -0
- package/tests/fixtures/replication-meta/workflows/run.workflow.ts +8 -0
- package/tests/fixtures/vars-tenant/vars/config.var.ts +23 -0
- package/tests/fixtures/vars-tenant/vars/private.var.ts +9 -0
- package/tests/fixtures/workflow-engine/workflows/failing.workflow.ts +34 -0
- package/tests/fixtures/workflow-engine/workflows/flaky.workflow.ts +23 -0
- package/tests/fixtures/workflow-engine/workflows/hang.workflow.ts +17 -0
- package/tests/fixtures/workflow-engine/workflows/simple.workflow.ts +19 -0
- package/tests/fixtures/workflow-engine/workflows/slow.workflow.ts +23 -0
- package/tests/fixtures/workflow-engine/workflows/versioned.workflow.ts +19 -0
- package/tests/fixtures/workflow-tenant/workflows/broken.workflow.ts +3 -0
- package/tests/fixtures/workflow-tenant/workflows/disabled.workflow.ts +8 -0
- package/tests/fixtures/workflow-tenant/workflows/invoice.workflow.ts +21 -0
- package/tests/fixtures/workflow-tenant/workflows/no-id.workflow.ts +7 -0
- package/tests/fixtures/workflow-tenant/workflows/order-duplicate.workflow.ts +13 -0
- package/tests/fixtures/workflow-tenant/workflows/order.workflow.ts +17 -0
- package/tests/hono.test.ts +6 -3
- package/tests/lifecycle.test.ts +96 -0
- package/tests/locks.test.ts +120 -0
- package/tests/mcp.test.ts +11 -11
- package/tests/messages.test.ts +258 -0
- package/tests/replication-control.test.ts +128 -0
- package/tests/replication-initial-sync.test.ts +86 -0
- package/tests/replication-meta.test.ts +243 -0
- package/tests/replication-only.test.ts +358 -0
- package/tests/replication.test.ts +188 -0
- package/tests/upload.test.ts +141 -8
- package/tests/vars-api.test.ts +123 -0
- package/tests/vars-replication.test.ts +96 -0
- package/tests/vars.test.ts +216 -0
- package/tests/workflow-engine.test.ts +340 -0
- package/tests/workflow-retention.test.ts +103 -0
- package/tests/workflow.test.ts +186 -0
- package/types/agent.d.ts +837 -0
- package/types/collection.d.ts +3 -0
- package/types/config.d.ts +80 -0
- package/types/file.d.ts +11 -8
- package/types/hook.d.ts +6 -0
- package/types/lifecycle.d.ts +77 -0
- package/types/mcp.d.ts +11 -1
- package/types/replication.d.ts +228 -0
- package/types/route.d.ts +7 -1
- package/types/scripts.d.ts +6 -0
- package/types/service.d.ts +7 -1
- package/types/tenant.d.ts +36 -0
- package/types/vars.d.ts +147 -0
- package/types/websocket.d.ts +6 -0
- package/types/workflow.d.ts +50 -3
- package/utils/func.ts +67 -52
package/server/flags.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a process actually runs.
|
|
3
|
+
*
|
|
4
|
+
* `api: false` disables everything the HTTP server carries — routes, services,
|
|
5
|
+
* MCP tools, middlewares, websockets — and the scripts that run alongside it.
|
|
6
|
+
*/
|
|
7
|
+
export type BootCapabilities = {
|
|
8
|
+
/** HTTP server: routes, services, MCP tools, middlewares, `/health` */
|
|
9
|
+
api: boolean
|
|
10
|
+
/** Replication engine: schedule, tombstones, `_replication_` state */
|
|
11
|
+
replication: boolean
|
|
12
|
+
/** `runScripts()` shortly after boot */
|
|
13
|
+
scripts: boolean
|
|
14
|
+
/** Socket.IO handlers and the `/socket.io/` endpoint */
|
|
15
|
+
sockets: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Named boot modes (configurable through `server.mode`, overridable by flags).
|
|
20
|
+
*
|
|
21
|
+
* - `full` (default): everything.
|
|
22
|
+
* - `replication-only`: replication engine only — no API at all.
|
|
23
|
+
* - `no-replication`: full server that never starts the replication engine.
|
|
24
|
+
* - `api-only`: the HTTP API and nothing around it (no replication, no scripts, no sockets).
|
|
25
|
+
*/
|
|
26
|
+
export type BootMode = 'full' | 'replication-only' | 'no-replication' | 'api-only'
|
|
27
|
+
|
|
28
|
+
export type BootFlags = {
|
|
29
|
+
/** `--replication-only` — replication engine only, no API */
|
|
30
|
+
replicationOnly: boolean
|
|
31
|
+
/** `--no-replication` — full server, replication engine not started */
|
|
32
|
+
noReplication: boolean
|
|
33
|
+
/** `--api-only` — the HTTP API and nothing around it */
|
|
34
|
+
apiOnly: boolean
|
|
35
|
+
/** `--no-scripts` — never run the tenant scripts (`*.run.ts` under `scripts/`) */
|
|
36
|
+
noScripts: boolean
|
|
37
|
+
/** `--no-sockets` — no Socket.IO handlers, no `/socket.io/` endpoint */
|
|
38
|
+
noSockets: boolean
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const FULL_CAPABILITIES: BootCapabilities = {
|
|
42
|
+
api: true,
|
|
43
|
+
replication: true,
|
|
44
|
+
scripts: true,
|
|
45
|
+
sockets: true,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const REPLICATION_ONLY: BootCapabilities = {
|
|
49
|
+
api: false,
|
|
50
|
+
replication: true,
|
|
51
|
+
scripts: false,
|
|
52
|
+
sockets: false,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const API_ONLY: BootCapabilities = {
|
|
56
|
+
api: true,
|
|
57
|
+
replication: false,
|
|
58
|
+
scripts: false,
|
|
59
|
+
sockets: false,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function bootModeCapabilities(mode?: BootMode): BootCapabilities {
|
|
63
|
+
switch (mode) {
|
|
64
|
+
case 'replication-only': return { ...REPLICATION_ONLY }
|
|
65
|
+
case 'api-only': return { ...API_ONLY }
|
|
66
|
+
case 'no-replication': return { ...FULL_CAPABILITIES, replication: false }
|
|
67
|
+
default: return { ...FULL_CAPABILITIES }
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Read the boot flags from the command line (camelCase spellings accepted).
|
|
73
|
+
*
|
|
74
|
+
* @example bun index.ts --replication-only
|
|
75
|
+
* @example bun index.ts --api-only
|
|
76
|
+
* @example bun index.ts --no-scripts --no-sockets
|
|
77
|
+
*/
|
|
78
|
+
function parseBootFlags(argv: string[] = process.argv): BootFlags {
|
|
79
|
+
const has = (...names: string[]) => names.some((name) => argv.includes(name))
|
|
80
|
+
return {
|
|
81
|
+
replicationOnly: has('--replication-only', '--replicationOnly'),
|
|
82
|
+
noReplication: has('--no-replication', '--noReplication'),
|
|
83
|
+
apiOnly: has('--api-only', '--apiOnly'),
|
|
84
|
+
noScripts: has('--no-scripts', '--noScripts'),
|
|
85
|
+
noSockets: has('--no-sockets', '--noSockets'),
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** True when the flags ask for contradictory things — worth warning the operator */
|
|
90
|
+
function conflictingBootFlags(flags: BootFlags): boolean {
|
|
91
|
+
return flags.replicationOnly && (flags.noReplication || flags.apiOnly)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* What the process will run: `server.mode` first, then the flags, which win.
|
|
96
|
+
* `--api-only` is the preset "API and nothing around it".
|
|
97
|
+
*/
|
|
98
|
+
function resolveCapabilities(flags: BootFlags, configured?: BootMode): BootCapabilities {
|
|
99
|
+
// A flag always wins over the configured mode
|
|
100
|
+
if (flags.replicationOnly) return { ...REPLICATION_ONLY }
|
|
101
|
+
if (flags.apiOnly) return { ...API_ONLY }
|
|
102
|
+
|
|
103
|
+
const caps = bootModeCapabilities(configured)
|
|
104
|
+
if (flags.noReplication) caps.replication = false
|
|
105
|
+
if (flags.noScripts) caps.scripts = false
|
|
106
|
+
if (flags.noSockets) caps.sockets = false
|
|
107
|
+
|
|
108
|
+
// Scripts and sockets belong to the API process
|
|
109
|
+
if (!caps.api) {
|
|
110
|
+
caps.scripts = false
|
|
111
|
+
caps.sockets = false
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return caps
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Disabled capabilities, for the banner and logs — e.g. `['scripts', 'sockets']` */
|
|
118
|
+
function offCapabilities(caps: BootCapabilities): (keyof BootCapabilities)[] {
|
|
119
|
+
return (Object.keys(caps) as (keyof BootCapabilities)[]).filter((key) => !caps[key])
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Closest named mode, used by the banner — all flags off is simply `full` */
|
|
123
|
+
function capabilitiesLabel(caps: BootCapabilities): BootMode {
|
|
124
|
+
if (!caps.api && caps.replication) return 'replication-only'
|
|
125
|
+
if (caps.api && !caps.replication && !caps.scripts && !caps.sockets) return 'api-only'
|
|
126
|
+
// `--no-scripts` / `--no-sockets` alone stay in `full`: the banner lists what is off
|
|
127
|
+
return 'full'
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export {
|
|
131
|
+
parseBootFlags,
|
|
132
|
+
conflictingBootFlags,
|
|
133
|
+
resolveCapabilities,
|
|
134
|
+
offCapabilities,
|
|
135
|
+
capabilitiesLabel,
|
|
136
|
+
}
|
package/server/hono.ts
CHANGED
|
@@ -11,8 +11,10 @@ import { Redis } from "ioredis"
|
|
|
11
11
|
import { cfg } from "./config"
|
|
12
12
|
import { rateLimit, createRedisStore, createMemoryStore, type RateLimitStore } from "./security"
|
|
13
13
|
import { initializeRoutes } from "./routes";
|
|
14
|
+
import { patterns } from "../lib/endpoints";
|
|
14
15
|
import { asyncContextStorage, requestCtxStorage } from "../lib/asyncContextStorage";
|
|
15
16
|
import { initializeApi } from "./api";
|
|
17
|
+
import { initializeAgents } from "./agents";
|
|
16
18
|
import { initializeMcp } from "./mcp";
|
|
17
19
|
import { getGlobalMiddlewares } from "../lib/middleware";
|
|
18
20
|
import { jwt } from "../utils/func";
|
|
@@ -326,8 +328,8 @@ function createApp(): Hono<{ Variables: HonoVariables }> {
|
|
|
326
328
|
keyGenerator: keyByClientIp(''),
|
|
327
329
|
}));
|
|
328
330
|
|
|
329
|
-
// stricter limit for login endpoints
|
|
330
|
-
app.use(
|
|
331
|
+
// stricter limit for login endpoints — the login is a collection action
|
|
332
|
+
app.use(patterns.login, rateLimit({
|
|
331
333
|
windowMs: cfg.server.rateLimit?.login?.windowMs ?? 60_000,
|
|
332
334
|
max: cfg.server.rateLimit?.login?.max ?? 10,
|
|
333
335
|
store,
|
|
@@ -345,7 +347,7 @@ function createApp(): Hono<{ Variables: HonoVariables }> {
|
|
|
345
347
|
|
|
346
348
|
|
|
347
349
|
const requestCtx: Record<string, string> = c.req.header();
|
|
348
|
-
//
|
|
350
|
+
// Flaw 1: never log sensitive headers (JWT, cookies)
|
|
349
351
|
delete requestCtx.authorization;
|
|
350
352
|
delete requestCtx.cookie;
|
|
351
353
|
requestCtxStorage.set('meta', {
|
|
@@ -399,7 +401,10 @@ function createApp(): Hono<{ Variables: HonoVariables }> {
|
|
|
399
401
|
// initialize api
|
|
400
402
|
initializeApi(app);
|
|
401
403
|
|
|
402
|
-
// initialize
|
|
404
|
+
// initialize the agents API (/api/:tenant_id/agents/:agent/:action)
|
|
405
|
+
initializeAgents(app);
|
|
406
|
+
|
|
407
|
+
// initialize MCP (tools served at /api/:tenant_id/mcp)
|
|
403
408
|
initializeMcp(app);
|
|
404
409
|
|
|
405
410
|
|
package/server/mcp.ts
CHANGED
|
@@ -10,72 +10,18 @@ import {
|
|
|
10
10
|
ErrorCode,
|
|
11
11
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
12
12
|
import { StreamableHTTPTransport } from "@hono/mcp";
|
|
13
|
-
import type Joi from "joi";
|
|
14
13
|
import { cfg } from "./config";
|
|
15
14
|
import { useRest } from "../database/rest";
|
|
15
|
+
import { createAgents } from "../lib/agents";
|
|
16
|
+
import { createApi } from "../lib/api";
|
|
16
17
|
import { logger } from "../utils/logger";
|
|
17
18
|
import type { McpTool, McpResource } from "../types/mcp";
|
|
18
19
|
import type { HonoVariables } from "./env";
|
|
20
|
+
import { joiToJsonSchema } from "../lib/jsonSchema";
|
|
21
|
+
import { patterns } from "../lib/endpoints";
|
|
19
22
|
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
function joiTypeToJson(type: string): string {
|
|
23
|
-
switch (type) {
|
|
24
|
-
case 'number': return 'number';
|
|
25
|
-
case 'integer': return 'integer';
|
|
26
|
-
case 'boolean': return 'boolean';
|
|
27
|
-
case 'date': return 'string';
|
|
28
|
-
default: return 'string';
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** Minimal Joi → JSON Schema converter (covers the common field types). */
|
|
33
|
-
function joiToJsonSchema(schema: Joi.Schema, describe = schema.describe() as any): any {
|
|
34
|
-
const node: any = {};
|
|
35
|
-
const type = describe?.type;
|
|
36
|
-
|
|
37
|
-
switch (type) {
|
|
38
|
-
case 'object': {
|
|
39
|
-
node.type = 'object';
|
|
40
|
-
const properties: Record<string, any> = {};
|
|
41
|
-
const required: string[] = [];
|
|
42
|
-
for (const [key, child] of Object.entries(describe.keys ?? {})) {
|
|
43
|
-
properties[key] = joiToJsonSchema(child as any, child);
|
|
44
|
-
if ((child as any)?.flags?.presence === 'required') required.push(key);
|
|
45
|
-
}
|
|
46
|
-
node.properties = properties;
|
|
47
|
-
if (required.length) node.required = required;
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
case 'array': {
|
|
51
|
-
node.type = 'array';
|
|
52
|
-
if (describe.items?.length) node.items = joiToJsonSchema(describe.items[0], describe.items[0]);
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
default: {
|
|
56
|
-
node.type = joiTypeToJson(type);
|
|
57
|
-
if (type === 'date') node.format = 'date-time';
|
|
58
|
-
if (type === 'string') {
|
|
59
|
-
for (const rule of describe.rules ?? []) {
|
|
60
|
-
if (['email', 'uri', 'uuid', 'isoDate', 'ip'].includes(rule.name)) {
|
|
61
|
-
node.format = rule.name;
|
|
62
|
-
}
|
|
63
|
-
if (rule.name === 'pattern' && rule.args?.regex) {
|
|
64
|
-
node.pattern = String(rule.args.regex).replace(/^\/|\/[gimsuy]*$/g, '');
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
if (describe.valids?.length && describe.valids.length <= 50) {
|
|
69
|
-
node.enum = describe.valids;
|
|
70
|
-
}
|
|
71
|
-
break;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (describe?.flags?.presence === 'required') node.description = node.description ?? 'required';
|
|
76
|
-
if (describe?.flags?.description) node.description = describe.flags.description;
|
|
77
|
-
return node;
|
|
78
|
-
}
|
|
23
|
+
// The Joi → JSON Schema converter is shared with the agent runtime — a tool
|
|
24
|
+
// must look identical whether it is exposed over MCP or to a model.
|
|
79
25
|
|
|
80
26
|
// ─── URI template matching (users://{id} → params) ───────────────────────
|
|
81
27
|
|
|
@@ -148,7 +94,13 @@ function buildServer(tenantId: string, tools: McpTool[], resources: McpResource[
|
|
|
148
94
|
|
|
149
95
|
const rest = new useRest({ tenant_id: tenantId });
|
|
150
96
|
try {
|
|
151
|
-
const result = await tool.exec({
|
|
97
|
+
const result = await tool.exec({
|
|
98
|
+
c: undefined as any,
|
|
99
|
+
rest,
|
|
100
|
+
args: value,
|
|
101
|
+
agents: createAgents(tenantId, rest),
|
|
102
|
+
api: createApi(rest),
|
|
103
|
+
});
|
|
152
104
|
const isError = !!(result as any)?.isError;
|
|
153
105
|
logger[isError ? 'warn' : 'info']('MCP tools/call', { method: 'tools/call', tenant: tenantId, tool: req.params.name, args: value, isError, duration: ms(start) });
|
|
154
106
|
if (result && Array.isArray(result.content)) return result;
|
|
@@ -205,6 +157,8 @@ function buildServer(tenantId: string, tools: McpTool[], resources: McpResource[
|
|
|
205
157
|
const result = await matched.resource.read({
|
|
206
158
|
c: undefined as any,
|
|
207
159
|
rest,
|
|
160
|
+
agents: createAgents(tenantId, rest),
|
|
161
|
+
api: createApi(rest),
|
|
208
162
|
params: matched.params,
|
|
209
163
|
uri,
|
|
210
164
|
});
|
|
@@ -221,7 +175,7 @@ function buildServer(tenantId: string, tools: McpTool[], resources: McpResource[
|
|
|
221
175
|
|
|
222
176
|
/**
|
|
223
177
|
* Expose each tenant's MCP tools & resources over the Model Context Protocol
|
|
224
|
-
* at `GET/POST /
|
|
178
|
+
* at `GET/POST /api/:tenant_id/mcp` (Streamable HTTP transport — works with
|
|
225
179
|
* Claude, Cursor, VS Code, and any MCP client).
|
|
226
180
|
*/
|
|
227
181
|
export function initializeMcp(app: Hono<{ Variables: HonoVariables }>) {
|
|
@@ -238,7 +192,7 @@ export function initializeMcp(app: Hono<{ Variables: HonoVariables }>) {
|
|
|
238
192
|
resourcesByTenant.set(resource._tenant_ ?? '', list);
|
|
239
193
|
}
|
|
240
194
|
|
|
241
|
-
app.all(
|
|
195
|
+
app.all(patterns.mcp, async (c: Context<{ Variables: HonoVariables }>) => {
|
|
242
196
|
const tenantId = c.req.param('tenant_id') ?? '';
|
|
243
197
|
const tools = toolsByTenant.get(tenantId) ?? [];
|
|
244
198
|
const resources = resourcesByTenant.get(tenantId) ?? [];
|
package/server/routes.ts
CHANGED
|
@@ -3,10 +3,26 @@ import { cfg } from "./config";
|
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { jwt } from "../utils/func";
|
|
5
5
|
import { useRest } from "../database/rest";
|
|
6
|
+
import { createAgents } from "../lib/agents";
|
|
7
|
+
import { createApi } from "../lib/api";
|
|
6
8
|
import { io } from "./io";
|
|
7
9
|
import { requestCtxStorage } from "../lib/asyncContextStorage";
|
|
8
10
|
import type { HonoVariables } from "./env";
|
|
9
11
|
|
|
12
|
+
/** The context of a route handler — `rest` and `agents` share the same tenant. */
|
|
13
|
+
function routeContext(c: any, tenantId: string) {
|
|
14
|
+
const rest = new useRest({ tenant_id: tenantId });
|
|
15
|
+
return {
|
|
16
|
+
c,
|
|
17
|
+
rest,
|
|
18
|
+
// Tenant-scoped LLM registry, bound to this request's `rest`
|
|
19
|
+
agents: createAgents(tenantId, rest),
|
|
20
|
+
api: createApi(rest),
|
|
21
|
+
jwt: jwt,
|
|
22
|
+
io: io,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
10
26
|
function initializeRoutes(app: Hono<{ Variables: HonoVariables }>) {
|
|
11
27
|
for (let route of cfg.routes ?? []) {
|
|
12
28
|
if (route._prefix_) {
|
|
@@ -24,42 +40,21 @@ function initializeRoutes(app: Hono<{ Variables: HonoVariables }>) {
|
|
|
24
40
|
if (route.method == "GET") {
|
|
25
41
|
app.get(routePath, async (c) => { //
|
|
26
42
|
resolveTenant();
|
|
27
|
-
return route.handler(
|
|
28
|
-
c,
|
|
29
|
-
rest: new useRest({
|
|
30
|
-
tenant_id: route._tenant_,
|
|
31
|
-
}),
|
|
32
|
-
jwt: jwt,
|
|
33
|
-
io: io,
|
|
34
|
-
});
|
|
43
|
+
return route.handler(routeContext(c, route._tenant_!));
|
|
35
44
|
});
|
|
36
45
|
}
|
|
37
46
|
|
|
38
47
|
if (route.method == 'POST') {
|
|
39
48
|
app.post(routePath, async (c) => {
|
|
40
49
|
resolveTenant();
|
|
41
|
-
return route.handler(
|
|
42
|
-
c,
|
|
43
|
-
rest: new useRest({
|
|
44
|
-
tenant_id: route._tenant_,
|
|
45
|
-
}),
|
|
46
|
-
jwt: jwt,
|
|
47
|
-
io: io,
|
|
48
|
-
});
|
|
50
|
+
return route.handler(routeContext(c, route._tenant_!));
|
|
49
51
|
});
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
if (route.method == "PUT") {
|
|
53
55
|
app.put(routePath, async (c) => { //
|
|
54
56
|
resolveTenant();
|
|
55
|
-
return route.handler(
|
|
56
|
-
c,
|
|
57
|
-
rest: new useRest({
|
|
58
|
-
tenant_id: route._tenant_,
|
|
59
|
-
}),
|
|
60
|
-
jwt: jwt,
|
|
61
|
-
io: io,
|
|
62
|
-
});
|
|
57
|
+
return route.handler(routeContext(c, route._tenant_!));
|
|
63
58
|
});
|
|
64
59
|
}
|
|
65
60
|
}
|