emit post-stream suffixes to chat output
When tool results are streamed, suffixes appended after execution (truncation hints, user-interruptions, PostTool context) were only written to the stored message history but never emitted to the chat stream. This meant they never appeared in D-Bus signals or the chat file. Accumulate suffixes explicitly and emit them as a final event when streaming was active, guaranteeing they appear at the end of the tool output in all output paths.
This commit is contained in:
parent
75f11a7dc9
commit
273a31c5f1
|
|
@ -345,6 +345,9 @@ func run(ctx context.Context, cfg agentConfig, state state) error {
|
|||
result = "error: no tool executor configured"
|
||||
isErr = true
|
||||
}
|
||||
// Accumulate suffix text (PostTool context, user-interruptions,
|
||||
// truncation hints) that must be emitted after streaming completes.
|
||||
var suffix string
|
||||
if cfg.PostTool != nil {
|
||||
hr := cfg.PostTool(ctx, tc.Name, tc.Arguments, result)
|
||||
if hr.Failed > 0 {
|
||||
|
|
@ -353,31 +356,37 @@ func run(ctx context.Context, cfg agentConfig, state state) error {
|
|||
if hr.Blocked {
|
||||
result = hr.Context
|
||||
} else if hr.Context != "" {
|
||||
result += "\n" + hr.Context
|
||||
suffix += "\n" + hr.Context
|
||||
}
|
||||
}
|
||||
if cfg.PopInject != nil {
|
||||
if injected := cfg.PopInject(); injected != "" {
|
||||
result += "\n\n<system-user-interruption>\n" + injected + "\n</system-user-interruption>"
|
||||
suffix += "\n\n<system-user-interruption>\n" + injected + "\n</system-user-interruption>"
|
||||
}
|
||||
}
|
||||
result += suffix
|
||||
// Safety ceiling: unconditionally cap all tool results at 128KB.
|
||||
if len(result) > defaultToolResultMaxBytes {
|
||||
orig := len(result)
|
||||
result = strings.ToValidUTF8(result[:defaultToolResultMaxBytes], "")
|
||||
result += fmt.Sprintf("\n\n[HARD LIMIT: %s output truncated — %d of %d bytes shown. This is a safety ceiling, not a semantic boundary.]",
|
||||
suffix = fmt.Sprintf("\n\n[HARD LIMIT: %s output truncated — %d of %d bytes shown. This is a safety ceiling, not a semantic boundary.]",
|
||||
tc.Name, defaultToolResultMaxBytes, orig)
|
||||
result += suffix
|
||||
}
|
||||
if readSafe && !isErr {
|
||||
resultCache.Store(tc.Name+"\x00"+string(tc.Arguments), result)
|
||||
}
|
||||
// Invalidate cache on write operations that may change file contents.
|
||||
if !readSafe && (tc.Name == "file_write" || tc.Name == "file_edit") {
|
||||
*resultCache = sync.Map{}
|
||||
}
|
||||
if !streamed {
|
||||
emit(cfg, Event{Role: "tool", Name: tc.Name, Content: result})
|
||||
} else if suffix != "" {
|
||||
// Emit suffixes that were appended after streaming completed
|
||||
// so they appear at the end of the chat output.
|
||||
emit(cfg, Event{Role: "tool", Name: tc.Name, Content: suffix})
|
||||
}
|
||||
if readSafe && !isErr {
|
||||
resultCache.Store(tc.Name+"\x00"+string(tc.Arguments), result)
|
||||
}
|
||||
// Invalidate cache on write operations that may change file contents.
|
||||
if !readSafe && (tc.Name == "file_write" || tc.Name == "file_edit") {
|
||||
*resultCache = sync.Map{}
|
||||
}
|
||||
if !streamed {
|
||||
emit(cfg, Event{Role: "tool", Name: tc.Name, Content: result})
|
||||
}
|
||||
tier := TierHot
|
||||
if !isErr && cfg.ClassifyTier != nil {
|
||||
tier = cfg.ClassifyTier(tc.Name, tc.Arguments)
|
||||
|
|
|
|||
Reference in New Issue