mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-14 13:22:37 +00:00
fix(omp): reopened chats no longer show extra "Custom message" rows (#6198)
After a daemon restart, an OMP chat replays from its session file. Three kinds of entries that the live timeline never shows were replayed as collapsed "Custom message" rows: - the rule-violation reminder OMP adds after a tool call matches one of its rules, a developer message that opens with <system-reminder reason="rule_violation" ...>, while only the bare <system-reminder> tag was hidden - the ttsr_injection entry OMP records alongside that reminder - the fileMention message an @-mentioned file adds, and the other OMP message roles the live timeline drops Closes #6131 Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
This commit is contained in:
@@ -252,6 +252,90 @@ describe("OMP history mapper", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test("replays a rule-violation run with the same rows the live timeline showed", async () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "omp-rule-reminder-history-"));
|
||||
const sessionFile = join(dir, "session.jsonl");
|
||||
writeFileSync(
|
||||
sessionFile,
|
||||
[
|
||||
{ type: "session", id: "root" },
|
||||
{
|
||||
type: "message",
|
||||
id: "prompt",
|
||||
parentId: "root",
|
||||
message: {
|
||||
role: "user",
|
||||
content: "Read @notes.md, then write tiny.ts",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "message",
|
||||
id: "mention",
|
||||
parentId: "prompt",
|
||||
message: {
|
||||
role: "fileMention",
|
||||
files: [
|
||||
{
|
||||
path: "notes.md",
|
||||
content: "[notes.md#468D]\n1:# notes",
|
||||
lineCount: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "ttsr_injection",
|
||||
id: "injection",
|
||||
parentId: "mention",
|
||||
injectedRules: ["ts-no-tiny-functions"],
|
||||
},
|
||||
{
|
||||
type: "message",
|
||||
id: "rule-reminder",
|
||||
parentId: "injection",
|
||||
message: {
|
||||
role: "developer",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: '<system-reminder reason="rule_violation" rule="ts-no-tiny-functions" path="builtin-defaults:ts-no-tiny-functions">\nAvoid tiny functions.\n</system-reminder>',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "message",
|
||||
id: "answer",
|
||||
parentId: "rule-reminder",
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "FINAL_ANSWER" }],
|
||||
},
|
||||
},
|
||||
]
|
||||
.map((entry) => JSON.stringify(entry))
|
||||
.join("\n"),
|
||||
);
|
||||
const events: AgentStreamEvent[] = [];
|
||||
for await (const event of streamOmpHistory({
|
||||
sessionFile,
|
||||
provider: "omp",
|
||||
}))
|
||||
events.push(event);
|
||||
expect(events.map((event) => event.item)).toEqual([
|
||||
{
|
||||
type: "user_message",
|
||||
text: "Read @notes.md, then write tiny.ts",
|
||||
messageId: "prompt",
|
||||
},
|
||||
{
|
||||
type: "assistant_message",
|
||||
text: "FINAL_ANSWER",
|
||||
messageId: "omp-history-assistant-1",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test("coalesces replayed subagent poll calls by target set", async () => {
|
||||
const events = await collectHistory([
|
||||
{
|
||||
|
||||
@@ -360,8 +360,7 @@ function mapEntryMessage(entry: OmpSessionEntry): OmpAgentMessage | null {
|
||||
content.length === 1 &&
|
||||
content[0]?.type === "text" &&
|
||||
typeof content[0].text === "string" &&
|
||||
content[0].text.trimStart().startsWith("<system-reminder>") &&
|
||||
content[0].text.trimEnd().endsWith("</system-reminder>")
|
||||
isSystemReminder(content[0].text)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
@@ -370,6 +369,19 @@ function mapEntryMessage(entry: OmpSessionEntry): OmpAgentMessage | null {
|
||||
if (["user", "assistant", "toolResult", "custom", "bashExecution"].includes(message.role)) {
|
||||
return message as unknown as OmpAgentMessage;
|
||||
}
|
||||
// OMP roles the live timeline does not render either, such as the fileMention that carries
|
||||
// an @-mentioned file's content.
|
||||
if (
|
||||
[
|
||||
"pythonExecution",
|
||||
"hookMessage",
|
||||
"branchSummary",
|
||||
"compactionSummary",
|
||||
"fileMention",
|
||||
].includes(message.role)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return visibleFallback(message.role, message);
|
||||
}
|
||||
if (entry.type === "custom_message") {
|
||||
@@ -399,6 +411,13 @@ function mapCustomMessageEntry(entry: OmpSessionEntry): OmpAgentMessage | null {
|
||||
} as OmpAgentMessage;
|
||||
}
|
||||
|
||||
// OMP's rule-violation reminder carries attributes: <system-reminder reason="rule_violation" ...>
|
||||
function isSystemReminder(text: string): boolean {
|
||||
return (
|
||||
/^<system-reminder[\s>]/.test(text.trimStart()) && text.trimEnd().endsWith("</system-reminder>")
|
||||
);
|
||||
}
|
||||
|
||||
function isControlEntryType(type: string): boolean {
|
||||
return (
|
||||
type === "session" ||
|
||||
@@ -410,6 +429,7 @@ function isControlEntryType(type: string): boolean {
|
||||
type === "system_prompt" ||
|
||||
type === "model_change" ||
|
||||
type === "thinking_level_change" ||
|
||||
type === "ttsr_injection" ||
|
||||
type === "tool_execution" ||
|
||||
type.startsWith("tool_execution_")
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user