@lobu/gateway 3.0.8 → 3.0.12
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/dist/api/platform.d.ts.map +1 -1
- package/dist/api/platform.js +8 -26
- package/dist/api/platform.js.map +1 -1
- package/dist/auth/mcp/proxy.d.ts +14 -0
- package/dist/auth/mcp/proxy.d.ts.map +1 -1
- package/dist/auth/mcp/proxy.js +149 -13
- package/dist/auth/mcp/proxy.js.map +1 -1
- package/dist/cli/gateway.d.ts.map +1 -1
- package/dist/cli/gateway.js +29 -0
- package/dist/cli/gateway.js.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/connections/chat-instance-manager.d.ts.map +1 -1
- package/dist/connections/chat-instance-manager.js +2 -1
- package/dist/connections/chat-instance-manager.js.map +1 -1
- package/dist/connections/interaction-bridge.d.ts +9 -2
- package/dist/connections/interaction-bridge.d.ts.map +1 -1
- package/dist/connections/interaction-bridge.js +132 -230
- package/dist/connections/interaction-bridge.js.map +1 -1
- package/dist/connections/message-handler-bridge.d.ts.map +1 -1
- package/dist/connections/message-handler-bridge.js +44 -26
- package/dist/connections/message-handler-bridge.js.map +1 -1
- package/dist/interactions.d.ts +9 -43
- package/dist/interactions.d.ts.map +1 -1
- package/dist/interactions.js +10 -52
- package/dist/interactions.js.map +1 -1
- package/dist/orchestration/base-deployment-manager.js +7 -7
- package/dist/orchestration/base-deployment-manager.js.map +1 -1
- package/dist/platform/unified-thread-consumer.d.ts.map +1 -1
- package/dist/platform/unified-thread-consumer.js +38 -34
- package/dist/platform/unified-thread-consumer.js.map +1 -1
- package/dist/routes/public/agent.d.ts +4 -0
- package/dist/routes/public/agent.d.ts.map +1 -1
- package/dist/routes/public/agent.js +21 -0
- package/dist/routes/public/agent.js.map +1 -1
- package/dist/services/core-services.d.ts.map +1 -1
- package/dist/services/core-services.js +4 -0
- package/dist/services/core-services.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/agent-config-routes.test.ts +0 -254
- package/src/__tests__/agent-history-routes.test.ts +0 -72
- package/src/__tests__/agent-routes.test.ts +0 -68
- package/src/__tests__/agent-schedules-routes.test.ts +0 -59
- package/src/__tests__/agent-settings-store.test.ts +0 -323
- package/src/__tests__/bedrock-model-catalog.test.ts +0 -40
- package/src/__tests__/bedrock-openai-service.test.ts +0 -157
- package/src/__tests__/bedrock-provider-module.test.ts +0 -56
- package/src/__tests__/chat-instance-manager-slack.test.ts +0 -204
- package/src/__tests__/chat-response-bridge.test.ts +0 -131
- package/src/__tests__/config-memory-plugins.test.ts +0 -92
- package/src/__tests__/config-request-store.test.ts +0 -127
- package/src/__tests__/connection-routes.test.ts +0 -144
- package/src/__tests__/core-services-store-selection.test.ts +0 -92
- package/src/__tests__/docker-deployment.test.ts +0 -1211
- package/src/__tests__/embedded-deployment.test.ts +0 -342
- package/src/__tests__/grant-store.test.ts +0 -148
- package/src/__tests__/http-proxy.test.ts +0 -281
- package/src/__tests__/instruction-service.test.ts +0 -37
- package/src/__tests__/link-buttons.test.ts +0 -112
- package/src/__tests__/lobu.test.ts +0 -32
- package/src/__tests__/mcp-config-service.test.ts +0 -347
- package/src/__tests__/mcp-proxy.test.ts +0 -694
- package/src/__tests__/message-handler-bridge.test.ts +0 -17
- package/src/__tests__/model-selection.test.ts +0 -172
- package/src/__tests__/oauth-templates.test.ts +0 -39
- package/src/__tests__/platform-adapter-slack-send.test.ts +0 -114
- package/src/__tests__/platform-helpers-model-resolution.test.ts +0 -253
- package/src/__tests__/provider-inheritance.test.ts +0 -212
- package/src/__tests__/routes/cli-auth.test.ts +0 -337
- package/src/__tests__/routes/interactions.test.ts +0 -121
- package/src/__tests__/secret-proxy.test.ts +0 -85
- package/src/__tests__/session-manager.test.ts +0 -572
- package/src/__tests__/setup.ts +0 -133
- package/src/__tests__/skill-and-mcp-registry.test.ts +0 -203
- package/src/__tests__/slack-routes.test.ts +0 -161
- package/src/__tests__/system-config-resolver.test.ts +0 -75
- package/src/__tests__/system-message-limiter.test.ts +0 -89
- package/src/__tests__/system-skills-service.test.ts +0 -362
- package/src/__tests__/transcription-service.test.ts +0 -222
- package/src/__tests__/utils/rate-limiter.test.ts +0 -102
- package/src/__tests__/worker-connection-manager.test.ts +0 -497
- package/src/__tests__/worker-job-router.test.ts +0 -722
- package/src/api/index.ts +0 -1
- package/src/api/platform.ts +0 -292
- package/src/api/response-renderer.ts +0 -157
- package/src/auth/agent-metadata-store.ts +0 -168
- package/src/auth/api-auth-middleware.ts +0 -69
- package/src/auth/api-key-provider-module.ts +0 -213
- package/src/auth/base-provider-module.ts +0 -201
- package/src/auth/bedrock/provider-module.ts +0 -110
- package/src/auth/chatgpt/chatgpt-oauth-module.ts +0 -185
- package/src/auth/chatgpt/device-code-client.ts +0 -218
- package/src/auth/chatgpt/index.ts +0 -1
- package/src/auth/claude/oauth-module.ts +0 -280
- package/src/auth/cli/token-service.ts +0 -249
- package/src/auth/external/client.ts +0 -560
- package/src/auth/external/device-code-client.ts +0 -235
- package/src/auth/mcp/config-service.ts +0 -420
- package/src/auth/mcp/proxy.ts +0 -1086
- package/src/auth/mcp/string-substitution.ts +0 -17
- package/src/auth/mcp/tool-cache.ts +0 -90
- package/src/auth/oauth/base-client.ts +0 -267
- package/src/auth/oauth/client.ts +0 -153
- package/src/auth/oauth/credentials.ts +0 -7
- package/src/auth/oauth/providers.ts +0 -69
- package/src/auth/oauth/state-store.ts +0 -150
- package/src/auth/oauth-templates.ts +0 -179
- package/src/auth/provider-catalog.ts +0 -220
- package/src/auth/provider-model-options.ts +0 -41
- package/src/auth/settings/agent-settings-store.ts +0 -565
- package/src/auth/settings/auth-profiles-manager.ts +0 -216
- package/src/auth/settings/index.ts +0 -12
- package/src/auth/settings/model-preference-store.ts +0 -52
- package/src/auth/settings/model-selection.ts +0 -135
- package/src/auth/settings/resolved-settings-view.ts +0 -298
- package/src/auth/settings/template-utils.ts +0 -44
- package/src/auth/settings/token-service.ts +0 -88
- package/src/auth/system-env-store.ts +0 -98
- package/src/auth/user-agents-store.ts +0 -68
- package/src/channels/binding-service.ts +0 -214
- package/src/channels/index.ts +0 -4
- package/src/cli/gateway.ts +0 -1312
- package/src/cli/index.ts +0 -74
- package/src/commands/built-in-commands.ts +0 -80
- package/src/commands/command-dispatcher.ts +0 -94
- package/src/commands/command-reply-adapters.ts +0 -27
- package/src/config/file-loader.ts +0 -618
- package/src/config/index.ts +0 -588
- package/src/config/network-allowlist.ts +0 -71
- package/src/connections/chat-instance-manager.ts +0 -1284
- package/src/connections/chat-response-bridge.ts +0 -618
- package/src/connections/index.ts +0 -7
- package/src/connections/interaction-bridge.ts +0 -831
- package/src/connections/message-handler-bridge.ts +0 -415
- package/src/connections/platform-auth-methods.ts +0 -15
- package/src/connections/types.ts +0 -84
- package/src/gateway/connection-manager.ts +0 -291
- package/src/gateway/index.ts +0 -698
- package/src/gateway/job-router.ts +0 -201
- package/src/gateway-main.ts +0 -200
- package/src/index.ts +0 -41
- package/src/infrastructure/queue/index.ts +0 -12
- package/src/infrastructure/queue/queue-producer.ts +0 -148
- package/src/infrastructure/queue/redis-queue.ts +0 -361
- package/src/infrastructure/queue/types.ts +0 -133
- package/src/infrastructure/redis/system-message-limiter.ts +0 -94
- package/src/interactions/config-request-store.ts +0 -198
- package/src/interactions.ts +0 -363
- package/src/lobu.ts +0 -311
- package/src/metrics/prometheus.ts +0 -159
- package/src/modules/module-system.ts +0 -179
- package/src/orchestration/base-deployment-manager.ts +0 -900
- package/src/orchestration/deployment-utils.ts +0 -98
- package/src/orchestration/impl/docker-deployment.ts +0 -620
- package/src/orchestration/impl/embedded-deployment.ts +0 -268
- package/src/orchestration/impl/index.ts +0 -8
- package/src/orchestration/impl/k8s/deployment.ts +0 -1061
- package/src/orchestration/impl/k8s/helpers.ts +0 -610
- package/src/orchestration/impl/k8s/index.ts +0 -1
- package/src/orchestration/index.ts +0 -333
- package/src/orchestration/message-consumer.ts +0 -584
- package/src/orchestration/scheduled-wakeup.ts +0 -704
- package/src/permissions/approval-policy.ts +0 -36
- package/src/permissions/grant-store.ts +0 -219
- package/src/platform/file-handler.ts +0 -66
- package/src/platform/link-buttons.ts +0 -57
- package/src/platform/renderer-utils.ts +0 -44
- package/src/platform/response-renderer.ts +0 -84
- package/src/platform/unified-thread-consumer.ts +0 -187
- package/src/platform.ts +0 -318
- package/src/proxy/http-proxy.ts +0 -752
- package/src/proxy/proxy-manager.ts +0 -81
- package/src/proxy/secret-proxy.ts +0 -402
- package/src/proxy/token-refresh-job.ts +0 -143
- package/src/routes/internal/audio.ts +0 -141
- package/src/routes/internal/device-auth.ts +0 -652
- package/src/routes/internal/files.ts +0 -226
- package/src/routes/internal/history.ts +0 -69
- package/src/routes/internal/images.ts +0 -127
- package/src/routes/internal/interactions.ts +0 -84
- package/src/routes/internal/middleware.ts +0 -23
- package/src/routes/internal/schedule.ts +0 -226
- package/src/routes/internal/types.ts +0 -22
- package/src/routes/openapi-auto.ts +0 -239
- package/src/routes/public/agent-access.ts +0 -23
- package/src/routes/public/agent-config.ts +0 -675
- package/src/routes/public/agent-history.ts +0 -422
- package/src/routes/public/agent-schedules.ts +0 -296
- package/src/routes/public/agent.ts +0 -1086
- package/src/routes/public/agents.ts +0 -373
- package/src/routes/public/channels.ts +0 -191
- package/src/routes/public/cli-auth.ts +0 -896
- package/src/routes/public/connections.ts +0 -574
- package/src/routes/public/landing.ts +0 -16
- package/src/routes/public/oauth.ts +0 -147
- package/src/routes/public/settings-auth.ts +0 -104
- package/src/routes/public/slack.ts +0 -173
- package/src/routes/shared/agent-ownership.ts +0 -101
- package/src/routes/shared/token-verifier.ts +0 -34
- package/src/services/bedrock-model-catalog.ts +0 -217
- package/src/services/bedrock-openai-service.ts +0 -658
- package/src/services/core-services.ts +0 -1072
- package/src/services/image-generation-service.ts +0 -257
- package/src/services/instruction-service.ts +0 -318
- package/src/services/mcp-registry.ts +0 -94
- package/src/services/platform-helpers.ts +0 -287
- package/src/services/session-manager.ts +0 -262
- package/src/services/settings-resolver.ts +0 -74
- package/src/services/system-config-resolver.ts +0 -89
- package/src/services/system-skills-service.ts +0 -229
- package/src/services/transcription-service.ts +0 -684
- package/src/session.ts +0 -110
- package/src/spaces/index.ts +0 -1
- package/src/spaces/space-resolver.ts +0 -17
- package/src/stores/in-memory-agent-store.ts +0 -403
- package/src/stores/redis-agent-store.ts +0 -279
- package/src/utils/public-url.ts +0 -44
- package/src/utils/rate-limiter.ts +0 -94
- package/tsconfig.json +0 -33
|
@@ -1,675 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent Config Routes
|
|
3
|
-
*
|
|
4
|
-
* Configuration endpoints mounted under /api/v1/agents/{agentId}/config
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
|
8
|
-
import type { AgentConfigStore, AuthProfile, SkillConfig } from "@lobu/core";
|
|
9
|
-
import type { ProviderCatalogService } from "../../auth/provider-catalog";
|
|
10
|
-
import { collectProviderModelOptions } from "../../auth/provider-model-options";
|
|
11
|
-
|
|
12
|
-
import type { AgentSettings, AgentSettingsStore } from "../../auth/settings";
|
|
13
|
-
import type { AuthProfilesManager } from "../../auth/settings/auth-profiles-manager";
|
|
14
|
-
import { getModelSelectionState } from "../../auth/settings/model-selection";
|
|
15
|
-
import {
|
|
16
|
-
canEditSettingsSection,
|
|
17
|
-
type ResolvedProviderView,
|
|
18
|
-
type ResolvedSectionView,
|
|
19
|
-
SETTINGS_SECTION_KEYS,
|
|
20
|
-
type SettingsSectionKey,
|
|
21
|
-
} from "../../auth/settings/resolved-settings-view";
|
|
22
|
-
import type { SettingsTokenPayload } from "../../auth/settings/token-service";
|
|
23
|
-
import type { UserAgentsStore } from "../../auth/user-agents-store";
|
|
24
|
-
import type { WorkerConnectionManager } from "../../gateway/connection-manager";
|
|
25
|
-
import type { IMessageQueue } from "../../infrastructure/queue";
|
|
26
|
-
import {
|
|
27
|
-
getModelProviderModules,
|
|
28
|
-
type ModelOption,
|
|
29
|
-
type ModelProviderModule,
|
|
30
|
-
} from "../../modules/module-system";
|
|
31
|
-
import type { ScheduledWakeupService } from "../../orchestration/scheduled-wakeup";
|
|
32
|
-
import type { GrantStore } from "../../permissions/grant-store";
|
|
33
|
-
import { createTokenVerifier } from "../shared/token-verifier";
|
|
34
|
-
import { verifySettingsSessionOrToken } from "./settings-auth";
|
|
35
|
-
|
|
36
|
-
const TAG = "Configuration";
|
|
37
|
-
const ErrorResponse = z.object({ error: z.string() });
|
|
38
|
-
const TokenQuery = z.object({ token: z.string().optional() });
|
|
39
|
-
const REDACTED_VALUE = "__LOBU_REDACTED__";
|
|
40
|
-
|
|
41
|
-
export interface ConfigChangeEntry {
|
|
42
|
-
category:
|
|
43
|
-
| "mcp"
|
|
44
|
-
| "provider"
|
|
45
|
-
| "model"
|
|
46
|
-
| "packages"
|
|
47
|
-
| "skills"
|
|
48
|
-
| "instructions"
|
|
49
|
-
| "env"
|
|
50
|
-
| "plugins"
|
|
51
|
-
| "logging";
|
|
52
|
-
action: "added" | "removed" | "updated" | "reordered";
|
|
53
|
-
summary: string;
|
|
54
|
-
details?: string[];
|
|
55
|
-
}
|
|
56
|
-
const SENSITIVE_KEY_PATTERN =
|
|
57
|
-
/(?:credential|secret|token|password|api(?:_|-)?key|authorization)/i;
|
|
58
|
-
|
|
59
|
-
type SanitizedAuthProfile = Omit<AuthProfile, "credential" | "metadata"> & {
|
|
60
|
-
credential: string;
|
|
61
|
-
credentialRedacted: true;
|
|
62
|
-
metadata?: Omit<NonNullable<AuthProfile["metadata"]>, "refreshToken"> & {
|
|
63
|
-
refreshToken?: string;
|
|
64
|
-
refreshTokenRedacted?: true;
|
|
65
|
-
};
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
type PublicAgentSettings = Omit<AgentSettings, "authProfiles"> & {
|
|
69
|
-
authProfiles?: SanitizedAuthProfile[];
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
// --- Route Definitions ---
|
|
73
|
-
|
|
74
|
-
const getConfigRoute = createRoute({
|
|
75
|
-
method: "get",
|
|
76
|
-
path: "/",
|
|
77
|
-
tags: [TAG],
|
|
78
|
-
summary: "Get agent configuration",
|
|
79
|
-
request: { query: TokenQuery },
|
|
80
|
-
responses: {
|
|
81
|
-
200: {
|
|
82
|
-
description: "Configuration",
|
|
83
|
-
content: {
|
|
84
|
-
"application/json": {
|
|
85
|
-
schema: z.any(),
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
401: {
|
|
90
|
-
description: "Unauthorized",
|
|
91
|
-
content: { "application/json": { schema: ErrorResponse } },
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
export interface ProviderCredentialStore {
|
|
97
|
-
hasCredentials(agentId: string): Promise<boolean>;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export interface AgentConfigRoutesConfig {
|
|
101
|
-
agentSettingsStore: AgentSettingsStore;
|
|
102
|
-
agentConfigStore: Pick<AgentConfigStore, "getMetadata" | "getSettings">;
|
|
103
|
-
userAgentsStore?: UserAgentsStore;
|
|
104
|
-
providerStores?: Record<string, ProviderCredentialStore>;
|
|
105
|
-
/**
|
|
106
|
-
* Provider connectivity overrides (e.g., system token means "connected" even if no user credentials are stored).
|
|
107
|
-
*/
|
|
108
|
-
providerConnectedOverrides?: Record<string, boolean>;
|
|
109
|
-
providerCatalogService?: ProviderCatalogService;
|
|
110
|
-
authProfilesManager?: AuthProfilesManager;
|
|
111
|
-
queue?: IMessageQueue;
|
|
112
|
-
connectionManager?: WorkerConnectionManager;
|
|
113
|
-
grantStore?: GrantStore;
|
|
114
|
-
scheduledWakeupService?: ScheduledWakeupService;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function getViewer(payload: SettingsTokenPayload | null | undefined): {
|
|
118
|
-
settingsMode?: "admin" | "user";
|
|
119
|
-
allowedScopes?: string[];
|
|
120
|
-
isAdmin?: boolean;
|
|
121
|
-
} {
|
|
122
|
-
return {
|
|
123
|
-
settingsMode: payload?.settingsMode,
|
|
124
|
-
allowedScopes: payload?.allowedScopes,
|
|
125
|
-
isAdmin: payload?.isAdmin,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function getProviderModelPreferencesFromSettings(
|
|
130
|
-
settings: AgentSettings | null | undefined
|
|
131
|
-
): Record<string, string> {
|
|
132
|
-
const directPreferences = Object.fromEntries(
|
|
133
|
-
Object.entries(settings?.providerModelPreferences || {})
|
|
134
|
-
.map(([providerId, modelRef]) => [providerId.trim(), modelRef.trim()])
|
|
135
|
-
.filter(([providerId, modelRef]) => providerId && modelRef)
|
|
136
|
-
);
|
|
137
|
-
if (Object.keys(directPreferences).length > 0) {
|
|
138
|
-
return directPreferences;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const fallbackPreferences: Record<string, string> = {};
|
|
142
|
-
for (const ip of settings?.installedProviders || []) {
|
|
143
|
-
if (ip.config?.modelPreference) {
|
|
144
|
-
fallbackPreferences[ip.providerId] = String(ip.config.modelPreference);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return fallbackPreferences;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function hasOwnSetting(
|
|
151
|
-
settings: AgentSettings | null | undefined,
|
|
152
|
-
key: keyof AgentSettings
|
|
153
|
-
): boolean {
|
|
154
|
-
return !!settings && Object.hasOwn(settings, key);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const SECTION_SETTING_KEYS: Record<
|
|
158
|
-
Exclude<SettingsSectionKey, "permissions" | "schedules">,
|
|
159
|
-
Array<keyof AgentSettings>
|
|
160
|
-
> = {
|
|
161
|
-
model: [
|
|
162
|
-
"installedProviders",
|
|
163
|
-
"authProfiles",
|
|
164
|
-
"model",
|
|
165
|
-
"modelSelection",
|
|
166
|
-
"providerModelPreferences",
|
|
167
|
-
],
|
|
168
|
-
"system-prompt": ["identityMd", "soulMd", "userMd"],
|
|
169
|
-
skills: ["skillsConfig", "mcpServers", "pluginsConfig"],
|
|
170
|
-
packages: ["nixConfig"],
|
|
171
|
-
logging: ["verboseLogging"],
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
function sectionHasLocalOverride(
|
|
175
|
-
section: SettingsSectionKey,
|
|
176
|
-
localSettings: AgentSettings | null | undefined
|
|
177
|
-
): boolean {
|
|
178
|
-
if (section === "permissions" || section === "schedules") {
|
|
179
|
-
return false;
|
|
180
|
-
}
|
|
181
|
-
return SECTION_SETTING_KEYS[section].some((key) =>
|
|
182
|
-
hasOwnSetting(localSettings, key)
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function sectionHasTemplateValue(
|
|
187
|
-
section: SettingsSectionKey,
|
|
188
|
-
templateSettings: AgentSettings | null | undefined
|
|
189
|
-
): boolean {
|
|
190
|
-
if (section === "permissions" || section === "schedules") {
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
return SECTION_SETTING_KEYS[section].some((key) =>
|
|
194
|
-
hasOwnSetting(templateSettings, key)
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function resolveSectionSource(
|
|
199
|
-
isSandbox: boolean,
|
|
200
|
-
hasLocalOverride: boolean,
|
|
201
|
-
hasTemplateValue: boolean
|
|
202
|
-
): "local" | "inherited" | "mixed" {
|
|
203
|
-
if (!isSandbox) return "local";
|
|
204
|
-
if (!hasLocalOverride && hasTemplateValue) return "inherited";
|
|
205
|
-
if (hasLocalOverride && hasTemplateValue) return "mixed";
|
|
206
|
-
return "local";
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function resolveProviderSources(
|
|
210
|
-
localSettings: AgentSettings | null,
|
|
211
|
-
effectiveSettings: AgentSettings | null,
|
|
212
|
-
templateSettings: AgentSettings | null,
|
|
213
|
-
isSandbox: boolean,
|
|
214
|
-
viewer: ReturnType<typeof getViewer>
|
|
215
|
-
): Record<string, ResolvedProviderView> {
|
|
216
|
-
const effectiveProviderIds = (
|
|
217
|
-
effectiveSettings?.installedProviders || []
|
|
218
|
-
).map((provider) => provider.providerId);
|
|
219
|
-
const localProviderIds = new Set(
|
|
220
|
-
(localSettings?.installedProviders || []).map(
|
|
221
|
-
(provider) => provider.providerId
|
|
222
|
-
)
|
|
223
|
-
);
|
|
224
|
-
const localProfileProviders = new Set(
|
|
225
|
-
(localSettings?.authProfiles || []).map((profile) => profile.provider)
|
|
226
|
-
);
|
|
227
|
-
const localPreferenceProviders = new Set(
|
|
228
|
-
Object.keys(localSettings?.providerModelPreferences || {})
|
|
229
|
-
);
|
|
230
|
-
const templateProviderIds = new Set(
|
|
231
|
-
(templateSettings?.installedProviders || []).map(
|
|
232
|
-
(provider) => provider.providerId
|
|
233
|
-
)
|
|
234
|
-
);
|
|
235
|
-
|
|
236
|
-
return Object.fromEntries(
|
|
237
|
-
effectiveProviderIds.map((providerId) => {
|
|
238
|
-
const hasLocalOverride =
|
|
239
|
-
localProviderIds.has(providerId) ||
|
|
240
|
-
localProfileProviders.has(providerId) ||
|
|
241
|
-
localPreferenceProviders.has(providerId);
|
|
242
|
-
|
|
243
|
-
const source = resolveSectionSource(
|
|
244
|
-
isSandbox,
|
|
245
|
-
hasLocalOverride,
|
|
246
|
-
templateProviderIds.has(providerId)
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
return [
|
|
250
|
-
providerId,
|
|
251
|
-
{
|
|
252
|
-
id: providerId,
|
|
253
|
-
source,
|
|
254
|
-
canEdit: canEditSettingsSection("model", viewer),
|
|
255
|
-
canReset: isSandbox && hasLocalOverride,
|
|
256
|
-
hasLocalOverride,
|
|
257
|
-
} satisfies ResolvedProviderView,
|
|
258
|
-
];
|
|
259
|
-
})
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
async function resolveSettingsView(
|
|
264
|
-
config: AgentConfigRoutesConfig,
|
|
265
|
-
agentId: string,
|
|
266
|
-
payload: SettingsTokenPayload | null
|
|
267
|
-
): Promise<{
|
|
268
|
-
scope: "agent" | "sandbox";
|
|
269
|
-
templateAgentId?: string;
|
|
270
|
-
templateAgentName?: string;
|
|
271
|
-
sections: Record<SettingsSectionKey, ResolvedSectionView>;
|
|
272
|
-
providerSources: Record<string, ResolvedProviderView>;
|
|
273
|
-
effectiveSettings: AgentSettings | null;
|
|
274
|
-
}> {
|
|
275
|
-
const viewer = getViewer(payload);
|
|
276
|
-
const localSettings = await config.agentSettingsStore.getSettings(agentId);
|
|
277
|
-
const effectiveSettings =
|
|
278
|
-
await config.agentSettingsStore.getEffectiveSettings(agentId);
|
|
279
|
-
const templateAgentId =
|
|
280
|
-
effectiveSettings?.templateAgentId || localSettings?.templateAgentId;
|
|
281
|
-
const templateSettings = templateAgentId
|
|
282
|
-
? await config.agentSettingsStore.getSettings(templateAgentId)
|
|
283
|
-
: null;
|
|
284
|
-
const templateAgentName = templateAgentId
|
|
285
|
-
? (await config.agentConfigStore.getMetadata(templateAgentId))?.name
|
|
286
|
-
: undefined;
|
|
287
|
-
const isSandbox = !!templateAgentId;
|
|
288
|
-
|
|
289
|
-
const sections = Object.fromEntries(
|
|
290
|
-
SETTINGS_SECTION_KEYS.map((section) => {
|
|
291
|
-
const hasLocalOverride = sectionHasLocalOverride(section, localSettings);
|
|
292
|
-
const hasTemplateValue = sectionHasTemplateValue(
|
|
293
|
-
section,
|
|
294
|
-
templateSettings
|
|
295
|
-
);
|
|
296
|
-
|
|
297
|
-
return [
|
|
298
|
-
section,
|
|
299
|
-
{
|
|
300
|
-
source: resolveSectionSource(
|
|
301
|
-
isSandbox,
|
|
302
|
-
hasLocalOverride,
|
|
303
|
-
hasTemplateValue
|
|
304
|
-
),
|
|
305
|
-
editable: canEditSettingsSection(section, viewer),
|
|
306
|
-
canReset: isSandbox && hasLocalOverride,
|
|
307
|
-
hasLocalOverride,
|
|
308
|
-
} satisfies ResolvedSectionView,
|
|
309
|
-
];
|
|
310
|
-
})
|
|
311
|
-
) as Record<SettingsSectionKey, ResolvedSectionView>;
|
|
312
|
-
|
|
313
|
-
return {
|
|
314
|
-
scope: isSandbox ? "sandbox" : "agent",
|
|
315
|
-
templateAgentId,
|
|
316
|
-
templateAgentName,
|
|
317
|
-
sections,
|
|
318
|
-
providerSources: resolveProviderSources(
|
|
319
|
-
localSettings,
|
|
320
|
-
effectiveSettings,
|
|
321
|
-
templateSettings,
|
|
322
|
-
isSandbox,
|
|
323
|
-
viewer
|
|
324
|
-
),
|
|
325
|
-
effectiveSettings,
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
async function buildResolvedConfigResponse(
|
|
330
|
-
config: AgentConfigRoutesConfig,
|
|
331
|
-
agentId: string,
|
|
332
|
-
payload: SettingsTokenPayload | null,
|
|
333
|
-
providerModels: Record<string, ModelOption[]>
|
|
334
|
-
): Promise<any> {
|
|
335
|
-
const [settingsView, grants, schedules] = await Promise.all([
|
|
336
|
-
resolveSettingsView(config, agentId, payload),
|
|
337
|
-
config.grantStore?.listGrants(agentId) ?? Promise.resolve([]),
|
|
338
|
-
config.scheduledWakeupService?.listPendingForAgent(agentId) ??
|
|
339
|
-
Promise.resolve([]),
|
|
340
|
-
]);
|
|
341
|
-
const settings = settingsView.effectiveSettings;
|
|
342
|
-
|
|
343
|
-
const providers: Record<
|
|
344
|
-
string,
|
|
345
|
-
{
|
|
346
|
-
connected: boolean;
|
|
347
|
-
userConnected: boolean;
|
|
348
|
-
systemConnected: boolean;
|
|
349
|
-
activeAuthType?: string;
|
|
350
|
-
authMethods?: string[];
|
|
351
|
-
}
|
|
352
|
-
> = {};
|
|
353
|
-
if (config.providerStores) {
|
|
354
|
-
for (const [name, store] of Object.entries(config.providerStores)) {
|
|
355
|
-
try {
|
|
356
|
-
const hasSystemCredentials =
|
|
357
|
-
config.providerConnectedOverrides?.[name] === true;
|
|
358
|
-
const hasUserCredentials = await store.hasCredentials(agentId);
|
|
359
|
-
|
|
360
|
-
const profiles = config.authProfilesManager
|
|
361
|
-
? await config.authProfilesManager.getProviderProfiles(agentId, name)
|
|
362
|
-
: [];
|
|
363
|
-
const now = Date.now();
|
|
364
|
-
const validProfiles = profiles.filter(
|
|
365
|
-
(profile) =>
|
|
366
|
-
!profile.metadata?.expiresAt || profile.metadata.expiresAt > now
|
|
367
|
-
);
|
|
368
|
-
|
|
369
|
-
providers[name] = {
|
|
370
|
-
connected: hasUserCredentials || hasSystemCredentials,
|
|
371
|
-
userConnected: hasUserCredentials,
|
|
372
|
-
systemConnected: hasSystemCredentials,
|
|
373
|
-
activeAuthType: validProfiles[0]?.authType,
|
|
374
|
-
authMethods: validProfiles.map((profile) => profile.authType),
|
|
375
|
-
};
|
|
376
|
-
} catch {
|
|
377
|
-
providers[name] = {
|
|
378
|
-
connected: false,
|
|
379
|
-
userConnected: false,
|
|
380
|
-
systemConnected: false,
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
const allModules = getModelProviderModules();
|
|
387
|
-
const allProviderMeta = allModules
|
|
388
|
-
.filter((module) => module.catalogVisible !== false)
|
|
389
|
-
.map((module: ModelProviderModule) => ({
|
|
390
|
-
id: module.providerId,
|
|
391
|
-
name: module.providerDisplayName,
|
|
392
|
-
iconUrl: module.providerIconUrl || "",
|
|
393
|
-
authType: (module.authType || "oauth") as
|
|
394
|
-
| "oauth"
|
|
395
|
-
| "device-code"
|
|
396
|
-
| "api-key",
|
|
397
|
-
supportedAuthTypes: (module.supportedAuthTypes as (
|
|
398
|
-
| "oauth"
|
|
399
|
-
| "device-code"
|
|
400
|
-
| "api-key"
|
|
401
|
-
)[]) || [
|
|
402
|
-
(module.authType || "oauth") as "oauth" | "device-code" | "api-key",
|
|
403
|
-
],
|
|
404
|
-
apiKeyInstructions: module.apiKeyInstructions || "",
|
|
405
|
-
apiKeyPlaceholder: module.apiKeyPlaceholder || "",
|
|
406
|
-
capabilities: [] as string[],
|
|
407
|
-
}));
|
|
408
|
-
|
|
409
|
-
const installedIds = (settings?.installedProviders || []).map(
|
|
410
|
-
(provider) => provider.providerId
|
|
411
|
-
);
|
|
412
|
-
const installedIdSet = new Set(installedIds);
|
|
413
|
-
const catalogProviders = allProviderMeta.filter(
|
|
414
|
-
(provider) => !installedIdSet.has(provider.id)
|
|
415
|
-
);
|
|
416
|
-
const providerIconUrls: Record<string, string> = {};
|
|
417
|
-
for (const provider of allProviderMeta) {
|
|
418
|
-
if (provider.iconUrl) {
|
|
419
|
-
providerIconUrls[provider.id] = provider.iconUrl;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
const providerMeta: Record<string, object> = {};
|
|
424
|
-
for (const provider of allProviderMeta) {
|
|
425
|
-
providerMeta[provider.id] = {
|
|
426
|
-
name: provider.name,
|
|
427
|
-
authType: provider.authType,
|
|
428
|
-
supportedAuthTypes: provider.supportedAuthTypes,
|
|
429
|
-
apiKeyInstructions: provider.apiKeyInstructions,
|
|
430
|
-
apiKeyPlaceholder: provider.apiKeyPlaceholder,
|
|
431
|
-
capabilities: provider.capabilities,
|
|
432
|
-
};
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
const sanitized = sanitizeSettingsForResponse(settings);
|
|
436
|
-
return {
|
|
437
|
-
agentId,
|
|
438
|
-
scope: settingsView.scope,
|
|
439
|
-
templateAgentId: settingsView.templateAgentId,
|
|
440
|
-
templateAgentName: settingsView.templateAgentName,
|
|
441
|
-
sections: settingsView.sections,
|
|
442
|
-
providerViews: settingsView.providerSources,
|
|
443
|
-
instructions: {
|
|
444
|
-
identity: sanitized.identityMd || "",
|
|
445
|
-
soul: sanitized.soulMd || "",
|
|
446
|
-
user: sanitized.userMd || "",
|
|
447
|
-
},
|
|
448
|
-
providers: {
|
|
449
|
-
order: installedIds,
|
|
450
|
-
status: providers,
|
|
451
|
-
catalog: catalogProviders,
|
|
452
|
-
meta: providerMeta,
|
|
453
|
-
models: providerModels,
|
|
454
|
-
preferences: getProviderModelPreferencesFromSettings(settings),
|
|
455
|
-
icons: providerIconUrls,
|
|
456
|
-
modelSelection: getModelSelectionState(settings || undefined),
|
|
457
|
-
configManaged: [] as string[],
|
|
458
|
-
},
|
|
459
|
-
skills: sanitized.skillsConfig?.skills || [],
|
|
460
|
-
mcpServers: sanitized.mcpServers || {},
|
|
461
|
-
tools: {
|
|
462
|
-
nixPackages: sanitized.nixConfig?.packages || [],
|
|
463
|
-
permissions: grants,
|
|
464
|
-
schedules: schedules.map((schedule) => ({
|
|
465
|
-
scheduleId: schedule.id,
|
|
466
|
-
task: schedule.task,
|
|
467
|
-
scheduledFor: schedule.triggerAt,
|
|
468
|
-
status: schedule.status,
|
|
469
|
-
isRecurring: schedule.isRecurring,
|
|
470
|
-
cron: schedule.cron,
|
|
471
|
-
iteration: schedule.iteration,
|
|
472
|
-
maxIterations: schedule.maxIterations,
|
|
473
|
-
})),
|
|
474
|
-
registries: [],
|
|
475
|
-
globalRegistries: [],
|
|
476
|
-
},
|
|
477
|
-
settings: {
|
|
478
|
-
verboseLogging: !!sanitized.verboseLogging,
|
|
479
|
-
memoryEnabled: !!process.env.MEMORY_URL,
|
|
480
|
-
},
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
export function createAgentConfigRoutes(
|
|
485
|
-
config: AgentConfigRoutesConfig
|
|
486
|
-
): OpenAPIHono {
|
|
487
|
-
const app = new OpenAPIHono();
|
|
488
|
-
|
|
489
|
-
const baseVerifyToken = createTokenVerifier({
|
|
490
|
-
userAgentsStore: config.userAgentsStore,
|
|
491
|
-
agentMetadataStore: config.agentConfigStore,
|
|
492
|
-
});
|
|
493
|
-
|
|
494
|
-
/**
|
|
495
|
-
* Verify settings token against agentId.
|
|
496
|
-
* Admin sessions bypass ownership checks.
|
|
497
|
-
* Owner-scoped browser sessions get admin-equivalent access for their own
|
|
498
|
-
* agents, while exact agent-scoped tokens remain limited unless they were
|
|
499
|
-
* explicitly minted as admin/user-mode sessions.
|
|
500
|
-
*/
|
|
501
|
-
const verifyToken = async (
|
|
502
|
-
payload: SettingsTokenPayload | null,
|
|
503
|
-
agentId: string
|
|
504
|
-
): Promise<SettingsTokenPayload | null> => {
|
|
505
|
-
if (!payload) return null;
|
|
506
|
-
if (payload.isAdmin || payload.settingsMode === "admin") {
|
|
507
|
-
return {
|
|
508
|
-
...payload,
|
|
509
|
-
isAdmin: true,
|
|
510
|
-
settingsMode: "admin",
|
|
511
|
-
};
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
const verified = await baseVerifyToken(payload, agentId);
|
|
515
|
-
if (!verified) return null;
|
|
516
|
-
|
|
517
|
-
if (verified.agentId || verified.settingsMode === "user") {
|
|
518
|
-
return verified;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
return {
|
|
522
|
-
...verified,
|
|
523
|
-
isAdmin: true,
|
|
524
|
-
settingsMode: "admin",
|
|
525
|
-
};
|
|
526
|
-
};
|
|
527
|
-
|
|
528
|
-
app.openapi(getConfigRoute, async (c): Promise<any> => {
|
|
529
|
-
const agentId = c.req.param("agentId") || "";
|
|
530
|
-
const payload = await verifyToken(verifySettingsSessionOrToken(c), agentId);
|
|
531
|
-
if (!payload) return c.json({ error: "Unauthorized" }, 401);
|
|
532
|
-
const providerModels = await collectProviderModelOptions(
|
|
533
|
-
agentId,
|
|
534
|
-
payload.userId
|
|
535
|
-
);
|
|
536
|
-
return c.json(
|
|
537
|
-
await buildResolvedConfigResponse(
|
|
538
|
-
config,
|
|
539
|
-
agentId,
|
|
540
|
-
payload,
|
|
541
|
-
providerModels
|
|
542
|
-
)
|
|
543
|
-
);
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
// --- Provider Catalog Endpoints ---
|
|
547
|
-
|
|
548
|
-
// GET /providers/catalog
|
|
549
|
-
app.get("/providers/catalog", async (c): Promise<any> => {
|
|
550
|
-
const agentId = c.req.param("agentId") || "";
|
|
551
|
-
const payload = await verifyToken(verifySettingsSessionOrToken(c), agentId);
|
|
552
|
-
if (!payload) return c.json({ error: "Unauthorized" }, 401);
|
|
553
|
-
|
|
554
|
-
if (!config.providerCatalogService) {
|
|
555
|
-
return c.json({ error: "Provider catalog not available" }, 503);
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
const allProviders = config.providerCatalogService.listCatalogProviders();
|
|
559
|
-
const effectiveSettings =
|
|
560
|
-
await config.agentSettingsStore.getEffectiveSettings(agentId);
|
|
561
|
-
const installed = effectiveSettings?.installedProviders || [];
|
|
562
|
-
const installedIds = new Set(installed.map((ip) => ip.providerId));
|
|
563
|
-
|
|
564
|
-
const catalog = allProviders.map((p) => ({
|
|
565
|
-
providerId: p.providerId,
|
|
566
|
-
name: p.providerDisplayName,
|
|
567
|
-
iconUrl: p.providerIconUrl || "",
|
|
568
|
-
authType: p.authType || "api-key",
|
|
569
|
-
description: p.catalogDescription || "",
|
|
570
|
-
installed: installedIds.has(p.providerId),
|
|
571
|
-
}));
|
|
572
|
-
|
|
573
|
-
return c.json({ catalog, installedProviders: installed });
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
// ===== Grant Endpoints (read-only) =====
|
|
577
|
-
|
|
578
|
-
if (config.grantStore) {
|
|
579
|
-
const grantStore = config.grantStore;
|
|
580
|
-
|
|
581
|
-
// GET /grants - List all active grants
|
|
582
|
-
app.get("/grants", async (c) => {
|
|
583
|
-
const agentId = c.req.param("agentId") || "";
|
|
584
|
-
const payload = await verifyToken(
|
|
585
|
-
verifySettingsSessionOrToken(c),
|
|
586
|
-
agentId
|
|
587
|
-
);
|
|
588
|
-
if (!payload) return c.json({ error: "Unauthorized" }, 401);
|
|
589
|
-
|
|
590
|
-
const grants = await grantStore.listGrants(agentId);
|
|
591
|
-
return c.json(grants);
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
return app;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
function sanitizeSettingsForResponse(
|
|
599
|
-
settings: AgentSettings | null
|
|
600
|
-
): PublicAgentSettings | Record<string, never> {
|
|
601
|
-
if (!settings) return {};
|
|
602
|
-
|
|
603
|
-
const sanitized = redactSensitiveFields(settings) as PublicAgentSettings;
|
|
604
|
-
|
|
605
|
-
if (sanitized.skillsConfig?.skills) {
|
|
606
|
-
sanitized.skillsConfig = {
|
|
607
|
-
skills: sanitized.skillsConfig.skills.map((skill) => {
|
|
608
|
-
const legacySkill = skill as SkillConfig & {
|
|
609
|
-
integrations?: unknown;
|
|
610
|
-
};
|
|
611
|
-
const {
|
|
612
|
-
integrations: _integrations,
|
|
613
|
-
modelPreference: _modelPreference,
|
|
614
|
-
thinkingLevel: _thinkingLevel,
|
|
615
|
-
...rest
|
|
616
|
-
} = legacySkill;
|
|
617
|
-
return rest;
|
|
618
|
-
}),
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
if (Array.isArray(settings.authProfiles)) {
|
|
623
|
-
sanitized.authProfiles = settings.authProfiles.map(sanitizeAuthProfile);
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
return sanitized;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
function sanitizeAuthProfile(profile: AuthProfile): SanitizedAuthProfile {
|
|
630
|
-
const hadRefreshToken = !!profile.metadata?.refreshToken;
|
|
631
|
-
const metadata = profile.metadata
|
|
632
|
-
? (redactSensitiveFields(
|
|
633
|
-
profile.metadata
|
|
634
|
-
) as SanitizedAuthProfile["metadata"])
|
|
635
|
-
: undefined;
|
|
636
|
-
|
|
637
|
-
if (metadata && hadRefreshToken) {
|
|
638
|
-
metadata.refreshTokenRedacted = true;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
return {
|
|
642
|
-
...profile,
|
|
643
|
-
credential: REDACTED_VALUE,
|
|
644
|
-
credentialRedacted: true,
|
|
645
|
-
metadata,
|
|
646
|
-
};
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
function redactSensitiveFields(value: unknown): unknown {
|
|
650
|
-
if (Array.isArray(value)) {
|
|
651
|
-
return value.map((entry) => redactSensitiveFields(entry));
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
if (!value || typeof value !== "object") {
|
|
655
|
-
return value;
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
const input = value as Record<string, unknown>;
|
|
659
|
-
const output: Record<string, unknown> = {};
|
|
660
|
-
|
|
661
|
-
for (const [key, rawValue] of Object.entries(input)) {
|
|
662
|
-
if (
|
|
663
|
-
typeof rawValue === "string" &&
|
|
664
|
-
rawValue.length > 0 &&
|
|
665
|
-
SENSITIVE_KEY_PATTERN.test(key)
|
|
666
|
-
) {
|
|
667
|
-
output[key] = REDACTED_VALUE;
|
|
668
|
-
continue;
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
output[key] = redactSensitiveFields(rawValue);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
return output;
|
|
675
|
-
}
|