10 Commits

Author SHA1 Message Date
Ed Zynda fd960921ca refactor: address code audit findings across SDK, cmd, and internals
- Remove deprecated GenerateWithLoopAndStreaming and TreeManager
  AppendFantasyMessage / AddFantasyMessages / GetFantasyMessages to
  close the SDK leakage caused by the kit.TreeManager type alias
- Switch extensionAPI method signatures to local Extension* aliases so
  pkg.go.dev signatures no longer expose internal package names
- Bundle runNormalMode dependencies into a runModeDeps struct, shrinking
  the runNonInteractive and runInteractive call sites from 40+ positional
  args to (ctx, deps)
- Add generic subscribeTyped[E Event] helper and collapse ~30 typed OnXxx
  wrappers in pkg/kit/events.go onto it (public signatures unchanged)
- Extract setupBashPipes / interpretBashExit in internal/core/bash.go to
  deduplicate the buffered and streaming execution paths
- Extract resolveAutoRouteAPIKey and wrapProviderErr helpers in
  internal/models/providers.go and uniformly apply them across every
  createXxxProvider site
- Reimplement internal/extensions/watcher.go as a thin wrapper over the
  general-purpose internal/watcher.ContentWatcher, eliminating ~130 LOC
  of duplicated fsnotify logic while preserving the existing test API
- Add ctx.Err() pre-flight checks in executeRead / Write / Edit / Ls so
  cancellation actually short-circuits pure file-IO tools
2026-06-06 19:22:05 +03:00
Ed Zynda 53f6682bd0 refactor(core): remove redundant single-edit mode from edit tool
- Remove top-level old_text/new_text params from edit tool schema
- Make edits array the sole interface; single edits pass 1-item array
- Simplify normalizeEditInput, removing dual-mode branching logic
- Update UI renderer to only read from edits array
- Remove old_text/new_text from bodyKeys in message summarizer
- Update web session HTML to iterate edits array
- Convert all single-edit tests to use Edits array
- Replace mixed-mode test with empty-array validation test
2026-04-23 16:33:55 +03:00
Ed Zynda 8b1665a4ce feat: add multi-edit support to edit tool
Implement multi-edit functionality matching Pi's approach:
- Add 'edits' array parameter for multiple disjoint replacements
- All edits matched against original content (non-incremental)
- Overlap detection prevents conflicting edits
- Duplicate detection ensures unique matches
- Atomic operations: all succeed or none applied
- Detailed error messages with edit indices (edits[0], etc.)
- Fuzzy matching works with multi-edit mode
- Backward compatible with single-edit mode (old_text/new_text)

Changes:
- internal/core/edit.go: Multi-edit logic, validation, overlap detection
- internal/ui/messages.go: Add 'edits' to body keys
- internal/ui/tool_renderers.go: Render multi-edit diffs
- internal/core/edit_test.go: 9 comprehensive multi-edit tests
2026-03-27 10:34:43 +03:00
Ed Zynda b99aafaeaa fix: correct fuzzy match position mapping and diff generation in edit tool
Two bugs fixed in internal/core/edit.go:

1. fuzzyMatch/mapFuzzyIndex returned wrong byte positions when trailing
   whitespace was stripped during normalization. The old rune-counting
   approach assumed 1:1 mapping between original and normalized strings,
   but whitespace trimming changes string length. This caused the
   replacement splice to cut at wrong boundaries, corrupting files.

   Fix: replaced with normalizeWithMap() that builds an explicit
   byte-position mapping during normalization. Also added ambiguity
   guard — multiple fuzzy matches now return no-match instead of
   silently picking the wrong one.

2. generateDiff marked the entire rest of the file as changed.
   The old code used countNewlines(old[changeIdx:]) to compute the
   diff range, which counted ALL newlines from the change point to EOF.

   Fix: replaced hand-rolled diff with udiff.Unified() (already a
   dependency) for correct standard unified diff output.

Added internal/core/edit_test.go with 33 tests covering fuzzyMatch
position mapping, normalizeWithMap correctness, generateDiff output,
and end-to-end executeEdit scenarios including corruption regression
tests.
2026-03-22 18:02:07 +03:00
Ed Zynda c94edc929b feat: add rich tool metadata to SDK and extension events (Gaps 1-8)
Thread ToolCallID, ToolKind, ParsedArgs, FileDiff metadata, StopReason,
SessionID, and StructuredMessages across the SDK event bus, extension
wrapper, app bridge, hooks, and ACP server layers.

- Gap 1: ToolCallID from Fantasy's ToolCallContent threaded end-to-end
- Gap 2: ToolKind via static lookup (execute/edit/read/search/agent)
- Gap 3+4: FileDiffInfo with DiffBlocks via fantasy.ToolResponse.Metadata
- Gap 5: StopReason from Fantasy FinishReason on TurnEndEvent/TurnResult
- Gap 6: Subagent sessions now opt-out (NoSession); SessionID in JSON output
- Gap 7: GetStructuredMessages() returns typed ContentParts
- Gap 8: ParsedArgs map[string]any on tool events for convenience

Edit/write tools attach structured diff metadata. ACP server uses real
ToolCallIDs. Extension and SDK events kept in sync with matching fields.
2026-03-16 11:10:05 +03:00
Ed Zynda c925a69aec fix: remaining staticcheck QF1012 WriteString(Sprintf) violations 2026-02-27 18:42:45 +03:00
Ed Zynda 25a3523c56 fix: use fmt.Fprintf instead of WriteString(Sprintf) (staticcheck QF1012) 2026-02-27 18:40:11 +03:00
Ed Zynda d8f40039fe export tools and tool factories with WithWorkDir option (Plan 01)
- Add ToolOption/WithWorkDir functional options pattern to internal/core
- Update all 7 tool constructors to accept ...ToolOption and resolve
  paths relative to the configured working directory
- Create pkg/kit/tools.go with public exports: individual constructors,
  bundles (AllTools, CodingTools, ReadOnlyTools), and WithWorkDir
- Add CoreTools field to AgentConfig/AgentCreationOptions so callers
  can inject custom tool sets instead of hardcoding core.AllTools()
- Add Tools field to kit.Options and GetTools() to kit.Kit
- Fully backward compatible: no-arg calls use os.Getwd() as before
2026-02-27 11:37:46 +03:00
Ed Zynda 6ac8d3983a add SendMessage to extension Context and fix all golangci-lint issues
SendMessage lets extensions inject messages into the conversation and
trigger new agent turns, enabling async patterns like background
subagent execution. It delegates to app.Run() which handles queueing.

CommandDef.Execute now receives Context so commands can access
SendMessage, Print*, and session metadata. The UI layer wraps the
call via runner.GetContext() at the boundary.

Also fixes all 20+ golangci-lint issues across the codebase:
errcheck, modernize (min/max/slices.Contains/SplitSeq/range-over-int),
staticcheck (error string casing), and unused code removal.
2026-02-27 00:41:48 +03:00
Ed Zynda 3f2a399e47 replace builtin MCP tools with native core tools and custom content blocks
Remove the entire internal/builtin package (bash, fetch, todo, http, fs
servers) and all inprocess/builtin transport support from config and
connection pool.

Add internal/core package with 7 direct fantasy.AgentTool implementations
matching pi's coding agent: bash, read, write, edit, grep, find, ls.
These execute in-process with zero MCP/JSON serialization overhead.

Add internal/message package with crush-inspired custom content blocks:
ContentPart interface with TextContent, ReasoningContent, ToolCall,
ToolResult, and Finish types. Messages carry heterogeneous Parts slices
with type-tagged JSON serialization for persistence and a ToFantasyMessages
bridge for LLM provider integration.

Core tools are always registered on the agent. External MCP servers remain
supported for additional tools, but MCP loading failures are now non-fatal
since core tools guarantee a working baseline.
2026-02-26 17:41:02 +03:00