Skip to content

Release 0.9.0: native gocoon provider + withdraw/unstake fix + reset#23

Merged
TONresistor merged 16 commits into
mainfrom
dev
Jun 19, 2026
Merged

Release 0.9.0: native gocoon provider + withdraw/unstake fix + reset#23
TONresistor merged 16 commits into
mainfrom
dev

Conversation

@TONresistor

@TONresistor TONresistor commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Release 0.9.0.

Highlights

  • Native gocoon provider replaces cocoon (breaking): OpenAI-compatible pure-Go COCOON client with a turnkey TON payment-channel lifecycle (auto-install + integrity-verify the runner, supervise it, set up / top-up / withdraw from the CLI teleton gocoon or the WebUI Gocoon page). Native tools/tool_calls replace the removed XML shim.
  • ToolSearch mode on by default; Codex in the WebUI provider selector.
  • Local SSE proxy in front of the runner (fixes pi-ai "empty response / zero tokens", surfaces runner errors).
  • Dead-code purge (cocoon, events/bus, memory/agent/sessions, telegram/callbacks, web SearchInput, lib/a11y).

Migration (breaking)

Set agent.provider: gocoon and rename the cocoon: config block to gocoon: (gocoon.port, default 10000). Legacy cocoon configs are auto-migrated on load.

Fund-safety fixes

  • Unstake/withdraw scanned the owner wallet instead of the fund wallet, leaving staked TON locked. Now scans the fund address and reads channel state.
  • Withdraw hardened against transient errors and re-runs (idempotent, re-broadcast-safe).
  • Agent-wallet sweep now holds the wallet tx-lock to prevent seqno theft from a concurrent send.

Release hygiene

  • Deps: npm audit fix in-range on root + web (root 8 vulns -> 1 low dev-only; web 4 -> 0). Major bumps (React 19, react-router 7, TS 6, etc.) deferred.
  • Gates green locally: typecheck, build, vitest (1508 tests), npm ci in sync.
  • Full notes in CHANGELOG.md under [0.9.0].

The tag v0.9.0 (pushed after merge) triggers npm + Docker + GitHub Release publishing.

…fecycle

- Replace the cocoon LLM provider with gocoon (pure-Go COCOON client, native
  OpenAI tool-calling); delete the XML tool-injection shim (src/cocoon/).
- src/gocoon/: installer (download v0.2.0 + SHA-256 + cache), supervisor
  (spawn gocoon-runner + health + watchdog), lifecycle (init/waitFunded/
  topup/withdrawAll) with a shared ProgressSink.
- CLI: teleton gocoon init|topup|withdraw|status.
- WebUI: /api/gocoon/* routes + Gocoon panel in Config.
- Auto-start: provider=gocoon installs + supervises the runner on start.
Swap the XML tool-injection cocoon shim for gocoon, a pure-Go COCOON
client exposing a native OpenAI-compatible API. Adds a turnkey TON
channel lifecycle: download and verify release binaries, supervise the
runner, init/fund/topup/withdraw, with auto-start when provider is
gocoon. Exposes it via the `teleton gocoon` CLI and a dedicated Gocoon
WebUI page. Pins gocoon v0.2.0; default model Qwen/Qwen3-32B.
pi-ai always sends stream:true and only parses Server-Sent Events, but
the gocoon runner returns a single JSON document, so streaming clients
parsed zero chunks and saw an empty response with zero tokens. Start a
local proxy (when provider is gocoon) that forwards to the runner and
frames its JSON reply as SSE, leaving gocoon itself unchanged. pi-ai
points at the proxy instead of the runner.
codex was in the backend registry but missing from the hardcoded
frontend provider list, so it never appeared in the WebUI. Add it, and
treat it as keyless in provider-meta (it authenticates via the Codex CLI
~/.codex/auth.json, no API key to paste) so the switch flow shows no key
field.
gocoon webui withdraw matches myduckai-agent: a Stop agent control,
destination validation, type-"withdraw" confirm, and live progress
polling, over the same withdrawAll the CLI uses.

Unstake fix: withdrawAll located the channel via the owner wallet
instead of the fund wallet (findClientSC(fundAddress)). The owner wallet
has no on-chain history, so the channel was never found, the close was
skipped, and only the liquid balance was withdrawn while the staked TON
stayed locked. It now closes the channel and waits for the refund before
draining, so the stake comes back.

Wallet reset: teleton gocoon reset (CLI), POST /gocoon/reset, and a Reset
wallet button delete the local wallet + config so the next setup creates
a fresh owner/node wallet. Guarded: refuses while the runner is up, or
while funds or a non-closed channel with stake remain. channelInfoOnChain
checks the channel state (not the contract account status, which stays
active after a cooperative close). --force overrides the fund/channel
checks.

Also a knip dead-code pass (events/bus, memory/agent/sessions,
telegram/callbacks, SearchInput, a11y, assorted dead exports) and a webui
cleanup (Dashboard, styles, AllowLists).
Drop the non-existent scripts/ entry from package.json files.
0.9.0 dropped 'cocoon' from the provider enum. Existing 0.8.6 configs
with agent.provider: cocoon now migrate to 'gocoon' (carrying a custom
cocoon.port) instead of failing config validation, mirroring the
claude-code -> anthropic shim. Adds a loader test for the migration.
The create-release job rendered ghcr.io/${{ github.repository }} (mixed
case) in the public install snippet, which the Docker CLI rejects. Use a
lowercased step output, matching the actual image push.
- findClientSC throws a typed ChannelNotFoundError only for a genuine
  no-channel case; transient tonapi/HTTP errors propagate so withdrawAll
  ABORTS instead of draining the liquid wallet while the stake stays
  locked and reporting success.
- withdrawAll decides liveness from the channel state (channelInfoOnChain
  stateName/stake), not the account status, so a re-run on an
  already-closed channel skips the close and sweeps the balance
  idempotently instead of re-closing and timing out.
- waitForRefund returns a boolean; on a slow cooperative refund the
  withdraw no longer hard-fails (misleading 'lost') but reports the
  refund pending (~12h unilateral fallback) and leaves funds for a
  re-run.
- resetWallet refuses when the channel state can't be verified (transient
  error) rather than risk deleting keys to a live stake.
- gocoon wallet withdraw gets a generous --timeout for slow finality.
A runner error (non-2xx, a {error} envelope, or a non-JSON body) was
reframed into an empty 200 SSE stream that the OpenAI SDK parses as a
successful zero-token reply, hiding failures (no workers / channel out of
balance) and letting the agent retry silently. Now non-2xx is forwarded
with its status and error envelopes/parse failures become SSE error
events the SDK throws on. Adds completionToSse tests.
The version sentinel only checked a version string, so an out-of-band
swap/corruption of gocoon/gocoon-runner went undetected. The sentinel
now records each binary's sha256 and ensureGocoonBinaries re-hashes
before reuse, re-downloading on mismatch. Legacy string sentinels
re-verify once.
`gocoon status` printed the owner wallet (no on-chain history, not the
deposit address) labelled 'COCOON wallet' — the same owner/fund
confusion behind the unstake bug; it now shows the fund address. The
WebUI top-up control is disabled while the runner is stopped (top-up
needs a live runner).
@TONresistor TONresistor merged commit e842680 into main Jun 19, 2026
8 checks passed
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