provider/openai: - Fix doubled tool call args (argsComplete flag): Ollama sends complete args in the first streaming chunk then repeats them as delta, causing doubled JSON and 400 errors in elfs - Handle fs: prefix (gemma4 uses fs:grep instead of fs.grep) - Add Reasoning field support for Ollama thinking output cmd/gnoma: - Early TTY detection so logger is created with correct destination before any component gets a reference to it (fixes slog WARN bleed into TUI textarea) permission: - Exempt spawn_elfs and agent tools from safety scanner: elf prompt text may legitimately mention .env/.ssh/credentials patterns and should not be blocked tui/app: - /init retry chain: no-tool-calls → spawn_elfs nudge → write nudge (ask for plain text output) → TUI fallback write from streamBuf - looksLikeAgentsMD + extractMarkdownDoc: validate and clean fallback content before writing (reject refusals, strip narrative preambles) - Collapse thinking output to 3 lines; ctrl+o to expand (live stream and committed messages) - Stream-level filter for model pseudo-tool-call blocks: suppresses <<tool_code>>...</tool_code>> and <<function_call>>...<tool_call|> from entering streamBuf across chunk boundaries - sanitizeAssistantText regex covers both block formats - Reset streamFilterClose at every turn start
35 lines
1.0 KiB
Go
35 lines
1.0 KiB
Go
package context
|
|
|
|
import "somegit.dev/Owlibou/gnoma/internal/message"
|
|
|
|
// safeSplitPoint adjusts a compaction split index to avoid orphaning tool
|
|
// results. If history[target] is a tool-result message, it walks backward
|
|
// until it finds a message that is not a tool result, so the assistant message
|
|
// that issued the tool calls stays in the "recent" window alongside its results.
|
|
//
|
|
// target is the index of the first message to keep in the recent window.
|
|
// Returns an adjusted index guaranteed to keep tool-call/tool-result pairs together.
|
|
func safeSplitPoint(history []message.Message, target int) int {
|
|
if target <= 0 || len(history) == 0 {
|
|
return 0
|
|
}
|
|
if target >= len(history) {
|
|
target = len(history) - 1
|
|
}
|
|
idx := target
|
|
for idx > 0 && hasToolResults(history[idx]) {
|
|
idx--
|
|
}
|
|
return idx
|
|
}
|
|
|
|
// hasToolResults reports whether msg contains any ContentToolResult blocks.
|
|
func hasToolResults(msg message.Message) bool {
|
|
for _, c := range msg.Content {
|
|
if c.Type == message.ContentToolResult {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|