Skip to content

v0.9.0 - The Unification Refactor

Choose a tag to compare

@Arthur-Ficial Arthur-Ficial released this 06 Apr 22:43

The Unification Refactor

This release eliminates the duplicated logic between singlePrompt() and chat() that caused bugs #37 and #43. Both now share a single processPrompt() function for retry, streaming, and MCP tool execution.

Bug Fixes

  • Chat+MCP crash fixed (#43): apfel --chat --mcp server.py no longer crashes with "Last message has no text content". The session is now built directly with tool definitions instead of requiring a user message at init time.
  • Ctrl-C exits chat cleanly: SIGINT is properly handled via a C-level handler around libedit. Previously Ctrl-C was silently swallowed by readline.
  • Context rotation preserves MCP tools: After context window rotation in chat mode, MCP tool definitions are re-injected into the new session. Previously, tools silently stopped working after the first rotation.
  • Summarizer respects --permissive: The summarize context strategy now uses makeModel(permissive:) instead of SystemLanguageModel.default, honoring the --permissive flag.

New Features

  • --debug for all modes (#44): The --debug flag now works in CLI single-prompt, chat, and server modes. Debug output goes to stderr and includes prompt info, response length, MCP tool execution, and context rotation events.
  • Missing error cases (#41): Added unsupportedGuide and decodingFailure to ApfelError with proper classification, CLI labels, HTTP status codes, and OpenAI error types.
  • Homebrew formula fix (#45): The odie "apfel requires Apple Silicon" hard error has been replaced with a caveats warning, allowing installation on machines where Homebrew's ARM detection may report incorrectly (e.g., M4 Mac Mini).

Architecture

  • Extracted processPrompt() - unified retry + streaming + MCP tool execution shared by singlePrompt() and chat()
  • Added ToolLogEntry and ProcessPromptResult types to ApfelCore
  • Added apfelDebugEnabled global flag with debugLog() functions
  • Added ContextConfig.permissive field threaded through to Summarizer
  • Dead code removed: sseStopChunk(), buildSystemPrompt(), formatToolResult()

Testing

  • 377 total tests (203 unit + 174 integration), all passing
  • 35 new chat integration tests covering every TUI scenario:
    • Startup, quit, exit, EOF, non-TTY rejection
    • Chat + MCP (no crash, tool listing, tool execution, tool log, system prompt combo)
    • Chat + system prompt (flag, short flag, env var)
    • Chat + debug (stderr output, prompt info, response info, stdout isolation)
    • Chat output formats (plain, JSON, JSONL, quiet)
    • Chat + flags (temperature, max-tokens, permissive, retry)
    • Chat multi-turn context retention
    • Ctrl-C at prompt, mid-line, during response, multiple times
    • Non-tool questions answered normally in MCP mode
  • Integration test conftest.py now auto-starts servers (no manual server startup needed)

Closed Issues

  • #41 - Review error handling: 3 GenerationError cases not classified
  • #42 - Use Apple Intelligence's ChatGPT extension (closed as won't-fix, outside scope)
  • #43 - Chat+MCP crash on startup
  • #44 - Add --debug mode for CLI and chat
  • #45 - Homebrew install returning Apple Silicon error on M4 Mac Mini

Update

brew upgrade apfel