You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@casbin.apache.org by hs...@apache.org on 2026/09/06 16:05:20 UTC
(casbin-gateway) 02/02: fix(chat): keep Codex's passing notices out of the reply
This is an automated email from the ASF dual-hosted git repository.
hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-gateway.git
commit 0ddd45549f82cc34980cbbbbcdf9f5ca8709b2ba
Author: Yang Luo <hs...@gmail.com>
AuthorDate: Mon Sep 7 00:05:10 2026 +0800
fix(chat): keep Codex's passing notices out of the reply
---
agentsession/event.go | 6 +++++-
agentsession/parse_codex.go | 5 ++++-
imbridge/render.go | 19 ++++++++++++++-----
web/src/pages/ChatPage.tsx | 14 +++++++++++++-
web/src/types.ts | 2 +-
5 files changed, 37 insertions(+), 9 deletions(-)
diff --git a/agentsession/event.go b/agentsession/event.go
index 57a663e..9483510 100644
--- a/agentsession/event.go
+++ b/agentsession/event.go
@@ -30,6 +30,10 @@ const (
EventUsage EventType = "usage"
EventDone EventType = "done"
EventError EventType = "error"
+ // EventNotice is something the agent mentioned in passing - a setting it
+ // ignored, a limit it worked around. The turn carried on, so it is kept out
+ // of the answer and shown beside it.
+ EventNotice EventType = "notice"
)
// Event is one piece of what an agent said, in a shape every agent is flattened
@@ -44,7 +48,7 @@ type Event struct {
CreatedTime string `json:"createdTime"`
// Text is the answer for EventText and EventThinking, and the message for
- // EventError.
+ // EventError and EventNotice.
Text string `json:"text,omitempty"`
ToolName string `json:"toolName,omitempty"`
diff --git a/agentsession/parse_codex.go b/agentsession/parse_codex.go
index 4e2ec37..1a16255 100644
--- a/agentsession/parse_codex.go
+++ b/agentsession/parse_codex.go
@@ -138,9 +138,12 @@ func emitCodexItem(item *codexItem, emit func(Event)) {
event.ToolName = "Edit"
event.ToolInput = firstOf(item.Text, item.Message)
emit(event)
+ // An error item is Codex saying something went sideways without the turn
+ // ending: a setting it dropped, a budget it trimmed to fit. A turn that
+ // really failed says so through turn.failed, which fails the run.
case "error":
if text := firstOf(item.Message, item.Text); text != "" {
- emit(textEvent(EventError, text))
+ emit(textEvent(EventNotice, text))
}
}
}
diff --git a/imbridge/render.go b/imbridge/render.go
index 7d1d200..f2f366a 100644
--- a/imbridge/render.go
+++ b/imbridge/render.go
@@ -25,6 +25,9 @@ import (
// what an agent did is most of what somebody watching wants to see.
type answerBuffer struct {
parts []string
+ // prose says the last part is the agent talking, which is the only part a
+ // fragment of prose may be joined onto.
+ prose bool
// dirty says something has arrived since the last time this was written out.
dirty bool
}
@@ -37,25 +40,31 @@ func (b *answerBuffer) add(event agentsession.Event) {
}
// Prose arrives in fragments, so it is joined onto the piece before it
// rather than starting a new one.
- if len(b.parts) > 0 && !strings.HasPrefix(b.parts[len(b.parts)-1], toolMarker) {
+ if b.prose {
b.parts[len(b.parts)-1] += event.Text
} else {
b.parts = append(b.parts, event.Text)
+ b.prose = true
}
case agentsession.EventToolUse:
b.parts = append(b.parts, toolMarker+toolLine(event))
+ b.prose = false
case agentsession.EventError:
- if event.Text != "" {
- b.parts = append(b.parts, "\n⚠ "+event.Text)
+ if event.Text == "" {
+ return
}
+ b.parts = append(b.parts, "\n⚠ "+event.Text)
+ b.prose = false
+ // What the agent mentioned in passing stays out of the chat: the answer is
+ // what somebody asked for, and a warning about a setting on top of every
+ // reply is noise. The session page still shows it.
default:
return
}
b.dirty = true
}
-// toolMarker starts the pieces that are a tool rather than prose, so a fragment
-// of prose is not appended onto one.
+// toolMarker sets a tool line apart from the prose around it.
const toolMarker = "· "
// toolInputLimit keeps a command in the message without the message becoming the
diff --git a/web/src/pages/ChatPage.tsx b/web/src/pages/ChatPage.tsx
index 883e190..93933ce 100644
--- a/web/src/pages/ChatPage.tsx
+++ b/web/src/pages/ChatPage.tsx
@@ -49,6 +49,9 @@ interface Turn {
seq: number;
prompt: string;
blocks: Block[];
+ // notices are what the agent mentioned in passing; they are shown beside the
+ // answer rather than in it, because the turn carried on regardless.
+ notices: string[];
error: string;
usage?: DrivenEvent;
done: boolean;
@@ -78,7 +81,7 @@ function toTurns(events: DrivenEvent[]): Turn[] {
for (const event of events) {
switch (event.type) {
case "prompt":
- turn = {seq: event.seq, prompt: event.text ?? "", blocks: [], error: "", done: false};
+ turn = {seq: event.seq, prompt: event.text ?? "", blocks: [], notices: [], error: "", done: false};
turns.push(turn);
break;
case "text":
@@ -112,6 +115,11 @@ function toTurns(events: DrivenEvent[]): Turn[] {
turn.error = event.text ?? "";
}
break;
+ case "notice":
+ if (turn && event.text && !turn.notices.includes(event.text)) {
+ turn.notices.push(event.text);
+ }
+ break;
case "done":
if (turn) {
turn.done = true;
@@ -166,6 +174,10 @@ function TurnView({turn}: {turn: Turn}) {
);
})}
+ {turn.notices.map(notice => (
+ <MessageAlert key={notice} variant="warning" description={notice} />
+ ))}
+
{turn.error ? <MessageAlert variant="destructive" title={turn.error} /> : null}
{turn.usage ? (
diff --git a/web/src/types.ts b/web/src/types.ts
index 978122c..adc40e6 100644
--- a/web/src/types.ts
+++ b/web/src/types.ts
@@ -553,7 +553,7 @@ export interface DrivenSession {
/** One piece of what a driven agent said, in the shape every agent is flattened into. */
export interface DrivenEvent {
- type: "prompt" | "text" | "thinking" | "toolUse" | "toolResult" | "usage" | "done" | "error";
+ type: "prompt" | "text" | "thinking" | "toolUse" | "toolResult" | "usage" | "done" | "error" | "notice";
seq: number;
createdTime: string;
text?: string;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@casbin.apache.org
For additional commands, e-mail: commits-help@casbin.apache.org