feat: HTTP /v1/chat/completions + WS bridge + process manager
Real first cut. OpenClaw routes agent turns via /v1/chat/completions (OpenAI-compatible SSE) into our bridge. Bridge ensures a long-lived claude process per session-key, pushes the user message as notifications/claude/channel into the running Claude Code, awaits a reply via the WS connection, streams the reply back as SSE deltas. - core/process-manager: spawn / track / reap claude processes, auto-confirm the --dangerously-load-development-channels dev-mode prompt by piping "1\n" to stdin shortly after spawn - web/bridge-server: unified HTTP + WS server, per-session FIFO queue, SSE heartbeat (empty content delta — SSE comments don't reset OpenClaw's idle watchdog), reply buffering for streaming progress chunks - index.ts: definePluginEntry for OpenClaw runtime + standalone-mode main for laptop smoke testing (just `bun index.ts`) Same-machine simplifications: no bridge token, no permission_request reverse channel. Session key = agent_id::chat_id (contractor-agent convention).
This commit is contained in:
@@ -3,22 +3,22 @@ import { resolve as resolvePath } from 'node:path'
|
||||
|
||||
export interface SynthesisConfig {
|
||||
bridgePort: number
|
||||
bridgeToken: string
|
||||
claudePluginRef: string
|
||||
channelWsPort: number
|
||||
permissionMode: string
|
||||
idleKillMs: number
|
||||
maxProcesses: number
|
||||
mappingDbPath: string
|
||||
channelName: string
|
||||
}
|
||||
|
||||
const DEFAULTS: SynthesisConfig = {
|
||||
bridgePort: 18801,
|
||||
bridgeToken: 'synthesis-local',
|
||||
claudePluginRef: 'plugin:synthesis-claude@local',
|
||||
permissionMode: 'acceptEdits',
|
||||
bridgePort: 18900,
|
||||
channelWsPort: 18901,
|
||||
permissionMode: 'bypassPermissions',
|
||||
idleKillMs: 3_600_000,
|
||||
maxProcesses: 16,
|
||||
mappingDbPath: '~/.openclaw/synthesis/sessions.json',
|
||||
channelName: 'synthesis',
|
||||
}
|
||||
|
||||
function expand(p: string): string {
|
||||
@@ -30,12 +30,12 @@ export function normalizeConfig(raw: unknown): SynthesisConfig {
|
||||
const r = (raw ?? {}) as Partial<SynthesisConfig>
|
||||
const merged: SynthesisConfig = {
|
||||
bridgePort: typeof r.bridgePort === 'number' ? r.bridgePort : DEFAULTS.bridgePort,
|
||||
bridgeToken: typeof r.bridgeToken === 'string' && r.bridgeToken ? r.bridgeToken : DEFAULTS.bridgeToken,
|
||||
claudePluginRef: typeof r.claudePluginRef === 'string' && r.claudePluginRef ? r.claudePluginRef : DEFAULTS.claudePluginRef,
|
||||
channelWsPort: typeof r.channelWsPort === 'number' ? r.channelWsPort : DEFAULTS.channelWsPort,
|
||||
permissionMode: typeof r.permissionMode === 'string' && r.permissionMode ? r.permissionMode : DEFAULTS.permissionMode,
|
||||
idleKillMs: typeof r.idleKillMs === 'number' ? r.idleKillMs : DEFAULTS.idleKillMs,
|
||||
maxProcesses: typeof r.maxProcesses === 'number' ? r.maxProcesses : DEFAULTS.maxProcesses,
|
||||
mappingDbPath: typeof r.mappingDbPath === 'string' && r.mappingDbPath ? r.mappingDbPath : DEFAULTS.mappingDbPath,
|
||||
channelName: typeof r.channelName === 'string' && r.channelName ? r.channelName : DEFAULTS.channelName,
|
||||
}
|
||||
merged.mappingDbPath = expand(merged.mappingDbPath)
|
||||
return merged
|
||||
|
||||
Reference in New Issue
Block a user