Repository navigation
computer: Let isolate code read module declarations from cf:computer - #240
Draft
mattzcarey wants to merge 1 commit into
Draft
mattzcarey wants to merge 1 commit into
mattzcarey wants to merge 1 commit into
Conversation
A host module's code runs in the Durable Object, so the isolate only
holds stubs that forward each call. Code had nothing to inspect: the
exec description gave one line of prose per module, printing a stub
showed the forwarding code, and printing a module namespace threw,
because console output was formatted with String(). Models guessed
call shapes instead, and ws:git made the guesses look like success:
cli("status") ran git with no arguments and returned its help text
with exit code 0.
Module factories now carry TypeScript declarations in a `types`
property, keyed by the name each one declares, and short `examples`.
The prebuilt modules declare all their exports. ws:tools writes each
tool's declaration from its description and JSON Schema input, which
forAISDKTools and forPiTools now pass through on each binding.
The JavaScript backend renders the declarations once per connection
and installs `cf:computer`, a built-in module like node:fs.
`docs(target)` returns a module's summary, declarations, and examples,
and `docs()` lists every module. `types(target)` returns only the
declarations. The target is a specifier, a namespace from
`import * as`, or one host export. The cf:* namespace is reserved, so
configured modules can no longer use it.
Each host stub is named after its export and prints its declaration
with a `{ [host code] }` body, as V8 prints a built-in with
`{ [native code] }`. console output follows Node.js formatting, so
objects, maps, and errors print legibly, and a namespace prints its
module's declaration.
ws:git exports now take exactly one options object. A string, an
array, or an argv starting with "git" is refused with the shape the
call expects.
馃 Changeset detectedLatest commit: ef7acbf The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
| } | ||
|
|
||
| function mentions(text: string, name: string): boolean { | ||
| const escaped = name.replace(/[$]/g, "\\$"); |
| import { call } from ${JSON.stringify(capabilitiesImport)}; | ||
| ${names.map((name, index) => `const fn${index} = (...args) => call(${namespace}, ${JSON.stringify(name)}, args);`).join("\n")} | ||
| import { hostExport } from ${JSON.stringify(introspectionImport)}; | ||
| ${names.map((name, index) => `const fn${index} = hostExport(${module}, ${JSON.stringify(name)}, (...args) => call(${namespace}, ${JSON.stringify(name)}, args));`).join("\n")} |
| import { call } from ${JSON.stringify(capabilitiesImport)}; | ||
| ${names.map((name, index) => `const fn${index} = (...args) => call(${namespace}, ${JSON.stringify(name)}, args);`).join("\n")} | ||
| import { hostExport } from ${JSON.stringify(introspectionImport)}; | ||
| ${names.map((name, index) => `const fn${index} = hostExport(${module}, ${JSON.stringify(name)}, (...args) => call(${namespace}, ${JSON.stringify(name)}, args));`).join("\n")} |
aron-cf
reviewed
Oct 15, 2026
| "@cloudflare/computer": minor | ||
| --- | ||
|
|
||
| JavaScript backend code can import `cf:computer` for each module's TypeScript declarations, and `console.log` prints a host export's declaration. Configured modules can no longer use `cf:*` specifiers, and `ws:git` rejects calls that pass anything other than one options object; see [`cf:computer`](https://github.com/cloudflare/computer/blob/main/docs/17_isolate_javascript.md#cfcomputer). |
Collaborator
There was a problem hiding this comment.
So excited for this 馃コ
I'm not sure about the module name. I don't think it should be ws: prefix (which I also think should become computer: or ext: or something that implies it's an extension. Alternatives ws:debug, ws:runtime, ws:help...
Also I think now I see it, we should just have one function. help(<thing>) that returns docs, types, source...
I could also be convinced that help should just be a global:
import * as git from "ws:git";
export default () => ({
modules: help().docs, // every module, one line each
git: help(git), // ws:git's interface, summary, declarations, and examples, as markdown
cli: help(git.cli), // one export's interface, declaration, with the types it names
byName: help("ws:git"), // a specifier works too, even for a module that failed to import
});
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Code running on the JavaScript backend can now look up how to call any module it can import. A built-in
cf:computermodule returns each module's TypeScript declarations and examples, and printing a host export shows its declaration.Models were guessing how to call host modules. While moving the agents harnesses to Computer, the pi harness needed several tries to get
ws:git'sclisignature right:(...args) => call("host/ws:git", "cli", args), andconsole.log(namespace)threw, because console output went throughString()cli("status")andcli(["status"])ran git with no arguments, so they returned its help text with exit code 0How it works:
types(TypeScript declarations keyed by name) andexamples. The prebuilt modules declare all their exports, andws:toolswrites each tool's declaration from thedescriptionandinputSchemathatforAISDKToolsandforPiToolsnow pass through.{ [host code] }in place of{ [native code] }. Console output follows Node.js formatting.ws:giterrors. A call that passes anything other than one options object, or anargvstarting with"git", is refused with the shape the call expects.cf:*specifiers are reserved, so configured modules can no longer use them.Tests ran (
npm testinpackages/computer). The new end-to-end cases run in workerd under both the legacy and new module registries.