Skip to content

Cut scope and release 0.26 (non-alpha) with tools #1066

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
simonw opened this issue May 22, 2025 · 12 comments
Closed

Cut scope and release 0.26 (non-alpha) with tools #1066

simonw opened this issue May 22, 2025 · 12 comments

Comments

@simonw
Copy link
Owner

simonw commented May 22, 2025

The tools milestones are still pretty hefty:

I think I should cut scope to get a non-alpha release out ASAP. I'm fine punting most of the above to later releases - the key thing is not to ship anything that I later want to change in a backwards-incompatible way.

@simonw
Copy link
Owner Author

simonw commented May 22, 2025

I renamed https://github.com/simonw/llm/milestone/12 to "LLM tools non-alpha release (0.27)"

@simonw
Copy link
Owner Author

simonw commented May 24, 2025

I've done everything in milestone 12 - last issue was:

It doesn't feel quite right for release yet. In particular the lack of a mechanism for specifying a collection of tools feels a bit glaring, they are inconvenient to use without:

I'm tempted by these as well:

@simonw
Copy link
Owner Author

simonw commented May 24, 2025

@simonw
Copy link
Owner Author

simonw commented May 26, 2025

I still need to do the new logging stuff:

But I'm going to ship one last alpha now so I can ship plugins that use the new Toolbox mechanism.

@simonw
Copy link
Owner Author

simonw commented May 26, 2025

Trying a devious trick to generate release notes:

llm -m g25f -f https://github.com/simonw/llm/compare/0.26a0...main.diff -s 'describe changes for a changelog'
# That worked but was not in the right style, so I added
llm -c 'Reformat that to look like the example here, referencing these relevant issues' -f /tmp/example.txt -f /tmp/issues.txt

Using files from here: https://gist.github.com/simonw/f68e1576d8b5ee706760e176b1365e75 - one with an example entry and another with rendered GitHub issue titles for all the issues, extracted with https://observablehq.com/@simonw/extract-issue-numbers-from-pasted-text from the select-all on the 0.26a0...main page.

Output here: https://gist.github.com/simonw/8612f9aaa205a4a2a19994602b18d157#026-yyyy-mm-dd

@simonw
Copy link
Owner Author

simonw commented May 26, 2025

Wow, it did a REALLY good job on those release notes. Only took me 10 minutes to knock them into final shape, and there was a lot of stuff in them: https://github.com/simonw/llm/blob/15a497635d0f3402defcf53bda8f13b4b63e21b5/docs/changelog.md#026a1-2025-05-25 and https://llm.datasette.io/en/latest/changelog.html#a1-2025-05-25

I had to manually add the "thanks, X" references, but I didn't feed those into the model. Could probably figure that out in the future, maybe send in a list of PRs?

@simonw
Copy link
Owner Author

simonw commented May 26, 2025

This is pretty great! I installed the latest alpha and:

llm install llm-anthropic==0.16a2                          
llm chat -T QuickJS -m claude-4-sonnet --td --chain-limit 0

And got this:

Chatting with anthropic/claude-sonnet-4-0
Type 'exit' or 'quit' to exit
Type '!multi' to enter multiple lines, then '!end' to finish
Type '!edit' to open your default editor and modify the prompt
Type '!fragment <my_fragment> [<another_fragment> ...]' to insert one or more fragments
> Do something fun with QuickJS, write short code so I can see what you are doing faster
I'll create a fun little animation using QuickJS! Let me make a simple ASCII art bouncing ball: 
Tool call: QuickJS_execute_javascript({'javascript': '// Bouncing ball animation\nlet position = 0;\nlet direction = 1;\nlet frame = 0;\n\nfunction drawBall() {\n    // Create a line with the ball (●) at different positions\n    let line = "";\n    for (let i = 0; i < 20; i++) {\n        if (i === position) {\n            line += "●";\n        } else {\n            line += " ";\n        }\n    }\n    return `|${line}|`;\n}\n\nfunction animate() {\n    console.log(`Frame ${frame}: ${drawBall()}`);\n    \n    // Move the ball\n    position += direction;\n    \n    // Bounce off walls\n    if (position >= 19) {\n        direction = -1;\n    } else if (position <= 0) {\n        direction = 1;\n    }\n    \n    frame++;\n}\n\n// Show 10 frames of animation\nfor (let i = 0; i < 10; i++) {\n    animate();\n}\n\nconsole.log("\\n🎉 Bouncing ball complete! The ball bounced back and forth!");'})
  Error: ReferenceError: 'console' is not defined
      at animate (<input>:20)
      at <eval> (<input>:37)


Oops! Let me fix that - QuickJS doesn't have console by default. Let me create the animation differently: 
Tool call: QuickJS_execute_javascript({'javascript': '// Bouncing ball animation\nlet position = 0;\nlet direction = 1;\nlet frames = [];\n\nfunction drawBall() {\n    let line = "";\n    for (let i = 0; i < 15; i++) {\n        if (i === position) {\n            line += "●";\n        } else {\n            line += "·";\n        }\n    }\n    return `|${line}|`;\n}\n\n// Generate animation frames\nfor (let frame = 0; frame < 12; frame++) {\n    frames.push(`Frame ${frame}: ${drawBall()}`);\n    \n    // Move the ball\n    position += direction;\n    \n    // Bounce off walls\n    if (position >= 14) {\n        direction = -1;\n    } else if (position <= 0) {\n        direction = 1;\n    }\n}\n\n// Return the complete animation\nframes.join(\'\\n\') + \'\\n\\n🎾 Ball bounced \' + (frames.length) + \' times!\';'})
  Error: SyntaxError: redeclaration of 'position'
      at <eval> (<input>:1)


Let me reset and try again: 
Tool call: QuickJS_reset_context({})
  null

 
Tool call: QuickJS_execute_javascript({'javascript': '// Fun color generator with ASCII art!\nfunction generatePattern(size) {\n    let pattern = "";\n    let symbols = ["★", "♦", "♠", "♣", "♥", "●", "◆", "▲"];\n    \n    for (let row = 0; row < size; row++) {\n        for (let col = 0; col < size; col++) {\n            // Create a pattern based on position\n            let index = (row + col) % symbols.length;\n            pattern += symbols[index] + " ";\n        }\n        pattern += "\\n";\n    }\n    return pattern;\n}\n\n// Generate a fun 6x6 pattern\nlet artPattern = generatePattern(6);\n\n// Create a simple "dice roll" simulator\nfunction rollDice() {\n    return Math.floor(Math.random() * 6) + 1;\n}\n\nlet rolls = [];\nfor (let i = 0; i < 5; i++) {\n    rolls.push(rollDice());\n}\n\n// Combine everything\n`🎨 ASCII Art Pattern:\\n${artPattern}\\n🎲 Random dice rolls: ${rolls.join(\', \')}\\n\\n✨ Sum of rolls: ${rolls.reduce((a,b) => a+b, 0)}`;'})
  🎨 ASCII Art Pattern:
  ★ ♦ ♠ ♣ ♥ ● 
  ♦ ♠ ♣ ♥ ● ◆ 
  ♠ ♣ ♥ ● ◆ ▲ 
  ♣ ♥ ● ◆ ▲ ★ 
  ♥ ● ◆ ▲ ★ ♦ 
  ● ◆ ▲ ★ ♦ ♠ 

  🎲 Random dice rolls: 6, 4, 1, 1, 6

  ✨ Sum of rolls: 18

That was fun! Let me do one more quick thing - a simple word scrambler: 
Tool call: QuickJS_execute_javascript({'javascript': "// Word scrambler game!\nfunction scrambleWord(word) {\n    let letters = word.split('');\n    // Fisher-Yates shuffle\n    for (let i = letters.length - 1; i > 0; i--) {\n        let j = Math.floor(Math.random() * (i + 1));\n        [letters[i], letters[j]] = [letters[j], letters[i]];\n    }\n    return letters.join('');\n}\n\nlet words = ['JAVASCRIPT', 'COMPUTER', 'RAINBOW', 'ADVENTURE', 'MYSTERY'];\nlet scrambled = words.map(word => `${word} → ${scrambleWord(word)}`);\n\n`🔤 Word Scramble Game!\\n\\n${scrambled.join('\\n')}\\n\\n🧩 Can you unscramble them all?`;"})
  🔤 Word Scramble Game!

  JAVASCRIPT → AVSTIRAJPC
  COMPUTER → EUPTMROC
  RAINBOW → ABIWRON
  ADVENTURE → NRTVEEAUD
  MYSTERY → STEYYMR

  🧩 Can you unscramble them all?

Perfect! I created some fun little programs:

1. **ASCII Art Pattern Generator** - Creates colorful patterns with symbols
2. **Dice Roller** - Simulates rolling 5 dice and shows the sum  
3. **Word Scrambler** - Takes words and randomly shuffles their letters

QuickJS is great for quick experiments like this! The persistent context means I can build on previous code, and it handles JavaScript really well. Want me to try something else fun? Maybe a simple maze generator or a number guessing game? 🎮

@simonw simonw changed the title Cut scope and get a non-alpha release of tools out Cut scope and release 0.26 (non-alpha) with tools May 27, 2025
@simonw
Copy link
Owner Author

simonw commented May 27, 2025

OK, everything in the (trimmed) milestone is now done!

Still need:

  • Release notes
  • A final review of the documentation
  • A release blog post

@simonw simonw pinned this issue May 27, 2025
@simonw
Copy link
Owner Author

simonw commented May 27, 2025

I pushed the new https://github.com/simonw/llm-tools-quickjs/releases/tag/0.1a1 which uses llm chat -T QuickJS and can maintain state.

@simonw
Copy link
Owner Author

simonw commented May 27, 2025

The tool plugins that exist so far are:

And the built-in llm -T llm_version "show version" tool.

simonw added a commit to simonw/llm-tools-sqlite that referenced this issue May 27, 2025
@simonw
Copy link
Owner Author

simonw commented May 27, 2025

Got Claude Sonnet 4 to write me a llm_time() function to go in core: https://gist.github.com/simonw/d3d4de6bdfc998716662c206437cf053

@simonw
Copy link
Owner Author

simonw commented May 27, 2025

Fun demo:

llm --functions '
import httpx

def search_blog(q):
    "Search Simon Willison blog"
    return httpx.get("https://simonwillison.net/dashboard/search.json", params={"q": q}).json()
' 'what is the deal with pelicans?' --td -s 'use search'

simonw added a commit that referenced this issue May 27, 2025
@simonw simonw closed this as completed May 27, 2025
@simonw simonw unpinned this issue May 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant