From 6807973a87b40c03ce0f8cc690e2e13d21281faa Mon Sep 17 00:00:00 2001 From: Jason Kneen Date: Mon, 15 Jun 2026 21:47:37 +0100 Subject: [PATCH] wire omnigent desktop provider --- src/main/chat/types.ts | 5 +- src/main/ipc/chat.ts | 37 ++++++++++-- src/renderer/src/config/providers.ts | 11 +++- .../src/hooks/useChatTileProviders.ts | 12 +++- src/shared/types.ts | 21 +++++++ test/omnigent-desktop-wiring.test.ts | 60 +++++++++++++++++++ 6 files changed, 136 insertions(+), 10 deletions(-) create mode 100644 test/omnigent-desktop-wiring.test.ts diff --git a/src/main/chat/types.ts b/src/main/chat/types.ts index c4f5654e..f83cbcba 100644 --- a/src/main/chat/types.ts +++ b/src/main/chat/types.ts @@ -1,4 +1,4 @@ -import type { Persona, ExecutionPreference, ExtensionChatTransportConfig } from '../../shared/types' +import type { Persona, ExecutionPreference, ExtensionChatTransportConfig, OmnigentSettings } from '../../shared/types' export interface ChatMessage { role: 'user' | 'assistant' | 'system' @@ -74,6 +74,7 @@ export interface ChatRequest { executionTarget?: 'local' | 'cloud' cloudHostId?: string | null executionPreference?: ExecutionPreference | null + omnigent?: OmnigentSettings | null jobId?: string | null jobSequence?: number runMode?: 'foreground' | 'background' @@ -103,4 +104,4 @@ export interface RuntimeChatSessionState { cloudHostId: string | null isStreaming: boolean messages: ChatMessage[] -} \ No newline at end of file +} diff --git a/src/main/ipc/chat.ts b/src/main/ipc/chat.ts index 5b69c2a9..2f7ddbbd 100644 --- a/src/main/ipc/chat.ts +++ b/src/main/ipc/chat.ts @@ -402,7 +402,11 @@ async function getExecutionRoutingState(): Promise<{ } function supportsDaemonChatProvider(provider: string | null | undefined): boolean { - return provider === 'claude' || provider === 'codex' || provider === 'opencode' || provider === 'hermes' + return provider === 'claude' || provider === 'codex' || provider === 'opencode' || provider === 'hermes' || provider === 'omnigent' +} + +function requiresDaemonChatProvider(provider: string | null | undefined): boolean { + return provider === 'omnigent' } function supportsProviderNativeBackground(provider: string | null | undefined): boolean { @@ -630,10 +634,10 @@ async function selectChatExecutionHost(req: ChatRequest): Promise host.type === 'local-daemon' && host.enabled !== false) + ?? getBuiltinExecutionHosts().find(host => host.type === 'local-daemon') + if (!localDaemonHost) { + throw new Error(`${provider || 'This provider'} requires daemon-backed chat, but no local daemon host is registered.`) + } + return localDaemonHost + } + + return null } async function buildProjectContext(workspaceDir: string | undefined): Promise<{ @@ -768,14 +786,21 @@ async function sendChatToDaemon(req: ChatRequest, host: ExecutionHostRecord): Pr effective: describeProjectContextEnvelope(projectContext), }) + const requestWithProviderSettings: ChatRequest = req.provider === 'omnigent' + ? { + ...req, + omnigent: req.omnigent ?? readSettingsSync().omnigent, + } + : req + const job = await hostRequest<{ id: string status: string }>(host, '/chat/job/start', { body: { request: { - ...req, - messages: getPreparedMessages(req), + ...requestWithProviderSettings, + messages: getPreparedMessages(requestWithProviderSettings), projectContext, }, }, diff --git a/src/renderer/src/config/providers.ts b/src/renderer/src/config/providers.ts index e6eb04f8..c28b7ae8 100644 --- a/src/renderer/src/config/providers.ts +++ b/src/renderer/src/config/providers.ts @@ -1,6 +1,6 @@ /** Chat provider/model/mode configuration — extracted from ChatTile for reuse. */ -export type BuiltinProvider = 'claude' | 'codex' | 'opencode' | 'openclaw' | 'hermes' | 'csagent' +export type BuiltinProvider = 'claude' | 'codex' | 'opencode' | 'openclaw' | 'hermes' | 'omnigent' | 'csagent' export interface ModelOption { id: string @@ -69,6 +69,9 @@ export const DEFAULT_MODELS: Record = { { id: 'openrouter/deepseek/deepseek-v4-pro', label: 'DeepSeek V4 Pro', description: 'openrouter' }, { id: 'openrouter/qwen/qwen3.6-plus', label: 'Qwen 3.6 Plus', description: 'openrouter' }, ], + omnigent: [ + { id: 'omnigent:default', label: 'Default agent', description: 'Configured/default Omnigent agent' }, + ], csagent: [ { id: 'anthropic/claude-sonnet-4-6', label: 'Sonnet 4.6' }, ], @@ -106,6 +109,9 @@ export const PROVIDER_MODES: Record = { { id: 'web', label: 'Web', description: 'Web + browser tools', color: '#3fb950' }, { id: 'query', label: 'Query', description: 'No tools, query only', color: '#58a6ff' }, ], + omnigent: [ + { id: 'default', label: 'Default', description: 'Use Omnigent agent defaults', color: '#3fb950' }, + ], csagent: [ { id: 'default', label: 'Default', description: 'Ask before risky actions', color: '#3fb950' }, { id: 'bypass', label: 'Bypass', description: 'Full auto, no approval', color: '#e54d2e' }, @@ -148,6 +154,7 @@ export const PROVIDER_LABELS: Record = { opencode: 'OpenCode', openclaw: 'OpenClaw', hermes: 'Hermes', + omnigent: 'Omnigent', csagent: 'Pi', } @@ -157,6 +164,7 @@ export function isBuiltinProvider(providerId: string): providerId is BuiltinProv || providerId === 'opencode' || providerId === 'openclaw' || providerId === 'hermes' + || providerId === 'omnigent' || providerId === 'csagent' } @@ -194,6 +202,7 @@ export function getApproxSystemOverheadTokens(providerId: string, modelId: strin if (normalizedProvider === 'opencode') return 12_000 if (normalizedProvider === 'openclaw') return 12_000 if (normalizedProvider === 'hermes') return 8_000 + if (normalizedProvider === 'omnigent') return 8_000 return 6_000 } diff --git a/src/renderer/src/hooks/useChatTileProviders.ts b/src/renderer/src/hooks/useChatTileProviders.ts index 04edafab..d191e817 100644 --- a/src/renderer/src/hooks/useChatTileProviders.ts +++ b/src/renderer/src/hooks/useChatTileProviders.ts @@ -36,6 +36,7 @@ const PROVIDER_ICON: Record = { opencode: React.createElement(Bot, { size: TOOLBAR_PILL_ICON_SIZE }), openclaw: React.createElement(OpenClawIcon, { size: TOOLBAR_PILL_ICON_SIZE }), hermes: React.createElement(HermesIcon, { size: TOOLBAR_PILL_ICON_SIZE }), + omnigent: React.createElement(Bot, { size: TOOLBAR_PILL_ICON_SIZE }), csagent: React.createElement(PiIcon, { size: TOOLBAR_PILL_ICON_SIZE }), } @@ -169,6 +170,14 @@ export function useChatTileProviders({ models: DEFAULT_MODELS.hermes, kind: 'builtin', }, + omnigent: { + id: 'omnigent', + label: PROVIDER_LABELS.omnigent, + noun: 'agent', + icon: PROVIDER_ICON.omnigent, + models: DEFAULT_MODELS.omnigent, + kind: 'builtin', + }, csagent: { id: 'csagent', label: PROVIDER_LABELS.csagent, @@ -213,6 +222,7 @@ export function useChatTileProviders({ builtinProviderEntries.opencode, builtinProviderEntries.openclaw, builtinProviderEntries.hermes, + builtinProviderEntries.omnigent, builtinProviderEntries.csagent, ...extensionProviderEntries, ], [builtinProviderEntries, extensionProviderEntries]) @@ -283,4 +293,4 @@ export function useChatTileProviders({ thinkingOptions, handleProviderChange, } -} \ No newline at end of file +} diff --git a/src/shared/types.ts b/src/shared/types.ts index dbfb3c3a..f7d5d374 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -593,6 +593,14 @@ export interface CodexExecutionSettings { executionProvider: 'cli' | 'sdk' } +export interface OmnigentSettings { + enabled: boolean + baseUrl: string + apiKey: string + agentId: string + autoStart: boolean +} + export interface AppSettings { // The three font tokens fonts: FontSettings @@ -647,6 +655,8 @@ export interface AppSettings { execution: ExecutionPreference // Codex execution backend for daemon-backed jobs. codex: CodexExecutionSettings + // Omnigent daemon provider configuration. + omnigent: OmnigentSettings // Last selected chat execution / permission mode by provider. chatProviderModes: Partial> // Daemon-owned background memory consolidation. @@ -785,6 +795,13 @@ export const DEFAULT_SETTINGS: AppSettings = { codex: { executionProvider: 'cli', }, + omnigent: { + enabled: true, + baseUrl: 'http://127.0.0.1:6767', + apiKey: '', + agentId: '', + autoStart: true, + }, chatProviderModes: {}, autoDream: { enabled: true, @@ -988,6 +1005,10 @@ export function withDefaultSettings(input: Partial | null | undefin ...DEFAULT_SETTINGS.codex, ...(settings.codex ?? {}), }, + omnigent: { + ...DEFAULT_SETTINGS.omnigent, + ...(settings.omnigent ?? {}), + }, chatProviderModes, autoDream: { ...DEFAULT_SETTINGS.autoDream, diff --git a/test/omnigent-desktop-wiring.test.ts b/test/omnigent-desktop-wiring.test.ts new file mode 100644 index 00000000..806130e2 --- /dev/null +++ b/test/omnigent-desktop-wiring.test.ts @@ -0,0 +1,60 @@ +import { describe, test } from 'node:test' +import { readFileSync } from 'node:fs' +import { expect } from './node-expect.ts' +import { + DEFAULT_MODELS, + PROVIDER_LABELS, + PROVIDER_MODES, + isBuiltinProvider, +} from '../src/renderer/src/config/providers.ts' +import { + DEFAULT_SETTINGS, + withDefaultSettings, + type AppSettings, +} from '../src/shared/types.ts' + +describe('Omnigent desktop provider wiring', () => { + test('exposes Omnigent as a built-in provider with a default agent option', () => { + expect(isBuiltinProvider('omnigent')).toBe(true) + expect(PROVIDER_LABELS.omnigent).toBe('Omnigent') + expect(DEFAULT_MODELS.omnigent[0]).toEqual({ + id: 'omnigent:default', + label: 'Default agent', + description: 'Configured/default Omnigent agent', + }) + expect(PROVIDER_MODES.omnigent[0].id).toBe('default') + }) + + test('normalizes AppSettings.omnigent with daemon-compatible defaults', () => { + expect(DEFAULT_SETTINGS.omnigent).toEqual({ + enabled: true, + baseUrl: 'http://127.0.0.1:6767', + apiKey: '', + agentId: '', + autoStart: true, + }) + + const settings = withDefaultSettings({ + omnigent: { + enabled: false, + apiKey: 'token', + }, + } as unknown as Partial) + + expect(settings.omnigent).toEqual({ + enabled: false, + baseUrl: 'http://127.0.0.1:6767', + apiKey: 'token', + agentId: '', + autoStart: true, + }) + }) + + test('main process forwards Omnigent settings in daemon job-start payloads', () => { + const source = readFileSync(`${process.cwd()}/src/main/ipc/chat.ts`, 'utf8') + + expect(source).toContain("provider === 'omnigent'") + expect(source).toContain('readSettingsSync().omnigent') + expect(source).toContain('requestWithProviderSettings') + }) +})