Skip to content

Runnable v2 code examples#331

Closed
sourishkrout wants to merge 53 commits into
Mirascope:mainfrom
sourishkrout:seb/runnable
Closed

Runnable v2 code examples#331
sourishkrout wants to merge 53 commits into
Mirascope:mainfrom
sourishkrout:seb/runnable

Conversation

@sourishkrout

@sourishkrout sourishkrout commented Nov 27, 2025

Copy link
Copy Markdown

This PR introduces a Pyodide runtime to exclusively running Mirascope v2's Anthropic examples (their SDK is Pyodide compatible) with pre-recorded cached HTTP interactions.

Here's what's implemented:

  • Runnable code blocks in /docs/mirascope/v2
  • Pyodide running in Worker Thread to prevent WASM blocking browser's UI thread
  • Safe-recording and validation of VCR.py cassettes for HTTP caching, see cachedHTTP/README.md.

What's missing:

  • Adding unit tests
  • Upstreaming Mirascope UI and changes to v2 examples
  • Not all block have cached HTTP recorded yet (for development; fixed easily)
  • Multi-model/-SDK support (currently limited to Anthropic due to WASM compat)

@sourishkrout sourishkrout marked this pull request as draft November 27, 2025 00:51
@sourishkrout sourishkrout marked this pull request as ready for review December 2, 2025 00:53
Comment thread cachedHTTP/pyproject.toml Outdated
Comment thread cachedHTTP/.python-version Outdated


@llm.call(provider="openai", model_id="gpt-5", tools=[get_book_info])
@llm.call(provider="anthropic", model_id="claude-sonnet-4-0", tools=[get_book_info])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we might want to use a more recent 4.5 series model in these examples

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

absolutely. examples are sync'd from the mirascope repo so ideally all these changes need to be made upstream.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, @teamdandelion has been doing that. I think we can leave as-is for now and worry about this later after we port the website in Mirascope/mirascope (we've made it a monorepo now where we're putting everything)



@llm.call(provider="openai:responses", model_id="gpt-5", thinking=True)
@llm.call(provider="openai:responses", model_id="claude-sonnet-4-0", thinking=True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is incorrect. an upcoming release of v2 alpha will make this impossible (since provider and model id will be a single string)

print(response.pretty())

with llm.model(provider="openai:responses", model_id="gpt-5", thinking=False):
with llm.model(provider="openai:responses", model_id="claude-sonnet-4-0", thinking=False):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Comment thread src/lib/content/vcr-cassettes.ts
Comment thread mirascope-ui/blocks/code-block/code-block.tsx Outdated

@teamdandelion teamdandelion left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! Besides the inline comments, my main questions are around maintainability and CI integration. As I understand it:

  • CI checks for every cassette file that it is fresh w.r.t. the corresponding py file
  • We know the py file was runnable as-written (post transformations) because that generated said cassette file
  • We can (with a fix I requested elsewhere) ensure that every py file has a matching cassette

Ergo, CI being green gives us an assurance that every example has a matching cassette and will run correctly in browser. Does that track?

A part of me wonders about having a CI job that actually loads pyodide in the bun test environment and tries running every example just to be sure, but that may be unnecessary (maybe we build that out only if we start actually seeing flakes)

Comment thread scripts/cachedHTTP/README.md
Comment thread package.json Outdated
Comment thread scripts/check-cassettes.ts Outdated
Comment on lines +88 to +95
const sensitiveKeys = [
"x-api-key",
"authorization",
"x-auth-token",
"api-key",
"x-anthropic-api-key",
"x-openai-api-key",
];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I wonder if we can come up with a strategy to ensure synchronization between the sensitive keys here and in the mirascope vcr.py config. So as to ensure that we don't add a new provider, strip the key in Mirascope snapshots, but accidentally leak them here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is somewhat related to (1) porting the website over into Mirascope/mirascope and (2) refactoring the MLX and Grok custom caching into a more reusable upgrade to VCR. Perhaps we can import the VCR config here from the mirascope tests to keep them in sync.

Comment thread src/lib/content/mdx-preprocessing.ts Outdated
@@ -0,0 +1,123 @@
"use client";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we actually using all these new components? I would love to slim this down to just components that are actually in use.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. We don't need all of them.

I was going to drop the unnecessary ones as part of upstreaming <CodeBlock .../> into mirascope-ui once the UX is settled which is still pending.

@@ -0,0 +1,60 @@
import * as React from "react";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise, do we actually need all the new components here?

Comment thread scripts/validate-cassettes.ts Outdated

console.log(`Validating cassette files in ${targetPath}...`);

const results = await validateCassetteDirectory(targetPath);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this will not catch the case where there are new python example files that are missing cassettes

Comment thread scripts/record-cached-http.ts
Comment thread scripts/record-cached-http.ts Outdated
@sourishkrout

sourishkrout commented Dec 3, 2025

Copy link
Copy Markdown
Author

Somehow VCR.py v8 breaks using the cached cassettes inside of Pyodide using Anthropic 🤦. Not going to diagnose this deeper since we're backing out Pyodide/WASM for now.

Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
…s done

Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
… display it

Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
Signed-off-by: Sebastian (Tiedtke) Huckleberry <sebastiantiedtke@gmail.com>
@sourishkrout

sourishkrout commented Dec 6, 2025

Copy link
Copy Markdown
Author

Opening a new PR since we've decided to directions. Superseded by #336.

@sourishkrout sourishkrout mentioned this pull request Dec 6, 2025
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants