Files
gnoma/internal/session/session.go
vikingowl cb2d63d06f feat: Ollama/gemma4 compat — /init flow, stream filter, safety fixes
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
2026-04-05 19:24:51 +02:00

70 lines
1.6 KiB
Go

package session
import (
"somegit.dev/Owlibou/gnoma/internal/engine"
"somegit.dev/Owlibou/gnoma/internal/stream"
)
// SessionState tracks the current state of a session.
type SessionState int
const (
StateIdle SessionState = iota
StateStreaming
StateToolExec
StateCancelled
StateError
StateClosed
)
func (s SessionState) String() string {
switch s {
case StateIdle:
return "idle"
case StateStreaming:
return "streaming"
case StateToolExec:
return "tool_exec"
case StateCancelled:
return "cancelled"
case StateError:
return "error"
case StateClosed:
return "closed"
default:
return "unknown"
}
}
// Status holds observable session state.
type Status struct {
State SessionState
Provider string
Model string
TokensUsed int64
TokensMax int64
TokenPercent int // 0-100
TokenState string // "ok", "warning", "critical"
TurnCount int
}
// Session is the boundary between UI and engine.
// All communication is via channels. No shared mutable state.
type Session interface {
// Send submits user input and begins an agentic turn.
Send(input string) error
// SendWithOptions is like Send but applies per-turn engine options.
SendWithOptions(input string, opts engine.TurnOptions) error
// Events returns the channel that receives streaming events.
// A new channel is created per Send(). Closed when the turn completes.
Events() <-chan stream.Event
// TurnResult returns the completed Turn after Events() is drained.
TurnResult() (*engine.Turn, error)
// Cancel aborts the current turn.
Cancel()
// Close shuts down the session.
Close() error
// Status returns current session state.
Status() Status
}