Skip to content

feat(python): expose embedded runtime host functions to agent tools - #2739

Merged
chaliy merged 3 commits into
mainfrom
feat/python-tool-external-functions
Oct 16, 2026
Merged

chaliy merged 3 commits into
mainfrom
feat/python-tool-external-functions

Conversation

@chaliy

@chaliy chaliy commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

What changed

Embedded Python and TypeScript programs can call registered async host functions through Python BashTool, LangChain, and deepagents. Python uses external_functions / external_handler; TypeScript has separate typescript_external_functions / typescript_external_handler options. Both can coexist and share the virtual filesystem.

Async execution runs handlers on the caller's event loop with the request's ContextVars. Sync execution uses a persistent private worker loop, including inside notebooks and FastAPI sync endpoints. Reset preserves registration; snapshot factories require the host to supply callbacks again. Cancellation is scoped to each execution, and recursive interpreter/live-filesystem access fails promptly instead of deadlocking. Native result deliveries drain before interpreter shutdown, preventing a reference-cleanup race exposed by immediate process exit after async execution.

Why

Closes #2737. Agents need to orchestrate host services from sandboxed programs while preserving the threading and loop behavior of existing integrations.

Before / After

Before: passing external_functions or external_handler to BashTool failed with an unexpected-keyword error; framework integrations could not expose host functions to embedded programs.

After: a registered lookup dispatcher returns {"value": 42} to either language:

python -c 'print(lookup(21, multiplier=2)["value"])'
42
ts -c 'const r = await lookup(21, {multiplier: 2}); r.value'
42

Evidence: real-interpreter regression tests cover both languages across sync/async calls, multiple threads and successive loops, Selector/uvloop, concurrent FastAPI requests, LangChain/deepagents, cancellation/timeout reuse, and reentry. A real Jupyter kernel executes the new notebook. The full Python suite passes 973 tests; targeted suites also pass on Python 3.9 and 3.14. Deterministic regressions cover native result-delivery cleanup for all three tool classes and private callback cancellation during process exit; 1,000 parallel subprocess runs passed after the shutdown fix (76 crashes before). Repository tests, pre-PR checks, all-feature Clippy, and the parallel-execution benchmark pass. CI additionally exercises macOS and Windows callback loops and Linux Python 3.9–3.14.

Risk

  • Medium: callback scheduling, cancellation, and lock reentry affect native threading behavior. Regression tests exercise these directly; handlers remain trusted host code and retain the existing Python host opt-in gate.
  • Existing ZapCode behavior loses console.log() output after a host-call suspension. Examples use final-expression or VFS output; this limitation is documented.
  • Native host handlers remain unavailable in Pyodide.

Checklist

  • Tests added or updated
  • Backward compatibility considered

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
bashkit 7dafe0c Commit Preview URL

Branch Preview URL
Oct 16 2026, 06:04 PM

@chaliy
chaliy merged commit a4484f7 into main Oct 16, 2026
40 checks passed
@chaliy
chaliy deleted the feat/python-tool-external-functions branch October 16, 2026 18:32
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.

[Feature request] Support external functions and handler for langchain/deepagents integration of bashkit-python

1 participant