)]}'
{
  "log": [
    {
      "commit": "d2fe3ba95b876365fa62e084dbdbae8153a2327c",
      "tree": "6ad8209a974d956d6242b42dd02c2a6fdf20e20a",
      "parents": [
        "0530da0092392838ce75df3ec366b32e24dddf20"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Wed Jul 23 13:05:47 2025 -0700"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Thu Jul 24 12:20:54 2025 -0700"
      },
      "message": "llm/ant: add claude userName helpers\n\nThis moves us towards functional opus support.\nIt also is a baby step towards restoring sanity to this code.\n\nAlso, stop treating model\u003d\"\" as \"sonnet\".\nThere\u0027s a default for the flag.\n"
    },
    {
      "commit": "44dfdce5edac084927f122988b6f5b783d67c93a",
      "tree": "dae838d2e9f89908f34edbc88c1019de10b5bf23",
      "parents": [
        "0d04c13e27e0008e9da1eb458a74ff8f7a55f682"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Wed Jul 23 13:02:29 2025 -0700"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Thu Jul 24 12:20:54 2025 -0700"
      },
      "message": "llm/ant: add APIKeyEnv\n"
    },
    {
      "commit": "57afbca4ac1dbd4351aae93302e34ee45b36a25f",
      "tree": "6c9222f0c81394c3f1089ceb040a4ca1a0ed9eb0",
      "parents": [
        "aa22eb7947ae6bb09ce558bcfa52a1d8b2b3286a"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Wed Jul 23 13:29:59 2025 -0700"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Wed Jul 23 17:19:23 2025 -0700"
      },
      "message": "llm: rename -dump-ant-calls to -dump-llm\n\nAnd tweak behavior.\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: s1605a29b744ae5f1k\n"
    },
    {
      "commit": "e75d0eac125c8b72f8fa899c7d6eb64d6bdedb9e",
      "tree": "261087d7f452f5e99b75bada3643fc0da9cc5427",
      "parents": [
        "f2b5ee0011655cae4e3c977eaec6255ae46a5b88"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Mon Jul 21 23:50:44 2025 +0000"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Mon Jul 21 19:46:45 2025 -0700"
      },
      "message": "llm/ant: convert dumpText constant to dump-ant-calls command line flag\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: sd58268f97ed95de8k\n"
    },
    {
      "commit": "f2b5ee0011655cae4e3c977eaec6255ae46a5b88",
      "tree": "c0ccbaa55962839542939083521b0a344a71c1d3",
      "parents": [
        "44de46c38652047d3ff70b59f69d00bad4985561"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Mon Jul 21 16:42:53 2025 -0700"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Mon Jul 21 19:46:45 2025 -0700"
      },
      "message": "llm/ant: dump debug to files, not stdout\n\n- doesn\u0027t break termui\n- easier to tell apart different requests\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: s0e399715e9573285k\n"
    },
    {
      "commit": "59bb27d160b935287944f39588d9fef84d9c2036",
      "tree": "a30a97916af6798745f9baf9c9a24aba24adc6e1",
      "parents": [
        "883e758cfa6b41658158d3ceff2dd69eb01d8b81"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Thu Jun 05 07:32:10 2025 -0700"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Thu Jun 05 12:05:33 2025 -0700"
      },
      "message": "llm: get costs from server\n\nCalculating costs on the client has the advantage\nthat it works when not using skaband.\n\nIt requires that we maintain multiple sources of truth, though.\nAnd it makes it very challenging to add serverside tools,\nsuch as Anthropic\u0027s web tool.\n\nThis commit switches sketch to rely on the server for all costs.\nIf not using skaband, no costs will be calculated, which also\nmeans that budget constraints won\u0027t work.\n\nIt\u0027s unfortunate, but at the moment it seems like the best path.\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": "0efb29db25ff141e6463b40675defc423a42379c",
      "tree": "19472c6271558f22e3b2ebd339f9e0e587f55009",
      "parents": [
        "78e7cf986aa461b62a923f6f5175ab94a12e2536"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Thu May 22 21:05:04 2025 -0700"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Sat May 24 12:06:12 2025 -0700"
      },
      "message": "llm/ant: switch default to Claude 4 sonnet"
    },
    {
      "commit": "0e8073a19a88ef5e7a03acc8b5f924bfda0afdd5",
      "tree": "e5511fc6781ee80ec5f8c257e6a9a16446b27ab9",
      "parents": [
        "3e6a4c4abe8714ebb04c0d4834bcc7230f4d4a03"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Thu May 22 21:04:51 2025 -0700"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Fri May 23 11:30:33 2025 -0700"
      },
      "message": "llm/ant: add Claude 4 sonnet/opus\n\nNot set as default yet.\nThere\u0027s a bit of prompt engineering work\nto do before we flip the switch."
    },
    {
      "commit": "3b5646ff27d0e644396524b8ca2c9a4c5891726c",
      "tree": "2fea328279fa22fedef6b570af10c4bb45aaaf7e",
      "parents": [
        "12989b0cf7cb542f1286d53c3dce86ae1d56773b"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Fri May 23 16:47:53 2025 +0000"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Fri May 23 10:06:40 2025 -0700"
      },
      "message": "llm/ant: prevent httprr cache misses from being retried\n\nPackage ant treated httprr\u0027s \u0027cached HTTP response not found\u0027 errors as\nretryable network errors, causing 30+ second delays and test\ntimeouts when httprr couldn\u0027t find matching requests.\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: s81a2a9035286ab41k"
    },
    {
      "commit": "a4500c98a8f7c2e5500d330d7f4e82037fb38239",
      "tree": "32f069d493f4e76ef425acfc8a87800f06d01091",
      "parents": [
        "613c0f5288dd0e18dc9fee09254161d78fc7acb7"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Thu May 15 15:38:32 2025 -0700"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Thu May 15 22:00:19 2025 -0700"
      },
      "message": "llm/ant: retry more on failure"
    },
    {
      "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": "7ce5fb76d8748ebf73c5adf9d6cd8eb67716fba8",
      "tree": "1890bd46f87cf7261ba5a6aaa3fd2d110e7d67cc",
      "parents": [
        "022b3638c2d2691d60f430d8984959c91eee46ab"
      ],
      "author": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Sat May 10 06:26:22 2025 -0700"
      },
      "committer": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Sat May 10 06:26:29 2025 -0700"
      },
      "message": "Revert \"llm: add service.ModelName\"\n\nTurns out I don\u0027t need this.\n\nThis reverts commit 022b3638c2d2691d60f430d8984959c91eee46ab.\n"
    },
    {
      "commit": "022b3638c2d2691d60f430d8984959c91eee46ab",
      "tree": "7459ef27d1e6d2ed83773acb9a33741fddbd730c",
      "parents": [
        "a997be617bd5548a307c708cdba325ea6562acec"
      ],
      "author": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Sat May 10 06:14:21 2025 -0700"
      },
      "committer": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Sat May 10 06:14:49 2025 -0700"
      },
      "message": "llm: add service.ModelName\n"
    },
    {
      "commit": "29fea840fbe3c279e1480d5f78cff4be697b7ca5",
      "tree": "44e4598253553f92de4dd089409f821243b1ca0f",
      "parents": [
        "5cca56ff3aec7785494c6a9fcd4e846900968ed1"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Tue May 06 01:51:09 2025 +0000"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Mon May 05 18:53:08 2025 -0700"
      },
      "message": "llm/ant: replace fmt.Printf with slog in retry logic\n\nBreaks termui.\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\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"
    }
  ]
}
