)]}'
{
  "log": [
    {
      "commit": "3dd3e4144d2e0b9fec6b5e0039ed12e2c0170265",
      "tree": "11eb418a7980cb9f7faa6b1a20dee2e811a24b13",
      "parents": [
        "a6b995b83277dd730e35a8f5be14c139d82a544e"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Tue Jul 22 20:32:03 2025 -0700"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Wed Jul 23 17:53:58 2025 -0700"
      },
      "message": "webui: add diff display for patches\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: s2e9bdfb014ddec3ck\n"
    },
    {
      "commit": "43b60b9b6906a2077175bcb1c3ea53b90d92a9f8",
      "tree": "14ecadd5c94db811087f97b0e7858f1482ff5f4e",
      "parents": [
        "95354b15c6469f871ecabd778c04304bcce16195"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Mon Jul 21 14:57:10 2025 -0700"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Mon Jul 21 19:46:45 2025 -0700"
      },
      "message": "llm: make Tool.Run return ToolOut\n\nThis is preliminary work towards\nallowing tools to add additional information.\nNo functional changes (at least, that\u0027s the intent).\n"
    },
    {
      "commit": "43a0bfc2227f07db26ff785470fbac35d309499a",
      "tree": "e1900f7602fed9ac779181b59790f6b1e0b44a7f",
      "parents": [
        "d9acaa785a8cc8b3cc14d6efcdd7ce45ffe3737f"
      ],
      "author": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Mon Jul 14 14:54:27 2025 -0700"
      },
      "committer": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Mon Jul 14 15:13:41 2025 -0700"
      },
      "message": "sketch: add debug handler to dump conversation history as JSON\n\nAdd HTTP debug endpoint /debug/conversation-history to dump agent conversation\nhistory as pretty-printed JSON for debugging purposes.\n\nSometimes, you just want to see what went on.\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: s6c9e876db9b3aa5ck\n"
    },
    {
      "commit": "882e7ea7097129ff75e3595b049df585976e12a1",
      "tree": "bdf436800495b973f3b8d808dc4ec9fdc83d4b31",
      "parents": [
        "1f8fe9c0531de311dc3847f766f748da28fc3368"
      ],
      "author": {
        "name": "philip.zeyliger",
        "email": "philip.zeyliger@gmail.com",
        "time": "Fri Jun 20 14:31:16 2025 +0000"
      },
      "committer": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Fri Jun 20 08:21:42 2025 -0700"
      },
      "message": "loop: preserve cumulative usage across conversation compaction\n\nconversation: add optional CumulativeUsage parameter to New function\n\nUpdate CompactConversation to preserve cumulative usage statistics when\nresetting the conversation, preventing usage numbers from being lost during\ncompaction.\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: s11dcb84790847494k\n"
    },
    {
      "commit": "e6c294dc139cf229ba790abc87a524016f98627f",
      "tree": "1a181005f78a908112288e814bd60205b060a436",
      "parents": [
        "2f0eb6995fc1041d23b8224a099013e89bb03f67"
      ],
      "author": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Wed Jun 04 16:55:21 2025 +0000"
      },
      "committer": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Wed Jun 04 09:57:17 2025 -0700"
      },
      "message": "budget: remove num-iterations and wall clock time limits\n\nRemove iteration count and time-based budget limits from the agent budget system\nwhile preserving the budget concept for dollar-based limits only.\n\nProblem Analysis:\nThe budget system previously supported three types of limits:\n1. MaxResponses (iteration count limit)\n2. MaxWallTime (wall clock time limit)\n3. MaxDollars (cost limit)\n\nThis created complexity in both implementation and user experience, with\nmultiple overlapping budget mechanisms that could trigger independently.\nThe iteration and time limits added limited value compared to the more\npractical dollar-based budget control.\n\nImplementation Changes:\n\n1. Budget Structure Simplification:\n   - Remove MaxResponses and MaxWallTime fields from Budget struct\n   - Keep only MaxDollars field for cost-based budget control\n   - Simplify Budget to single-field struct with clear purpose\n\n2. CLI Flag Removal:\n   - Remove -max-iterations flag from command line interface\n   - Remove -max-wall-time flag from command line interface\n   - Keep -max-dollars flag with same functionality\n   - Remove unused time import from cmd/sketch/main.go\n\n3. Budget Logic Streamlining:\n   - Simplify ResetBudget() to only adjust MaxDollars based on usage\n   - Simplify overBudget() to only check dollar limits\n   - Remove iteration and time checking logic throughout\n\n4. Container Configuration Updates:\n   - Remove MaxIterations and MaxWallTime from ContainerConfig struct\n   - Remove corresponding docker command arguments\n   - Maintain MaxDollars configuration and passing\n\n5. UI Cleanup:\n   - Remove budget display of max responses and max wall time from termui\n   - Keep dollar-based budget information display\n\n6. Test Updates:\n   - Update test Budget initialization to use only MaxDollars\n   - Verify all existing tests continue to pass\n\nTechnical Details:\n- Budget struct now contains only MaxDollars float64 field\n- ResetBudget adjusts budget by adding current TotalCostUSD to MaxDollars\n- overBudget checks only dollar spending against MaxDollars limit\n- CLI help shows only -max-dollars option, no iteration/time options\n- Docker container launch passes only max-dollars parameter\n\nBenefits:\n- Simplified budget system with single, clear cost control mechanism\n- Reduced complexity in budget logic and error handling\n- Cleaner CLI interface with fewer confusing options\n- More predictable budget behavior focused on practical cost limits\n- Easier to understand and configure for users\n\nTesting:\n- All existing tests pass with updated budget structure\n- CLI help verification shows only max-dollars option\n- Build verification confirms no compilation errors\n- Budget functionality preserved for dollar-based limits\n\nThis change streamlines the budget system to focus on practical cost control\nwhile maintaining all existing dollar-based budget functionality and removing\ncomplexity around iteration and time-based limits.\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: sa7be127e12d43ee7k\n"
    },
    {
      "commit": "b8a8f35348326b8daf69e31efc77d37fac4bd276",
      "tree": "fa7a59c5951dbd3ecb5e6bf840ac7b45167a9e74",
      "parents": [
        "b5739403b1b6ec6fac909b258bd47ce5a338940e"
      ],
      "author": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Mon Jun 02 07:39:37 2025 -0700"
      },
      "committer": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Mon Jun 02 17:01:19 2025 -0700"
      },
      "message": "loop: implement comprehensive conversation compaction system\n\n\"comprehensive\" is over-stating it. Currently, users get\nthe dreaded:\n\n\terror: failed to continue conversation: status 400 Bad Request:\n\t{\"type\":\"error\",\"error\":{\"type\":\"invalid_request_error\",\"message\":\"input\n\tlength and max_tokens exceed context limit: 197257 + 8192 \u003e 200000,\n\tdecrease input length or max_tokens and try again\"}}\n\nThat\u0027s... annoying. Instead, let\u0027s compact automatically. I was going to\nstart with adding a /compact command or button, but it turns out that\nteasing that through the system is annoying, because the agent state\nmachine is intended to be somewhat single-threaded, and what do you do\nwhen a /compact comes in while other things are going on. It\u0027s possible,\nbut it was genuinely easier to prompt my way into doing it\nautomatically.\n\nI originally set the threshold to 75%, but given that 8192/200000 is 4%,\nI just changed it to 94%.\n\nWe\u0027ll see how well it works!\n\n~~~~\n\nImplement automatic conversation compaction to manage token limits and prevent\ncontext overflow, with enhanced UX feedback and accurate token tracking.\n\nProblem Analysis:\nLarge conversations could exceed model context limits, causing failures\nwhen total tokens approached or exceeded the maximum context window.\nWithout automatic management, users would experience unexpected errors\nand conversation interruptions in long sessions.\n\nImplementation:\n\n1. Automatic Compaction Infrastructure:\n   - Added ShouldCompact() method to detect when compaction is needed\n   - Configurable token thresholds for different compaction triggers\n   - Integration with existing loop state machine for seamless operation\n\n2. Accurate Token Counting:\n   - Enhanced context size estimation using actual token usage from LLM responses\n   - Track real token consumption rather than relying on estimates\n   - Account for tool calls, system prompts, and conversation history\n\n3. Compaction Logic and Timing:\n   - Triggered at 75% of context limit (configurable threshold)\n   - Preserves recent conversation context while compacting older messages\n   - Maintains conversation continuity and coherence\n\n4. Enhanced User Experience:\n   - Visual indicators in webui when compaction occurs\n   - Token count display showing current usage vs limits\n   - Clear messaging about compaction status and reasoning\n   - Timeline updates to reflect compacted conversation state\n\n5. UI Component Updates:\n   - sketch-timeline.ts: Added compaction status display\n   - sketch-timeline-message.ts: Enhanced message rendering for compacted state\n   - sketch-app-shell.ts: Token count integration and status updates\n\nTechnical Details:\n- Thread-safe implementation with proper mutex usage\n- Preserves conversation metadata and essential context\n- Configurable compaction strategies for different use cases\n- Comprehensive error handling and fallback behavior\n- Integration with existing LLM provider implementations (Claude, OpenAI, Gemini)\n\nTesting:\n- Added unit tests for ShouldCompact logic with various scenarios\n- Verified compaction triggers at correct token thresholds\n- Confirmed UI updates reflect compaction status accurately\n- All existing tests continue to pass without regression\n\nBenefits:\n- Prevents context overflow errors in long conversations\n- Maintains conversation quality while managing resource limits\n- Provides clear user feedback about system behavior\n- Enables unlimited conversation length with automatic management\n- Improves overall system reliability and user experience\n\nThis system ensures sketch can handle conversations of any length while\nmaintaining performance and providing transparent feedback to users about\ntoken usage and compaction activities.\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: s28a53f4e442aa169k\n"
    },
    {
      "commit": "a3e28fb8e570ab7e43f84d2f5c5fcecb81d00618",
      "tree": "5469d620466a368eae9f342bd240178e0e0cf57b",
      "parents": [
        "15cc2e75ed6dc840c78bc7f2b2075d40d5f22470"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Fri May 30 15:53:23 2025 +0000"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Fri May 30 12:34:24 2025 -0700"
      },
      "message": "llm/conversation: fix duplicate tool results in insertMissingToolResults\n\nFix critical bug in insertMissingToolResults function that created duplicate\ntool_result blocks when multiple tool uses were missing results, causing\nClaude API 400 errors with message \"each tool_use must have a single result\".\n\nProblem Analysis:\nThe function was designed to add error tool results for tool uses that\nwere requested but had no corresponding tool_result in the user message\n(e.g., when hitting budget limits). However, when multiple tool uses\nwere missing results, the function incorrectly duplicated results:\n\n1. First iteration: adds tool1 result to prefix, sets msg.Content \u003d [tool1] + original\n2. Second iteration: adds tool2 to prefix, sets msg.Content \u003d [tool1, tool2] + [tool1] + original\n\nThis created duplicate tool_result blocks with the same tool_use_id, violating\nClaude\u0027s API requirements and causing 400 Bad Request errors.\n\nRoot Cause:\nThe msg.Content assignment was inside the loop that builds the prefix:\n\nSolution:\nMove the msg.Content assignment outside the loop, after all missing\ntool results have been collected:\n\nTesting:\nAdded comprehensive test coverage for insertMissingToolResults with scenarios:\n- Single missing tool result\n- Multiple missing tool results (the problematic case)\n- No missing results when results already present\n- No tool uses in previous message\n\nThe test specifically verifies no duplicate tool_use_ids are created\nand that all expected tool results are present exactly once.\n\nThis fix resolves the \"multiple tool_result blocks with id\" error\nthat was occurring in deep conversations with tool usage.\n\nFixes #121\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: s07f278af38b745aak"
    },
    {
      "commit": "495c1fa247565e21b36bcb847c6cd3f08e0e196f",
      "tree": "5c7031ad37f4f0181824664f15220f87c7314861",
      "parents": [
        "b6bc113f9ebb00084285e8c3aeaf2fd4a648afc0"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Thu May 29 00:37:22 2025 +0000"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Thu May 29 15:12:53 2025 -0700"
      },
      "message": "claudetool: add just-in-time tool installation for bash commands\n\nImplements automatic tool installation when bash commands use missing tools,\nproviding a seamless experience for the LLM to Just Use tools it knows ought to exist.\n\nCore Features:\n\n1. Command Analysis Pipeline:\n   - Parse bash commands to extract individual tools/programs\n   - Use exec.LookPath to check if tools exist in PATH\n   - Handle shell built-ins, absolute/relative paths correctly\n   - Support complex command chaining with \u0026\u0026, ||, ;, and |\n\n2. Subagent Tool Installation:\n   - Spawn dedicated subagents to install missing tools\n\nThe system preserves existing bash tool behavior while adding invisible\ntool installation. Original commands run regardless of installation\nsuccess/failure, avoiding agent confusion.\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: s226cd6260a6469e9k\n"
    },
    {
      "commit": "ab6a811066a89a1e499253a7f854e6dd0a777ce5",
      "tree": "c7ad7a41b2cb9518b3460a1e9b4e8252b48942df",
      "parents": [
        "83b2d35b61eb68c0d633a10c2f5b7c0905e584df"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Sat May 24 12:22:00 2025 -0700"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Sat May 24 12:28:01 2025 -0700"
      },
      "message": "all: update tests for claude 4"
    },
    {
      "commit": "64f2aa8db137ee801120fe38b19f60103a2326dd",
      "tree": "b322e422ac17af0e9ed0e59ea9f6d91d40291f5c",
      "parents": [
        "b81d7d476ff2d104d34d3a637f2bd826a2a89eaf"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Wed May 14 18:31:05 2025 +0000"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Wed May 14 13:53:29 2025 -0700"
      },
      "message": "loop: make multiplechoice tool calls end the turn\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: s8d507faf9c095824sk\n"
    },
    {
      "commit": "31785aed38e0f63fa736430c6240c8a76b8285dc",
      "tree": "35916d3dbedaeac296ece3dd57610efd82c99c8d",
      "parents": [
        "5c7f95714f34ea327b8f300238da6491dedd6adb"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Tue May 06 01:50:58 2025 +0000"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Mon May 12 19:17:50 2025 -0700"
      },
      "message": "loop: add knowledge_base tool for on-demand information\n\nThe knowledge_base tool provides a way for agents to access specialized information\nwhen needed. Initial topics include:\n\n- sketch: how to use Sketch, including SSH, secrets, and file management\n- go_iterators: information about Go\u0027s iterator feature added in Go 1.22\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\n"
    },
    {
      "commit": "72252cbcb97840d724133be67c4c69cc69ebb2d3",
      "tree": "a361499dc3fa6b9af2be3e74cfd59fd8ba34690e",
      "parents": [
        "7ce5fb76d8748ebf73c5adf9d6cd8eb67716fba8"
      ],
      "author": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Sat May 10 17:00:08 2025 -0700"
      },
      "committer": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Sat May 10 17:00:08 2025 -0700"
      },
      "message": "llm and everything: Update ToolResult to use []Content instead of string for multimodal support\n\nThis was a journey. The sketch-generated summary below is acceptable,\nbut I want to tell you about it in my voice too. The goal was to send\nscreenshots to Claude, so that it could... look at them. Currently\nthe take screenshot and read screenshot tools are different, and they\u0027ll\nneed to be renamed/prompt-engineered a bit, but that\u0027s all fine.\n\nThe miserable part was that we had to change the return value\nof tool from string to Content[], and this crosses several layers:\n - llm.Tool\n - llm.Content\n - ant.Content \u0026 openai and gemini friends\n - AgentMessage [we left this alone]\n\nExtra fun is that Claude\u0027s API for sending images has nested Content\nfields, and empty string and missing needs to be distinguished for the\nText field (because lots of shell commands return the empty string!).\n\nFor the UI, I made us transform the results into a string, dropping\nimages. This would have been yet more churn for not much obvious\nbenefit. Plus, it was going to break skaband\u0027s compatibility, and ...\nyet more work.\n\nOpenAI and Gemini don\u0027t obviously support images in this same way,\nso they just don\u0027t get the tools.\n\n~~~~~~~~~~ Sketch said:\n\nThis architectural change transforms tool results from plain strings to []Content arrays, enabling multimodal interaction in the system. Key changes include:\n\n- Core structural changes:\n  - Modified ToolResult type from string to []Content across all packages\n  - Added MediaType field to Content struct for MIME type support\n  - Created TextContent and ImageContent helper functions\n  - Updated all tool.Run implementations to return []Content\n\n- Image handling:\n  - Implemented base64 image support in Anthropic adapter\n  - Added proper media type detection and content formatting\n  - Created browser_read_image tool for displaying screenshots\n  - Updated browser_screenshot to provide usable image paths\n\n- Adapter improvements:\n  - Updated all LLM adapters (ANT, OAI, GEM) to handle content arrays\n  - Added specialized image content handling in the Anthropic adapter\n  - Ensured proper JSON serialization/deserialization for all content types\n  - Improved test coverage for content arrays\n\n- UI enhancements:\n  - Added omitempty tags to reduce JSON response size\n  - Updated TypeScript types to handle array content\n  - Made field naming consistent (tool_error vs is_error)\n  - Preserved backward compatibility for existing consumers\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: s1a2b3c4d5e6f7g8h\n"
    },
    {
      "commit": "4d54493fe3808ecd0c6a9a4d0bbcc7786e97b094",
      "tree": "9877409fc95aaa32aed882426ea15464b8036e34",
      "parents": [
        "a4ad8af8b08a54326bbbd99d57110a42c459c54e"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Wed May 07 13:33:53 2025 +0000"
      },
      "committer": {
        "name": "Autoformatter",
        "email": "bot@sketch.dev",
        "time": "Thu May 08 19:25:30 2025 +0000"
      },
      "message": "all: support hiding subconvo output\n\nSome of it is systematically noisy.\n"
    },
    {
      "commit": "3659d8714d31bad050d36043b67efd76a8d53b77",
      "tree": "2803c54c63628e397e63bdbbe4fa2647a4d5f556",
      "parents": [
        "021557a7d33dacd4fedb9a4677fc93c48569d57a"
      ],
      "author": {
        "name": "David Crawshaw",
        "email": "david@zentus.com",
        "time": "Mon May 05 17:52:23 2025 -0700"
      },
      "committer": {
        "name": "David Crawshaw",
        "email": "david@zentus.com",
        "time": "Mon May 05 17:52:27 2025 -0700"
      },
      "message": "all: more gemini key plumbing\n"
    },
    {
      "commit": "4f84ab729ddbf428b0e891940f08f70b4edee05c",
      "tree": "f2e52e4a01c188ada1f5acf8b2a013029b999495",
      "parents": [
        "44f9b4cec11e269a52fbfc099989ab425b8e125f"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Tue Apr 22 16:40:54 2025 -0700"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Fri May 02 12:57:44 2025 -0700"
      },
      "message": "all: support openai-compatible models\n\nThe support is rather minimal at this point:\nOnly hard-coded models, only -unsafe, only -skabandaddr\u003d\"\".\n\nThe \"shared\" LLM package is strongly Claude-flavored.\n\nWe can fix all of this and more over time, if we are inspired to.\n(Maybe we\u0027ll switch to https://github.com/maruel/genai?)\n\nThe goal for now is to get the rough structure in place.\nI\u0027ve rebased and rebuilt this more times than I care to remember.\n"
    }
  ]
}
