Commit Graph

807 Commits

Author SHA1 Message Date
Dhanji R. Prasanna
0234920446 Print g3 progress and status on same line
- print_g3_progress now uses print! instead of println!
- print_g3_status completes the line with just the status
- Result: 'g3: compacting session ... [done]' on one line
2026-01-17 17:28:20 +05:30
Dhanji R. Prasanna
8dad00bdd0 Colorize session name in cyan in continuation prompt 2026-01-17 15:58:46 +05:30
Dhanji R. Prasanna
0d6a66a252 Compress session continuation prompt to single line
- Combine session info and resume prompt on one line
- Show result inline after user input (y/n)
- Green '... resuming ... [done]' on successful resume
- Dark grey '... starting fresh' when declining
- Yellow '... failed: <error>' on restore failure
2026-01-17 15:56:05 +05:30
Dhanji R. Prasanna
5622e5b21e refactor(cli): show only loaded items in startup status line
Changes the startup status line to only display items that were
actually loaded, instead of showing dots for missing items.

Before: "   · README  · AGENTS.md  ✓ Memory"
After:  "   ✓ Memory"

Also adds include prompt to the status line when specified:
"   ✓ prompt.md  ✓ Memory"

The order matches the load order: README → AGENTS.md → include prompt → Memory
2026-01-17 15:35:37 +05:30
Dhanji R. Prasanna
4877f8ae8a test(cli): add integration tests for --include-prompt and --no-auto-memory flags
Adds blackbox tests to verify:
- --include-prompt option is recognized by CLI parser
- --include-prompt appears in help output
- --no-auto-memory option is recognized by CLI parser
- --no-auto-memory appears in help output
2026-01-17 15:27:04 +05:30
Dhanji R. Prasanna
b0740b63c2 feat(cli): add --no-auto-memory flag to disable memory reminder in agent mode
Adds a flag to disable the automatic memory update reminder that runs
at the end of agent mode. Useful when running agents that should not
modify project memory.
2026-01-17 15:24:16 +05:30
Dhanji R. Prasanna
6bb5448d3f feat(project_files): add read_include_prompt() and update combine_project_content()
- Add read_include_prompt() function to read prompt content from a file
- Update combine_project_content() to accept include_prompt parameter
- Change prompt order: cwd → agents → readme → language → include_prompt → memory
- Add section markers around Project Memory for clearer boundaries
- Add comprehensive tests for include prompt functionality and ordering
2026-01-17 15:20:01 +05:30
Dhanji R. Prasanna
e45d5b25f3 feat(cli): wire up --include-prompt in main CLI and agent mode
Updates lib.rs and agent_mode.rs to read the include prompt file
and pass it through to combine_project_content(). The include prompt
is placed after language prompts but before project memory.
2026-01-17 15:19:55 +05:30
Dhanji R. Prasanna
56e8fddfc4 feat(cli): add --include-prompt flag for dynamic prompt injection
Adds a new CLI flag that allows users to include additional prompt
content from a file. The content is appended to the system prompt
before project memory is loaded.
2026-01-17 15:19:49 +05:30
Dhanji R. Prasanna
d89439d4b8 Fix macOS security policy rejection after install
After copying binaries to ~/.local/bin, macOS AppleSystemPolicy would
reject them because the linker-signed code signature becomes invalid.

Now re-sign binaries with ad-hoc signature after copying on macOS.
2026-01-17 11:41:45 +05:30
Dhanji R. Prasanna
d600b600b8 Always keep chromedriver running for faster subsequent startups
Removed the persistent_chrome config flag - chromedriver is now always
kept running after webdriver_quit. This eliminates startup latency for
subsequent WebDriver sessions.

Safaridriver is still killed on quit since it doesn't benefit from
persistence in the same way.

Updated quit message to correctly indicate chromedriver remains running.
2026-01-17 09:48:10 +05:30
Dhanji R. Prasanna
8ed360024f Add persistent ChromeDriver support for faster WebDriver startup
When webdriver_start is called, now checks if chromedriver is already
running on the configured port and reuses it instead of spawning a new
process. This significantly reduces startup time for subsequent sessions.

New config option:
  [webdriver]
  persistent_chrome = true  # Keep chromedriver running between sessions

When enabled, webdriver_quit closes the browser session but leaves
chromedriver running for reuse by the next session.
2026-01-17 09:26:25 +05:30
Dhanji R. Prasanna
eb6268641f Fix --safari flag being blocked by Chrome diagnostics
When --safari was passed, Chrome diagnostics were still running because
--chrome-headless defaults to true. This caused the CLI to hang while
running diagnostics for a browser that wouldn't be used.

Now skip Chrome diagnostics when --safari is explicitly set.
2026-01-17 09:20:21 +05:30
Dhanji R. Prasanna
e3967a9948 refactor: remove animation from context thinning display
Simplify print_context_thinning to just print the message directly.
The message already contains proper ANSI formatting from context_window.rs.

Removes the flash animation and 'Context optimized successfully' footer.
2026-01-17 05:00:12 +05:30
Dhanji R. Prasanna
b8193bf9f9 style: use orange color for [no changes] status in thinning message 2026-01-17 04:53:42 +05:30
Dhanji R. Prasanna
74b1b9bea3 refactor: simplify context thinning status message
Change format from verbose emoji-based message to cleaner status line:
  Before:  🥒 Context thinned at 70%: 7 tool results, ~33839 chars saved 
  After:  g3: thinning context ... 70% -> 40% ... [done]

The new format shows before/after percentages and uses bold green for
'g3:' and '[done]' to match other status messages.

Also removes unused emoji() and label() methods from ThinScope.
2026-01-17 04:47:16 +05:30
Dhanji R. Prasanna
c7984fd4c2 fix: account for base64 encoding overhead in image size limit
The Anthropic API has a 5MB limit on base64-encoded images, not raw file
size. Base64 encoding increases size by ~33% (4/3 ratio), so a 4MB raw
image becomes ~5.3MB encoded, exceeding the limit.

Changed MAX_IMAGE_SIZE from 5MB to ~3.75MB (5MB * 3/4) to trigger
resizing before the base64-encoded result exceeds the API limit.

Also updated target resize size to 3.6MB to leave margin.
2026-01-16 21:29:05 +05:30
Dhanji R. Prasanna
1003386f7f Auto-resize large images (>=5MB) in read_image tool
Images >= 5MB are now automatically resized to < 4.9MB using ImageMagick
before being sent to the LLM. This prevents API errors from oversized images.

- Uses iterative quality/scale reduction to find optimal size
- Converts to JPEG for better compression
- Shows original and resized size in terminal output (e.g., '6.2 MB → 4.1 MB (resized)')
- Falls back to original if ImageMagick fails or isn't available
2026-01-16 21:09:38 +05:30
Dhanji R. Prasanna
fc702168ab Add streaming completion integration test with mock LLM provider
Adds tests to verify that:
- All streaming chunks are processed before control returns to caller
- Both tool calls in a multi-tool-call stream are executed
- The finished signal properly terminates stream processing

Also adds Agent::new_for_test() to allow injecting mock providers.
2026-01-16 20:52:32 +05:30
Dhanji R. Prasanna
0e33465342 Add print_g3_progress/print_g3_status methods for consistent status messages 2026-01-16 20:28:24 +05:30
Dhanji R. Prasanna
95f89d3f8e Simplify compaction status messages 2026-01-16 20:26:35 +05:30
Dhanji R. Prasanna
415226ca84 Add newline before context progress display 2026-01-16 20:24:29 +05:30
Dhanji R. Prasanna
cebec23075 Fix duplicate response printing in interactive mode
The response was being printed twice: once during streaming and again
after task completion. Removed the redundant print_smart() call since
streaming already displays the response in real-time.
2026-01-16 14:48:50 +05:30
Dhanji R. Prasanna
4c6878a63d Set process title to agent name in agent mode
When running g3 --agent butler, the process title is now "g3 [butler]"
which shows up in ps, Activity Monitor, top, etc.

Uses the proctitle crate for cross-platform support.
2026-01-16 14:37:58 +05:30
Dhanji R. Prasanna
1f6a5671b2 Use agent name as prompt in --agent --chat mode (e.g., "butler>")
Changed run_interactive() parameter from bool to Option<&str> agent_name.
When agent_name is Some, use it as the prompt instead of "g3>".
2026-01-16 13:58:45 +05:30
Dhanji R. Prasanna
2e6bef4b24 Auto-memory: call once on exit for --agent --chat, per-turn for single-shot
When running g3 --agent <name> --chat:
- Skip per-turn memory checkpoint calls (too onerous)
- Call memory checkpoint once when exiting (Ctrl-D)

When running g3 --agent <name> (single-shot):
- Preserve existing behavior: call memory checkpoint after each turn

This keeps the auto-memory feature useful without being intrusive
in interactive agent sessions.
2026-01-16 13:35:40 +05:30
Dhanji R. Prasanna
6068249827 Simplify --agent --chat startup: minimal output, no session resume
When running g3 --agent <name> --chat, the output is now minimal:
- Workspace path (-> ~/path)
- Status line (README/AGENTS.md/Memory)
- Context progress bar
- Prompt (g3>)

Skipped in this mode:
- Session resume prompts
- "agent mode | name (source)" header
- "g3 programming agent" welcome
- Provider info display
- Language guidance messages

Added from_agent_mode parameter to run_interactive() to control
whether verbose welcome and session resume are shown.
2026-01-16 13:31:10 +05:30
Dhanji R. Prasanna
7c59d1993c Fix auto-memory JSON leak: tool call printed raw to UI
The JSON filter only suppresses tool calls at line boundaries. When
"Memory checkpoint: " was printed without a trailing newline, the LLM
response `{"tool": "remember", ...}` appeared on the same line and
leaked through to the UI.

Fix:
- Add trailing newline to "Memory checkpoint:" message
- Reset JSON filter state before streaming the response

Added test: test_tool_call_not_at_line_start_passes_through
Documents the filter behavior and references the fix location.
2026-01-16 13:10:18 +05:30
Dhanji R. Prasanna
94544c8f6a Add interactive mode support for agents with --chat flag
- Remove chat from conflicts_with_all for --agent flag
- Add chat parameter to run_agent_mode()
- Run interactive loop instead of single task when --chat is passed

Usage: g3 --agent <name> --chat
2026-01-16 12:01:56 +05:30
Dhanji R. Prasanna
6bd9c51e8e feat: shell output pagination and optimized read_file with seek
- Shell outputs > 8KB are truncated to first 500 chars
- Full output saved to .g3/sessions/<session_id>/tools/shell_stdout_<id>.txt
- LLM can use read_file with start/end to paginate through large outputs
- read_file now uses seek() for O(1) random access instead of reading entire file
- UTF-8 safe: reads extra bytes at boundaries to find valid char positions
- Falls back to lossy conversion for binary files (no panics)

Files changed:
- paths.rs: get_tools_output_dir(), generate_short_id()
- shell.rs: truncate_large_output() integration
- file_ops.rs: seek-based read_file_range() helper
- New test: read_file_utf8_test.rs
2026-01-16 09:16:16 +05:30
Dhanji R. Prasanna
ce5183b296 style: compress studio auto-accept output
- Replace verbose auto-accept messages with single line
- Format: 'studio: session <id> ... [merged]'
- Refactor cmd_accept to use accept_session() with configurable prefix
- Remove 'completed successfully' and 'Auto-accepting' messages
2026-01-16 07:30:27 +05:30
Dhanji R. Prasanna
e2385faba1 style: compress studio session startup output
- Replace verbose multi-line output with single line
- Format: 'studio: new session <id>'
- 'studio:' in bold green, session id in inline-code orange (RGB 216,177,114)
- Remove separator lines and 'Starting g3 agent' message
2026-01-16 07:24:22 +05:30
Dhanji R. Prasanna
ef5aa75e6b style: simplify studio accept/discard output messages
- Change verbose emoji messages to minimal format
- Print '> session <id> ...' first, then status after operation completes
- 'merged' shown in bold green
- 'discarded' shown in bold yellow
2026-01-16 07:17:36 +05:30
Dhanji R. Prasanna
01cb4f6691 fix: use consistent max_tokens defaults across providers
- Fix aliasing issue where resolve_max_tokens() used fallback_default_max_tokens
  (8192) instead of provider-specific defaults
- Update fallback_default_max_tokens from 8192 to 32000
- Set provider-specific max_tokens defaults:
  - Anthropic: 32000
  - OpenAI: 32000 (was 16000)
  - Databricks: 32000 (was 50000, now matches Anthropic as passthru)
  - Embedded: 2048
- Context window lengths unchanged:
  - OpenAI: 400,000
  - Anthropic: 200,000
  - Databricks (Claude): 200,000

This fixes the 'LLM response was cut off due to max_tokens limit' error
in agent mode that occurred because 8192 was being used instead of 32000.
2026-01-16 07:05:57 +05:30
Dhanji R. Prasanna
65e0217c68 Add unit tests for studio session management
New tests:
- test_new_session_has_short_id
- test_new_interactive_session
- test_branch_name_format
- test_session_save_and_load
- test_session_mark_complete
- test_session_mark_paused
- test_list_empty_sessions
- test_backwards_compatibility_no_session_type

Added tempfile as dev dependency for temp directory tests.
2026-01-16 06:52:23 +05:30
Dhanji R. Prasanna
78f9207d27 Add interactive mode to studio
New commands:
- studio cli (alias: c) - Start a new interactive g3 session in an isolated worktree
- studio resume <id> (alias: r) - Resume a paused interactive session
- Bare 'studio' now defaults to 'studio cli'

Session changes:
- Added SessionStatus::Paused for sessions that can be resumed
- Added SessionType enum (OneShot, Interactive) for future use
- Interactive sessions use inherited stdio for direct TTY access
- Sessions are marked as Paused when user exits g3

Workflow:
1. studio        # creates worktree, runs g3 interactively
2. (work in g3, exit when done)
3. studio resume <id>  # continue working
4. studio accept <id>  # merge to main when finished
2026-01-16 06:48:24 +05:30
Dhanji R. Prasanna
637884f84b Fix duplicate todo_read display in agent mode
The print_todo_compact() function was missing the call to clear the
streaming hint line before printing the final tool output. This caused
the tool name to appear twice when the hint line wasn't cleared:

  ● todo_read     ● todo_read   | empty

Added the missing handle_hint(ToolParsingHint::Complete) call to match
the behavior of print_tool_compact().
2026-01-16 06:38:11 +05:30
Dhanji R. Prasanna
25d35529e7 Fix --accept flag being passed through to g3 in studio run
When --accept was passed after positional args (e.g., 'studio run --agent
carmack task --accept'), clap's trailing_var_arg captured it as part of
g3_args instead of parsing it as the studio flag. This caused g3 to error
with 'unexpected argument --accept'.

- Extract filter_accept_flag() helper to detect and remove --accept from
  trailing args
- Set auto_accept=true if --accept found in either position
- Add 5 unit tests for the filtering logic
2026-01-15 21:05:13 +05:30
Dhanji R. Prasanna
a84fead03b refactor: improve readability of streaming parser and JSON filter
Agent: carmack

Changes:
- streaming_parser.rs: Unified find_first/last_tool_call_start into single
  find_tool_call_start with SearchDirection enum, reducing duplication.
  Simplified is_json_invalidated from 45 to 20 lines with clearer logic.
  Fixed redundant !escape_next check in find_complete_json_object_end.

- filter_json.rs: Simplified check_tool_pattern from 40 to 24 lines.
  Replaced repetitive prefix checks with loop over ["t", "to", "too", "tool"].
  Reduced trailing return statements with direct expression returns.

- ui_writer_impl.rs: Added ansi module for duration color constants.
  Simplified duration_color function by removing redundant comments.

- language_prompts.rs: Fixed test assertions to match actual prompt content
  ("obvious, readable Racket" instead of "RACKET-SPECIFIC GUIDANCE").

All 174+ tests pass. No behavior changes.
2026-01-15 13:49:29 +05:30
Dhanji R. Prasanna
0ae1a13cdb feat: real-time tool call streaming indicator with blinking UI
- Add ToolParsingHint enum (Detected/Active/Complete) for UI feedback
- New UiWriter methods: print_tool_streaming_hint(), print_tool_streaming_active()
- Refactor ConsoleUiWriter state to use atomics in ParsingHintState
- Add tool_call_streaming field to CompletionChunk for provider hints
- Anthropic provider sends streaming hints when tool name detected
- New streaming helpers: make_tool_streaming_hint(), make_tool_streaming_active()

Parser improvements:
- Add is_json_invalidated() to detect false positive tool patterns
- Fix tool result poisoning when file contents contain partial JSON
- Unescaped newlines in strings or prose after JSON invalidates detection

User sees ' ● tool_name |' immediately when tool call starts streaming,
with blinking indicator while args are received.
2026-01-15 13:49:29 +05:30
Dhanji R. Prasanna
d68f059acf fix: detect invalidated JSON tool calls to prevent parser poisoning
When partial JSON tool call patterns appear in LLM output (e.g., from
quoting file content), the parser would incorrectly report them as
"incomplete tool calls", triggering auto-continue loops.

Fix: Added is_json_invalidated() to detect when partial JSON has been
invalidated by subsequent content that cannot be valid JSON:
- Unescaped newline inside a string (invalid JSON)
- Newline followed by prose text outside a string

The check is only applied to incomplete JSON - complete tool calls
with trailing text are still correctly detected.

Added 6 new tests covering:
- Tool results with partial JSON patterns
- LLM quoting file content inline vs on own line
- Comment prefixes (// # -- etc) with partial patterns
- Real incomplete tool calls (should still be detected)
2026-01-15 13:49:29 +05:30
Dhanji R. Prasanna
999ac6fe66 fix: prevent parser poisoning from inline tool-call JSON patterns
The streaming parser was incorrectly detecting tool call patterns that
appeared inline in prose (e.g., when explaining the format), causing
g3 to return control mid-task.

Fix: Modified find_first_tool_call_start() and find_last_tool_call_start()
to only recognize patterns that appear on their own line (at start of
buffer or after newline with only whitespace before the pattern).

Changes:
- Added is_on_own_line() helper to check line-boundary conditions
- Updated detection methods to skip inline patterns
- Removed sanitize_inline_tool_patterns() and LBRACE_HOMOGLYPH (no longer needed)
- Rewrote tests for new behavior
- Added streaming_repro tests that use process_chunk() to verify the exact bug scenario

28 tests covering: streaming repro, line boundaries, Unicode, code contexts, edge cases
2026-01-15 13:49:29 +05:30
Dhanji R. Prasanna
616e0898c7 Add performance deep cuts and parameterize guidance
Performance:
- Beware list-ref in a loop (O(n²) trap)
- Consolidated performance section with data structure selection rationale
- for/fold for single-pass result building

Parameters and dynamic scope:
- Good uses: ports, logging, config, test fixtures
- Bad uses: hidden global state, implicit argument passing
- Document when functions read from parameters

Also simplified Continuations section (parameterize now has its own section).
2026-01-15 13:49:29 +05:30
Dhanji R. Prasanna
52cd19a015 Refine carmack.racket.md with deeper Racket idioms
Major improvements:
- Iteration idioms: for/fold example, for*/list, in-naturals for indices
- Data structure mutability: when to use mutable hash/vector/box
- let/let*/define style: use let* when order matters
- Contracts section: when to use define/contract, ->i, boundary focus
- Naming: -ref/-set/-update suffixes for custom types
- Size heuristics: semantic ('one abstraction per module') not numeric
- Module hygiene: explicit provides only, contract-out when correctness matters

Removed:
- Packages/tooling section (covered in base racket.md injection)

Now 119 lines of actionable, non-obvious Racket guidance.
2026-01-15 13:49:29 +05:30
Dhanji R. Prasanna
e222b9affc Add non-obvious Racket style guide recommendations
From docs.racket-lang.org/style, added only the non-obvious tips:
- Prefer define over let/let* (reduces indentation)
- Put provide before require (interface at top)
- Use racket/base for libraries (faster loading)
- Naming: prefix functions with data type (board-free-spaces)
- Use in-list/in-vector explicitly in for loops (performance)
- Use module+ test submodules with raco test
- Size limits: ~500 lines/module, ~66 lines/function

Skipped basic conventions LLMs already know (predicate suffixes, etc).
2026-01-15 13:49:29 +05:30
Dhanji R. Prasanna
5ad9fb3718 Improve carmack.racket.md with code examples and Racket-specific guidance
Changes:
- Add concrete code examples for match/cond and contract-out
- Add Phase separation section (for-syntax vs runtime)
- Add Continuations section (call/ec over call/cc, parameterize)
- Add Concurrency section (places, threads, channels, sync)
- Add Gotchas section (eq?/equal?/eqv?, null?/empty?, string=?)
- Tighten Packages/tooling (raco pkg install --auto, info.rkt)

Removed generic advice:
- 'Don't swallow exceptions' (obvious)
- 'Add docstrings/comments' (obvious)
- 'Include runnable examples' (obvious)
- 'Optimize the bottleneck only' (obvious)
- Entire 'Output expectations' section (meta, not Racket-specific)
- Removed oddly specific 'file/sha1, file-watch' reference
2026-01-15 13:49:29 +05:30
Dhanji R. Prasanna
65807eea99 Add carmack.rust.md agent-specific language prompt
Rust-specific readability guidance for the carmack agent including:
- let...else example for shallow control flow
- Async: don't block the runtime (tokio::fs, spawn_blocking, Send)
- Visibility: prefer pub(crate), private fields with accessors
- Generics: impl Trait over explicit params, avoid complex where clauses
- Improved iterator guidance: if you need a comment, use a loop
- UTF-8 string slicing warnings
- Ownership/lifetime pragmatism
- Anti-patterns: no macros/typestate/proc-macros unless already in repo

Also adds Rust detection to LANGUAGE_PROMPTS (empty base prompt,
agent-specific prompts handle the guidance).
2026-01-15 13:49:29 +05:30
Jochen
6d1aa62ba7 Merge pull request #63 from cjustice/fix/tracing-subscriber-panic
Fix tracing subscriber panic in scout agent
2026-01-15 12:54:31 +11:00
Jochen
0bca05a1ba Merge pull request #62 from cjustice/fix/planning-verbose-flag
Fix: Initialize logging before planning mode check
2026-01-15 12:51:11 +11:00
Dhanji R. Prasanna
85ea8fe69c Update project memory with agent-specific language prompts
Document the new agent+language prompt injection feature including:
- AGENT_LANGUAGE_PROMPTS static array location
- get_agent_language_prompt() and get_agent_language_prompts_for_workspace_with_langs()
- File naming pattern: prompts/langs/<agent>.<lang>.md
- Instructions for adding new agent+lang prompts
2026-01-15 06:43:42 +05:30