From 664713776a3cfac69c37e72b8dea27f3407acfce Mon Sep 17 00:00:00 2001 From: Haileyesus Date: Tue, 7 Apr 2026 13:53:59 +0300 Subject: [PATCH] feat: add comprehensive tests for LLM sessions and skills services - Introduced tests for session synchronization, file delegation, session updates, and artifact deletion in sessions.test.ts. - Added tests for skill discovery and invocation across various scopes in skills.test.ts. - Created new types for MCP and provider skills to enhance type safety and clarity. - Refactored routes to use the updated llmSessionsService from the i-runtime module. - Removed deprecated session indexers and consolidated related functionality. --- package.json | 2 +- .../ai-runtime.registry.ts} | 10 +-- .../ai-runtime.routes.ts} | 10 +-- .../providers/base}/abstract.provider.ts | 2 +- .../providers/base}/base-cli.provider.ts | 4 +- .../providers/base}/base-sdk.provider.ts | 4 +- .../providers/claude}/claude-mcp.runtime.ts | 6 +- .../claude}/claude-skills.runtime.ts | 4 +- .../providers/claude}/claude.provider.ts | 8 +- .../providers/codex}/codex-mcp.runtime.ts | 6 +- .../providers/codex}/codex-skills.runtime.ts | 4 +- .../providers/codex}/codex.provider.ts | 8 +- .../providers/cursor}/cursor-mcp.runtime.ts | 6 +- .../cursor}/cursor-skills.runtime.ts | 4 +- .../providers/cursor}/cursor.provider.ts | 8 +- .../providers/gemini}/gemini-mcp.runtime.ts | 6 +- .../gemini}/gemini-skills.runtime.ts | 4 +- .../providers/gemini}/gemini.provider.ts | 8 +- .../providers/provider.interface.ts | 1 + .../shared/mcp}/base-provider-mcp.runtime.ts | 4 +- .../shared/mcp}/mcp-runtime.utils.ts | 2 +- .../shared/skills}/skills-runtime.utils.ts | 2 +- .../services/ai-runtime.service.ts} | 4 +- .../services/messages-unifier.service.ts | 2 +- .../services/sessions-watcher.service.ts | 2 +- .../services/sessions.service.ts | 4 +- .../claude.session-indexer.ts | 4 +- .../session-indexers/codex.session-indexer.ts | 4 +- .../cursor.session-indexer.ts | 4 +- .../gemini.session-indexer.ts | 4 +- .../ai-runtime/session-indexers/index.ts | 15 ++++ .../session-indexer.interface.ts | 0 .../session-indexers/session-indexer.utils.ts | 0 .../tests/images.test.ts} | 10 +-- .../tests/mcp.test.ts} | 2 +- .../tests/messages-unifier.test.ts} | 2 +- .../tests/providers.test.ts} | 10 +-- .../tests/sessions.test.ts} | 6 +- .../tests/skills.test.ts} | 2 +- server/src/modules/ai-runtime/types/index.ts | 3 + .../src/modules/ai-runtime/types/mcp.types.ts | 66 ++++++++++++++ .../types/provider.types.ts} | 89 +------------------ .../modules/ai-runtime/types/skills.types.ts | 23 +++++ server/src/modules/codex/codex.routes.js | 2 +- server/src/modules/gemini/gemini.routes.js | 2 +- .../src/modules/llm/session-indexers/index.ts | 15 ---- .../projects/projects.inline.routes.js | 2 +- .../modules/workspaces/workspaces.service.ts | 2 +- server/src/runner.ts | 4 +- 49 files changed, 202 insertions(+), 194 deletions(-) rename server/src/modules/{llm/llm.registry.ts => ai-runtime/ai-runtime.registry.ts} (68%) rename server/src/modules/{llm/llm.routes.ts => ai-runtime/ai-runtime.routes.ts} (98%) rename server/src/modules/{llm/providers => ai-runtime/providers/base}/abstract.provider.ts (98%) rename server/src/modules/{llm/providers => ai-runtime/providers/base}/base-cli.provider.ts (98%) rename server/src/modules/{llm/providers => ai-runtime/providers/base}/base-sdk.provider.ts (96%) rename server/src/modules/{llm/providers/runtimes => ai-runtime/providers/claude}/claude-mcp.runtime.ts (94%) rename server/src/modules/{llm/providers/runtimes => ai-runtime/providers/claude}/claude-skills.runtime.ts (97%) rename server/src/modules/{llm/providers => ai-runtime/providers/claude}/claude.provider.ts (96%) rename server/src/modules/{llm/providers/runtimes => ai-runtime/providers/codex}/codex-mcp.runtime.ts (93%) rename server/src/modules/{llm/providers/runtimes => ai-runtime/providers/codex}/codex-skills.runtime.ts (92%) rename server/src/modules/{llm/providers => ai-runtime/providers/codex}/codex.provider.ts (95%) rename server/src/modules/{llm/providers/runtimes => ai-runtime/providers/cursor}/cursor-mcp.runtime.ts (93%) rename server/src/modules/{llm/providers/runtimes => ai-runtime/providers/cursor}/cursor-skills.runtime.ts (91%) rename server/src/modules/{llm/providers => ai-runtime/providers/cursor}/cursor.provider.ts (90%) rename server/src/modules/{llm/providers/runtimes => ai-runtime/providers/gemini}/gemini-mcp.runtime.ts (93%) rename server/src/modules/{llm/providers/runtimes => ai-runtime/providers/gemini}/gemini-skills.runtime.ts (91%) rename server/src/modules/{llm/providers => ai-runtime/providers/gemini}/gemini.provider.ts (86%) create mode 100644 server/src/modules/ai-runtime/providers/provider.interface.ts rename server/src/modules/{llm/providers/runtimes => ai-runtime/providers/shared/mcp}/base-provider-mcp.runtime.ts (98%) rename server/src/modules/{llm/providers/runtimes => ai-runtime/providers/shared/mcp}/mcp-runtime.utils.ts (98%) rename server/src/modules/{llm/providers/runtimes => ai-runtime/providers/shared/skills}/skills-runtime.utils.ts (99%) rename server/src/modules/{llm/services/llm.service.ts => ai-runtime/services/ai-runtime.service.ts} (98%) rename server/src/modules/{llm => ai-runtime}/services/messages-unifier.service.ts (99%) rename server/src/modules/{llm => ai-runtime}/services/sessions-watcher.service.ts (98%) rename server/src/modules/{llm => ai-runtime}/services/sessions.service.ts (97%) rename server/src/modules/{llm => ai-runtime}/session-indexers/claude.session-indexer.ts (94%) rename server/src/modules/{llm => ai-runtime}/session-indexers/codex.session-indexer.ts (94%) rename server/src/modules/{llm => ai-runtime}/session-indexers/cursor.session-indexer.ts (96%) rename server/src/modules/{llm => ai-runtime}/session-indexers/gemini.session-indexer.ts (96%) create mode 100644 server/src/modules/ai-runtime/session-indexers/index.ts rename server/src/modules/{llm => ai-runtime}/session-indexers/session-indexer.interface.ts (100%) rename server/src/modules/{llm => ai-runtime}/session-indexers/session-indexer.utils.ts (100%) rename server/src/modules/{llm/tests/llm-unifier.images.test.ts => ai-runtime/tests/images.test.ts} (93%) rename server/src/modules/{llm/tests/llm-unifier.mcp.test.ts => ai-runtime/tests/mcp.test.ts} (99%) rename server/src/modules/{llm/tests/llm-unifier.messages.test.ts => ai-runtime/tests/messages-unifier.test.ts} (99%) rename server/src/modules/{llm/tests/llm-unifier.providers.test.ts => ai-runtime/tests/providers.test.ts} (95%) rename server/src/modules/{llm/tests/llm-unifier.sessions.test.ts => ai-runtime/tests/sessions.test.ts} (97%) rename server/src/modules/{llm/tests/llm-unifier.skills.test.ts => ai-runtime/tests/skills.test.ts} (99%) create mode 100644 server/src/modules/ai-runtime/types/index.ts create mode 100644 server/src/modules/ai-runtime/types/mcp.types.ts rename server/src/modules/{llm/providers/provider.interface.ts => ai-runtime/types/provider.types.ts} (52%) create mode 100644 server/src/modules/ai-runtime/types/skills.types.ts delete mode 100644 server/src/modules/llm/session-indexers/index.ts diff --git a/package.json b/package.json index 3614437c..4fe8d997 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "preview": "vite preview", "typecheck:client": "tsc --noEmit -p tsconfig.json", "typecheck:server": "tsc --noEmit -p server/tsconfig.json", - "test:server": "tsx --tsconfig server/tsconfig.json --test server/src/modules/llm/tests/*.test.ts", + "test:server": "tsx --tsconfig server/tsconfig.json --test server/src/modules/ai-runtime/tests/*.test.ts", "verify:server": "npm run typecheck:server && npm run test:server && npm run server:build", "typecheck": "npm run typecheck:client && npm run typecheck:server", "lint": "eslint src/", diff --git a/server/src/modules/llm/llm.registry.ts b/server/src/modules/ai-runtime/ai-runtime.registry.ts similarity index 68% rename from server/src/modules/llm/llm.registry.ts rename to server/src/modules/ai-runtime/ai-runtime.registry.ts index b893aa7e..1499f1b9 100644 --- a/server/src/modules/llm/llm.registry.ts +++ b/server/src/modules/ai-runtime/ai-runtime.registry.ts @@ -1,8 +1,8 @@ -import type { IProvider } from '@/modules/llm/providers/provider.interface.js'; -import { ClaudeProvider } from '@/modules/llm/providers/claude.provider.js'; -import { CodexProvider } from '@/modules/llm/providers/codex.provider.js'; -import { CursorProvider } from '@/modules/llm/providers/cursor.provider.js'; -import { GeminiProvider } from '@/modules/llm/providers/gemini.provider.js'; +import type { IProvider } from '@/modules/ai-runtime/types/index.js'; +import { ClaudeProvider } from '@/modules/ai-runtime/providers/claude/claude.provider.js'; +import { CodexProvider } from '@/modules/ai-runtime/providers/codex/codex.provider.js'; +import { CursorProvider } from '@/modules/ai-runtime/providers/cursor/cursor.provider.js'; +import { GeminiProvider } from '@/modules/ai-runtime/providers/gemini/gemini.provider.js'; import type { LLMProvider } from '@/shared/types/app.js'; import { AppError } from '@/shared/utils/app-error.js'; diff --git a/server/src/modules/llm/llm.routes.ts b/server/src/modules/ai-runtime/ai-runtime.routes.ts similarity index 98% rename from server/src/modules/llm/llm.routes.ts rename to server/src/modules/ai-runtime/ai-runtime.routes.ts index 4d9be07c..b2a93c92 100644 --- a/server/src/modules/llm/llm.routes.ts +++ b/server/src/modules/ai-runtime/ai-runtime.routes.ts @@ -3,10 +3,10 @@ import express, { type NextFunction, type Request, type Response } from 'express import { asyncHandler } from '@/shared/http/async-handler.js'; import { AppError } from '@/shared/utils/app-error.js'; import { createApiErrorResponse, createApiSuccessResponse } from '@/shared/http/api-response.js'; -import { llmService } from '@/modules/llm/services/llm.service.js'; -import { llmSessionsService } from '@/modules/llm/services/sessions.service.js'; -import type { McpScope, McpTransport, UpsertProviderMcpServerInput } from '@/modules/llm/providers/provider.interface.js'; -import { llmMessagesUnifier } from '@/modules/llm/services/messages-unifier.service.js'; +import { llmService } from '@/modules/ai-runtime/services/ai-runtime.service.js'; +import { llmSessionsService } from '@/modules/ai-runtime/services/sessions.service.js'; +import type { McpScope, McpTransport, UpsertProviderMcpServerInput } from '@/modules/ai-runtime/types/index.js'; +import { llmMessagesUnifier } from '@/modules/ai-runtime/services/messages-unifier.service.js'; import type { LLMProvider } from '@/shared/types/app.js'; import { logger } from '@/shared/utils/logger.js'; @@ -530,7 +530,7 @@ router.use((error: unknown, _req: Request, res: Response, _next: NextFunction) = const message = error instanceof Error ? error.message : 'Unexpected LLM route failure.'; logger.error(message, { - module: 'llm.routes', + module: 'ai-runtime.routes', }); res.status(500).json(createApiErrorResponse('INTERNAL_ERROR', message)); diff --git a/server/src/modules/llm/providers/abstract.provider.ts b/server/src/modules/ai-runtime/providers/base/abstract.provider.ts similarity index 98% rename from server/src/modules/llm/providers/abstract.provider.ts rename to server/src/modules/ai-runtime/providers/base/abstract.provider.ts index 0d8d659a..98c14777 100644 --- a/server/src/modules/llm/providers/abstract.provider.ts +++ b/server/src/modules/ai-runtime/providers/base/abstract.provider.ts @@ -9,7 +9,7 @@ import type { ProviderSessionEvent, ProviderSessionSnapshot, StartSessionInput, -} from '@/modules/llm/providers/provider.interface.js'; +} from '@/modules/ai-runtime/types/index.js'; import type { LLMProvider } from '@/shared/types/app.js'; const MAX_EVENT_BUFFER_SIZE = 2_000; diff --git a/server/src/modules/llm/providers/base-cli.provider.ts b/server/src/modules/ai-runtime/providers/base/base-cli.provider.ts similarity index 98% rename from server/src/modules/llm/providers/base-cli.provider.ts rename to server/src/modules/ai-runtime/providers/base/base-cli.provider.ts index 207cdde5..efabcb6a 100644 --- a/server/src/modules/llm/providers/base-cli.provider.ts +++ b/server/src/modules/ai-runtime/providers/base/base-cli.provider.ts @@ -4,14 +4,14 @@ import type { ChildProcessWithoutNullStreams } from 'node:child_process'; import spawn from 'cross-spawn'; -import { AbstractProvider } from '@/modules/llm/providers/abstract.provider.js'; +import { AbstractProvider } from '@/modules/ai-runtime/providers/base/abstract.provider.js'; import type { MutableProviderSession, ProviderCapabilities, ProviderSessionEvent, ProviderSessionSnapshot, StartSessionInput, -} from '@/modules/llm/providers/provider.interface.js'; +} from '@/modules/ai-runtime/types/index.js'; import { createStreamLineAccumulator } from '@/shared/platform/stream.js'; import type { LLMProvider } from '@/shared/types/app.js'; diff --git a/server/src/modules/llm/providers/base-sdk.provider.ts b/server/src/modules/ai-runtime/providers/base/base-sdk.provider.ts similarity index 96% rename from server/src/modules/llm/providers/base-sdk.provider.ts rename to server/src/modules/ai-runtime/providers/base/base-sdk.provider.ts index 790a245c..01912ad1 100644 --- a/server/src/modules/llm/providers/base-sdk.provider.ts +++ b/server/src/modules/ai-runtime/providers/base/base-sdk.provider.ts @@ -1,13 +1,13 @@ import { randomUUID } from 'node:crypto'; -import { AbstractProvider } from '@/modules/llm/providers/abstract.provider.js'; +import { AbstractProvider } from '@/modules/ai-runtime/providers/base/abstract.provider.js'; import type { MutableProviderSession, ProviderCapabilities, ProviderSessionEvent, ProviderSessionSnapshot, StartSessionInput, -} from '@/modules/llm/providers/provider.interface.js'; +} from '@/modules/ai-runtime/types/index.js'; import type { LLMProvider } from '@/shared/types/app.js'; type CreateSdkExecutionInput = StartSessionInput & { diff --git a/server/src/modules/llm/providers/runtimes/claude-mcp.runtime.ts b/server/src/modules/ai-runtime/providers/claude/claude-mcp.runtime.ts similarity index 94% rename from server/src/modules/llm/providers/runtimes/claude-mcp.runtime.ts rename to server/src/modules/ai-runtime/providers/claude/claude-mcp.runtime.ts index 0e29ddf5..f27ffa74 100644 --- a/server/src/modules/llm/providers/runtimes/claude-mcp.runtime.ts +++ b/server/src/modules/ai-runtime/providers/claude/claude-mcp.runtime.ts @@ -6,8 +6,8 @@ import type { McpScope, ProviderMcpServer, UpsertProviderMcpServerInput, -} from '@/modules/llm/providers/provider.interface.js'; -import { BaseProviderMcpRuntime } from '@/modules/llm/providers/runtimes/base-provider-mcp.runtime.js'; +} from '@/modules/ai-runtime/types/index.js'; +import { BaseProviderMcpRuntime } from '@/modules/ai-runtime/providers/shared/mcp/base-provider-mcp.runtime.js'; import { readJsonConfig, readObjectRecord, @@ -15,7 +15,7 @@ import { readStringArray, readStringRecord, writeJsonConfig, -} from '@/modules/llm/providers/runtimes/mcp-runtime.utils.js'; +} from '@/modules/ai-runtime/providers/shared/mcp/mcp-runtime.utils.js'; /** * Claude MCP runtime backed by `~/.claude.json` and project `.mcp.json`. diff --git a/server/src/modules/llm/providers/runtimes/claude-skills.runtime.ts b/server/src/modules/ai-runtime/providers/claude/claude-skills.runtime.ts similarity index 97% rename from server/src/modules/llm/providers/runtimes/claude-skills.runtime.ts rename to server/src/modules/ai-runtime/providers/claude/claude-skills.runtime.ts index f63be028..7ad2ee22 100644 --- a/server/src/modules/llm/providers/runtimes/claude-skills.runtime.ts +++ b/server/src/modules/ai-runtime/providers/claude/claude-skills.runtime.ts @@ -2,8 +2,8 @@ import { readFile } from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; -import type { IProviderSkillsRuntime, ProviderSkill } from '@/modules/llm/providers/provider.interface.js'; -import { deduplicateSkills, listSkillsFromDirectory } from '@/modules/llm/providers/runtimes/skills-runtime.utils.js'; +import type { IProviderSkillsRuntime, ProviderSkill } from '@/modules/ai-runtime/types/index.js'; +import { deduplicateSkills, listSkillsFromDirectory } from '@/modules/ai-runtime/providers/shared/skills/skills-runtime.utils.js'; /** * Claude skills runtime backed by user/project/plugin skill directories. diff --git a/server/src/modules/llm/providers/claude.provider.ts b/server/src/modules/ai-runtime/providers/claude/claude.provider.ts similarity index 96% rename from server/src/modules/llm/providers/claude.provider.ts rename to server/src/modules/ai-runtime/providers/claude/claude.provider.ts index cbcc00ec..4ff34500 100644 --- a/server/src/modules/llm/providers/claude.provider.ts +++ b/server/src/modules/ai-runtime/providers/claude/claude.provider.ts @@ -7,7 +7,7 @@ import { import path from 'node:path'; import { readFile } from 'node:fs/promises'; -import { BaseSdkProvider } from '@/modules/llm/providers/base-sdk.provider.js'; +import { BaseSdkProvider } from '@/modules/ai-runtime/providers/base/base-sdk.provider.js'; import type { IProviderMcpRuntime, IProviderSkillsRuntime, @@ -15,9 +15,9 @@ import type { ProviderSessionEvent, RuntimePermissionMode, StartSessionInput, -} from '@/modules/llm/providers/provider.interface.js'; -import { ClaudeMcpRuntime } from '@/modules/llm/providers/runtimes/claude-mcp.runtime.js'; -import { ClaudeSkillsRuntime } from '@/modules/llm/providers/runtimes/claude-skills.runtime.js'; +} from '@/modules/ai-runtime/types/index.js'; +import { ClaudeMcpRuntime } from '@/modules/ai-runtime/providers/claude/claude-mcp.runtime.js'; +import { ClaudeSkillsRuntime } from '@/modules/ai-runtime/providers/claude/claude-skills.runtime.js'; type ClaudeExecutionInput = StartSessionInput & { sessionId: string; diff --git a/server/src/modules/llm/providers/runtimes/codex-mcp.runtime.ts b/server/src/modules/ai-runtime/providers/codex/codex-mcp.runtime.ts similarity index 93% rename from server/src/modules/llm/providers/runtimes/codex-mcp.runtime.ts rename to server/src/modules/ai-runtime/providers/codex/codex-mcp.runtime.ts index f732e7db..f558800c 100644 --- a/server/src/modules/llm/providers/runtimes/codex-mcp.runtime.ts +++ b/server/src/modules/ai-runtime/providers/codex/codex-mcp.runtime.ts @@ -6,8 +6,8 @@ import type { McpScope, ProviderMcpServer, UpsertProviderMcpServerInput, -} from '@/modules/llm/providers/provider.interface.js'; -import { BaseProviderMcpRuntime } from '@/modules/llm/providers/runtimes/base-provider-mcp.runtime.js'; +} from '@/modules/ai-runtime/types/index.js'; +import { BaseProviderMcpRuntime } from '@/modules/ai-runtime/providers/shared/mcp/base-provider-mcp.runtime.js'; import { readObjectRecord, readOptionalString, @@ -15,7 +15,7 @@ import { readStringRecord, readTomlConfig, writeTomlConfig, -} from '@/modules/llm/providers/runtimes/mcp-runtime.utils.js'; +} from '@/modules/ai-runtime/providers/shared/mcp/mcp-runtime.utils.js'; /** * Codex MCP runtime backed by user/project `.codex/config.toml`. diff --git a/server/src/modules/llm/providers/runtimes/codex-skills.runtime.ts b/server/src/modules/ai-runtime/providers/codex/codex-skills.runtime.ts similarity index 92% rename from server/src/modules/llm/providers/runtimes/codex-skills.runtime.ts rename to server/src/modules/ai-runtime/providers/codex/codex-skills.runtime.ts index b2a6dbec..e8769831 100644 --- a/server/src/modules/llm/providers/runtimes/codex-skills.runtime.ts +++ b/server/src/modules/ai-runtime/providers/codex/codex-skills.runtime.ts @@ -1,13 +1,13 @@ import os from 'node:os'; import path from 'node:path'; -import type { IProviderSkillsRuntime, ProviderSkill, ProviderSkillScope } from '@/modules/llm/providers/provider.interface.js'; +import type { IProviderSkillsRuntime, ProviderSkill, ProviderSkillScope } from '@/modules/ai-runtime/types/index.js'; import { deduplicateDirectories, deduplicateSkills, findGitRepoRoot, listSkillsFromDirectory, -} from '@/modules/llm/providers/runtimes/skills-runtime.utils.js'; +} from '@/modules/ai-runtime/providers/shared/skills/skills-runtime.utils.js'; /** * Codex skills runtime backed by repo/user/admin/system skill directories. diff --git a/server/src/modules/llm/providers/codex.provider.ts b/server/src/modules/ai-runtime/providers/codex/codex.provider.ts similarity index 95% rename from server/src/modules/llm/providers/codex.provider.ts rename to server/src/modules/ai-runtime/providers/codex/codex.provider.ts index 9fd32c7e..a800e0aa 100644 --- a/server/src/modules/llm/providers/codex.provider.ts +++ b/server/src/modules/ai-runtime/providers/codex/codex.provider.ts @@ -2,16 +2,16 @@ import os from 'node:os'; import path from 'node:path'; import { readFile } from 'node:fs/promises'; -import { BaseSdkProvider } from '@/modules/llm/providers/base-sdk.provider.js'; +import { BaseSdkProvider } from '@/modules/ai-runtime/providers/base/base-sdk.provider.js'; import type { IProviderMcpRuntime, IProviderSkillsRuntime, ProviderModel, ProviderSessionEvent, StartSessionInput, -} from '@/modules/llm/providers/provider.interface.js'; -import { CodexMcpRuntime } from '@/modules/llm/providers/runtimes/codex-mcp.runtime.js'; -import { CodexSkillsRuntime } from '@/modules/llm/providers/runtimes/codex-skills.runtime.js'; +} from '@/modules/ai-runtime/types/index.js'; +import { CodexMcpRuntime } from '@/modules/ai-runtime/providers/codex/codex-mcp.runtime.js'; +import { CodexSkillsRuntime } from '@/modules/ai-runtime/providers/codex/codex-skills.runtime.js'; import { AppError } from '@/shared/utils/app-error.js'; type CodexExecutionInput = StartSessionInput & { diff --git a/server/src/modules/llm/providers/runtimes/cursor-mcp.runtime.ts b/server/src/modules/ai-runtime/providers/cursor/cursor-mcp.runtime.ts similarity index 93% rename from server/src/modules/llm/providers/runtimes/cursor-mcp.runtime.ts rename to server/src/modules/ai-runtime/providers/cursor/cursor-mcp.runtime.ts index 77b05295..c439f2f4 100644 --- a/server/src/modules/llm/providers/runtimes/cursor-mcp.runtime.ts +++ b/server/src/modules/ai-runtime/providers/cursor/cursor-mcp.runtime.ts @@ -6,8 +6,8 @@ import type { McpScope, ProviderMcpServer, UpsertProviderMcpServerInput, -} from '@/modules/llm/providers/provider.interface.js'; -import { BaseProviderMcpRuntime } from '@/modules/llm/providers/runtimes/base-provider-mcp.runtime.js'; +} from '@/modules/ai-runtime/types/index.js'; +import { BaseProviderMcpRuntime } from '@/modules/ai-runtime/providers/shared/mcp/base-provider-mcp.runtime.js'; import { readJsonConfig, readObjectRecord, @@ -15,7 +15,7 @@ import { readStringArray, readStringRecord, writeJsonConfig, -} from '@/modules/llm/providers/runtimes/mcp-runtime.utils.js'; +} from '@/modules/ai-runtime/providers/shared/mcp/mcp-runtime.utils.js'; /** * Cursor MCP runtime backed by user/project `.cursor/mcp.json`. diff --git a/server/src/modules/llm/providers/runtimes/cursor-skills.runtime.ts b/server/src/modules/ai-runtime/providers/cursor/cursor-skills.runtime.ts similarity index 91% rename from server/src/modules/llm/providers/runtimes/cursor-skills.runtime.ts rename to server/src/modules/ai-runtime/providers/cursor/cursor-skills.runtime.ts index e550f3ae..01e09bb8 100644 --- a/server/src/modules/llm/providers/runtimes/cursor-skills.runtime.ts +++ b/server/src/modules/ai-runtime/providers/cursor/cursor-skills.runtime.ts @@ -1,12 +1,12 @@ import os from 'node:os'; import path from 'node:path'; -import type { IProviderSkillsRuntime, ProviderSkill, ProviderSkillScope } from '@/modules/llm/providers/provider.interface.js'; +import type { IProviderSkillsRuntime, ProviderSkill, ProviderSkillScope } from '@/modules/ai-runtime/types/index.js'; import { deduplicateDirectories, deduplicateSkills, listSkillsFromDirectory, -} from '@/modules/llm/providers/runtimes/skills-runtime.utils.js'; +} from '@/modules/ai-runtime/providers/shared/skills/skills-runtime.utils.js'; /** * Cursor skills runtime backed by user/project skill directories. diff --git a/server/src/modules/llm/providers/cursor.provider.ts b/server/src/modules/ai-runtime/providers/cursor/cursor.provider.ts similarity index 90% rename from server/src/modules/llm/providers/cursor.provider.ts rename to server/src/modules/ai-runtime/providers/cursor/cursor.provider.ts index 18e10bf4..3d9b6e27 100644 --- a/server/src/modules/llm/providers/cursor.provider.ts +++ b/server/src/modules/ai-runtime/providers/cursor/cursor.provider.ts @@ -1,12 +1,12 @@ -import { BaseCliProvider } from '@/modules/llm/providers/base-cli.provider.js'; +import { BaseCliProvider } from '@/modules/ai-runtime/providers/base/base-cli.provider.js'; import type { IProviderMcpRuntime, IProviderSkillsRuntime, ProviderModel, StartSessionInput, -} from '@/modules/llm/providers/provider.interface.js'; -import { CursorMcpRuntime } from '@/modules/llm/providers/runtimes/cursor-mcp.runtime.js'; -import { CursorSkillsRuntime } from '@/modules/llm/providers/runtimes/cursor-skills.runtime.js'; +} from '@/modules/ai-runtime/types/index.js'; +import { CursorMcpRuntime } from '@/modules/ai-runtime/providers/cursor/cursor-mcp.runtime.js'; +import { CursorSkillsRuntime } from '@/modules/ai-runtime/providers/cursor/cursor-skills.runtime.js'; type CursorExecutionInput = StartSessionInput & { sessionId: string; diff --git a/server/src/modules/llm/providers/runtimes/gemini-mcp.runtime.ts b/server/src/modules/ai-runtime/providers/gemini/gemini-mcp.runtime.ts similarity index 93% rename from server/src/modules/llm/providers/runtimes/gemini-mcp.runtime.ts rename to server/src/modules/ai-runtime/providers/gemini/gemini-mcp.runtime.ts index 48c46207..c26b7efb 100644 --- a/server/src/modules/llm/providers/runtimes/gemini-mcp.runtime.ts +++ b/server/src/modules/ai-runtime/providers/gemini/gemini-mcp.runtime.ts @@ -6,8 +6,8 @@ import type { McpScope, ProviderMcpServer, UpsertProviderMcpServerInput, -} from '@/modules/llm/providers/provider.interface.js'; -import { BaseProviderMcpRuntime } from '@/modules/llm/providers/runtimes/base-provider-mcp.runtime.js'; +} from '@/modules/ai-runtime/types/index.js'; +import { BaseProviderMcpRuntime } from '@/modules/ai-runtime/providers/shared/mcp/base-provider-mcp.runtime.js'; import { readJsonConfig, readObjectRecord, @@ -15,7 +15,7 @@ import { readStringArray, readStringRecord, writeJsonConfig, -} from '@/modules/llm/providers/runtimes/mcp-runtime.utils.js'; +} from '@/modules/ai-runtime/providers/shared/mcp/mcp-runtime.utils.js'; /** * Gemini MCP runtime backed by user/project `.gemini/settings.json`. diff --git a/server/src/modules/llm/providers/runtimes/gemini-skills.runtime.ts b/server/src/modules/ai-runtime/providers/gemini/gemini-skills.runtime.ts similarity index 91% rename from server/src/modules/llm/providers/runtimes/gemini-skills.runtime.ts rename to server/src/modules/ai-runtime/providers/gemini/gemini-skills.runtime.ts index c51b7e18..82ad619a 100644 --- a/server/src/modules/llm/providers/runtimes/gemini-skills.runtime.ts +++ b/server/src/modules/ai-runtime/providers/gemini/gemini-skills.runtime.ts @@ -1,12 +1,12 @@ import os from 'node:os'; import path from 'node:path'; -import type { IProviderSkillsRuntime, ProviderSkill, ProviderSkillScope } from '@/modules/llm/providers/provider.interface.js'; +import type { IProviderSkillsRuntime, ProviderSkill, ProviderSkillScope } from '@/modules/ai-runtime/types/index.js'; import { deduplicateDirectories, deduplicateSkills, listSkillsFromDirectory, -} from '@/modules/llm/providers/runtimes/skills-runtime.utils.js'; +} from '@/modules/ai-runtime/providers/shared/skills/skills-runtime.utils.js'; /** * Gemini skills runtime backed by user/project skill directories. diff --git a/server/src/modules/llm/providers/gemini.provider.ts b/server/src/modules/ai-runtime/providers/gemini/gemini.provider.ts similarity index 86% rename from server/src/modules/llm/providers/gemini.provider.ts rename to server/src/modules/ai-runtime/providers/gemini/gemini.provider.ts index 8e11f53d..a4ff8e6d 100644 --- a/server/src/modules/llm/providers/gemini.provider.ts +++ b/server/src/modules/ai-runtime/providers/gemini/gemini.provider.ts @@ -1,12 +1,12 @@ -import { BaseCliProvider } from '@/modules/llm/providers/base-cli.provider.js'; +import { BaseCliProvider } from '@/modules/ai-runtime/providers/base/base-cli.provider.js'; import type { IProviderMcpRuntime, IProviderSkillsRuntime, ProviderModel, StartSessionInput, -} from '@/modules/llm/providers/provider.interface.js'; -import { GeminiMcpRuntime } from '@/modules/llm/providers/runtimes/gemini-mcp.runtime.js'; -import { GeminiSkillsRuntime } from '@/modules/llm/providers/runtimes/gemini-skills.runtime.js'; +} from '@/modules/ai-runtime/types/index.js'; +import { GeminiMcpRuntime } from '@/modules/ai-runtime/providers/gemini/gemini-mcp.runtime.js'; +import { GeminiSkillsRuntime } from '@/modules/ai-runtime/providers/gemini/gemini-skills.runtime.js'; type GeminiExecutionInput = StartSessionInput & { sessionId: string; diff --git a/server/src/modules/ai-runtime/providers/provider.interface.ts b/server/src/modules/ai-runtime/providers/provider.interface.ts new file mode 100644 index 00000000..d09f51d0 --- /dev/null +++ b/server/src/modules/ai-runtime/providers/provider.interface.ts @@ -0,0 +1 @@ +export * from '@/modules/ai-runtime/types/index.js'; diff --git a/server/src/modules/llm/providers/runtimes/base-provider-mcp.runtime.ts b/server/src/modules/ai-runtime/providers/shared/mcp/base-provider-mcp.runtime.ts similarity index 98% rename from server/src/modules/llm/providers/runtimes/base-provider-mcp.runtime.ts rename to server/src/modules/ai-runtime/providers/shared/mcp/base-provider-mcp.runtime.ts index 6fddb770..e2e2497d 100644 --- a/server/src/modules/llm/providers/runtimes/base-provider-mcp.runtime.ts +++ b/server/src/modules/ai-runtime/providers/shared/mcp/base-provider-mcp.runtime.ts @@ -6,13 +6,13 @@ import type { McpTransport, ProviderMcpServer, UpsertProviderMcpServerInput, -} from '@/modules/llm/providers/provider.interface.js'; +} from '@/modules/ai-runtime/types/index.js'; import { normalizeServerName, resolveWorkspacePath, runHttpServerProbe, runStdioServerProbe, -} from '@/modules/llm/providers/runtimes/mcp-runtime.utils.js'; +} from '@/modules/ai-runtime/providers/shared/mcp/mcp-runtime.utils.js'; /** * Shared MCP runtime for provider-specific config readers/writers. diff --git a/server/src/modules/llm/providers/runtimes/mcp-runtime.utils.ts b/server/src/modules/ai-runtime/providers/shared/mcp/mcp-runtime.utils.ts similarity index 98% rename from server/src/modules/llm/providers/runtimes/mcp-runtime.utils.ts rename to server/src/modules/ai-runtime/providers/shared/mcp/mcp-runtime.utils.ts index 87305e14..a1e40d78 100644 --- a/server/src/modules/llm/providers/runtimes/mcp-runtime.utils.ts +++ b/server/src/modules/ai-runtime/providers/shared/mcp/mcp-runtime.utils.ts @@ -5,7 +5,7 @@ import { once } from 'node:events'; import spawn from 'cross-spawn'; import TOML from '@iarna/toml'; -import type { ProviderMcpServer } from '@/modules/llm/providers/provider.interface.js'; +import type { ProviderMcpServer } from '@/modules/ai-runtime/types/index.js'; import { AppError } from '@/shared/utils/app-error.js'; /** diff --git a/server/src/modules/llm/providers/runtimes/skills-runtime.utils.ts b/server/src/modules/ai-runtime/providers/shared/skills/skills-runtime.utils.ts similarity index 99% rename from server/src/modules/llm/providers/runtimes/skills-runtime.utils.ts rename to server/src/modules/ai-runtime/providers/shared/skills/skills-runtime.utils.ts index f82133b3..5dd08dab 100644 --- a/server/src/modules/llm/providers/runtimes/skills-runtime.utils.ts +++ b/server/src/modules/ai-runtime/providers/shared/skills/skills-runtime.utils.ts @@ -2,7 +2,7 @@ import { access, readFile, readdir } from 'node:fs/promises'; import path from 'node:path'; import type { LLMProvider } from '@/shared/types/app.js'; -import type { ProviderSkill, ProviderSkillScope } from '@/modules/llm/providers/provider.interface.js'; +import type { ProviderSkill, ProviderSkillScope } from '@/modules/ai-runtime/types/index.js'; /** * Tests whether a path exists. diff --git a/server/src/modules/llm/services/llm.service.ts b/server/src/modules/ai-runtime/services/ai-runtime.service.ts similarity index 98% rename from server/src/modules/llm/services/llm.service.ts rename to server/src/modules/ai-runtime/services/ai-runtime.service.ts index f057705d..2466dbc6 100644 --- a/server/src/modules/llm/services/llm.service.ts +++ b/server/src/modules/ai-runtime/services/ai-runtime.service.ts @@ -1,6 +1,6 @@ import type { LLMProvider } from '@/shared/types/app.js'; import { AppError } from '@/shared/utils/app-error.js'; -import { llmProviderRegistry } from '@/modules/llm/llm.registry.js'; +import { llmProviderRegistry } from '@/modules/ai-runtime/ai-runtime.registry.js'; import type { McpScope, ProviderMcpServer, @@ -10,7 +10,7 @@ import type { RuntimePermissionMode, StartSessionInput, UpsertProviderMcpServerInput, -} from '@/modules/llm/providers/provider.interface.js'; +} from '@/modules/ai-runtime/types/index.js'; /** * Converts unknown request values into optional trimmed strings. diff --git a/server/src/modules/llm/services/messages-unifier.service.ts b/server/src/modules/ai-runtime/services/messages-unifier.service.ts similarity index 99% rename from server/src/modules/llm/services/messages-unifier.service.ts rename to server/src/modules/ai-runtime/services/messages-unifier.service.ts index 324202dd..f91f2af1 100644 --- a/server/src/modules/llm/services/messages-unifier.service.ts +++ b/server/src/modules/ai-runtime/services/messages-unifier.service.ts @@ -1,4 +1,4 @@ -import type { ProviderSessionEvent } from '@/modules/llm/providers/provider.interface.js'; +import type { ProviderSessionEvent } from '@/modules/ai-runtime/types/index.js'; import type { LLMProvider } from '@/shared/types/app.js'; export type UnifiedMessageType = diff --git a/server/src/modules/llm/services/sessions-watcher.service.ts b/server/src/modules/ai-runtime/services/sessions-watcher.service.ts similarity index 98% rename from server/src/modules/llm/services/sessions-watcher.service.ts rename to server/src/modules/ai-runtime/services/sessions-watcher.service.ts index 178f5d67..02ac2af3 100644 --- a/server/src/modules/llm/services/sessions-watcher.service.ts +++ b/server/src/modules/ai-runtime/services/sessions-watcher.service.ts @@ -3,7 +3,7 @@ import os from 'node:os'; import path from 'node:path'; import { promises as fsPromises } from 'node:fs'; -import { llmSessionsService } from '@/modules/llm/services/sessions.service.js'; +import { llmSessionsService } from '@/modules/ai-runtime/services/sessions.service.js'; import type { LLMProvider } from '@/shared/types/app.js'; import { logger } from '@/shared/utils/logger.js'; diff --git a/server/src/modules/llm/services/sessions.service.ts b/server/src/modules/ai-runtime/services/sessions.service.ts similarity index 97% rename from server/src/modules/llm/services/sessions.service.ts rename to server/src/modules/ai-runtime/services/sessions.service.ts index dc02f25a..66ae2fcb 100644 --- a/server/src/modules/llm/services/sessions.service.ts +++ b/server/src/modules/ai-runtime/services/sessions.service.ts @@ -5,8 +5,8 @@ import { scanStateDb } from '@/shared/database/repositories/scan-state.db.js'; import { sessionsDb } from '@/shared/database/repositories/sessions.db.js'; import type { LLMProvider } from '@/shared/types/app.js'; import { AppError } from '@/shared/utils/app-error.js'; -import { sessionIndexers } from '@/modules/llm/session-indexers/index.js'; -import { llmMessagesUnifier, type UnifiedChatMessage } from '@/modules/llm/services/messages-unifier.service.js'; +import { sessionIndexers } from '@/modules/ai-runtime/session-indexers/index.js'; +import { llmMessagesUnifier, type UnifiedChatMessage } from '@/modules/ai-runtime/services/messages-unifier.service.js'; type SyncResult = { processedByProvider: Record; diff --git a/server/src/modules/llm/session-indexers/claude.session-indexer.ts b/server/src/modules/ai-runtime/session-indexers/claude.session-indexer.ts similarity index 94% rename from server/src/modules/llm/session-indexers/claude.session-indexer.ts rename to server/src/modules/ai-runtime/session-indexers/claude.session-indexer.ts index e7fb6ed4..d976a56e 100644 --- a/server/src/modules/llm/session-indexers/claude.session-indexer.ts +++ b/server/src/modules/ai-runtime/session-indexers/claude.session-indexer.ts @@ -8,8 +8,8 @@ import { findFilesRecursivelyCreatedAfter, normalizeSessionName, readFileTimestamps, -} from '@/modules/llm/session-indexers/session-indexer.utils.js'; -import type { ISessionIndexer } from '@/modules/llm/session-indexers/session-indexer.interface.js'; +} from '@/modules/ai-runtime/session-indexers/session-indexer.utils.js'; +import type { ISessionIndexer } from '@/modules/ai-runtime/session-indexers/session-indexer.interface.js'; type ParsedSession = { sessionId: string; diff --git a/server/src/modules/llm/session-indexers/codex.session-indexer.ts b/server/src/modules/ai-runtime/session-indexers/codex.session-indexer.ts similarity index 94% rename from server/src/modules/llm/session-indexers/codex.session-indexer.ts rename to server/src/modules/ai-runtime/session-indexers/codex.session-indexer.ts index 20be3d94..0d708e4f 100644 --- a/server/src/modules/llm/session-indexers/codex.session-indexer.ts +++ b/server/src/modules/ai-runtime/session-indexers/codex.session-indexer.ts @@ -8,8 +8,8 @@ import { findFilesRecursivelyCreatedAfter, normalizeSessionName, readFileTimestamps, -} from '@/modules/llm/session-indexers/session-indexer.utils.js'; -import type { ISessionIndexer } from '@/modules/llm/session-indexers/session-indexer.interface.js'; +} from '@/modules/ai-runtime/session-indexers/session-indexer.utils.js'; +import type { ISessionIndexer } from '@/modules/ai-runtime/session-indexers/session-indexer.interface.js'; type ParsedSession = { sessionId: string; diff --git a/server/src/modules/llm/session-indexers/cursor.session-indexer.ts b/server/src/modules/ai-runtime/session-indexers/cursor.session-indexer.ts similarity index 96% rename from server/src/modules/llm/session-indexers/cursor.session-indexer.ts rename to server/src/modules/ai-runtime/session-indexers/cursor.session-indexer.ts index 90d03c73..eb261886 100644 --- a/server/src/modules/llm/session-indexers/cursor.session-indexer.ts +++ b/server/src/modules/ai-runtime/session-indexers/cursor.session-indexer.ts @@ -11,8 +11,8 @@ import { listDirectoryEntriesSafe, normalizeSessionName, readFileTimestamps, -} from '@/modules/llm/session-indexers/session-indexer.utils.js'; -import type { ISessionIndexer } from '@/modules/llm/session-indexers/session-indexer.interface.js'; +} from '@/modules/ai-runtime/session-indexers/session-indexer.utils.js'; +import type { ISessionIndexer } from '@/modules/ai-runtime/session-indexers/session-indexer.interface.js'; type ParsedSession = { sessionId: string; diff --git a/server/src/modules/llm/session-indexers/gemini.session-indexer.ts b/server/src/modules/ai-runtime/session-indexers/gemini.session-indexer.ts similarity index 96% rename from server/src/modules/llm/session-indexers/gemini.session-indexer.ts rename to server/src/modules/ai-runtime/session-indexers/gemini.session-indexer.ts index 7c4abf12..34529895 100644 --- a/server/src/modules/llm/session-indexers/gemini.session-indexer.ts +++ b/server/src/modules/ai-runtime/session-indexers/gemini.session-indexer.ts @@ -7,8 +7,8 @@ import { findFilesRecursivelyCreatedAfter, normalizeSessionName, readFileTimestamps, -} from '@/modules/llm/session-indexers/session-indexer.utils.js'; -import type { ISessionIndexer } from '@/modules/llm/session-indexers/session-indexer.interface.js'; +} from '@/modules/ai-runtime/session-indexers/session-indexer.utils.js'; +import type { ISessionIndexer } from '@/modules/ai-runtime/session-indexers/session-indexer.interface.js'; type ParsedSession = { sessionId: string; diff --git a/server/src/modules/ai-runtime/session-indexers/index.ts b/server/src/modules/ai-runtime/session-indexers/index.ts new file mode 100644 index 00000000..6b03f924 --- /dev/null +++ b/server/src/modules/ai-runtime/session-indexers/index.ts @@ -0,0 +1,15 @@ +import type { ISessionIndexer } from '@/modules/ai-runtime/session-indexers/session-indexer.interface.js'; +import { ClaudeSessionIndexer } from '@/modules/ai-runtime/session-indexers/claude.session-indexer.js'; +import { CodexSessionIndexer } from '@/modules/ai-runtime/session-indexers/codex.session-indexer.js'; +import { CursorSessionIndexer } from '@/modules/ai-runtime/session-indexers/cursor.session-indexer.js'; +import { GeminiSessionIndexer } from '@/modules/ai-runtime/session-indexers/gemini.session-indexer.js'; + +/** + * Provider-specific session indexers used by the sync orchestrator. + */ +export const sessionIndexers: ISessionIndexer[] = [ + new ClaudeSessionIndexer(), + new CodexSessionIndexer(), + new CursorSessionIndexer(), + new GeminiSessionIndexer(), +]; diff --git a/server/src/modules/llm/session-indexers/session-indexer.interface.ts b/server/src/modules/ai-runtime/session-indexers/session-indexer.interface.ts similarity index 100% rename from server/src/modules/llm/session-indexers/session-indexer.interface.ts rename to server/src/modules/ai-runtime/session-indexers/session-indexer.interface.ts diff --git a/server/src/modules/llm/session-indexers/session-indexer.utils.ts b/server/src/modules/ai-runtime/session-indexers/session-indexer.utils.ts similarity index 100% rename from server/src/modules/llm/session-indexers/session-indexer.utils.ts rename to server/src/modules/ai-runtime/session-indexers/session-indexer.utils.ts diff --git a/server/src/modules/llm/tests/llm-unifier.images.test.ts b/server/src/modules/ai-runtime/tests/images.test.ts similarity index 93% rename from server/src/modules/llm/tests/llm-unifier.images.test.ts rename to server/src/modules/ai-runtime/tests/images.test.ts index 1ff3a1a4..146f72f4 100644 --- a/server/src/modules/llm/tests/llm-unifier.images.test.ts +++ b/server/src/modules/ai-runtime/tests/images.test.ts @@ -6,11 +6,11 @@ import test from 'node:test'; import { AppError } from '@/shared/utils/app-error.js'; import { llmAssetsService } from '@/modules/assets/assets.service.js'; -import { ClaudeProvider } from '@/modules/llm/providers/claude.provider.js'; -import { CodexProvider } from '@/modules/llm/providers/codex.provider.js'; -import { CursorProvider } from '@/modules/llm/providers/cursor.provider.js'; -import { GeminiProvider } from '@/modules/llm/providers/gemini.provider.js'; -import { llmService } from '@/modules/llm/services/llm.service.js'; +import { ClaudeProvider } from '@/modules/ai-runtime/providers/claude/claude.provider.js'; +import { CodexProvider } from '@/modules/ai-runtime/providers/codex/codex.provider.js'; +import { CursorProvider } from '@/modules/ai-runtime/providers/cursor/cursor.provider.js'; +import { GeminiProvider } from '@/modules/ai-runtime/providers/gemini/gemini.provider.js'; +import { llmService } from '@/modules/ai-runtime/services/ai-runtime.service.js'; const asyncEvents = async function* (events: unknown[]) { for (const event of events) { diff --git a/server/src/modules/llm/tests/llm-unifier.mcp.test.ts b/server/src/modules/ai-runtime/tests/mcp.test.ts similarity index 99% rename from server/src/modules/llm/tests/llm-unifier.mcp.test.ts rename to server/src/modules/ai-runtime/tests/mcp.test.ts index b88aa59a..e1b5cc72 100644 --- a/server/src/modules/llm/tests/llm-unifier.mcp.test.ts +++ b/server/src/modules/ai-runtime/tests/mcp.test.ts @@ -8,7 +8,7 @@ import test from 'node:test'; import TOML from '@iarna/toml'; import { AppError } from '@/shared/utils/app-error.js'; -import { llmService } from '@/modules/llm/services/llm.service.js'; +import { llmService } from '@/modules/ai-runtime/services/ai-runtime.service.js'; const patchHomeDir = (nextHomeDir: string) => { const original = os.homedir; diff --git a/server/src/modules/llm/tests/llm-unifier.messages.test.ts b/server/src/modules/ai-runtime/tests/messages-unifier.test.ts similarity index 99% rename from server/src/modules/llm/tests/llm-unifier.messages.test.ts rename to server/src/modules/ai-runtime/tests/messages-unifier.test.ts index 248df952..1bc58b79 100644 --- a/server/src/modules/llm/tests/llm-unifier.messages.test.ts +++ b/server/src/modules/ai-runtime/tests/messages-unifier.test.ts @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { llmMessagesUnifier } from '@/modules/llm/services/messages-unifier.service.js'; +import { llmMessagesUnifier } from '@/modules/ai-runtime/services/messages-unifier.service.js'; /** * This test covers helper-3 Claude normalization: user/assistant/thinking/tool-use/tool-result/error. diff --git a/server/src/modules/llm/tests/llm-unifier.providers.test.ts b/server/src/modules/ai-runtime/tests/providers.test.ts similarity index 95% rename from server/src/modules/llm/tests/llm-unifier.providers.test.ts rename to server/src/modules/ai-runtime/tests/providers.test.ts index 459c0c1d..2b35658f 100644 --- a/server/src/modules/llm/tests/llm-unifier.providers.test.ts +++ b/server/src/modules/ai-runtime/tests/providers.test.ts @@ -5,11 +5,11 @@ import path from 'node:path'; import test from 'node:test'; import { AppError } from '@/shared/utils/app-error.js'; -import { llmService } from '@/modules/llm/services/llm.service.js'; -import { CursorProvider } from '@/modules/llm/providers/cursor.provider.js'; -import { GeminiProvider } from '@/modules/llm/providers/gemini.provider.js'; -import { CodexProvider } from '@/modules/llm/providers/codex.provider.js'; -import { ClaudeProvider } from '@/modules/llm/providers/claude.provider.js'; +import { llmService } from '@/modules/ai-runtime/services/ai-runtime.service.js'; +import { CursorProvider } from '@/modules/ai-runtime/providers/cursor/cursor.provider.js'; +import { GeminiProvider } from '@/modules/ai-runtime/providers/gemini/gemini.provider.js'; +import { CodexProvider } from '@/modules/ai-runtime/providers/codex/codex.provider.js'; +import { ClaudeProvider } from '@/modules/ai-runtime/providers/claude/claude.provider.js'; const asyncEvents = async function* (events: unknown[]) { for (const event of events) { diff --git a/server/src/modules/llm/tests/llm-unifier.sessions.test.ts b/server/src/modules/ai-runtime/tests/sessions.test.ts similarity index 97% rename from server/src/modules/llm/tests/llm-unifier.sessions.test.ts rename to server/src/modules/ai-runtime/tests/sessions.test.ts index 7ff2fd5e..b35c218e 100644 --- a/server/src/modules/llm/tests/llm-unifier.sessions.test.ts +++ b/server/src/modules/ai-runtime/tests/sessions.test.ts @@ -7,10 +7,10 @@ import test from 'node:test'; import { AppError } from '@/shared/utils/app-error.js'; import { scanStateDb } from '@/shared/database/repositories/scan-state.db.js'; import { sessionsDb } from '@/shared/database/repositories/sessions.db.js'; -import { llmSessionsService } from '@/modules/llm/services/sessions.service.js'; -import { sessionIndexers } from '@/modules/llm/session-indexers/index.js'; +import { llmSessionsService } from '@/modules/ai-runtime/services/sessions.service.js'; +import { sessionIndexers } from '@/modules/ai-runtime/session-indexers/index.js'; import { conversationSearchService } from '@/modules/conversations/conversation-search.service.js'; -import type { ISessionIndexer } from '@/modules/llm/session-indexers/session-indexer.interface.js'; +import type { ISessionIndexer } from '@/modules/ai-runtime/session-indexers/session-indexer.interface.js'; const patchMethod = (target: T, key: K, replacement: T[K]) => { const original = target[key]; diff --git a/server/src/modules/llm/tests/llm-unifier.skills.test.ts b/server/src/modules/ai-runtime/tests/skills.test.ts similarity index 99% rename from server/src/modules/llm/tests/llm-unifier.skills.test.ts rename to server/src/modules/ai-runtime/tests/skills.test.ts index 6bad1837..296764fc 100644 --- a/server/src/modules/llm/tests/llm-unifier.skills.test.ts +++ b/server/src/modules/ai-runtime/tests/skills.test.ts @@ -4,7 +4,7 @@ import os from 'node:os'; import path from 'node:path'; import test from 'node:test'; -import { llmService } from '@/modules/llm/services/llm.service.js'; +import { llmService } from '@/modules/ai-runtime/services/ai-runtime.service.js'; const patchHomeDir = (nextHomeDir: string) => { const original = os.homedir; diff --git a/server/src/modules/ai-runtime/types/index.ts b/server/src/modules/ai-runtime/types/index.ts new file mode 100644 index 00000000..35cd0df6 --- /dev/null +++ b/server/src/modules/ai-runtime/types/index.ts @@ -0,0 +1,3 @@ +export * from '@/modules/ai-runtime/types/provider.types.js'; +export * from '@/modules/ai-runtime/types/mcp.types.js'; +export * from '@/modules/ai-runtime/types/skills.types.js'; diff --git a/server/src/modules/ai-runtime/types/mcp.types.ts b/server/src/modules/ai-runtime/types/mcp.types.ts new file mode 100644 index 00000000..24822d0a --- /dev/null +++ b/server/src/modules/ai-runtime/types/mcp.types.ts @@ -0,0 +1,66 @@ +import type { LLMProvider } from '@/shared/types/app.js'; + +export type McpScope = 'user' | 'local' | 'project'; + +export type McpTransport = 'stdio' | 'http' | 'sse'; + +/** + * Provider MCP server descriptor normalized for frontend consumption. + */ +export type ProviderMcpServer = { + provider: LLMProvider; + name: string; + scope: McpScope; + transport: McpTransport; + command?: string; + args?: string[]; + env?: Record; + cwd?: string; + url?: string; + headers?: Record; + envVars?: string[]; + bearerTokenEnvVar?: string; + envHttpHeaders?: Record; +}; + +/** + * Shared payload shape for MCP server create/update operations. + */ +export type UpsertProviderMcpServerInput = { + name: string; + scope?: McpScope; + transport: McpTransport; + workspacePath?: string; + command?: string; + args?: string[]; + env?: Record; + cwd?: string; + url?: string; + headers?: Record; + envVars?: string[]; + bearerTokenEnvVar?: string; + envHttpHeaders?: Record; +}; + +/** + * MCP runtime contract for one provider. + */ +export interface IProviderMcpRuntime { + listServers(options?: { workspacePath?: string }): Promise>; + listServersForScope(scope: McpScope, options?: { workspacePath?: string }): Promise; + upsertServer(input: UpsertProviderMcpServerInput): Promise; + removeServer( + input: { name: string; scope?: McpScope; workspacePath?: string }, + ): Promise<{ removed: boolean; provider: LLMProvider; name: string; scope: McpScope }>; + runServer( + input: { name: string; scope?: McpScope; workspacePath?: string }, + ): Promise<{ + provider: LLMProvider; + name: string; + scope: McpScope; + transport: McpTransport; + reachable: boolean; + statusCode?: number; + error?: string; + }>; +} diff --git a/server/src/modules/llm/providers/provider.interface.ts b/server/src/modules/ai-runtime/types/provider.types.ts similarity index 52% rename from server/src/modules/llm/providers/provider.interface.ts rename to server/src/modules/ai-runtime/types/provider.types.ts index aedf24bd..0ba5cd7f 100644 --- a/server/src/modules/llm/providers/provider.interface.ts +++ b/server/src/modules/ai-runtime/types/provider.types.ts @@ -1,4 +1,6 @@ import type { LLMProvider } from '@/shared/types/app.js'; +import type { IProviderMcpRuntime } from '@/modules/ai-runtime/types/mcp.types.js'; +import type { IProviderSkillsRuntime } from '@/modules/ai-runtime/types/skills.types.js'; export type ProviderExecutionFamily = 'sdk' | 'cli'; @@ -6,12 +8,6 @@ export type ProviderSessionStatus = 'running' | 'completed' | 'failed' | 'stoppe export type RuntimePermissionMode = 'ask' | 'allow' | 'deny'; -export type McpScope = 'user' | 'local' | 'project'; - -export type McpTransport = 'stdio' | 'http' | 'sse'; - -export type ProviderSkillScope = 'user' | 'project' | 'plugin' | 'repo' | 'admin' | 'system'; - /** * Advertises optional provider behaviors so route/service code can gate features. */ @@ -20,57 +16,6 @@ export type ProviderCapabilities = { supportsThinkingModeControl: boolean; }; -/** - * Provider MCP server descriptor normalized for frontend consumption. - */ -export type ProviderMcpServer = { - provider: LLMProvider; - name: string; - scope: McpScope; - transport: McpTransport; - command?: string; - args?: string[]; - env?: Record; - cwd?: string; - url?: string; - headers?: Record; - envVars?: string[]; - bearerTokenEnvVar?: string; - envHttpHeaders?: Record; -}; - -/** - * Shared payload shape for MCP server create/update operations. - */ -export type UpsertProviderMcpServerInput = { - name: string; - scope?: McpScope; - transport: McpTransport; - workspacePath?: string; - command?: string; - args?: string[]; - env?: Record; - cwd?: string; - url?: string; - headers?: Record; - envVars?: string[]; - bearerTokenEnvVar?: string; - envHttpHeaders?: Record; -}; - -/** - * Unified skill descriptor returned by provider skill runtimes. - */ -export type ProviderSkill = { - provider: LLMProvider; - scope: ProviderSkillScope; - name: string; - description?: string; - invocation: string; - filePath: string; - pluginName?: string; -}; - /** * Provider model descriptor normalized for frontend consumption. */ @@ -145,36 +90,6 @@ export interface IProvider { listSessions(): ProviderSessionSnapshot[]; } -/** - * MCP runtime contract for one provider. - */ -export interface IProviderMcpRuntime { - listServers(options?: { workspacePath?: string }): Promise>; - listServersForScope(scope: McpScope, options?: { workspacePath?: string }): Promise; - upsertServer(input: UpsertProviderMcpServerInput): Promise; - removeServer( - input: { name: string; scope?: McpScope; workspacePath?: string }, - ): Promise<{ removed: boolean; provider: LLMProvider; name: string; scope: McpScope }>; - runServer( - input: { name: string; scope?: McpScope; workspacePath?: string }, - ): Promise<{ - provider: LLMProvider; - name: string; - scope: McpScope; - transport: McpTransport; - reachable: boolean; - statusCode?: number; - error?: string; - }>; -} - -/** - * Skills runtime contract for one provider. - */ -export interface IProviderSkillsRuntime { - listSkills(options?: { workspacePath?: string }): Promise; -} - /** * Internal mutable session state used by provider base classes. */ diff --git a/server/src/modules/ai-runtime/types/skills.types.ts b/server/src/modules/ai-runtime/types/skills.types.ts new file mode 100644 index 00000000..3a0bd194 --- /dev/null +++ b/server/src/modules/ai-runtime/types/skills.types.ts @@ -0,0 +1,23 @@ +import type { LLMProvider } from '@/shared/types/app.js'; + +export type ProviderSkillScope = 'user' | 'project' | 'plugin' | 'repo' | 'admin' | 'system'; + +/** + * Unified skill descriptor returned by provider skill runtimes. + */ +export type ProviderSkill = { + provider: LLMProvider; + scope: ProviderSkillScope; + name: string; + description?: string; + invocation: string; + filePath: string; + pluginName?: string; +}; + +/** + * Skills runtime contract for one provider. + */ +export interface IProviderSkillsRuntime { + listSkills(options?: { workspacePath?: string }): Promise; +} diff --git a/server/src/modules/codex/codex.routes.js b/server/src/modules/codex/codex.routes.js index 4e6dd1c7..cfdd232e 100644 --- a/server/src/modules/codex/codex.routes.js +++ b/server/src/modules/codex/codex.routes.js @@ -6,7 +6,7 @@ import os from 'os'; import TOML from '@iarna/toml'; import { getCodexSessions } from '../../../projects.js'; import { sessionsDb } from '@/shared/database/repositories/sessions.db.js'; -import { llmSessionsService } from '@/modules/llm/services/sessions.service.js'; +import { llmSessionsService } from '@/modules/ai-runtime/services/sessions.service.js'; const router = express.Router(); diff --git a/server/src/modules/gemini/gemini.routes.js b/server/src/modules/gemini/gemini.routes.js index d7c99018..6e9368ea 100644 --- a/server/src/modules/gemini/gemini.routes.js +++ b/server/src/modules/gemini/gemini.routes.js @@ -1,6 +1,6 @@ import express from 'express'; import sessionManager from '../../../sessionManager.js'; -import { llmSessionsService } from '@/modules/llm/services/sessions.service.js'; +import { llmSessionsService } from '@/modules/ai-runtime/services/sessions.service.js'; const router = express.Router(); diff --git a/server/src/modules/llm/session-indexers/index.ts b/server/src/modules/llm/session-indexers/index.ts deleted file mode 100644 index eb67bf49..00000000 --- a/server/src/modules/llm/session-indexers/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { ISessionIndexer } from '@/modules/llm/session-indexers/session-indexer.interface.js'; -import { ClaudeSessionIndexer } from '@/modules/llm/session-indexers/claude.session-indexer.js'; -import { CodexSessionIndexer } from '@/modules/llm/session-indexers/codex.session-indexer.js'; -import { CursorSessionIndexer } from '@/modules/llm/session-indexers/cursor.session-indexer.js'; -import { GeminiSessionIndexer } from '@/modules/llm/session-indexers/gemini.session-indexer.js'; - -/** - * Provider-specific session indexers used by the sync orchestrator. - */ -export const sessionIndexers: ISessionIndexer[] = [ - new ClaudeSessionIndexer(), - new CodexSessionIndexer(), - new CursorSessionIndexer(), - new GeminiSessionIndexer(), -]; diff --git a/server/src/modules/projects/projects.inline.routes.js b/server/src/modules/projects/projects.inline.routes.js index e2fbbbbf..aef23ecb 100644 --- a/server/src/modules/projects/projects.inline.routes.js +++ b/server/src/modules/projects/projects.inline.routes.js @@ -11,7 +11,7 @@ import { } from '../../../projects.js'; import { sessionsDb } from '@/shared/database/repositories/sessions.db.js'; import { workspaceOriginalPathsDb } from '@/shared/database/repositories/workspace-original-paths.db.js'; -import { llmSessionsService } from '@/modules/llm/services/sessions.service.js'; +import { llmSessionsService } from '@/modules/ai-runtime/services/sessions.service.js'; import { authenticateToken } from '../auth/auth.middleware.js'; import { getWorkspaceNameFromPath, WORKSPACES_ROOT, validateWorkspacePath } from './projects.utils.js'; diff --git a/server/src/modules/workspaces/workspaces.service.ts b/server/src/modules/workspaces/workspaces.service.ts index 8d230c10..5162f68a 100644 --- a/server/src/modules/workspaces/workspaces.service.ts +++ b/server/src/modules/workspaces/workspaces.service.ts @@ -1,6 +1,6 @@ import path from 'node:path'; -import { llmSessionsService } from '@/modules/llm/services/sessions.service.js'; +import { llmSessionsService } from '@/modules/ai-runtime/services/sessions.service.js'; import { sessionsDb } from '@/shared/database/repositories/sessions.db.js'; import { workspaceOriginalPathsDb } from '@/shared/database/repositories/workspace-original-paths.db.js'; import type { SessionsRow } from '@/shared/database/types.js'; diff --git a/server/src/runner.ts b/server/src/runner.ts index b184d103..6cdbdfa4 100644 --- a/server/src/runner.ts +++ b/server/src/runner.ts @@ -8,7 +8,7 @@ import { dirname } from 'path'; import { fileURLToPath } from 'url'; import { initializeDatabase } from '@/shared/database/init-db.js'; -import { initializeWatcher } from '@/modules/llm/services/sessions-watcher.service.js'; +import { initializeWatcher } from '@/modules/ai-runtime/services/sessions-watcher.service.js'; import { configureWebPush } from '@/modules/push-sub/push-sub.services.js'; import { getConnectableHost } from '@/shared/utils/networkHosts.js'; import { logger } from '@/shared/utils/logger.js'; @@ -92,7 +92,7 @@ const [ importRoute('./modules/workspaces/workspaces.routes.js'), importRoute('./modules/projects/projects.inline.routes.js'), importRoute('./modules/files/files.routes.js'), - importRoute('./modules/llm/llm.routes.js'), + importRoute('./modules/ai-runtime/ai-runtime.routes.js'), importRoute('./modules/assets/assets.routes.js'), ]);