)]}'
{
  "log": [
    {
      "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": "5c654f6e66db881f17e202ec60cf7c997f7c0bad",
      "tree": "592c244e6468ffbbe3bc2c1f80270877402f5ea6",
      "parents": [
        "664404e9e53fe0d28a35f9b6da2274e3bdea4c4b"
      ],
      "author": {
        "name": "Autoformatter",
        "email": "bot@sketch.dev",
        "time": "Thu Jun 05 19:06:51 2025 +0000"
      },
      "committer": {
        "name": "Autoformatter",
        "email": "bot@sketch.dev",
        "time": "Thu Jun 05 19:06:51 2025 +0000"
      },
      "message": "all: fix formatting\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": "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": "a9d87aa69cfefdc91ec7aaa6bc42907749748e76",
      "tree": "0575b15619881ac1bedfc71dd552c05b64bbe152",
      "parents": [
        "df6d7b4a0d5fcf59cfed41cd518bb9489f80da5e"
      ],
      "author": {
        "name": "David Crawshaw",
        "email": "david@zentus.com",
        "time": "Tue May 06 10:08:56 2025 -0700"
      },
      "committer": {
        "name": "David Crawshaw",
        "email": "david@zentus.com",
        "time": "Tue May 06 10:08:56 2025 -0700"
      },
      "message": "llm/gem: remove unused field\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": "5a23406f6959384e3edc402eaf9c271648195786",
      "tree": "dc6ff3715a427f7ee2a3645ea712f0a7da9705d2",
      "parents": [
        "3b4d2b8f8b805d4fb28e0b5854bb2c0494a8ea26"
      ],
      "author": {
        "name": "David Crawshaw",
        "email": "david@zentus.com",
        "time": "Sun May 04 17:52:08 2025 +0000"
      },
      "committer": {
        "name": "David Crawshaw",
        "email": "david@zentus.com",
        "time": "Sun May 04 13:00:22 2025 -0700"
      },
      "message": "ll/gem: implement Gemini Pro 2.5 support\n\nStill to do:\n- container support\n- sketch.dev support\n\nFor #60\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\n"
    },
    {
      "commit": "3b4d2b8f8b805d4fb28e0b5854bb2c0494a8ea26",
      "tree": "d09f99b13a29133fdc5053eac7e256fa9cc723d0",
      "parents": [
        "bdfb126de211f5f2fabb39498de00acde5faf58f"
      ],
      "author": {
        "name": "David Crawshaw",
        "email": "david@zentus.com",
        "time": "Sun May 04 10:48:25 2025 -0700"
      },
      "committer": {
        "name": "David Crawshaw",
        "email": "david@zentus.com",
        "time": "Sun May 04 10:48:25 2025 -0700"
      },
      "message": "gemini: basic gemini API wrapper\n"
    }
  ]
}
