Last updated: 2026-08-08. Branch: main. Working tree: clean.
11 commits are committed locally but NOT pushed (dff21d7..0119b7a).
Ongoing maintenance of Antares (Go backend + React/Vite dashboard in web/).
This session cleared the open PR, added an LLM provider, and fixed a run of
dashboard and Discord/Telegram gateway issues reported by the user. Everything
below is done and green unless called out under Next Steps.
- Toolchain: always build/test with
GOTOOLCHAIN=go1.26.3(the repo needs Go 1.26; httpcloak v1.6.8 forces it). A barego buildmay pick the wrong toolchain. - Dev:
make devruns BOTH the Air-reloaded backend on :8787 and Vite on :5173. Open :5173 — it hot-reloads the frontend and proxies/apito :8787. :8787 serves the embedded React bundle, which Air does NOT rebuild on frontend changes, so it shows a stale UI untilmake build-webruns. Several "the fix didn't work" reports this session were just the user viewing :8787. - Embedded bundle:
make build-webbuildsweb/distand copies it tointernal/server/dist(which is gitignored except.gitkeep— keep that file;make build-webdeletes it, sotouch internal/server/dist/.gitkeepafter). - Run the binary: on macOS use
antares serve --foreground. Cross-compiledCGO_ENABLED=0darwin binaries get an invalid ad-hoc signature and are SIGKILLed (exit 137) on other machines — fix withcodesign --force --sign -. - Tests:
GOTOOLCHAIN=go1.26.3 go test ./...→ 32 packages, all green.
- Merged PR #18 (
dff21d7) + review fixes (5d8406a): edit_file CRLF/line- prefix recovery, vps_run timeouts + new vps_upload/vps_download SFTP tools, persisted context compaction, dashboard session persistence, MCP refresh, composer history, Gemini thoughtSignature. Review fixes I added on top:ANTARES_API_KEY/ANTARES_BASE_URLhad gone silently inert (PR inverted credential precedence); restored env-override viainline*FromEnvflags.POST /api/mcp/refreshnil-panic when MCP unconfigured (typed-nil in interface); guarded.vps_download/vps_uploadcould truncate the destination on a mid-transfer timeout, and download copied the remote file's perm bits (world-writable risk); both now stream to a temp path + rename, download forces 0600.
- OpenCode Go (Zen) provider (
4693848): newkind: opencode. It routes per-model — MiniMax/Qwen → Anthropic/messages+ x-api-key, everything else → OpenAI/chat/completions+ Bearer (seeinternal/llm/opencode.go). Family match is prefix-based. Verified endpoints answer 401 (not 404) live. - Dashboard scroll judder while streaming (
b0b00ac): moved the streaming indicator out of the Virtuoso Footer, memoised components,followOutput={true}, stableinitialTopMostItemIndex. - Transcript OOM crash ("Aw, Snap!") on a tool-heavy turn (
e738c7c): the whole turn is ONE Virtuoso item (list virtualises messages, not segments), and unmemoised segment children made it O(N²) re-render. Fixed by memoisingToolCallCard,ReasoningBlock, newTextSegment. (LCS diff was ruled out by benchmark — write_file takes the cheap empty-old branch.) - Per-tab resumed session (
a16f4bb): the "resume last session" pointer moved fromlocalStorage(shared across tabs) tosessionStorage(per-tab), so two tabs can hold different sessions. Auth token stays in localStorage. - Gateway trio (
7abfb93):reply_mode: "always"now actually works (handleMessagenever read it before); per-user group sessions viaGatewaySessionKey(folds user id into the KV key in groups — thegroup_sessions_per_userflag was defined but never used); newnonetoolset for a tool-free chat turn. - Discord replies (
47ae931): the bot now replies to the triggering message (message_reference) + pings the author, first chunk only. Shared body builderdiscordMessagePayload. - Sender identity to the agent (
f76833e): captures Discord server nickname (member.nick) +global_name; system prompt gets aTalking to: <name> (<platform> user id <id>)line. Fixes the bot saying "I can't see your nick". - Per-user RAG (
0119b7a): opt-inrag.per_user. Each user gets their own RAG collection (rag.UserCollection);indexUserTurnsummarises each turn into durable facts via the aux model and indexes them;autoContextfolds the user's collection in first. Toggle surfaces automatically in the config editor.
- Benchmark before fixing. The OOM's first suspect (LCS diff) was cleared by a quick micro-benchmark — the real cause was O(N²) re-render. Don't fix by hypothesis alone here.
- Reflected config schema. Adding a
yaml-tagged field to a config struct makes it appear in the dashboard config editor automatically (config.Schema()walks the struct). Add the path tocommon/helptables ininternal/config/schema.gofor tier + description; no frontend work. - Small pure helpers + unit tests for the risky gateway logic
(
messageAddressesBot,discordDisplayName,GatewaySessionKey,discordMessagePayload,UserCollection) instead of trying to test the network-touching handlers. - Worktree + subagent to review the large PR #18 without polluting the main tree.
- Disk kept filling (ENOSPC, <500 MiB free) mid-session, which fails Go builds cryptically. The USER frees space themselves — do not delete anything without explicit say-so.
make devrun from inside the agent's tool sandbox gets killed on session teardown and leaves orphanair/viteprocesses that then hold ports 5173/8787. Tell the user to run it in their own terminal.- Viewing :8787 instead of :5173 repeatedly looked like "the fix didn't land". Always confirm which port the user is on.
ResolveBindingskips disabled bindings, so a binding withreply_mode: alwaysbutenabled: falsedoes nothing — the likely real cause of the user's original "always doesn't work". They must enable the binding.- gopls shows stale "undefined" diagnostics from a lowercase-path module alias;
the real
go buildis authoritative, trust it over the editor.
-
Push the 11 local commits once the user is ready (they have not asked yet — do NOT push without confirmation).
-
Agent loop guardrail (still open — the fix once proposed here was tried and reverted). The agent can loop writing the same file with slightly different contents; the repeat tracker fingerprints name+args, so changing the content never trips it. The fix this note used to recommend — treat repeated
write_file/edit_fileto the SAME path as a repeat regardless of content — was implemented and then removed again in "Tell a stuck loop apart from ordinary progress". Keying on the path alone cannot tell three different edits to one file from one edit made three times, so it fired on ordinary work, which for a coding agent is most of the work. Do not reintroduce it.repeatKeyis now uniform over the full normalised arguments for every tool, andinternal/agent/repeat_guard_test.gofails ifwrite_file,edit_fileorvps_uploadis given a coarser key again. Those are the three names that ever carried a special case, and the test names each of them; it asserts nothing about any other tool, so a coarser key introduced for a different tool would pass. The loop itself is therefore still unsolved: a model that varies the content each time is bounded only by the ceilings below, and any replacement needs a signal other than the call fingerprint. This is what produced the giant turn that caused the OOM in item 4 — the frontend is now hardened, but the loop remains.The ceilings as they actually stand: the hard stop is 60 tool calls per segment (
HardStopAfter),grContinuemay reset it up to 4× (maxGuardrailContinues,harness.go:477) for five segments, andAbsoluteMaxToolCalls: 200(config/defaults.go:137) caps the whole run regardless — so 200 calls, not the ~600 this note previously claimed. -
Rotate exposed credentials. The Z.ai API key and Voyage embed key were visible in
~/.antares/config.yamlread during earlier sessions. Still outstanding; user's call. -
macOS release signing in
scripts/release-build.sh: darwin release binaries needcodesign --force --sign -or they SIGKILL on other Macs. -
Live verification of this session's gateway/RAG work (needs a real Discord bot + RAG enabled): nickname shows in prompt;
reply_mode: alwayson an ENABLED binding answers un-addressed messages; per-user sessions stay separate; replies thread correctly;rag.per_userpopulatesuser-discord-*collections. -
Custom-provider "Add" UI — backend fully supports multiple custom providers; only the dashboard "add" form is missing. Deferred by the user earlier.
internal/llm/opencode.go,internal/llm/client.go— OpenCode provider + kind wiring.internal/gateway/discord.go,telegram.go,binding.go— reply_mode, replies, identity,GatewaySessionKey.internal/agent/ragcontext.go—autoContext,indexTurn,indexUserTurn,summariseUserTurn.internal/rag/user.go—UserCollection.internal/config/config.go,schema.go,load.go—rag.per_user, inline-cred env flags, reflected schema.internal/tools/registry.go—nonetoolset.web/src/pages/ChatPage.tsx— streaming indicator, memoised segments, per-tab session.web/src/components/chat/ToolCallCard.tsx— memoised.