@lobu/gateway 2.8.0 → 3.0.6
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/package.json +2 -2
- package/src/__tests__/agent-config-routes.test.ts +254 -0
- package/src/__tests__/agent-history-routes.test.ts +72 -0
- package/src/__tests__/agent-routes.test.ts +68 -0
- package/src/__tests__/agent-schedules-routes.test.ts +59 -0
- package/src/__tests__/agent-settings-store.test.ts +323 -0
- package/src/__tests__/chat-instance-manager-slack.test.ts +204 -0
- package/src/__tests__/chat-response-bridge.test.ts +131 -0
- package/src/__tests__/config-memory-plugins.test.ts +92 -0
- package/src/__tests__/config-request-store.test.ts +127 -0
- package/src/__tests__/connection-routes.test.ts +144 -0
- package/src/__tests__/core-services-store-selection.test.ts +92 -0
- package/src/__tests__/docker-deployment.test.ts +1211 -0
- package/src/__tests__/embedded-deployment.test.ts +342 -0
- package/src/__tests__/grant-store.test.ts +148 -0
- package/src/__tests__/http-proxy.test.ts +281 -0
- package/src/__tests__/instruction-service.test.ts +37 -0
- package/src/__tests__/link-buttons.test.ts +112 -0
- package/src/__tests__/lobu.test.ts +32 -0
- package/src/__tests__/mcp-config-service.test.ts +347 -0
- package/src/__tests__/mcp-proxy.test.ts +696 -0
- package/src/__tests__/message-handler-bridge.test.ts +17 -0
- package/src/__tests__/model-selection.test.ts +172 -0
- package/src/__tests__/oauth-templates.test.ts +39 -0
- package/src/__tests__/platform-adapter-slack-send.test.ts +114 -0
- package/src/__tests__/platform-helpers-model-resolution.test.ts +253 -0
- package/src/__tests__/provider-inheritance.test.ts +212 -0
- package/src/__tests__/routes/cli-auth.test.ts +337 -0
- package/src/__tests__/routes/interactions.test.ts +121 -0
- package/src/__tests__/secret-proxy.test.ts +85 -0
- package/src/__tests__/session-manager.test.ts +572 -0
- package/src/__tests__/setup.ts +133 -0
- package/src/__tests__/skill-and-mcp-registry.test.ts +203 -0
- package/src/__tests__/slack-routes.test.ts +161 -0
- package/src/__tests__/system-config-resolver.test.ts +75 -0
- package/src/__tests__/system-message-limiter.test.ts +89 -0
- package/src/__tests__/system-skills-service.test.ts +362 -0
- package/src/__tests__/transcription-service.test.ts +222 -0
- package/src/__tests__/utils/rate-limiter.test.ts +102 -0
- package/src/__tests__/worker-connection-manager.test.ts +497 -0
- package/src/__tests__/worker-job-router.test.ts +722 -0
- package/src/api/index.ts +1 -0
- package/src/api/platform.ts +292 -0
- package/src/api/response-renderer.ts +157 -0
- package/src/auth/agent-metadata-store.ts +168 -0
- package/src/auth/api-auth-middleware.ts +69 -0
- package/src/auth/api-key-provider-module.ts +213 -0
- package/src/auth/base-provider-module.ts +201 -0
- package/src/auth/chatgpt/chatgpt-oauth-module.ts +185 -0
- package/src/auth/chatgpt/device-code-client.ts +218 -0
- package/src/auth/chatgpt/index.ts +1 -0
- package/src/auth/claude/oauth-module.ts +280 -0
- package/src/auth/cli/token-service.ts +249 -0
- package/src/auth/external/client.ts +560 -0
- package/src/auth/external/device-code-client.ts +225 -0
- package/src/auth/mcp/config-service.ts +392 -0
- package/src/auth/mcp/proxy.ts +1088 -0
- package/src/auth/mcp/string-substitution.ts +17 -0
- package/src/auth/mcp/tool-cache.ts +90 -0
- package/src/auth/oauth/base-client.ts +267 -0
- package/src/auth/oauth/client.ts +153 -0
- package/src/auth/oauth/credentials.ts +7 -0
- package/src/auth/oauth/providers.ts +69 -0
- package/src/auth/oauth/state-store.ts +150 -0
- package/src/auth/oauth-templates.ts +179 -0
- package/src/auth/provider-catalog.ts +220 -0
- package/src/auth/provider-model-options.ts +41 -0
- package/src/auth/settings/agent-settings-store.ts +565 -0
- package/src/auth/settings/auth-profiles-manager.ts +216 -0
- package/src/auth/settings/index.ts +12 -0
- package/src/auth/settings/model-preference-store.ts +52 -0
- package/src/auth/settings/model-selection.ts +135 -0
- package/src/auth/settings/resolved-settings-view.ts +298 -0
- package/src/auth/settings/template-utils.ts +44 -0
- package/src/auth/settings/token-service.ts +88 -0
- package/src/auth/system-env-store.ts +98 -0
- package/src/auth/user-agents-store.ts +68 -0
- package/src/channels/binding-service.ts +214 -0
- package/src/channels/index.ts +4 -0
- package/src/cli/gateway.ts +1304 -0
- package/src/cli/index.ts +74 -0
- package/src/commands/built-in-commands.ts +80 -0
- package/src/commands/command-dispatcher.ts +94 -0
- package/src/commands/command-reply-adapters.ts +27 -0
- package/src/config/file-loader.ts +618 -0
- package/src/config/index.ts +588 -0
- package/src/config/network-allowlist.ts +71 -0
- package/src/connections/chat-instance-manager.ts +1284 -0
- package/src/connections/chat-response-bridge.ts +618 -0
- package/src/connections/index.ts +7 -0
- package/src/connections/interaction-bridge.ts +831 -0
- package/src/connections/message-handler-bridge.ts +415 -0
- package/src/connections/platform-auth-methods.ts +15 -0
- package/src/connections/types.ts +84 -0
- package/src/gateway/connection-manager.ts +291 -0
- package/src/gateway/index.ts +700 -0
- package/src/gateway/job-router.ts +201 -0
- package/src/gateway-main.ts +200 -0
- package/src/index.ts +41 -0
- package/src/infrastructure/queue/index.ts +12 -0
- package/src/infrastructure/queue/queue-producer.ts +148 -0
- package/src/infrastructure/queue/redis-queue.ts +361 -0
- package/src/infrastructure/queue/types.ts +133 -0
- package/src/infrastructure/redis/system-message-limiter.ts +94 -0
- package/src/interactions/config-request-store.ts +198 -0
- package/src/interactions.ts +363 -0
- package/src/lobu.ts +311 -0
- package/src/metrics/prometheus.ts +159 -0
- package/src/modules/module-system.ts +179 -0
- package/src/orchestration/base-deployment-manager.ts +900 -0
- package/src/orchestration/deployment-utils.ts +98 -0
- package/src/orchestration/impl/docker-deployment.ts +620 -0
- package/src/orchestration/impl/embedded-deployment.ts +268 -0
- package/src/orchestration/impl/index.ts +8 -0
- package/src/orchestration/impl/k8s/deployment.ts +1061 -0
- package/src/orchestration/impl/k8s/helpers.ts +610 -0
- package/src/orchestration/impl/k8s/index.ts +1 -0
- package/src/orchestration/index.ts +333 -0
- package/src/orchestration/message-consumer.ts +584 -0
- package/src/orchestration/scheduled-wakeup.ts +704 -0
- package/src/permissions/approval-policy.ts +36 -0
- package/src/permissions/grant-store.ts +219 -0
- package/src/platform/file-handler.ts +66 -0
- package/src/platform/link-buttons.ts +57 -0
- package/src/platform/renderer-utils.ts +44 -0
- package/src/platform/response-renderer.ts +84 -0
- package/src/platform/unified-thread-consumer.ts +187 -0
- package/src/platform.ts +318 -0
- package/src/proxy/http-proxy.ts +752 -0
- package/src/proxy/proxy-manager.ts +81 -0
- package/src/proxy/secret-proxy.ts +402 -0
- package/src/proxy/token-refresh-job.ts +143 -0
- package/src/routes/internal/audio.ts +141 -0
- package/src/routes/internal/device-auth.ts +566 -0
- package/src/routes/internal/files.ts +226 -0
- package/src/routes/internal/history.ts +69 -0
- package/src/routes/internal/images.ts +127 -0
- package/src/routes/internal/interactions.ts +84 -0
- package/src/routes/internal/middleware.ts +23 -0
- package/src/routes/internal/schedule.ts +226 -0
- package/src/routes/internal/types.ts +22 -0
- package/src/routes/openapi-auto.ts +239 -0
- package/src/routes/public/agent-access.ts +23 -0
- package/src/routes/public/agent-config.ts +675 -0
- package/src/routes/public/agent-history.ts +422 -0
- package/src/routes/public/agent-schedules.ts +296 -0
- package/src/routes/public/agent.ts +1086 -0
- package/src/routes/public/agents.ts +373 -0
- package/src/routes/public/channels.ts +191 -0
- package/src/routes/public/cli-auth.ts +883 -0
- package/src/routes/public/connections.ts +574 -0
- package/src/routes/public/landing.ts +16 -0
- package/src/routes/public/oauth.ts +147 -0
- package/src/routes/public/settings-auth.ts +104 -0
- package/src/routes/public/slack.ts +173 -0
- package/src/routes/shared/agent-ownership.ts +101 -0
- package/src/routes/shared/token-verifier.ts +34 -0
- package/src/services/core-services.ts +1053 -0
- package/src/services/image-generation-service.ts +257 -0
- package/src/services/instruction-service.ts +318 -0
- package/src/services/mcp-registry.ts +94 -0
- package/src/services/platform-helpers.ts +287 -0
- package/src/services/session-manager.ts +262 -0
- package/src/services/settings-resolver.ts +74 -0
- package/src/services/system-config-resolver.ts +90 -0
- package/src/services/system-skills-service.ts +229 -0
- package/src/services/transcription-service.ts +684 -0
- package/src/session.ts +110 -0
- package/src/spaces/index.ts +1 -0
- package/src/spaces/space-resolver.ts +17 -0
- package/src/stores/in-memory-agent-store.ts +403 -0
- package/src/stores/redis-agent-store.ts +279 -0
- package/src/utils/public-url.ts +44 -0
- package/src/utils/rate-limiter.ts +94 -0
- package/tsconfig.json +33 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobu/gateway",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.6",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Lobu SDK — embed AI agents with platform adapters, worker orchestration, and MCP proxy",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@hono/node-server": "^1.19.9",
|
|
41
41
|
"@hono/zod-openapi": "^1.2.1",
|
|
42
42
|
"@kubernetes/client-node": "0.21.0",
|
|
43
|
-
"@lobu/core": "
|
|
43
|
+
"@lobu/core": "workspace:*",
|
|
44
44
|
"@scalar/hono-api-reference": "^0.9.39",
|
|
45
45
|
"@sentry/node": "^10.19.0",
|
|
46
46
|
"bullmq": "^5.31.5",
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
3
|
+
import { encrypt } from "@lobu/core";
|
|
4
|
+
import { MockRedisClient } from "@lobu/core/testing";
|
|
5
|
+
import { AgentMetadataStore } from "../auth/agent-metadata-store";
|
|
6
|
+
import { AgentSettingsStore } from "../auth/settings/agent-settings-store";
|
|
7
|
+
import { GrantStore } from "../permissions/grant-store";
|
|
8
|
+
import { createAgentConfigRoutes } from "../routes/public/agent-config";
|
|
9
|
+
import { setAuthProvider } from "../routes/public/settings-auth";
|
|
10
|
+
|
|
11
|
+
describe("agent config routes", () => {
|
|
12
|
+
let originalEncryptionKey: string | undefined;
|
|
13
|
+
let redis: MockRedisClient;
|
|
14
|
+
let agentSettingsStore: AgentSettingsStore;
|
|
15
|
+
let agentMetadataStore: AgentMetadataStore;
|
|
16
|
+
let grantStore: GrantStore;
|
|
17
|
+
|
|
18
|
+
beforeEach(async () => {
|
|
19
|
+
originalEncryptionKey = process.env.ENCRYPTION_KEY;
|
|
20
|
+
process.env.ENCRYPTION_KEY =
|
|
21
|
+
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
|
|
22
|
+
redis = new MockRedisClient();
|
|
23
|
+
agentSettingsStore = new AgentSettingsStore(redis as any);
|
|
24
|
+
agentMetadataStore = new AgentMetadataStore(redis as any);
|
|
25
|
+
grantStore = new GrantStore(redis as any);
|
|
26
|
+
|
|
27
|
+
await agentMetadataStore.createAgent(
|
|
28
|
+
"template-agent",
|
|
29
|
+
"Template Agent",
|
|
30
|
+
"telegram",
|
|
31
|
+
"u1"
|
|
32
|
+
);
|
|
33
|
+
await agentMetadataStore.createAgent(
|
|
34
|
+
"telegram-1",
|
|
35
|
+
"Telegram Sandbox",
|
|
36
|
+
"telegram",
|
|
37
|
+
"u1",
|
|
38
|
+
{ parentConnectionId: "conn-1" }
|
|
39
|
+
);
|
|
40
|
+
await redis.set(
|
|
41
|
+
"connection:conn-1",
|
|
42
|
+
JSON.stringify({ templateAgentId: "template-agent" })
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
await agentSettingsStore.saveSettings("template-agent", {
|
|
46
|
+
identityMd: "Template identity",
|
|
47
|
+
soulMd: "Template soul",
|
|
48
|
+
userMd: "Template user",
|
|
49
|
+
installedProviders: [{ providerId: "chatgpt", installedAt: 1 }],
|
|
50
|
+
verboseLogging: true,
|
|
51
|
+
});
|
|
52
|
+
await agentSettingsStore.saveSettings("telegram-1", {
|
|
53
|
+
identityMd: "Local identity",
|
|
54
|
+
});
|
|
55
|
+
await grantStore.grant("telegram-1", "api.openai.com", null);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
afterEach(() => {
|
|
59
|
+
if (originalEncryptionKey !== undefined) {
|
|
60
|
+
process.env.ENCRYPTION_KEY = originalEncryptionKey;
|
|
61
|
+
} else {
|
|
62
|
+
delete process.env.ENCRYPTION_KEY;
|
|
63
|
+
}
|
|
64
|
+
setAuthProvider(null);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
function buildApp() {
|
|
68
|
+
const app = new OpenAPIHono();
|
|
69
|
+
const scheduledWakeupService = {
|
|
70
|
+
async listPendingForAgent(agentId: string) {
|
|
71
|
+
if (agentId !== "telegram-1") return [];
|
|
72
|
+
return [
|
|
73
|
+
{
|
|
74
|
+
id: "schedule-1",
|
|
75
|
+
task: "Check provider state",
|
|
76
|
+
triggerAt: "2026-03-30T18:00:00.000Z",
|
|
77
|
+
status: "pending",
|
|
78
|
+
isRecurring: false,
|
|
79
|
+
iteration: 1,
|
|
80
|
+
maxIterations: 1,
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
},
|
|
84
|
+
async cancelByAgent() {
|
|
85
|
+
return true;
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
app.route(
|
|
90
|
+
"/api/v1/agents/:agentId/config",
|
|
91
|
+
createAgentConfigRoutes({
|
|
92
|
+
agentSettingsStore,
|
|
93
|
+
agentConfigStore: {
|
|
94
|
+
getSettings: (agentId: string) =>
|
|
95
|
+
agentSettingsStore.getSettings(agentId),
|
|
96
|
+
getMetadata: (agentId: string) =>
|
|
97
|
+
agentMetadataStore.getMetadata(agentId),
|
|
98
|
+
},
|
|
99
|
+
grantStore,
|
|
100
|
+
scheduledWakeupService: scheduledWakeupService as any,
|
|
101
|
+
})
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
return app;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
test("GET /config returns effective sandbox settings with provenance", async () => {
|
|
108
|
+
setAuthProvider(() => ({
|
|
109
|
+
agentId: "telegram-1",
|
|
110
|
+
userId: "u1",
|
|
111
|
+
platform: "telegram",
|
|
112
|
+
exp: Date.now() + 60_000,
|
|
113
|
+
settingsMode: "user",
|
|
114
|
+
allowedScopes: [
|
|
115
|
+
"view-model",
|
|
116
|
+
"system-prompt",
|
|
117
|
+
"permissions",
|
|
118
|
+
"schedules",
|
|
119
|
+
],
|
|
120
|
+
}));
|
|
121
|
+
|
|
122
|
+
const app = buildApp();
|
|
123
|
+
const response = await app.request("/api/v1/agents/telegram-1/config");
|
|
124
|
+
expect(response.status).toBe(200);
|
|
125
|
+
|
|
126
|
+
const data = (await response.json()) as any;
|
|
127
|
+
expect(data.scope).toBe("sandbox");
|
|
128
|
+
expect(data.templateAgentId).toBe("template-agent");
|
|
129
|
+
expect(data.templateAgentName).toBe("Template Agent");
|
|
130
|
+
expect(data.instructions.identity).toBe("Local identity");
|
|
131
|
+
expect(data.instructions.soul).toBe("Template soul");
|
|
132
|
+
expect(data.providers.order).toEqual(["chatgpt"]);
|
|
133
|
+
expect(data.sections.model.source).toBe("inherited");
|
|
134
|
+
expect(data.sections.model.editable).toBe(false);
|
|
135
|
+
expect(data.sections["system-prompt"].source).toBe("mixed");
|
|
136
|
+
expect(data.providerViews.chatgpt.source).toBe("inherited");
|
|
137
|
+
expect(data.providerViews.chatgpt.canEdit).toBe(false);
|
|
138
|
+
expect(data.tools.permissions).toHaveLength(1);
|
|
139
|
+
expect(data.tools.schedules).toHaveLength(1);
|
|
140
|
+
expect(data.tools.schedules[0]?.scheduleId).toBe("schedule-1");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("GET /config accepts direct query token auth", async () => {
|
|
144
|
+
const app = buildApp();
|
|
145
|
+
const token = encrypt(
|
|
146
|
+
JSON.stringify({
|
|
147
|
+
agentId: "telegram-1",
|
|
148
|
+
userId: "u1",
|
|
149
|
+
platform: "telegram",
|
|
150
|
+
exp: Date.now() + 60_000,
|
|
151
|
+
settingsMode: "user",
|
|
152
|
+
allowedScopes: ["view-model", "system-prompt", "permissions"],
|
|
153
|
+
})
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
const response = await app.request(
|
|
157
|
+
`/api/v1/agents/telegram-1/config?token=${encodeURIComponent(token)}`
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
expect(response.status).toBe(200);
|
|
161
|
+
const data = (await response.json()) as any;
|
|
162
|
+
expect(data.agentId).toBe("telegram-1");
|
|
163
|
+
expect(data.scope).toBe("sandbox");
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("GET /config keeps exact agent tokens read-only when settingsMode is missing", async () => {
|
|
167
|
+
const app = buildApp();
|
|
168
|
+
const token = encrypt(
|
|
169
|
+
JSON.stringify({
|
|
170
|
+
agentId: "telegram-1",
|
|
171
|
+
userId: "u1",
|
|
172
|
+
platform: "telegram",
|
|
173
|
+
exp: Date.now() + 60_000,
|
|
174
|
+
})
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
const response = await app.request(
|
|
178
|
+
`/api/v1/agents/telegram-1/config?token=${encodeURIComponent(token)}`
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
expect(response.status).toBe(200);
|
|
182
|
+
const data = (await response.json()) as any;
|
|
183
|
+
expect(data.sections.model.editable).toBe(false);
|
|
184
|
+
expect(data.sections["system-prompt"].editable).toBe(false);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("GET /config rejects direct query token for the wrong agent", async () => {
|
|
188
|
+
const app = buildApp();
|
|
189
|
+
const token = encrypt(
|
|
190
|
+
JSON.stringify({
|
|
191
|
+
agentId: "template-agent",
|
|
192
|
+
userId: "u1",
|
|
193
|
+
platform: "telegram",
|
|
194
|
+
exp: Date.now() + 60_000,
|
|
195
|
+
settingsMode: "user",
|
|
196
|
+
})
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const response = await app.request(
|
|
200
|
+
`/api/v1/agents/telegram-1/config?token=${encodeURIComponent(token)}`
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
expect(response.status).toBe(401);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("GET /config reads effective settings from the settings store", async () => {
|
|
207
|
+
setAuthProvider(() => ({
|
|
208
|
+
agentId: "telegram-1",
|
|
209
|
+
userId: "u1",
|
|
210
|
+
platform: "telegram",
|
|
211
|
+
exp: Date.now() + 60_000,
|
|
212
|
+
settingsMode: "user",
|
|
213
|
+
allowedScopes: ["view-model", "system-prompt"],
|
|
214
|
+
}));
|
|
215
|
+
|
|
216
|
+
const app = new OpenAPIHono();
|
|
217
|
+
app.route(
|
|
218
|
+
"/api/v1/agents/:agentId/config",
|
|
219
|
+
createAgentConfigRoutes({
|
|
220
|
+
agentSettingsStore,
|
|
221
|
+
agentConfigStore: {
|
|
222
|
+
getSettings: async () => null,
|
|
223
|
+
getMetadata: (agentId: string) =>
|
|
224
|
+
agentMetadataStore.getMetadata(agentId),
|
|
225
|
+
},
|
|
226
|
+
})
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
const response = await app.request("/api/v1/agents/telegram-1/config");
|
|
230
|
+
|
|
231
|
+
expect(response.status).toBe(200);
|
|
232
|
+
const data = (await response.json()) as any;
|
|
233
|
+
expect(data.instructions.identity).toBe("Local identity");
|
|
234
|
+
expect(data.instructions.soul).toBe("Template soul");
|
|
235
|
+
expect(data.providers.order).toEqual(["chatgpt"]);
|
|
236
|
+
expect(data.templateAgentId).toBe("template-agent");
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test("GET /config grants owners full access even when browser session has no settingsMode", async () => {
|
|
240
|
+
setAuthProvider(() => ({
|
|
241
|
+
userId: "u1",
|
|
242
|
+
platform: "telegram",
|
|
243
|
+
exp: Date.now() + 60_000,
|
|
244
|
+
}));
|
|
245
|
+
|
|
246
|
+
const app = buildApp();
|
|
247
|
+
const response = await app.request("/api/v1/agents/telegram-1/config");
|
|
248
|
+
|
|
249
|
+
expect(response.status).toBe(200);
|
|
250
|
+
const data = (await response.json()) as any;
|
|
251
|
+
expect(data.sections.model.editable).toBe(true);
|
|
252
|
+
expect(data.sections["system-prompt"].editable).toBe(true);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { MockRedisClient } from "@lobu/core/testing";
|
|
4
|
+
import { AgentMetadataStore } from "../auth/agent-metadata-store";
|
|
5
|
+
import { UserAgentsStore } from "../auth/user-agents-store";
|
|
6
|
+
import { createAgentHistoryRoutes } from "../routes/public/agent-history";
|
|
7
|
+
import { setAuthProvider } from "../routes/public/settings-auth";
|
|
8
|
+
|
|
9
|
+
describe("agent history routes", () => {
|
|
10
|
+
let redis: MockRedisClient;
|
|
11
|
+
let agentMetadataStore: AgentMetadataStore;
|
|
12
|
+
let userAgentsStore: UserAgentsStore;
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
redis = new MockRedisClient();
|
|
16
|
+
agentMetadataStore = new AgentMetadataStore(redis as any);
|
|
17
|
+
userAgentsStore = new UserAgentsStore(redis as any);
|
|
18
|
+
|
|
19
|
+
await agentMetadataStore.createAgent(
|
|
20
|
+
"agent-1",
|
|
21
|
+
"Agent 1",
|
|
22
|
+
"external",
|
|
23
|
+
"u1"
|
|
24
|
+
);
|
|
25
|
+
await userAgentsStore.addAgent("external", "u1", "agent-1");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
setAuthProvider(null);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("rejects sessions that do not own the requested agent", async () => {
|
|
33
|
+
setAuthProvider(() => ({
|
|
34
|
+
userId: "u2",
|
|
35
|
+
platform: "external",
|
|
36
|
+
exp: Date.now() + 60_000,
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
const app = new Hono();
|
|
40
|
+
app.route(
|
|
41
|
+
"/api/v1/agents/:agentId/history",
|
|
42
|
+
createAgentHistoryRoutes({
|
|
43
|
+
connectionManager: {
|
|
44
|
+
getDeploymentsForAgent() {
|
|
45
|
+
return [];
|
|
46
|
+
},
|
|
47
|
+
getHttpUrl() {
|
|
48
|
+
return null;
|
|
49
|
+
},
|
|
50
|
+
} as any,
|
|
51
|
+
agentConfigStore: {
|
|
52
|
+
getMetadata: (agentId: string) =>
|
|
53
|
+
agentMetadataStore.getMetadata(agentId),
|
|
54
|
+
listSandboxes: async () => [],
|
|
55
|
+
},
|
|
56
|
+
userAgentsStore,
|
|
57
|
+
})
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const response = await app.request(
|
|
61
|
+
"/api/v1/agents/agent-1/history/status",
|
|
62
|
+
{
|
|
63
|
+
headers: {
|
|
64
|
+
host: "localhost",
|
|
65
|
+
},
|
|
66
|
+
method: "GET",
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
expect(response.status).toBe(401);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { MockRedisClient } from "@lobu/core/testing";
|
|
3
|
+
import { AgentMetadataStore } from "../auth/agent-metadata-store";
|
|
4
|
+
import { AgentSettingsStore } from "../auth/settings/agent-settings-store";
|
|
5
|
+
import { UserAgentsStore } from "../auth/user-agents-store";
|
|
6
|
+
import { createAgentRoutes } from "../routes/public/agents";
|
|
7
|
+
import { setAuthProvider } from "../routes/public/settings-auth";
|
|
8
|
+
|
|
9
|
+
describe("agent routes", () => {
|
|
10
|
+
let redis: MockRedisClient;
|
|
11
|
+
let agentMetadataStore: AgentMetadataStore;
|
|
12
|
+
let agentSettingsStore: AgentSettingsStore;
|
|
13
|
+
let userAgentsStore: UserAgentsStore;
|
|
14
|
+
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
redis = new MockRedisClient();
|
|
17
|
+
agentMetadataStore = new AgentMetadataStore(redis as any);
|
|
18
|
+
agentSettingsStore = new AgentSettingsStore(redis as any);
|
|
19
|
+
userAgentsStore = new UserAgentsStore(redis as any);
|
|
20
|
+
|
|
21
|
+
await agentMetadataStore.createAgent(
|
|
22
|
+
"agent-1",
|
|
23
|
+
"Agent 1",
|
|
24
|
+
"telegram",
|
|
25
|
+
"u1"
|
|
26
|
+
);
|
|
27
|
+
await userAgentsStore.addAgent("telegram", "u1", "agent-1");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
setAuthProvider(null);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("lists agents for external browser sessions by owner userId", async () => {
|
|
35
|
+
setAuthProvider(() => ({
|
|
36
|
+
userId: "u1",
|
|
37
|
+
oauthUserId: "u1",
|
|
38
|
+
platform: "external",
|
|
39
|
+
exp: Date.now() + 60_000,
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
const app = createAgentRoutes({
|
|
43
|
+
userAgentsStore,
|
|
44
|
+
agentMetadataStore,
|
|
45
|
+
agentSettingsStore,
|
|
46
|
+
channelBindingService: {
|
|
47
|
+
async getBinding() {
|
|
48
|
+
return null;
|
|
49
|
+
},
|
|
50
|
+
async createBinding() {
|
|
51
|
+
return true;
|
|
52
|
+
},
|
|
53
|
+
async listBindings() {
|
|
54
|
+
return [];
|
|
55
|
+
},
|
|
56
|
+
async deleteAllBindings() {
|
|
57
|
+
return 0;
|
|
58
|
+
},
|
|
59
|
+
} as any,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const response = await app.request("/");
|
|
63
|
+
expect(response.status).toBe(200);
|
|
64
|
+
const data = (await response.json()) as any;
|
|
65
|
+
expect(data.agents).toHaveLength(1);
|
|
66
|
+
expect(data.agents[0]?.agentId).toBe("agent-1");
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
3
|
+
import { MockRedisClient } from "@lobu/core/testing";
|
|
4
|
+
import { AgentMetadataStore } from "../auth/agent-metadata-store";
|
|
5
|
+
import { UserAgentsStore } from "../auth/user-agents-store";
|
|
6
|
+
import { createAgentSchedulesRoutes } from "../routes/public/agent-schedules";
|
|
7
|
+
import { setAuthProvider } from "../routes/public/settings-auth";
|
|
8
|
+
|
|
9
|
+
describe("agent schedules routes", () => {
|
|
10
|
+
let redis: MockRedisClient;
|
|
11
|
+
let agentMetadataStore: AgentMetadataStore;
|
|
12
|
+
let userAgentsStore: UserAgentsStore;
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
redis = new MockRedisClient();
|
|
16
|
+
agentMetadataStore = new AgentMetadataStore(redis as any);
|
|
17
|
+
userAgentsStore = new UserAgentsStore(redis as any);
|
|
18
|
+
|
|
19
|
+
await agentMetadataStore.createAgent(
|
|
20
|
+
"agent-1",
|
|
21
|
+
"Agent 1",
|
|
22
|
+
"external",
|
|
23
|
+
"u1"
|
|
24
|
+
);
|
|
25
|
+
await userAgentsStore.addAgent("external", "u1", "agent-1");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
setAuthProvider(null);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("rejects neutral sessions that do not own the agent", async () => {
|
|
33
|
+
setAuthProvider(() => ({
|
|
34
|
+
userId: "u2",
|
|
35
|
+
platform: "external",
|
|
36
|
+
exp: Date.now() + 60_000,
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
const app = new OpenAPIHono();
|
|
40
|
+
app.route(
|
|
41
|
+
"/api/v1/agents/:agentId/schedules",
|
|
42
|
+
createAgentSchedulesRoutes({
|
|
43
|
+
scheduledWakeupService: {
|
|
44
|
+
async listPendingForAgent() {
|
|
45
|
+
return [];
|
|
46
|
+
},
|
|
47
|
+
} as any,
|
|
48
|
+
userAgentsStore,
|
|
49
|
+
agentMetadataStore: {
|
|
50
|
+
getMetadata: (agentId: string) =>
|
|
51
|
+
agentMetadataStore.getMetadata(agentId),
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const response = await app.request("/api/v1/agents/agent-1/schedules");
|
|
57
|
+
expect(response.status).toBe(401);
|
|
58
|
+
});
|
|
59
|
+
});
|