execute_code
- Cancellation now reaches inside the SDK via an AsyncLocalStorage scope:
timeout, MCP cancel, or a newer call rejects pending waits and blocks
further action packets, including those inside walkTo().
- One execution per bot: a new call supersedes the running one and starts
once it has unwound; disconnect_bot does the same.
- Cancelled user code parks on bot/sdk calls instead of throwing, so a
catch-all loop can't spin and starve the server.
- Console capture is routed per execution, so concurrent bots no longer
clobber each other's output; leftover logs go to stderr.
- Stale world state warns and still runs, so a stale client can be diagnosed.
- Credentials are redacted from logs, results and launch messages.
SDK
- bot.mineRock() waits for ore plus Mining XP; interactLoc docs note that
success can mean the action only started.
- walkTo() takes options.timeout (default 120s), refuses stale state, and
reports the real last position.
- runScript uses the same cancellation scope for timeouts and signals.
Docs trimmed of duplicated or stale execute_code text.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Following the README, `bun bots/<name>/script.ts` with no browser tab or lite
runner attached printed "Connected", ran every action against nothing, and
exited 0. runScript never launches a client (autoLaunchBrowser: false), and
the README said the SDK would.
There are two ways that happened:
- No client ever attached: the gateway has no state, connect() times out its
ready wait and then "continues anyway".
- A client attached earlier but has gone: the gateway replays the state it
cached, so the ready check passes on a snapshot minutes old.
runScript now waits up to 10s for `tick` to advance after connecting. It
compares ticks, not getStateAge(), because that mixes gateway and local
clocks; a live run measured -343ms. If no tick arrives it throws an error
that names both ways to start a client, and a failed connect now sets
exitCode 1.
The README Getting Started and CLAUDE.md now include the lite runner step,
the README no longer claims scripts launch a client, and the CLAUDE.md
troubleshooting entry no longer points at an option runScript doesn't expose.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The filter runs in two independent layers, both now gated:
- Engine: WordEnc.filter skips censoring (bad words, domains, TLDs,
fragments) when NODE_PROFANITY_FILTER=false, keeping casing
normalization. Covers public chat ingest and PM encode.
- Browser client: the setting is injected via bot.ejs/client.ejs into
the Client constructor and sets WordFilter.enabled, so the local
re-filter follows the server automatically.
- Lite client: new SessionOptions.profanityFilter; the runner reads
PROFANITY_FILTER from bot.env / process env (no server config
channel exists headless).
Default unchanged (filter on).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Improve agent API docs and validation
* Drop the wiki search tool
Removes wiki/search.ts and its test. The index only covered names, aliases,
summaries and Sources lines, so it had worse recall than grep on body text
(e.g. "cow hide" missed skills/crafting.md), and normalize() stripped
underscores so map-square queries matched every neighbouring square
(m50_50 returned m50_53 NPCs). The computed mapSquareBounds were only
indexed as text, so coordinate lookups — the one thing grep can't do —
never worked.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Regenerate the wiki from server/content
Adds the coordinate-samples column to NPC location tables and picks up
content drift the checked-in pages had missed (807 NPC, 117 shop, 1573 item
pages; 335 of them new). Examples: Aubury now stocks 1000 chaos/death runes
rather than 500, and shop rows point at "Vial of water"/"Bolts" instead of
the stale "Vial"/"Bolt" names.
Also stops all three generators from crashing on their final step. Each one
read wiki/README.md unconditionally, but that file has never existed, so the
index update threw ENOENT on every run. Skip it when absent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Dead code/files (zero references, verified):
- server/engine/RuneScriptCompiler.jar (12.7MB) — replaced by
@lostcityrs/runescript TS package in the 274 upgrade
- server/engine/package-lock.json — bun-only repo; also gitignored so
vendor syncs don't reintroduce it
- server/engine/.github/ — vendored CI, can never run from a nested path
- server/engine/public/maped/ + view/maped.ejs — unreachable map editor
- server/gateway/{rsbot,run-recorder.ts,bunfig.toml} + bin/cli/login
package.json entries — all point at files/dirs that no longer exist
- server/webclient/.gitmodules + empty emsdk/tinymidipcm gitlinks —
submodules never initialized; build uses committed prebuilt wasm
- sdk/package.json — publish manifest for a never-published package
- sdk/test/zanaris-pathfinding.ts — duplicate of zanaris-navigation.ts;
its unique waypoint folded into the survivor
Dead dependencies (lockfiles regenerated):
- gateway: puppeteer + @anthropic-ai/sdk (~54MB + Chromium download per
Docker build, zero gateway imports); puppeteer now a root devDependency
since sdk/test/utils/browser.ts is its real consumer
- engine: @2004scape/rsmod-pathfinder (replaced by in-engine routefinder;
server/vendor copy is the SDK's), tsx, redundant @jimp direct pins
Also: README art (promo.gif 31MB + svgs) moved from server/content/title/
to docs/media/ so it stops shipping in every Docker image; stale
gateway/agent-state gitignore entry dropped; DEVELOPERS.md stale rows fixed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Flip the default so newly-created bots show other players' public chat
(SHOW_CHAT=true) instead of opting in. The controller code (sdk/runner.ts,
mcp/api) already defaulted to true, but the bot.env template wrote
SHOW_CHAT=false into every new bot and the docs said off-by-default; this makes
the default consistent. Template -> SHOW_CHAT=true, create-bot.ts defaults to
chat-on with a --no-chat/--hide-chat opt-out (--show-chat kept as a no-op for
back-compat), sdk default fallback false -> true, README updated. Existing bots
keep their explicit SHOW_CHAT=false until changed individually.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The daemon process and CLI exec subcommand caused AI models to hang
by spawning separate connections instead of using the MCP execute_code
tool. Background scripts also conflicted with the MCP server's
connection since the gateway allowed multiple controllers.
- Delete sdk/daemon.ts
- Strip exec/stop subcommands and all daemon comms from sdk/cli.ts
- Add controller pre-emption in gateway: new control-mode SDK
connections disconnect existing controllers for the same bot
- SDK handles pre-emption gracefully (no auto-reconnect loop)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two issues:
1. Success detection only checked inventory.length, which doesn't change
for stackable items (coins, arrows, bones). Now also checks if the
ground item disappeared and if total inventory count increased.
2. Door retry triggered on timeout, not just cant_reach. A timeout from
stacking/despawn doesn't mean a door is blocking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>