You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by as...@apache.org on 2026/09/01 18:09:52 UTC
(maka) branch main updated: fix(desktop): declare a mode for Bot sessions
This is an automated email from the ASF dual-hosted git repository.
Astro-Han pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/maka.git
The following commit(s) were added to refs/heads/main by this push:
new 6b9de442f6 fix(desktop): declare a mode for Bot sessions
6b9de442f6 is described below
commit 6b9de442f653759fef68627ba3cb0ed1d705bcfc
Author: NekoPunch <95...@users.noreply.github.com>
AuthorDate: Tue Sep 1 11:09:47 2026 -0700
fix(desktop): declare a mode for Bot sessions
Every Bot conversation — Feishu, Telegram, WeCom — answered
`Maka 暂时无法处理这条消息:机器人对话处理失败` and never created a session, while the
platform connection itself stayed healthy.
`explore` is a boundary a product mode confers, not one a caller may request directly
(`create-session-input.ts`). The Bot adapter asked for it directly: `permissionMode:
'explore'` with no `mode`. `prepareCreate` rejected that, and the rejection matched no
category in `generalizedErrorMessage`, so what the user saw was a generic fallback that
read like a platform or credentials fault. Desktop chat was never affected — it starts
at `ask`.
A Bot session is exactly such a product intent, so `bot` joins `SESSION_START_MODE_SPECS`
and the adapter names the mode instead of asking for the boundary. Unlike Deep Research it
carries no name of its own: `prepareCreate` resolves `mode?.name ?? input.name`, and a
fixed spec name would flatten `飞书 任务` and `Telegram 任务` into one label, so
`SessionStartModeSpec.name` becomes optional. The `mode:bot` label is reserved for free,
since `prepareCreate` already refuses caller-supplied mode labels.
`session.create.mode` therefore accepts a value it did not before, and a Host that predates
it answers `Invalid Session start mode`, so `RUNTIME_HOST_COMPATIBILITY_EPOCH` moves 89 → 90.
The mode registry moves from `deep-research.ts` to `session-start-mode.ts`. It was born
there when Deep Research was its only member; `bot` is a sibling, not a Deep Research
detail, and nobody looks for Bot permissions in a file named for Deep Research. Pure move.
A mode without a name of its own also exposed a sibling defect: `sessions:create` dropped
the requested name whenever a mode was present, which held only while every mode carried
one. It now forwards the name either way and leaves the precedence to the Host. The Bot
adapter talks to the Host directly and never took that path, so that is a contract repair
rather than a second user-visible bug. Both regressions are guarded where they were
rejected — at the coordinator and at the IPC handler; the Bot adapter's own test reached
neither, because its fake client returns a session without entering `prepareCreate`, which
is why this shipped.
Deliberately not covered: `bot-incoming-main.ts` still swallows `invalid_request` into
`机器人对话处理失败`, which is what made this take a packaged-app patch to diagnose, and
`updateSessionConfiguration` still admits `explore` with no mode — the path `prepareSession`
uses to re-arm a bound Bot session.
Fixes #4193
Generated-by: Claude Code
---
apps/desktop/renderer-architecture.json | 4 +-
.../runtime-host-bot-session-adapter.test.ts | 4 +-
.../runtime-host-session-catalog-ipc-main.test.ts | 61 +++++++++++++++++++-
apps/desktop/src/main/create-session-input.ts | 4 +-
.../src/main/runtime-host-bot-session-adapter.ts | 2 +-
.../main/runtime-host-session-catalog-ipc-main.ts | 3 +-
.../src/renderer/app-shell-command-actions.ts | 2 +-
.../renderer/app-shell-session-start-actions.ts | 2 +-
.../application/contracts/session-start-mode.ts | 20 +++++++
packages/core/package.json | 1 +
packages/core/src/deep-research.ts | 42 +-------------
packages/core/src/runtime-inputs.ts | 2 +-
packages/core/src/session-start-mode.ts | 65 ++++++++++++++++++++++
.../__tests__/session-catalog-coordinator.test.ts | 34 +++++++++++
packages/runtime-host/src/protocol/index.ts | 4 +-
.../runtime-host/src/protocol/session-catalog.ts | 2 +-
.../src/server/session-catalog-coordinator.ts | 2 +-
17 files changed, 197 insertions(+), 57 deletions(-)
diff --git a/apps/desktop/renderer-architecture.json b/apps/desktop/renderer-architecture.json
index 14d7786e93..36e9bb5369 100644
--- a/apps/desktop/renderer-architecture.json
+++ b/apps/desktop/renderer-architecture.json
@@ -429,13 +429,13 @@
"dependencyPaths": {
"../preload/diagnostics-contract.js": 1,
"./app-shell-copy.js": 1,
+ "./application/contracts/session-start-mode.js": 1,
"./command-palette-commands.js": 1,
"./command-palette-types.js": 1,
"./conversation-markdown.js": 1,
"./default-runtime-host-operation.js": 1,
"./locales/settings-test-result-copy.js": 1,
"./locales/shell-copy.js": 1,
- "@maka/core/deep-research": 1,
"@maka/core/llm-connections": 1,
"@maka/core/permission": 1,
"@maka/core/session": 1,
@@ -754,10 +754,10 @@
],
"dependencyPaths": {
"../preload/bridge-contract.js": 1,
+ "./application/contracts/session-start-mode.js": 1,
"./locales/shell-copy.js": 1,
"./model-connection-errors.js": 1,
"./session-workspace-errors.js": 1,
- "@maka/core/deep-research": 1,
"@maka/core/ui-locale": 1,
"@maka/ui": 1
},
diff --git a/apps/desktop/src/main/__tests__/runtime-host-bot-session-adapter.test.ts b/apps/desktop/src/main/__tests__/runtime-host-bot-session-adapter.test.ts
index e9fd46f15a..780eaae806 100644
--- a/apps/desktop/src/main/__tests__/runtime-host-bot-session-adapter.test.ts
+++ b/apps/desktop/src/main/__tests__/runtime-host-bot-session-adapter.test.ts
@@ -36,7 +36,7 @@ import { runtimeHostSessionFixture } from './runtime-host-session-test-fixture.j
type BotClient = RuntimeHostBotSessionAdapterDeps['client'];
-test('creates an explore Session through the Host-owned default model route', async () => {
+test('creates a bot-mode Session through the Host-owned default model route', async () => {
const creates: unknown[] = [];
const changes: unknown[] = [];
const client = botClient({
@@ -68,7 +68,7 @@ test('creates an explore Session through the Host-owned default model route', as
name: 'Telegram conversation',
labels: ['bot', 'telegram'],
modelTarget: { kind: 'default' },
- permissionMode: 'explore',
+ mode: 'bot',
},
]);
assert.deepEqual(changes, [
diff --git a/apps/desktop/src/main/__tests__/runtime-host-session-catalog-ipc-main.test.ts b/apps/desktop/src/main/__tests__/runtime-host-session-catalog-ipc-main.test.ts
index a173957d97..26ae63728f 100644
--- a/apps/desktop/src/main/__tests__/runtime-host-session-catalog-ipc-main.test.ts
+++ b/apps/desktop/src/main/__tests__/runtime-host-session-catalog-ipc-main.test.ts
@@ -19,8 +19,13 @@
import assert from 'node:assert/strict';
import test from 'node:test';
-import type { SessionCatalogProjection } from '@maka/runtime-host/protocol';
-import { toDesktopHostSessionSummary } from '../runtime-host-session-catalog-ipc-main.js';
+import type { IpcMain } from 'electron';
+import type { SessionCatalogProjection, SessionCreateInput } from '@maka/runtime-host/protocol';
+import {
+ registerRuntimeHostSessionCatalogIpc,
+ toDesktopHostSessionSummary,
+ type RuntimeHostSessionCatalogIpcDeps,
+} from '../runtime-host-session-catalog-ipc-main.js';
test('maps Runtime Host live run state without collapsing unknown and known-empty', () => {
const unknown = toDesktopHostSessionSummary(projection());
@@ -36,6 +41,58 @@ test('maps Runtime Host live run state without collapsing unknown and known-empt
assert.deepEqual(running.runningTurnIds, ['turn-live']);
});
+test('session creation forwards the caller name for a mode that carries none', async () => {
+ const creates: SessionCreateInput[] = [];
+ const ipc = ipcHarness();
+ registerRuntimeHostSessionCatalogIpc(createDeps(creates), ipc as unknown as IpcMain);
+
+ await ipc.invoke('sessions:create', { mode: 'bot', name: '飞书 任务' });
+ await ipc.invoke('sessions:create', { mode: 'deep_research', name: '飞书 任务' });
+
+ assert.deepEqual(
+ creates.map((input) => [input.mode, input.name]),
+ [
+ ['bot', '飞书 任务'],
+ ['deep_research', '飞书 任务'],
+ ],
+ );
+});
+
+type IpcHandler = Parameters<Pick<IpcMain, 'handle'>['handle']>[1];
+
+function ipcHarness() {
+ const handlers = new Map<string, IpcHandler>();
+ return {
+ handle(channel: string, handler: IpcHandler) {
+ handlers.set(channel, handler);
+ },
+ async invoke(channel: string, ...args: unknown[]): Promise<unknown> {
+ const handler = handlers.get(channel);
+ assert.ok(handler, `missing handler: ${channel}`);
+ return handler({} as never, ...args);
+ },
+ };
+}
+
+function createDeps(creates: SessionCreateInput[]): RuntimeHostSessionCatalogIpcDeps {
+ return {
+ client: {
+ createSession: async (input: SessionCreateInput) => {
+ creates.push(input);
+ return projection({ id: input.sessionId });
+ },
+ } as unknown as RuntimeHostSessionCatalogIpcDeps['client'],
+ runningTurnIds: () => [],
+ resolveCreateProject: async () => ({ kind: 'host_path', path: '/workspace' }),
+ emitSessionsChanged: () => {},
+ releaseSessionResources: () => {},
+ sessionCopyCleanup: {
+ ownCreation: async <T>(_creation: unknown, operation: () => Promise<T>) => operation(),
+ recover: async () => ({ removed: [], failed: [] }),
+ } as unknown as RuntimeHostSessionCatalogIpcDeps['sessionCopyCleanup'],
+ };
+}
+
function projection(overrides: Partial<SessionCatalogProjection> = {}): SessionCatalogProjection {
return {
id: 'session-1',
diff --git a/apps/desktop/src/main/create-session-input.ts b/apps/desktop/src/main/create-session-input.ts
index b61ea0b931..d098cf9614 100644
--- a/apps/desktop/src/main/create-session-input.ts
+++ b/apps/desktop/src/main/create-session-input.ts
@@ -43,7 +43,7 @@ import type { OrchestrationMode } from '@maka/core/orchestration';
import type { PermissionMode } from '@maka/core/permission';
-import type { SessionStartMode } from '@maka/core/deep-research';
+import type { SessionStartMode } from '@maka/core/session-start-mode';
import { DEFAULT_SESSION_NAME } from '@maka/core/session-name';
import { isChatDefaultPermissionMode } from '@maka/core/settings';
@@ -52,7 +52,7 @@ import { isCollaborationMode } from '@maka/core/collaboration';
import { isOrchestrationMode } from '@maka/core/orchestration';
-import { isSessionStartMode } from '@maka/core/deep-research';
+import { isSessionStartMode } from '@maka/core/session-start-mode';
/**
* `unknown`, because this is an IPC boundary and the renderer's type is a
diff --git a/apps/desktop/src/main/runtime-host-bot-session-adapter.ts b/apps/desktop/src/main/runtime-host-bot-session-adapter.ts
index e0d0f31a90..9f7fdfc275 100644
--- a/apps/desktop/src/main/runtime-host-bot-session-adapter.ts
+++ b/apps/desktop/src/main/runtime-host-bot-session-adapter.ts
@@ -76,7 +76,7 @@ export function createRuntimeHostBotSessionAdapter(
name: input.name,
labels: [...input.labels],
modelTarget: { kind: 'default' },
- permissionMode: 'explore',
+ mode: 'bot',
});
} catch (error) {
if (
diff --git a/apps/desktop/src/main/runtime-host-session-catalog-ipc-main.ts b/apps/desktop/src/main/runtime-host-session-catalog-ipc-main.ts
index cda8a0fb38..f4c2586e5e 100644
--- a/apps/desktop/src/main/runtime-host-session-catalog-ipc-main.ts
+++ b/apps/desktop/src/main/runtime-host-session-catalog-ipc-main.ts
@@ -132,7 +132,8 @@ export function registerRuntimeHostSessionCatalogIpc(
sessionId: newId(),
workspace,
...(request.mode === undefined ? {} : { mode: request.mode }),
- ...(request.mode === undefined ? { name: request.name } : {}),
+ // A nameless mode (`bot`) keeps the caller's name, so always forward it.
+ name: request.name,
...(request.labels === undefined ? {} : { labels: request.labels }),
modelTarget: normalizeModelTarget(input),
...normalizeCreateThinkingLevel(input?.thinkingLevel),
diff --git a/apps/desktop/src/renderer/app-shell-command-actions.ts b/apps/desktop/src/renderer/app-shell-command-actions.ts
index 0cfcb58143..61a60dc34d 100644
--- a/apps/desktop/src/renderer/app-shell-command-actions.ts
+++ b/apps/desktop/src/renderer/app-shell-command-actions.ts
@@ -20,12 +20,12 @@
import { useMemo, useRef } from "react";
import type { LlmConnection } from '@maka/core/llm-connections';
import type { PermissionMode } from '@maka/core/permission';
-import type { SessionStartMode } from '@maka/core/deep-research';
import type { SessionSummary, StoredMessage } from '@maka/core/session';
import type { SettingsSection, ThemePreference } from '@maka/core/settings';
import type { UiLocale } from '@maka/core/ui-locale';
import type { NavSelection } from "@maka/ui";
import type { DesktopManualDiagnosticTarget } from '../preload/diagnostics-contract.js';
+import type { SessionStartMode } from './application/contracts/session-start-mode.js';
import {
defaultRuntimeHostDiagnosticTarget,
runOnDefaultRuntimeHost,
diff --git a/apps/desktop/src/renderer/app-shell-session-start-actions.ts b/apps/desktop/src/renderer/app-shell-session-start-actions.ts
index 344ebbd502..48309d896f 100644
--- a/apps/desktop/src/renderer/app-shell-session-start-actions.ts
+++ b/apps/desktop/src/renderer/app-shell-session-start-actions.ts
@@ -17,10 +17,10 @@
* under the License.
*/
-import type { SessionStartMode } from '@maka/core/deep-research';
import type { UiLocale } from '@maka/core/ui-locale';
import type { NavSelection } from '@maka/ui';
import type { DesktopNewTaskTarget } from '../preload/bridge-contract.js';
+import type { SessionStartMode } from './application/contracts/session-start-mode.js';
import { getShellCopy, localizedShellErrorMessage } from './locales/shell-copy.js';
import {
isNoRealConnectionError,
diff --git a/apps/desktop/src/renderer/application/contracts/session-start-mode.ts b/apps/desktop/src/renderer/application/contracts/session-start-mode.ts
new file mode 100644
index 0000000000..dfcc44e660
--- /dev/null
+++ b/apps/desktop/src/renderer/application/contracts/session-start-mode.ts
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export type { SessionStartMode } from '@maka/core/session-start-mode';
diff --git a/packages/core/package.json b/packages/core/package.json
index bace3c8bc0..6a76b3ed8d 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -79,6 +79,7 @@
"./work-board": "./dist/work-board.js",
"./workhub-creation-intent": "./dist/workhub-creation-intent.js",
"./deep-research": "./dist/deep-research.js",
+ "./session-start-mode": "./dist/session-start-mode.js",
"./long-term-memory": "./dist/long-term-memory.js",
"./local-memory": "./dist/local-memory.js",
"./web-search": "./dist/web-search.js",
diff --git a/packages/core/src/deep-research.ts b/packages/core/src/deep-research.ts
index 9f480ed920..3088a90fee 100644
--- a/packages/core/src/deep-research.ts
+++ b/packages/core/src/deep-research.ts
@@ -20,47 +20,7 @@
/** Read-only Deep Research session semantics and prompt contract. */
import type { DeepResearchRun } from './deep-research-run.js';
-import type { PermissionMode } from './permission.js';
-
-/**
- * A product intent a caller can open a new session at, distinct from the
- * ordinary chat that needs no intent at all. Absence is spelled `undefined`,
- * not a `'chat'` member: a second spelling of "no mode" is a second thing to
- * keep in agreement.
- */
-export interface SessionStartModeSpec {
- readonly name: string;
- readonly labels: readonly string[];
- readonly permissionMode: PermissionMode;
-}
-
-export const SESSION_START_MODE_SPECS = {
- deep_research: {
- name: 'Deep Research',
- labels: ['mode:deep_research'],
- permissionMode: 'explore',
- },
-} as const satisfies Record<string, SessionStartModeSpec>;
-
-export type SessionStartMode = keyof typeof SESSION_START_MODE_SPECS;
-export const SESSION_START_MODES: readonly SessionStartMode[] = Object.keys(
- SESSION_START_MODE_SPECS,
-) as SessionStartMode[];
-export const SESSION_START_MODE_LABELS: readonly string[] = [
- ...new Set(Object.values(SESSION_START_MODE_SPECS).flatMap((spec) => spec.labels)),
-];
-
-export function isSessionStartMode(value: unknown): value is SessionStartMode {
- return typeof value === 'string' && Object.hasOwn(SESSION_START_MODE_SPECS, value);
-}
-
-export function sessionStartModeSpec(mode: SessionStartMode): SessionStartModeSpec {
- return SESSION_START_MODE_SPECS[mode];
-}
-
-export function isSessionStartModeLabel(value: unknown): value is string {
- return typeof value === 'string' && SESSION_START_MODE_LABELS.includes(value);
-}
+import { SESSION_START_MODE_SPECS } from './session-start-mode.js';
export const DEEP_RESEARCH_SESSION_NAME = SESSION_START_MODE_SPECS.deep_research.name;
export const DEEP_RESEARCH_SESSION_LABEL = SESSION_START_MODE_SPECS.deep_research.labels[0];
diff --git a/packages/core/src/runtime-inputs.ts b/packages/core/src/runtime-inputs.ts
index a3ac133ed2..b104f44346 100644
--- a/packages/core/src/runtime-inputs.ts
+++ b/packages/core/src/runtime-inputs.ts
@@ -34,7 +34,7 @@ import type { PermissionMode } from './permission.js';
import type { ThinkingLevel } from './model-thinking.js';
import type { CollaborationMode } from './collaboration.js';
import type { OrchestrationMode, TurnOrchestration } from './orchestration.js';
-import type { SessionStartMode } from './deep-research.js';
+import type { SessionStartMode } from './session-start-mode.js';
import type { SubagentWorkspaceBinding } from './subagent-workspace.js';
import type { ToolMode } from './tool-mode.js';
import type { TurnOrigin } from './turn-origin.js';
diff --git a/packages/core/src/session-start-mode.ts b/packages/core/src/session-start-mode.ts
new file mode 100644
index 0000000000..b90dc13859
--- /dev/null
+++ b/packages/core/src/session-start-mode.ts
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import type { PermissionMode } from './permission.js';
+
+/**
+ * A product intent a caller can open a new session at, distinct from the
+ * ordinary chat that needs no intent at all. Absence is spelled `undefined`,
+ * not a `'chat'` member: a second spelling of "no mode" is a second thing to
+ * keep in agreement.
+ */
+export interface SessionStartModeSpec {
+ /** Omitted where the mode keeps the caller's name, as `bot` does. */
+ readonly name?: string;
+ readonly labels: readonly string[];
+ readonly permissionMode: PermissionMode;
+}
+
+export const SESSION_START_MODE_SPECS = {
+ deep_research: {
+ name: 'Deep Research',
+ labels: ['mode:deep_research'],
+ permissionMode: 'explore',
+ },
+ bot: {
+ labels: ['mode:bot'],
+ permissionMode: 'explore',
+ },
+} as const satisfies Record<string, SessionStartModeSpec>;
+
+export type SessionStartMode = keyof typeof SESSION_START_MODE_SPECS;
+export const SESSION_START_MODES: readonly SessionStartMode[] = Object.keys(
+ SESSION_START_MODE_SPECS,
+) as SessionStartMode[];
+export const SESSION_START_MODE_LABELS: readonly string[] = [
+ ...new Set(Object.values(SESSION_START_MODE_SPECS).flatMap((spec) => spec.labels)),
+];
+
+export function isSessionStartMode(value: unknown): value is SessionStartMode {
+ return typeof value === 'string' && Object.hasOwn(SESSION_START_MODE_SPECS, value);
+}
+
+export function sessionStartModeSpec(mode: SessionStartMode): SessionStartModeSpec {
+ return SESSION_START_MODE_SPECS[mode];
+}
+
+export function isSessionStartModeLabel(value: unknown): value is string {
+ return typeof value === 'string' && SESSION_START_MODE_LABELS.includes(value);
+}
diff --git a/packages/runtime-host/src/__tests__/session-catalog-coordinator.test.ts b/packages/runtime-host/src/__tests__/session-catalog-coordinator.test.ts
index c02dde9c3c..614998f366 100644
--- a/packages/runtime-host/src/__tests__/session-catalog-coordinator.test.ts
+++ b/packages/runtime-host/src/__tests__/session-catalog-coordinator.test.ts
@@ -921,6 +921,40 @@ test('creation materializes Deep Research semantics inside the Host transaction'
assert.equal(fixture.drainRequests(), 0);
});
+test('bot mode grants explore while keeping the Bot-supplied Session name', async () => {
+ let created: Parameters<CatalogStores['createStableSession']>[0] | undefined;
+ const fixture = createFixture({
+ stores: {
+ createStableSession: async (request) => {
+ created = request;
+ return {
+ kind: 'existing',
+ record: headerSnapshot(sessionHeader(request.sessionId, request.input.labels ?? []), 3),
+ };
+ },
+ },
+ });
+
+ const outcome = await fixture.coordinator.handlers['session.create'](
+ {
+ sessionId: fixture.sessionId,
+ workspace: { kind: 'host_path', path: process.cwd() },
+ mode: 'bot',
+ name: '飞书 任务',
+ labels: ['bot', 'feishu'],
+ modelTarget: { kind: 'default' },
+ },
+ context,
+ );
+
+ assert.equal(outcome.ok, true);
+ assert.ok(created);
+ assert.equal(created.input.name, '飞书 任务');
+ assert.deepEqual(created.input.labels, ['bot', 'feishu', 'mode:bot']);
+ assert.equal(created.input.permissionMode, 'explore');
+ assert.equal(fixture.drainRequests(), 0);
+});
+
test('configuration update admits Plan mode through Runtime authority', async () => {
const fixture = createFixture();
const input = configurationInput(fixture.sessionId, fixture.revision());
diff --git a/packages/runtime-host/src/protocol/index.ts b/packages/runtime-host/src/protocol/index.ts
index 2a1706def0..a173fdbc4a 100644
--- a/packages/runtime-host/src/protocol/index.ts
+++ b/packages/runtime-host/src/protocol/index.ts
@@ -100,7 +100,9 @@ export const RUNTIME_HOST_REGISTRATION_SCHEMA_VERSION = 1 as const;
export const RUNTIME_HOST_PROTOCOL_VERSION = 0 as const;
// Increment when the same protocol version no longer guarantees safe Client-Host
// interoperability. Mismatches are rejected before domain commands are admitted.
-export const RUNTIME_HOST_COMPATIBILITY_EPOCH = 89 as const;
+export const RUNTIME_HOST_COMPATIBILITY_EPOCH = 90 as const;
+// 90: `session.create.mode` accepts the Bot session mode. A Host that predates
+// it rejects the value as an invalid Session start mode.
// 89: The Host refreshes its models.dev catalog at startup and announces the
// swap with a `connection.catalog.changed` frame, which an older client's
// strict frame decoder rejects as an unknown kind.
diff --git a/packages/runtime-host/src/protocol/session-catalog.ts b/packages/runtime-host/src/protocol/session-catalog.ts
index da2ffcbbd6..0820a6b693 100644
--- a/packages/runtime-host/src/protocol/session-catalog.ts
+++ b/packages/runtime-host/src/protocol/session-catalog.ts
@@ -20,7 +20,7 @@
import { isCollaborationMode, type CollaborationMode } from '@maka/core/collaboration';
import { isOrchestrationMode, type OrchestrationMode } from '@maka/core/orchestration';
import { isPermissionMode, type PermissionMode } from '@maka/core/permission';
-import { isSessionStartMode, type SessionStartMode } from '@maka/core/deep-research';
+import { isSessionStartMode, type SessionStartMode } from '@maka/core/session-start-mode';
import {
isSessionBlockedReason,
isSessionToolProfile,
diff --git a/packages/runtime-host/src/server/session-catalog-coordinator.ts b/packages/runtime-host/src/server/session-catalog-coordinator.ts
index 18e8d05e56..3180a34226 100644
--- a/packages/runtime-host/src/server/session-catalog-coordinator.ts
+++ b/packages/runtime-host/src/server/session-catalog-coordinator.ts
@@ -32,7 +32,7 @@ import { DEFAULT_SESSION_NAME, normalizeUserSessionName } from '@maka/core/sessi
import {
isSessionStartModeLabel as isExecutionSemanticLabel,
sessionStartModeSpec,
-} from '@maka/core/deep-research';
+} from '@maka/core/session-start-mode';
import {
isWorkHubCoordinationSessionId,
isWorkHubCoordinationSessionTarget,
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org