mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-29 01:31:18 +00:00
fix(tui): accept canonical session-key aliases in chat event routing
This commit is contained in:
@@ -41,6 +41,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
- Gateway/chat streaming tool-boundary text retention: merge assistant delta segments into per-run chat buffers so pre-tool text is preserved in live chat deltas/finals when providers emit post-tool assistant segments as non-prefix snapshots. (#36957) Thanks @Datyedyeguy.
|
- Gateway/chat streaming tool-boundary text retention: merge assistant delta segments into per-run chat buffers so pre-tool text is preserved in live chat deltas/finals when providers emit post-tool assistant segments as non-prefix snapshots. (#36957) Thanks @Datyedyeguy.
|
||||||
- TUI/model indicator freshness: prevent stale session snapshots from overwriting freshly patched model selection (and reset per-session freshness when switching session keys) so `/model` updates reflect immediately instead of lagging by one or more commands. (#21255) Thanks @kowza.
|
- TUI/model indicator freshness: prevent stale session snapshots from overwriting freshly patched model selection (and reset per-session freshness when switching session keys) so `/model` updates reflect immediately instead of lagging by one or more commands. (#21255) Thanks @kowza.
|
||||||
- TUI/final-error rendering fallback: when a chat `final` event has no renderable assistant content but includes envelope `errorMessage`, render the formatted error text instead of collapsing to `"(no output)"`, preserving actionable failure context in-session. (#14687) Thanks @Mquarmoc.
|
- TUI/final-error rendering fallback: when a chat `final` event has no renderable assistant content but includes envelope `errorMessage`, render the formatted error text instead of collapsing to `"(no output)"`, preserving actionable failure context in-session. (#14687) Thanks @Mquarmoc.
|
||||||
|
- TUI/session-key alias event matching: treat chat events whose session keys are canonical aliases (for example `agent:<id>:main` vs `main`) as the same session while preserving cross-agent isolation, so assistant replies no longer disappear or surface in another terminal window due to strict key-form mismatch. (#33937) Thanks @yjh1412.
|
||||||
- OpenAI Codex OAuth/login hardening: fail OAuth completion early when the returned token is missing `api.responses.write`, and allow `openclaw models auth login --provider openai-codex` to use the built-in OAuth path even when no provider plugins are installed. (#36660) Thanks @driesvints.
|
- OpenAI Codex OAuth/login hardening: fail OAuth completion early when the returned token is missing `api.responses.write`, and allow `openclaw models auth login --provider openai-codex` to use the built-in OAuth path even when no provider plugins are installed. (#36660) Thanks @driesvints.
|
||||||
- OpenAI Codex OAuth/scope request parity: augment the OAuth authorize URL with required API scopes (`api.responses.write`, `model.request`, `api.model.read`) before browser handoff so OAuth tokens include runtime model/request permissions expected by OpenAI API calls. (#24720) Thanks @Skippy-Gunboat.
|
- OpenAI Codex OAuth/scope request parity: augment the OAuth authorize URL with required API scopes (`api.responses.write`, `model.request`, `api.model.read`) before browser handoff so OAuth tokens include runtime model/request permissions expected by OpenAI API calls. (#24720) Thanks @Skippy-Gunboat.
|
||||||
- Onboarding/API key input hardening: strip non-Latin1 Unicode artifacts from normalized secret input (while preserving Latin-1 content and internal spaces) so malformed copied API keys cannot trigger HTTP header `ByteString` construction crashes; adds regression coverage for shared normalization and MiniMax auth header usage. (#24496) Thanks @fa6maalassaf.
|
- Onboarding/API key input hardening: strip non-Latin1 Unicode artifacts from normalized secret input (while preserving Latin-1 content and internal spaces) so malformed copied API keys cannot trigger HTTP header `ByteString` construction crashes; adds regression coverage for shared normalization and MiniMax auth header usage. (#24496) Thanks @fa6maalassaf.
|
||||||
|
|||||||
@@ -193,6 +193,44 @@ describe("tui-event-handlers: handleAgentEvent", () => {
|
|||||||
expect(chatLog.startTool).toHaveBeenCalledWith("tc1", "exec", undefined);
|
expect(chatLog.startTool).toHaveBeenCalledWith("tc1", "exec", undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("accepts chat events when session key is an alias of the active canonical key", () => {
|
||||||
|
const { state, chatLog, handleChatEvent } = createHandlersHarness({
|
||||||
|
state: {
|
||||||
|
currentSessionKey: "agent:main:main",
|
||||||
|
activeChatRunId: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
handleChatEvent({
|
||||||
|
runId: "run-alias",
|
||||||
|
sessionKey: "main",
|
||||||
|
state: "delta",
|
||||||
|
message: { content: "hello" },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(state.activeChatRunId).toBe("run-alias");
|
||||||
|
expect(chatLog.updateAssistant).toHaveBeenCalledWith("hello", "run-alias");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not cross-match canonical session keys from different agents", () => {
|
||||||
|
const { chatLog, handleChatEvent } = createHandlersHarness({
|
||||||
|
state: {
|
||||||
|
currentAgentId: "alpha",
|
||||||
|
currentSessionKey: "agent:alpha:main",
|
||||||
|
activeChatRunId: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
handleChatEvent({
|
||||||
|
runId: "run-other-agent",
|
||||||
|
sessionKey: "agent:beta:main",
|
||||||
|
state: "delta",
|
||||||
|
message: { content: "should be ignored" },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(chatLog.updateAssistant).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it("clears run mapping when the session changes", () => {
|
it("clears run mapping when the session changes", () => {
|
||||||
const { state, chatLog, tui, handleChatEvent, handleAgentEvent } = createHandlersHarness({
|
const { state, chatLog, tui, handleChatEvent, handleAgentEvent } = createHandlersHarness({
|
||||||
state: { activeChatRunId: null },
|
state: { activeChatRunId: null },
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { parseAgentSessionKey } from "../sessions/session-key-utils.js";
|
||||||
import { asString, extractTextFromMessage, isCommandMessage } from "./tui-formatters.js";
|
import { asString, extractTextFromMessage, isCommandMessage } from "./tui-formatters.js";
|
||||||
import { TuiStreamAssembler } from "./tui-stream-assembler.js";
|
import { TuiStreamAssembler } from "./tui-stream-assembler.js";
|
||||||
import type { AgentEvent, ChatEvent, TuiStateAccess } from "./tui-types.js";
|
import type { AgentEvent, ChatEvent, TuiStateAccess } from "./tui-types.js";
|
||||||
@@ -146,13 +147,36 @@ export function createEventHandlers(context: EventHandlerContext) {
|
|||||||
void loadHistory?.();
|
void loadHistory?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isSameSessionKey = (left: string | undefined, right: string | undefined): boolean => {
|
||||||
|
const normalizedLeft = (left ?? "").trim().toLowerCase();
|
||||||
|
const normalizedRight = (right ?? "").trim().toLowerCase();
|
||||||
|
if (!normalizedLeft || !normalizedRight) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (normalizedLeft === normalizedRight) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const parsedLeft = parseAgentSessionKey(normalizedLeft);
|
||||||
|
const parsedRight = parseAgentSessionKey(normalizedRight);
|
||||||
|
if (parsedLeft && parsedRight) {
|
||||||
|
return parsedLeft.agentId === parsedRight.agentId && parsedLeft.rest === parsedRight.rest;
|
||||||
|
}
|
||||||
|
if (parsedLeft) {
|
||||||
|
return parsedLeft.rest === normalizedRight;
|
||||||
|
}
|
||||||
|
if (parsedRight) {
|
||||||
|
return normalizedLeft === parsedRight.rest;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
const handleChatEvent = (payload: unknown) => {
|
const handleChatEvent = (payload: unknown) => {
|
||||||
if (!payload || typeof payload !== "object") {
|
if (!payload || typeof payload !== "object") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const evt = payload as ChatEvent;
|
const evt = payload as ChatEvent;
|
||||||
syncSessionKey();
|
syncSessionKey();
|
||||||
if (evt.sessionKey !== state.currentSessionKey) {
|
if (!isSameSessionKey(evt.sessionKey, state.currentSessionKey)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (finalizedRuns.has(evt.runId)) {
|
if (finalizedRuns.has(evt.runId)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user