refactor: preserve companion context boundaries

This commit is contained in:
Shakker
2026-08-11 23:36:08 +02:00
parent 281fe1e502
commit 72528033b2
24 changed files with 56 additions and 55 deletions
@@ -1 +1 @@
{"contentHash":"94b1959bd0129a903cc4608ebf04f4107a76e9c63f83ce765ebabaf5d351880d","entrypoint":"agent-harness-runtime","importSpecifier":"openclaw/plugin-sdk/agent-harness-runtime"}
{"contentHash":"7c5c92898e62f52b09c51a1dd55bcb758eb8a40a983cf9c079c913d95dba3b58","entrypoint":"agent-harness-runtime","importSpecifier":"openclaw/plugin-sdk/agent-harness-runtime"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"8d05bd692044b96ea39dc57b57d85d5ab0d203890d07e30205f881a36ff1ef9a","entrypoint":"agent-harness","importSpecifier":"openclaw/plugin-sdk/agent-harness"}
{"contentHash":"0069a9c1609324d148c10ae79fed31195bbd8d866a864d546ef8df3a9eb6f2eb","entrypoint":"agent-harness","importSpecifier":"openclaw/plugin-sdk/agent-harness"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"a74e00e9516ef7432d3328e8427b8b6a9b328fa046be88a0f6f8a9dfb2f9eb93","entrypoint":"agent-runtime","importSpecifier":"openclaw/plugin-sdk/agent-runtime"}
{"contentHash":"c7afeee04708492266b2cb6d742b00d6a1e170971a08b40a6178dae914eb6723","entrypoint":"agent-runtime","importSpecifier":"openclaw/plugin-sdk/agent-runtime"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"2f55da92897662de7da62b07293cfa08436d4d3d3f2e001f7f17ba9d3f6b857d","entrypoint":"channel-core","importSpecifier":"openclaw/plugin-sdk/channel-core"}
{"contentHash":"7a28969db8490d4b3c3f6f8c05db564ec89508030523a95a8a4248f8d9072edf","entrypoint":"channel-core","importSpecifier":"openclaw/plugin-sdk/channel-core"}
@@ -1 +1 @@
{"contentHash":"c1581b642422551d651709070c1f514766bb4f8b1839156d108bf21f40385dfd","entrypoint":"channel-entry-contract","importSpecifier":"openclaw/plugin-sdk/channel-entry-contract"}
{"contentHash":"532feed49e6fd72b81b4ce744d7284519158999cebb31db751174470fb63a3cc","entrypoint":"channel-entry-contract","importSpecifier":"openclaw/plugin-sdk/channel-entry-contract"}
@@ -1 +1 @@
{"contentHash":"0cefff48a3bb852d24762e709f6a1a18ec4c5995b58f98cf00e32e802f888b99","entrypoint":"channel-message","importSpecifier":"openclaw/plugin-sdk/channel-message"}
{"contentHash":"68796f883fb54466351cb0a077f3fd1f71ad6d6d1df53248f0d382e77a5f486f","entrypoint":"channel-message","importSpecifier":"openclaw/plugin-sdk/channel-message"}
@@ -1 +1 @@
{"contentHash":"c1cecc011c8dd65c39772504918f421d06f20a19d9a3f69ca8f65c5d0386337c","entrypoint":"channel-outbound","importSpecifier":"openclaw/plugin-sdk/channel-outbound"}
{"contentHash":"69a92cf59ee4dd7c66431a80aed3f32e0b4e830789e4cab7b4173ec2d502bcfc","entrypoint":"channel-outbound","importSpecifier":"openclaw/plugin-sdk/channel-outbound"}
@@ -1 +1 @@
{"contentHash":"cd8df374743a9e8e837f91554524b5269028ddf956715e73388553285143abcc","entrypoint":"channel-plugin-common","importSpecifier":"openclaw/plugin-sdk/channel-plugin-common"}
{"contentHash":"22ee5f9631d28579af7419f2e1263ecfa903f557b3b3e9962769e3a1fb61489d","entrypoint":"channel-plugin-common","importSpecifier":"openclaw/plugin-sdk/channel-plugin-common"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"2d415a89cd6c86f74c93c53bf1f50542da8c86f6740834523c04c3fff17ce112","entrypoint":"core","importSpecifier":"openclaw/plugin-sdk/core"}
{"contentHash":"432dc3f2d69b09ae1f8c64bf5c1b4f43d2a748ab79d90862ff2a9aadaa4af43f","entrypoint":"core","importSpecifier":"openclaw/plugin-sdk/core"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"774f94ebc272467ca053e63578576e51d14e33c3f7d4b6d3d87bf6dbf8a9ee2c","entrypoint":"discord","importSpecifier":"openclaw/plugin-sdk/discord"}
{"contentHash":"1f02b35bfc99cc8bdeea415dc430d832a74d9b1ff7e52243fea224a7a006425b","entrypoint":"discord","importSpecifier":"openclaw/plugin-sdk/discord"}
@@ -1 +1 @@
{"contentHash":"0f532b319124103380919829d8f11052c67b2481619c10da0be3c15bc1780757","entrypoint":"inbound-reply-dispatch","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch"}
{"contentHash":"6bff1e7ef600d59cfbe7adb7a67ed9ffe8173e50f89ba618f6f190e90fc74da9","entrypoint":"inbound-reply-dispatch","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch"}
@@ -1 +1 @@
{"contentHash":"b5d401c0fb43b473847b554efe1b8c543bf4b36936eb63b8cc999b117b8a6cff","entrypoint":"meeting-runtime","importSpecifier":"openclaw/plugin-sdk/meeting-runtime"}
{"contentHash":"8e07f0c6667ff6dfcafdf2dc98be90b0cc6aa8d8449bd1e35227976c63c4f8df","entrypoint":"meeting-runtime","importSpecifier":"openclaw/plugin-sdk/meeting-runtime"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"39f96b2b6eda3ca580e8acaeae00326869852191ddb98e93e2a1fd0859528e26","entrypoint":"plugin-entry","importSpecifier":"openclaw/plugin-sdk/plugin-entry"}
{"contentHash":"9be8b6ce4a747459accac5b8b4a64023f464d437d1117e3148b1199461dbb402","entrypoint":"plugin-entry","importSpecifier":"openclaw/plugin-sdk/plugin-entry"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"623d1669c4d237d6628b2ba36546f173b93f0b589aa8403c166e8d297e8ecb6a","entrypoint":"plugin-runtime","importSpecifier":"openclaw/plugin-sdk/plugin-runtime"}
{"contentHash":"c2e4b880b08c352ba57f781a0c629d15066c5842a287dac3727b1dd5d8561811","entrypoint":"plugin-runtime","importSpecifier":"openclaw/plugin-sdk/plugin-runtime"}
@@ -1 +1 @@
{"contentHash":"e31e5f3718f4843b3a7290ec60b747e2764585fad20bd2b55d739c12820246e1","entrypoint":"provider-catalog-runtime","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime"}
{"contentHash":"e4df60d58a485eed9e2b1509dded473da589102ad14a4ae7ba5cedb2250dc33c","entrypoint":"provider-catalog-runtime","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"d58f7527e51a8d16f49aaaad6b7bd5d366fd89152539427735e3ffe7090ebf11","entrypoint":"tool-plugin","importSpecifier":"openclaw/plugin-sdk/tool-plugin"}
{"contentHash":"06fad1eff295b30e25b2aa52c6259e67f2e74c15a5bd7f15e9e5e6c3d9be4934","entrypoint":"tool-plugin","importSpecifier":"openclaw/plugin-sdk/tool-plugin"}
@@ -1 +1 @@
{"contentHash":"7a4f8a5c6a523c2440769ca3d6fbd9e5b590207e013c2f00624d3ebcec5a72e6","entrypoint":"webhook-ingress","importSpecifier":"openclaw/plugin-sdk/webhook-ingress"}
{"contentHash":"6e792826511277b2940a7e788cffdaa647dff60767073ec0a0278d3d6319535d","entrypoint":"webhook-ingress","importSpecifier":"openclaw/plugin-sdk/webhook-ingress"}
@@ -63,10 +63,9 @@ export type SessionTranscriptBoundedMessageTailPage = SessionTranscriptMessageEv
serializedBytes: number;
};
export type SessionTranscriptBoundedContextMessageTailPage =
SessionTranscriptBoundedMessageTailPage & {
contextSummary?: { text: string; ts: number };
};
type SessionTranscriptBoundedContextMessageTailPage = SessionTranscriptBoundedMessageTailPage & {
contextSummary?: { text: string; ts: number };
};
function parseMessageEventRow(row: {
event_json: string;
@@ -29,6 +29,7 @@ import type {
} from "./server-chat-state.js";
import { resolveVisibleActiveSessionRunState } from "./server-methods/session-active-runs.js";
import { mapTaskSummary, type TaskEventPayload } from "./server-methods/task-summary.js";
import { defaultSessionCompanionContextReader } from "./session-companion-context.js";
import { createSessionCompanion } from "./session-companion.js";
import { createSessionObserver } from "./session-observer.js";
import type { TerminalSessionManager } from "./terminal/session-manager.js";
@@ -96,6 +97,7 @@ export function startGatewayEventSubscriptions(params: {
broadcastToConnIds: params.broadcastToConnIds,
});
const sessionCompanion = createSessionCompanion({
contextReader: defaultSessionCompanionContextReader,
getConfig: getRuntimeConfig,
sessionObserver,
});
+3 -6
View File
@@ -10,10 +10,7 @@ import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { Message, Usage } from "../llm/types.js";
import { redactToolPayloadText } from "../logging/redact.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import {
defaultSessionCompanionContextReader,
type SessionCompanionContextReader,
} from "./session-companion-context.js";
import type { SessionCompanionContextReader } from "./session-companion-context.js";
import {
buildSessionCompanionRunConfig,
SESSION_COMPANION_TOOLS,
@@ -58,7 +55,7 @@ export type SessionCompanionAskDeps = {
getCompanionSnapshot: (sessionKey: string) => SessionObserverCompanionSnapshot;
};
resolveUtilityModelRef?: typeof resolveUtilityModelRefForAgent;
contextReader?: SessionCompanionContextReader;
contextReader: SessionCompanionContextReader;
run?: (params: SessionCompanionRunParams) => Promise<string>;
now?: () => number;
setTimeoutFn?: typeof setTimeout;
@@ -366,7 +363,7 @@ function contextError(
export function createSessionCompanionAskRuntime(params: SessionCompanionAskRuntimeParams) {
const resolveUtilityModelRef = params.resolveUtilityModelRef ?? resolveUtilityModelRefForAgent;
const contextReader = params.contextReader ?? defaultSessionCompanionContextReader;
const contextReader = params.contextReader;
const run = params.run ?? defaultRun;
const setTimeoutFn = params.setTimeoutFn ?? setTimeout;
const clearTimeoutFn = params.clearTimeoutFn ?? clearTimeout;
+4 -12
View File
@@ -8,6 +8,10 @@ import {
readSessionTranscriptBoundedContextMessageTailPage,
} from "../config/sessions/session-accessor.sqlite-active-events.js";
import { redactToolPayloadText } from "../logging/redact.js";
import type {
SessionCompanionContextMessage,
SessionCompanionPreparedContext,
} from "./session-companion-state.js";
import { loadSessionEntryReadOnly } from "./session-utils.js";
const CONTEXT_MAX_MESSAGES = 40;
@@ -17,18 +21,6 @@ const CONTEXT_READ_PAGE_MESSAGES = CONTEXT_MAX_MESSAGES * 4;
const CONTEXT_READ_MAX_SCANNED_MESSAGES = 4096;
const CONTEXT_READ_MAX_BYTES = 1024 * 1024;
type SessionCompanionContextMessage = {
role: "assistant" | "summary" | "user";
text: string;
ts: number;
};
export type SessionCompanionPreparedContext = {
empty: boolean;
messages: SessionCompanionContextMessage[];
sessionId: string;
};
type SessionCompanionContextReadResult =
| { kind: "ready"; context: SessionCompanionPreparedContext }
| { kind: "missing" }
+13 -1
View File
@@ -1,7 +1,19 @@
import type { SessionCompanionExchange } from "../../packages/gateway-protocol/src/schema/sessions.js";
export type SessionCompanionContextMessage = {
role: "assistant" | "summary" | "user";
text: string;
ts: number;
};
export type SessionCompanionPreparedContext = {
empty: boolean;
messages: SessionCompanionContextMessage[];
sessionId: string;
};
export type SessionCompanionThread = {
context: import("./session-companion-context.js").SessionCompanionPreparedContext;
context: SessionCompanionPreparedContext;
digestText: string;
exchanges: SessionCompanionExchange[];
lastNoteSequence: number;
+1 -1
View File
@@ -62,13 +62,13 @@ function createHarness(overrides?: {
})),
);
const deps = {
contextReader: { currentSessionId, read: readContext },
getConfig: () => cfg,
sessionObserver: { getCompanionSnapshot },
resolveUtilityModelRef: () => "openai/gpt-5.6-luna",
run,
now: overrides?.now ?? (() => 100),
};
Object.assign(deps, { contextReader: { currentSessionId, read: readContext } });
const service = createSessionCompanion(deps);
return { currentSessionId, getCompanionSnapshot, readContext, run, service };
}
@@ -202,23 +202,22 @@ function companionHasActivity(thread: ChatSessionCompanionThread): boolean {
);
}
const COMPANION_HINT_KEYS = {
busy: "chat.rail.askBusy",
"history-unavailable": "chat.rail.askHistoryUnavailable",
missing: "chat.rail.askMissing",
"model-unavailable": "chat.rail.askModelUnavailable",
"rate-limited": "chat.rail.askRateLimited",
unavailable: "chat.rail.askUnavailable",
} as const satisfies Record<
NonNullable<ChatSessionCompanionThread["hint"]>,
Parameters<typeof t>[0]
>;
function companionHintKey(
hint: NonNullable<ChatSessionCompanionThread["hint"]>,
): Parameters<typeof t>[0] {
switch (hint) {
case "busy":
return "chat.rail.askBusy";
case "history-unavailable":
return "chat.rail.askHistoryUnavailable";
case "missing":
return "chat.rail.askMissing";
case "model-unavailable":
return "chat.rail.askModelUnavailable";
case "rate-limited":
return "chat.rail.askRateLimited";
case "unavailable":
return "chat.rail.askUnavailable";
}
return COMPANION_HINT_KEYS[hint];
}
export class ChatSessionRailElement extends OpenClawLightDomElement {