@lobu/gateway 3.0.5 → 3.0.7

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.
Files changed (175) hide show
  1. package/package.json +2 -2
  2. package/src/__tests__/agent-config-routes.test.ts +254 -0
  3. package/src/__tests__/agent-history-routes.test.ts +72 -0
  4. package/src/__tests__/agent-routes.test.ts +68 -0
  5. package/src/__tests__/agent-schedules-routes.test.ts +59 -0
  6. package/src/__tests__/agent-settings-store.test.ts +323 -0
  7. package/src/__tests__/chat-instance-manager-slack.test.ts +204 -0
  8. package/src/__tests__/chat-response-bridge.test.ts +131 -0
  9. package/src/__tests__/config-memory-plugins.test.ts +92 -0
  10. package/src/__tests__/config-request-store.test.ts +127 -0
  11. package/src/__tests__/connection-routes.test.ts +144 -0
  12. package/src/__tests__/core-services-store-selection.test.ts +92 -0
  13. package/src/__tests__/docker-deployment.test.ts +1211 -0
  14. package/src/__tests__/embedded-deployment.test.ts +342 -0
  15. package/src/__tests__/grant-store.test.ts +148 -0
  16. package/src/__tests__/http-proxy.test.ts +281 -0
  17. package/src/__tests__/instruction-service.test.ts +37 -0
  18. package/src/__tests__/link-buttons.test.ts +112 -0
  19. package/src/__tests__/lobu.test.ts +32 -0
  20. package/src/__tests__/mcp-config-service.test.ts +347 -0
  21. package/src/__tests__/mcp-proxy.test.ts +696 -0
  22. package/src/__tests__/message-handler-bridge.test.ts +17 -0
  23. package/src/__tests__/model-selection.test.ts +172 -0
  24. package/src/__tests__/oauth-templates.test.ts +39 -0
  25. package/src/__tests__/platform-adapter-slack-send.test.ts +114 -0
  26. package/src/__tests__/platform-helpers-model-resolution.test.ts +253 -0
  27. package/src/__tests__/provider-inheritance.test.ts +212 -0
  28. package/src/__tests__/routes/cli-auth.test.ts +337 -0
  29. package/src/__tests__/routes/interactions.test.ts +121 -0
  30. package/src/__tests__/secret-proxy.test.ts +85 -0
  31. package/src/__tests__/session-manager.test.ts +572 -0
  32. package/src/__tests__/setup.ts +133 -0
  33. package/src/__tests__/skill-and-mcp-registry.test.ts +203 -0
  34. package/src/__tests__/slack-routes.test.ts +161 -0
  35. package/src/__tests__/system-config-resolver.test.ts +75 -0
  36. package/src/__tests__/system-message-limiter.test.ts +89 -0
  37. package/src/__tests__/system-skills-service.test.ts +362 -0
  38. package/src/__tests__/transcription-service.test.ts +222 -0
  39. package/src/__tests__/utils/rate-limiter.test.ts +102 -0
  40. package/src/__tests__/worker-connection-manager.test.ts +497 -0
  41. package/src/__tests__/worker-job-router.test.ts +722 -0
  42. package/src/api/index.ts +1 -0
  43. package/src/api/platform.ts +292 -0
  44. package/src/api/response-renderer.ts +157 -0
  45. package/src/auth/agent-metadata-store.ts +168 -0
  46. package/src/auth/api-auth-middleware.ts +69 -0
  47. package/src/auth/api-key-provider-module.ts +213 -0
  48. package/src/auth/base-provider-module.ts +201 -0
  49. package/src/auth/chatgpt/chatgpt-oauth-module.ts +185 -0
  50. package/src/auth/chatgpt/device-code-client.ts +218 -0
  51. package/src/auth/chatgpt/index.ts +1 -0
  52. package/src/auth/claude/oauth-module.ts +280 -0
  53. package/src/auth/cli/token-service.ts +249 -0
  54. package/src/auth/external/client.ts +560 -0
  55. package/src/auth/external/device-code-client.ts +225 -0
  56. package/src/auth/mcp/config-service.ts +392 -0
  57. package/src/auth/mcp/proxy.ts +1088 -0
  58. package/src/auth/mcp/string-substitution.ts +17 -0
  59. package/src/auth/mcp/tool-cache.ts +90 -0
  60. package/src/auth/oauth/base-client.ts +267 -0
  61. package/src/auth/oauth/client.ts +153 -0
  62. package/src/auth/oauth/credentials.ts +7 -0
  63. package/src/auth/oauth/providers.ts +69 -0
  64. package/src/auth/oauth/state-store.ts +150 -0
  65. package/src/auth/oauth-templates.ts +179 -0
  66. package/src/auth/provider-catalog.ts +220 -0
  67. package/src/auth/provider-model-options.ts +41 -0
  68. package/src/auth/settings/agent-settings-store.ts +565 -0
  69. package/src/auth/settings/auth-profiles-manager.ts +216 -0
  70. package/src/auth/settings/index.ts +12 -0
  71. package/src/auth/settings/model-preference-store.ts +52 -0
  72. package/src/auth/settings/model-selection.ts +135 -0
  73. package/src/auth/settings/resolved-settings-view.ts +298 -0
  74. package/src/auth/settings/template-utils.ts +44 -0
  75. package/src/auth/settings/token-service.ts +88 -0
  76. package/src/auth/system-env-store.ts +98 -0
  77. package/src/auth/user-agents-store.ts +68 -0
  78. package/src/channels/binding-service.ts +214 -0
  79. package/src/channels/index.ts +4 -0
  80. package/src/cli/gateway.ts +1304 -0
  81. package/src/cli/index.ts +74 -0
  82. package/src/commands/built-in-commands.ts +80 -0
  83. package/src/commands/command-dispatcher.ts +94 -0
  84. package/src/commands/command-reply-adapters.ts +27 -0
  85. package/src/config/file-loader.ts +618 -0
  86. package/src/config/index.ts +588 -0
  87. package/src/config/network-allowlist.ts +71 -0
  88. package/src/connections/chat-instance-manager.ts +1284 -0
  89. package/src/connections/chat-response-bridge.ts +618 -0
  90. package/src/connections/index.ts +7 -0
  91. package/src/connections/interaction-bridge.ts +831 -0
  92. package/src/connections/message-handler-bridge.ts +415 -0
  93. package/src/connections/platform-auth-methods.ts +15 -0
  94. package/src/connections/types.ts +84 -0
  95. package/src/gateway/connection-manager.ts +291 -0
  96. package/src/gateway/index.ts +700 -0
  97. package/src/gateway/job-router.ts +201 -0
  98. package/src/gateway-main.ts +200 -0
  99. package/src/index.ts +41 -0
  100. package/src/infrastructure/queue/index.ts +12 -0
  101. package/src/infrastructure/queue/queue-producer.ts +148 -0
  102. package/src/infrastructure/queue/redis-queue.ts +361 -0
  103. package/src/infrastructure/queue/types.ts +133 -0
  104. package/src/infrastructure/redis/system-message-limiter.ts +94 -0
  105. package/src/interactions/config-request-store.ts +198 -0
  106. package/src/interactions.ts +363 -0
  107. package/src/lobu.ts +311 -0
  108. package/src/metrics/prometheus.ts +159 -0
  109. package/src/modules/module-system.ts +179 -0
  110. package/src/orchestration/base-deployment-manager.ts +900 -0
  111. package/src/orchestration/deployment-utils.ts +98 -0
  112. package/src/orchestration/impl/docker-deployment.ts +620 -0
  113. package/src/orchestration/impl/embedded-deployment.ts +268 -0
  114. package/src/orchestration/impl/index.ts +8 -0
  115. package/src/orchestration/impl/k8s/deployment.ts +1061 -0
  116. package/src/orchestration/impl/k8s/helpers.ts +610 -0
  117. package/src/orchestration/impl/k8s/index.ts +1 -0
  118. package/src/orchestration/index.ts +333 -0
  119. package/src/orchestration/message-consumer.ts +584 -0
  120. package/src/orchestration/scheduled-wakeup.ts +704 -0
  121. package/src/permissions/approval-policy.ts +36 -0
  122. package/src/permissions/grant-store.ts +219 -0
  123. package/src/platform/file-handler.ts +66 -0
  124. package/src/platform/link-buttons.ts +57 -0
  125. package/src/platform/renderer-utils.ts +44 -0
  126. package/src/platform/response-renderer.ts +84 -0
  127. package/src/platform/unified-thread-consumer.ts +187 -0
  128. package/src/platform.ts +318 -0
  129. package/src/proxy/http-proxy.ts +752 -0
  130. package/src/proxy/proxy-manager.ts +81 -0
  131. package/src/proxy/secret-proxy.ts +402 -0
  132. package/src/proxy/token-refresh-job.ts +143 -0
  133. package/src/routes/internal/audio.ts +141 -0
  134. package/src/routes/internal/device-auth.ts +566 -0
  135. package/src/routes/internal/files.ts +226 -0
  136. package/src/routes/internal/history.ts +69 -0
  137. package/src/routes/internal/images.ts +127 -0
  138. package/src/routes/internal/interactions.ts +84 -0
  139. package/src/routes/internal/middleware.ts +23 -0
  140. package/src/routes/internal/schedule.ts +226 -0
  141. package/src/routes/internal/types.ts +22 -0
  142. package/src/routes/openapi-auto.ts +239 -0
  143. package/src/routes/public/agent-access.ts +23 -0
  144. package/src/routes/public/agent-config.ts +675 -0
  145. package/src/routes/public/agent-history.ts +422 -0
  146. package/src/routes/public/agent-schedules.ts +296 -0
  147. package/src/routes/public/agent.ts +1086 -0
  148. package/src/routes/public/agents.ts +373 -0
  149. package/src/routes/public/channels.ts +191 -0
  150. package/src/routes/public/cli-auth.ts +883 -0
  151. package/src/routes/public/connections.ts +574 -0
  152. package/src/routes/public/landing.ts +16 -0
  153. package/src/routes/public/oauth.ts +147 -0
  154. package/src/routes/public/settings-auth.ts +104 -0
  155. package/src/routes/public/slack.ts +173 -0
  156. package/src/routes/shared/agent-ownership.ts +101 -0
  157. package/src/routes/shared/token-verifier.ts +34 -0
  158. package/src/services/core-services.ts +1053 -0
  159. package/src/services/image-generation-service.ts +257 -0
  160. package/src/services/instruction-service.ts +318 -0
  161. package/src/services/mcp-registry.ts +94 -0
  162. package/src/services/platform-helpers.ts +287 -0
  163. package/src/services/session-manager.ts +262 -0
  164. package/src/services/settings-resolver.ts +74 -0
  165. package/src/services/system-config-resolver.ts +90 -0
  166. package/src/services/system-skills-service.ts +229 -0
  167. package/src/services/transcription-service.ts +684 -0
  168. package/src/session.ts +110 -0
  169. package/src/spaces/index.ts +1 -0
  170. package/src/spaces/space-resolver.ts +17 -0
  171. package/src/stores/in-memory-agent-store.ts +403 -0
  172. package/src/stores/redis-agent-store.ts +279 -0
  173. package/src/utils/public-url.ts +44 -0
  174. package/src/utils/rate-limiter.ts +94 -0
  175. package/tsconfig.json +33 -0
@@ -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
+ }