Skip to content

Add OpenRouter, JEV, and a GotA strategy bot - #74

Open
treeform wants to merge 8 commits into
mainfrom
polyworld-llm
Open

treeform wants to merge 8 commits into
mainfrom
polyworld-llm

Conversation

@treeform

@treeform treeform commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Adds native Nim OpenRouter calls to the BASIC hosts in Gods of the Arena, Call to Adventure, and Light vs Dark. The game uses the environment's sidecar when configured, with per-player accounting headers, or direct HTTPS OpenRouter access for local runs. It ships no Python helper or subprocess.

  • Ordinary text calls, raw JSON requests, response inspection, and SSE text extraction support standard LLMs and provider-specific JSON fields. Requests, retained replies, and timeouts are bounded.
  • JEV helpers build SystemOne state and typed questions, then expose choice, score, and probability answers to BASIC.
  • Headless runs can set a tick rate and choose a barrier that submits every seat's requests before waiting for all to settle. The existing unrestricted-speed asynchronous mode remains the default.
  • examples/gods_of_the_arena/players/jev.bas sends a text match summary and asks JEV for a strategy and lane every 15 simulation seconds. It follows farming, ganking, pushing, defending, or regrouping advice, handles movement and emergency retreats locally, and retains its plan on incomplete or failed replies.

Includes BASIC examples, configuration documentation, libcurl packaging, and tests. tests/manual_jev.nim makes exactly one paid direct OpenRouter request when explicitly run; it is excluded from CI. Uploaded neural networks remain outside this work.

llms.nim contains the BASIC bindings and calls Curly's startRequest and pollForResponse directly. Each player has one LlmClient, one pending request, and the latest completed response string with its HTTP status and error. New responses replace old ones. oracles.nim only prepares JEV payloads and interprets answers, retaining the latest answer set. Normal text and JEV calls share the same pending-request limit. JSON parsing uses jsony.

Each player lazily creates one Curly worker. SSE responses become available after the stream ends. Body/header limits are checked after Curly buffers the response. A host deadline settles the BASIC call and barrier while the seat stays busy until the underlying transfer completes; late replies are discarded. Curly's transport timeout rounds up to whole seconds, and cleanup waits for outstanding transfers. The lockfiles include the request cleanup fix in guzba/curly#28.

The GotA/LvD mailbox example reads a DM, asks an LLM for a reply, and sends it back to the sender using the game's existing mailbox routing.

Validation:

  • nim check tests/tests.nim and the complete test suite passed.
  • Native mock-sidecar tests passed for normal text, raw requests, completed SSE responses, errors, timeout recovery, late replies, response replacement, client reset/reopen, JEV answers, and concurrent request barriers.
  • The actual GotA host ran jev.bas against mock replies for all five strategies, lane changes, stage summaries, periodic refresh, incomplete replies, HTTP failure, and emergency retreat.
  • All three game host tests and native Coworld builds passed; hosted runtime integration passed for GotA, CTA, and LVD.
  • Allocation counters verify zero allocations/frees for 1,000 fill/drain cycles of the 100-slot inboxes and 1,000 GotA BASIC decisions through the mailbox callbacks and VM restart.
  • One paid direct OpenRouter call returned HTTP 200 from typesafe/jev-1.13-20260917 (TypeSafe), selecting farm and mid. Usage: 542 input tokens, 90 output tokens, reported cost $0.000022764. This live check preceded the Curly transport change; the current transport is tested with local mocks and the captured response passes BASIC readback offline. No second paid call was made.
  • nim check tests/manual_jev.nim and compilation pass; all automated LLM tests use local mocks or the captured response.
  • A 60-second GotA match with remote calls disabled completed with all ten scripts active, including jev.bas using its fallback plan.

Deployment note: JEV requires the sidecar to expose /v1/systemone. The inspected local Metta sidecar has Chat Completions and Anthropic routes but no explicit SystemOne route. Direct OpenRouter JEV was verified by the manual request above; the hosted sidecar deployment remains unverified. Raw access is bounded JSON/SSE; multipart uploads and arbitrary custom headers are not exposed.

@treeform
treeform changed the base branch from polyworld-mailboxes to main September 24, 2026 19:47
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.

1 participant