feat: wire new providers, auth, mention-gating, and browser into daemon
Update config schema with server auth fields (token, tailscale_identity, auth_http), channel mention settings, browser config, and openrouter/bedrock provider enum values. Wire GeminiClient, BedrockClient, OpenRouter into createClientFromConfig. Initialize BrowserManager and register browser tools in daemon startup. Pass auth config and channel mention settings through to gateway and adapters. Add puppeteer-core, @google/generative-ai, and @aws-sdk/client-bedrock-runtime dependencies.
This commit is contained in:
@@ -40,6 +40,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.39.0",
|
||||
"@aws-sdk/client-bedrock-runtime": "^3.985.0",
|
||||
"@google/generative-ai": "^0.24.1",
|
||||
"@modelcontextprotocol/sdk": "^1.26.0",
|
||||
"@mozilla/readability": "^0.5.0",
|
||||
"@slack/bolt": "^4.6.0",
|
||||
@@ -56,6 +58,7 @@
|
||||
"marked-terminal": "^7.3.0",
|
||||
"ollama": "^0.5.0",
|
||||
"openai": "^4.0.0",
|
||||
"puppeteer-core": "^24.37.2",
|
||||
"react": "^19.0.0",
|
||||
"turndown": "^7.2.0",
|
||||
"whatsapp-web.js": "^1.34.6",
|
||||
|
||||
Generated
+1083
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1,2 +1,2 @@
|
||||
export { loadConfig } from './loader.js';
|
||||
export { configSchema, type Config, type TelegramConfig, type ModelConfig, type CronJobConfig, type AgentsConfig, type CompactionConfig, type ToolProfile, type ToolOverrideConfig, type ToolsConfig, type SandboxConfig, type AgentConfigEntry, type RoutingConfig } from './schema.js';
|
||||
export { configSchema, type Config, type TelegramConfig, type ModelConfig, type CronJobConfig, type AgentsConfig, type CompactionConfig, type ToolProfile, type ToolOverrideConfig, type ToolsConfig, type SandboxConfig, type AgentConfigEntry, type RoutingConfig, type ServerConfig } from './schema.js';
|
||||
|
||||
+23
-1
@@ -3,16 +3,23 @@ import { z } from 'zod';
|
||||
const telegramSchema = z.object({
|
||||
bot_token: z.string().min(1, 'Bot token is required'),
|
||||
allowed_chat_ids: z.array(z.number()).min(1, 'At least one chat ID required'),
|
||||
require_mention: z.boolean().default(true),
|
||||
});
|
||||
|
||||
const serverSchema = z.object({
|
||||
tailscale_only: z.boolean().default(true),
|
||||
localhost: z.boolean().default(true),
|
||||
port: z.number().default(18800),
|
||||
/** Static bearer token for gateway auth. If set, all connections must provide it. */
|
||||
token: z.string().optional(),
|
||||
/** Trust Tailscale-User-Login header for identity. */
|
||||
tailscale_identity: z.boolean().default(false),
|
||||
/** Apply token auth to HTTP requests too (not just WebSocket). Default: true when token is set. */
|
||||
auth_http: z.boolean().default(true),
|
||||
});
|
||||
|
||||
const modelConfigSchema = z.object({
|
||||
provider: z.enum(['anthropic', 'openai', 'gemini', 'ollama', 'llamacpp']),
|
||||
provider: z.enum(['anthropic', 'openai', 'gemini', 'ollama', 'llamacpp', 'openrouter', 'bedrock']),
|
||||
model: z.string(),
|
||||
endpoint: z.string().optional(),
|
||||
api_key: z.string().optional(),
|
||||
@@ -133,13 +140,25 @@ const slackSchema = z.object({
|
||||
app_token: z.string().min(1, 'App token is required'),
|
||||
signing_secret: z.string().min(1, 'Signing secret is required'),
|
||||
allowed_channel_ids: z.array(z.string()).default([]),
|
||||
require_mention: z.boolean().default(false),
|
||||
}).optional();
|
||||
|
||||
const whatsappSchema = z.object({
|
||||
allowed_numbers: z.array(z.string()).default([]),
|
||||
allowed_group_ids: z.array(z.string()).default([]),
|
||||
require_mention: z.boolean().default(true),
|
||||
data_dir: z.string().optional(),
|
||||
}).optional();
|
||||
|
||||
const browserSchema = z.object({
|
||||
enabled: z.boolean().default(false),
|
||||
executable_path: z.string().optional(),
|
||||
ws_endpoint: z.string().optional(),
|
||||
headless: z.boolean().default(true),
|
||||
max_pages: z.number().min(1).max(20).default(5),
|
||||
default_timeout: z.number().min(1000).max(120000).default(30000),
|
||||
}).default({});
|
||||
|
||||
const processSchema = z.object({
|
||||
max_concurrent: z.number().min(1).max(50).default(10),
|
||||
max_runtime_minutes: z.number().min(1).max(1440).default(60),
|
||||
@@ -237,6 +256,7 @@ export const configSchema = z.object({
|
||||
compaction: compactionSchema,
|
||||
memory: memorySchema,
|
||||
process: processSchema,
|
||||
browser: browserSchema,
|
||||
retry: retrySchema,
|
||||
web_search: webSearchSchema,
|
||||
prompt: promptSchema,
|
||||
@@ -255,6 +275,7 @@ export type CompactionConfig = z.infer<typeof compactionSchema>;
|
||||
export type MemoryConfig = z.infer<typeof memorySchema>;
|
||||
export type WebSearchConfig = z.infer<typeof webSearchSchema>;
|
||||
export type ProcessConfig = z.infer<typeof processSchema>;
|
||||
export type BrowserConfig = z.infer<typeof browserSchema>;
|
||||
export type DiscordConfig = z.infer<typeof discordSchema>;
|
||||
export type SlackConfig = z.infer<typeof slackSchema>;
|
||||
export type WhatsAppConfig = z.infer<typeof whatsappSchema>;
|
||||
@@ -266,3 +287,4 @@ export type ToolsConfig = z.infer<typeof toolsSchema>;
|
||||
export type SandboxConfig = z.infer<typeof sandboxSchema>;
|
||||
export type AgentConfigEntry = z.infer<typeof agentConfigEntrySchema>;
|
||||
export type RoutingConfig = z.infer<typeof routingSchema>;
|
||||
export type ServerConfig = z.infer<typeof serverSchema>;
|
||||
|
||||
+53
-5
@@ -1,11 +1,11 @@
|
||||
import { Lifecycle } from './lifecycle.js';
|
||||
import type { Config, ModelConfig } from '../config/index.js';
|
||||
import { AnthropicClient, OpenAIClient, OllamaClient, LlamaCppClient, ModelRouter, DEFAULT_RETRY_CONFIG } from '../models/index.js';
|
||||
import { AnthropicClient, OpenAIClient, OllamaClient, LlamaCppClient, GeminiClient, BedrockClient, ModelRouter, DEFAULT_RETRY_CONFIG } from '../models/index.js';
|
||||
import type { ModelClient, RetryConfig } from '../models/index.js';
|
||||
import { AgentOrchestrator, type DelegationConfig } from '../backends/index.js';
|
||||
import { SessionStore, SessionManager } from '../session/index.js';
|
||||
import { HookEngine } from '../hooks/index.js';
|
||||
import { ToolRegistry, ToolExecutor, ToolPolicy, allBuiltinTools, createWebSearchTools, createProcessTools, ProcessManager } from '../tools/index.js';
|
||||
import { ToolRegistry, ToolExecutor, ToolPolicy, allBuiltinTools, createWebSearchTools, createProcessTools, ProcessManager, BrowserManager, createBrowserTools } from '../tools/index.js';
|
||||
import type { Tool } from '../tools/types.js';
|
||||
import { MemoryStore } from '../memory/index.js';
|
||||
import { createMemoryTools } from '../tools/builtin/index.js';
|
||||
@@ -39,6 +39,7 @@ export interface DaemonContext {
|
||||
agentConfigRegistry: AgentConfigRegistry;
|
||||
agentRouter: AgentRouter;
|
||||
sandboxManager?: SandboxManager;
|
||||
browserManager?: BrowserManager;
|
||||
}
|
||||
|
||||
function loadSystemPrompt(config: Config): string {
|
||||
@@ -91,12 +92,23 @@ export function createClientFromConfig(cfg: ModelConfig): ModelClient {
|
||||
authToken: cfg.auth_token,
|
||||
});
|
||||
case 'gemini':
|
||||
// Gemini support not yet implemented — fall back to OpenAI-compatible client
|
||||
console.warn(`Gemini provider not yet implemented for model "${cfg.model}", using OpenAI-compatible client`);
|
||||
return new OpenAIClient({
|
||||
return new GeminiClient({
|
||||
model: cfg.model,
|
||||
apiKey: cfg.api_key,
|
||||
});
|
||||
case 'openrouter':
|
||||
return new OpenAIClient({
|
||||
model: cfg.model,
|
||||
apiKey: cfg.api_key ?? process.env.OPENROUTER_API_KEY,
|
||||
baseURL: cfg.endpoint ?? 'https://openrouter.ai/api/v1',
|
||||
});
|
||||
case 'bedrock':
|
||||
return new BedrockClient({
|
||||
model: cfg.model,
|
||||
region: cfg.endpoint,
|
||||
accessKeyId: cfg.api_key,
|
||||
secretAccessKey: cfg.auth_token,
|
||||
});
|
||||
default:
|
||||
throw new Error(`Unknown model provider: ${(cfg as Record<string, unknown>).provider}`);
|
||||
}
|
||||
@@ -415,6 +427,28 @@ export async function startDaemon(config: Config): Promise<DaemonContext> {
|
||||
console.log('Process manager stopped');
|
||||
});
|
||||
|
||||
// Initialize browser manager and register browser tools (if enabled)
|
||||
let browserManager: BrowserManager | undefined;
|
||||
if (config.browser?.enabled) {
|
||||
browserManager = new BrowserManager({
|
||||
executablePath: config.browser.executable_path,
|
||||
wsEndpoint: config.browser.ws_endpoint,
|
||||
headless: config.browser.headless,
|
||||
maxPages: config.browser.max_pages,
|
||||
defaultTimeout: config.browser.default_timeout,
|
||||
});
|
||||
|
||||
for (const tool of createBrowserTools(browserManager)) {
|
||||
toolRegistry.register(tool);
|
||||
}
|
||||
console.log(`Browser tools enabled (headless=${config.browser.headless})`);
|
||||
|
||||
lifecycle.onShutdown(async () => {
|
||||
await browserManager!.shutdown();
|
||||
console.log('Browser manager stopped');
|
||||
});
|
||||
}
|
||||
|
||||
const toolExecutor = new ToolExecutor(toolRegistry, hookEngine);
|
||||
|
||||
// Initialize tool policy from config
|
||||
@@ -505,6 +539,11 @@ export async function startDaemon(config: Config): Promise<DaemonContext> {
|
||||
systemPrompt,
|
||||
toolRegistry,
|
||||
toolExecutor,
|
||||
auth: {
|
||||
token: config.server.token,
|
||||
tailscaleIdentity: config.server.tailscale_identity,
|
||||
},
|
||||
authHttp: config.server.auth_http,
|
||||
uiDir: resolve(import.meta.dirname, '../gateway/ui'),
|
||||
config,
|
||||
restart: async () => {
|
||||
@@ -515,6 +554,10 @@ export async function startDaemon(config: Config): Promise<DaemonContext> {
|
||||
},
|
||||
});
|
||||
|
||||
if (config.server.token) {
|
||||
console.log(`Gateway auth: token required${config.server.tailscale_identity ? ' + Tailscale identity' : ''}`);
|
||||
}
|
||||
|
||||
// ── Channel Registry ──────────────────────────────────────────
|
||||
|
||||
const channelRegistry = new ChannelRegistry();
|
||||
@@ -537,6 +580,7 @@ export async function startDaemon(config: Config): Promise<DaemonContext> {
|
||||
const telegramAdapter = new TelegramAdapter({
|
||||
botToken: config.telegram.bot_token,
|
||||
allowedChatIds: config.telegram.allowed_chat_ids,
|
||||
requireMention: config.telegram.require_mention,
|
||||
hookEngine,
|
||||
});
|
||||
channelRegistry.register(telegramAdapter);
|
||||
@@ -559,6 +603,7 @@ export async function startDaemon(config: Config): Promise<DaemonContext> {
|
||||
appToken: config.slack.app_token,
|
||||
signingSecret: config.slack.signing_secret,
|
||||
allowedChannelIds: config.slack.allowed_channel_ids.length > 0 ? config.slack.allowed_channel_ids : undefined,
|
||||
requireMention: config.slack.require_mention,
|
||||
});
|
||||
channelRegistry.register(slackAdapter);
|
||||
}
|
||||
@@ -567,6 +612,8 @@ export async function startDaemon(config: Config): Promise<DaemonContext> {
|
||||
if (config.whatsapp) {
|
||||
const whatsappAdapter = new WhatsAppAdapter({
|
||||
allowedNumbers: config.whatsapp.allowed_numbers.length > 0 ? config.whatsapp.allowed_numbers : undefined,
|
||||
allowedGroupIds: config.whatsapp.allowed_group_ids.length > 0 ? config.whatsapp.allowed_group_ids : undefined,
|
||||
requireMention: config.whatsapp.require_mention,
|
||||
dataDir: config.whatsapp.data_dir,
|
||||
});
|
||||
channelRegistry.register(whatsappAdapter);
|
||||
@@ -635,6 +682,7 @@ export async function startDaemon(config: Config): Promise<DaemonContext> {
|
||||
agentConfigRegistry,
|
||||
agentRouter,
|
||||
sandboxManager,
|
||||
browserManager,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user