@lobu/gateway 3.0.5 → 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/src/cli/index.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { ConfigError, createLogger, initSentry, initTracing } from "@lobu/core";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import {
|
|
6
|
+
buildGatewayConfig,
|
|
7
|
+
displayGatewayConfig,
|
|
8
|
+
loadEnvFile,
|
|
9
|
+
} from "../config";
|
|
10
|
+
import { startGateway } from "./gateway";
|
|
11
|
+
|
|
12
|
+
const logger = createLogger("cli");
|
|
13
|
+
|
|
14
|
+
async function main() {
|
|
15
|
+
const program = new Command();
|
|
16
|
+
|
|
17
|
+
program
|
|
18
|
+
.name("lobu-gateway")
|
|
19
|
+
.description(
|
|
20
|
+
"Lobu gateway service — API-driven platform connections via Chat SDK"
|
|
21
|
+
)
|
|
22
|
+
.version("1.0.0");
|
|
23
|
+
|
|
24
|
+
program
|
|
25
|
+
.option("--env <path>", "Path to .env file (default: .env)")
|
|
26
|
+
.option("--validate", "Validate configuration and exit")
|
|
27
|
+
.option("--show-config", "Display parsed configuration and exit")
|
|
28
|
+
.action(async (options) => {
|
|
29
|
+
try {
|
|
30
|
+
loadEnvFile(options.env);
|
|
31
|
+
|
|
32
|
+
await initSentry();
|
|
33
|
+
|
|
34
|
+
initTracing({
|
|
35
|
+
serviceName: "lobu-gateway",
|
|
36
|
+
serviceVersion: process.env.npm_package_version || "2.0.0",
|
|
37
|
+
tempoEndpoint: process.env.TEMPO_ENDPOINT,
|
|
38
|
+
enabled: !!process.env.TEMPO_ENDPOINT,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const config = buildGatewayConfig();
|
|
42
|
+
|
|
43
|
+
if (options.validate) {
|
|
44
|
+
console.log("Configuration is valid");
|
|
45
|
+
displayGatewayConfig(config);
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (options.showConfig) {
|
|
50
|
+
displayGatewayConfig(config);
|
|
51
|
+
process.exit(0);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
await startGateway(config);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (error instanceof ConfigError) {
|
|
57
|
+
logger.error("Configuration error:", error.message);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
logger.error(
|
|
61
|
+
"Failed to start gateway:",
|
|
62
|
+
error instanceof Error ? error.message : String(error)
|
|
63
|
+
);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await program.parseAsync(process.argv);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
main().catch((error) => {
|
|
72
|
+
logger.error("CLI error:", error);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { CommandContext, CommandRegistry } from "@lobu/core";
|
|
2
|
+
import type { AgentSettingsStore } from "../auth/settings";
|
|
3
|
+
import {
|
|
4
|
+
getModelSelectionState,
|
|
5
|
+
resolveEffectiveModelRef,
|
|
6
|
+
} from "../auth/settings/model-selection";
|
|
7
|
+
|
|
8
|
+
export interface BuiltInCommandDeps {
|
|
9
|
+
agentSettingsStore: AgentSettingsStore;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Register all built-in slash commands on the given registry.
|
|
14
|
+
*/
|
|
15
|
+
export function registerBuiltInCommands(
|
|
16
|
+
registry: CommandRegistry,
|
|
17
|
+
deps: BuiltInCommandDeps
|
|
18
|
+
): void {
|
|
19
|
+
registry.register({
|
|
20
|
+
name: "new",
|
|
21
|
+
description: "Save context to memory and start a fresh session",
|
|
22
|
+
handler: async (ctx: CommandContext) => {
|
|
23
|
+
// Handled by message-handler-bridge before slash dispatch
|
|
24
|
+
await ctx.reply("Starting new session...");
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
registry.register({
|
|
29
|
+
name: "clear",
|
|
30
|
+
description: "Clear chat history and start fresh",
|
|
31
|
+
handler: async (ctx: CommandContext) => {
|
|
32
|
+
// Handled by message-handler-bridge before slash dispatch
|
|
33
|
+
await ctx.reply("Chat history cleared.");
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
registry.register({
|
|
38
|
+
name: "help",
|
|
39
|
+
description: "Show available commands",
|
|
40
|
+
handler: async (ctx: CommandContext) => {
|
|
41
|
+
const commands = registry.getAll();
|
|
42
|
+
const lines = commands.map((c) => `/${c.name} - ${c.description}`);
|
|
43
|
+
await ctx.reply(
|
|
44
|
+
`Available commands:\n${lines.join("\n")}\n\nYou can also just send a message to start a conversation with the agent.`
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
registry.register({
|
|
50
|
+
name: "status",
|
|
51
|
+
description: "Show current agent status",
|
|
52
|
+
handler: async (ctx: CommandContext) => {
|
|
53
|
+
if (!ctx.agentId) {
|
|
54
|
+
await ctx.reply("No agent is configured for this conversation yet.");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const settings = await deps.agentSettingsStore.getSettings(ctx.agentId);
|
|
59
|
+
|
|
60
|
+
const modelSelection = getModelSelectionState(settings);
|
|
61
|
+
const effectiveModel = resolveEffectiveModelRef(settings);
|
|
62
|
+
const model = effectiveModel || "auto";
|
|
63
|
+
const mcpCount = settings?.mcpServers
|
|
64
|
+
? Object.keys(settings.mcpServers).length
|
|
65
|
+
: 0;
|
|
66
|
+
const skillsCount = settings?.skillsConfig?.skills
|
|
67
|
+
? Object.keys(settings.skillsConfig.skills).length
|
|
68
|
+
: 0;
|
|
69
|
+
|
|
70
|
+
const parts = [
|
|
71
|
+
`Agent: ${ctx.agentId}`,
|
|
72
|
+
`Model: ${model} (${modelSelection.mode})`,
|
|
73
|
+
`MCP servers: ${mcpCount}`,
|
|
74
|
+
`Skills: ${skillsCount}`,
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
await ctx.reply(parts.join("\n"));
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type CommandContext,
|
|
3
|
+
type CommandRegistry,
|
|
4
|
+
createLogger,
|
|
5
|
+
} from "@lobu/core";
|
|
6
|
+
import type { ChannelBindingService } from "../channels";
|
|
7
|
+
import { platformAgentId } from "../spaces";
|
|
8
|
+
|
|
9
|
+
const logger = createLogger("command-dispatcher");
|
|
10
|
+
|
|
11
|
+
export interface CommandDispatchInput {
|
|
12
|
+
platform: string;
|
|
13
|
+
userId: string;
|
|
14
|
+
channelId: string;
|
|
15
|
+
teamId?: string;
|
|
16
|
+
isGroup: boolean;
|
|
17
|
+
conversationId?: string;
|
|
18
|
+
connectionId?: string;
|
|
19
|
+
reply: CommandContext["reply"];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface CommandDispatcherDeps {
|
|
23
|
+
registry: CommandRegistry;
|
|
24
|
+
channelBindingService: ChannelBindingService;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class CommandDispatcher {
|
|
28
|
+
private registry: CommandRegistry;
|
|
29
|
+
private channelBindingService: ChannelBindingService;
|
|
30
|
+
|
|
31
|
+
constructor(deps: CommandDispatcherDeps) {
|
|
32
|
+
this.registry = deps.registry;
|
|
33
|
+
this.channelBindingService = deps.channelBindingService;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async tryHandleSlashText(
|
|
37
|
+
rawText: string,
|
|
38
|
+
input: CommandDispatchInput
|
|
39
|
+
): Promise<boolean> {
|
|
40
|
+
const match = rawText.trim().match(/^\/(\w+)(?:\s+(.*))?$/);
|
|
41
|
+
if (!match?.[1]) return false;
|
|
42
|
+
return this.tryHandle(match[1], match[2]?.trim() || "", input);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async tryHandle(
|
|
46
|
+
commandName: string,
|
|
47
|
+
commandArgs: string,
|
|
48
|
+
input: CommandDispatchInput
|
|
49
|
+
): Promise<boolean> {
|
|
50
|
+
const agentId = await this.resolveAgentId(input);
|
|
51
|
+
|
|
52
|
+
logger.info(
|
|
53
|
+
{
|
|
54
|
+
platform: input.platform,
|
|
55
|
+
commandName,
|
|
56
|
+
userId: input.userId,
|
|
57
|
+
channelId: input.channelId,
|
|
58
|
+
teamId: input.teamId,
|
|
59
|
+
agentId,
|
|
60
|
+
},
|
|
61
|
+
"Dispatching command"
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return this.registry.tryHandle(commandName, {
|
|
65
|
+
userId: input.userId,
|
|
66
|
+
channelId: input.channelId,
|
|
67
|
+
conversationId: input.conversationId,
|
|
68
|
+
connectionId: input.connectionId,
|
|
69
|
+
agentId,
|
|
70
|
+
args: commandArgs,
|
|
71
|
+
platform: input.platform,
|
|
72
|
+
reply: input.reply,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private async resolveAgentId(input: CommandDispatchInput): Promise<string> {
|
|
77
|
+
// Check channel binding first (Slack multi-tenant)
|
|
78
|
+
const binding = await this.channelBindingService.getBinding(
|
|
79
|
+
input.platform,
|
|
80
|
+
input.channelId,
|
|
81
|
+
input.teamId
|
|
82
|
+
);
|
|
83
|
+
if (binding?.agentId) {
|
|
84
|
+
return binding.agentId;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return platformAgentId(
|
|
88
|
+
input.platform,
|
|
89
|
+
input.userId,
|
|
90
|
+
input.channelId,
|
|
91
|
+
input.isGroup
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CommandContext } from "@lobu/core";
|
|
2
|
+
|
|
3
|
+
export function createChatReply(
|
|
4
|
+
postFn: (content: any) => Promise<void>
|
|
5
|
+
): CommandContext["reply"] {
|
|
6
|
+
return async (text, options) => {
|
|
7
|
+
if (options?.url) {
|
|
8
|
+
const { Card, CardText, Actions, LinkButton } = await import("chat");
|
|
9
|
+
const linkButton: any = LinkButton({
|
|
10
|
+
url: options.url,
|
|
11
|
+
label: options.urlLabel || "Open",
|
|
12
|
+
});
|
|
13
|
+
if (options.webApp) {
|
|
14
|
+
linkButton.webApp = true;
|
|
15
|
+
}
|
|
16
|
+
const card = Card({
|
|
17
|
+
children: [CardText(text), Actions([linkButton])],
|
|
18
|
+
});
|
|
19
|
+
await postFn({
|
|
20
|
+
card,
|
|
21
|
+
fallbackText: `${text}\n${options.urlLabel || "Open"}: ${options.url}`,
|
|
22
|
+
});
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
await postFn(text);
|
|
26
|
+
};
|
|
27
|
+
}
|