- /api/ai500 returned a success/data envelope but the web httpClient
wraps the raw body as data, so the panel read coins as undefined and
showed the empty state; return a flat {coins,count} body like
/api/symbols
- the agent rendered AI500 rankings as a markdown table that the chat
UI flattens into an unreadable line: tool note + system prompt now
mandate numbered lists (one coin per line) and ban tables outright
- provider/nofxos: GetAI500ListCached — 5min TTL cache with stale
fallback on upstream failure; ResolveClient routes through the claw402
gateway when a wallet key is configured (user's claw402 model key ->
CLAW402_WALLET_KEY env -> direct nofxos)
- new GET /api/ai500 endpoint serving the score-sorted board
- new get_ai500_list agent tool + prompt rule: when the user wants coin
picks or creates a strategy without naming coins, consult AI500's
high-scoring entries by default
- web: AI500 sidebar panel (rank, score badge, gain since entry,
5min auto-refresh); clicking an entry asks the agent to analyze it
suspendActiveContexts clears all active contexts after parking a task on
the snapshot stack, so the active-context guard alone let the agentic
loop hijack resume requests and strand suspended tasks. Check the
snapshot stack in shouldUseAgenticTurn.
- system prompt (zh+en): finish-the-work-then-report rule — chain tools in
the current turn, never promise background work; prefill industry-standard
defaults instead of interrogating field by field, batch any unavoidable
questions into one
- manage_strategy tool description: create only needs name, omitted config
merges from the default template, one-shot summary + confirmed=true flow
- manage_trader tool description: resolve exchange/model/strategy bindings
via list tools instead of asking the user for IDs
thinkAndAct/thinkAndActStream now try the native function-calling loop
first for fresh conversations; in-flight legacy flows (skill sessions,
workflows, execution states, pending proposals) stay on the legacy stack
until they finish. NOFX_AGENT_V2=off restores the old routing entirely.
One standard tool-use loop replaces the need for layered JSON routing:
the LLM sees all 22 tools plus real multi-turn history, every tool result
(including errors) returns to the loop as an observation, and the final
user-facing reply is always LLM-written. Interruptions report exactly
which tools already executed so side effects are never silently lost or
repeated by fallback paths. Gated by NOFX_AGENT_V2 (default on).
The strategy prompt the LLM saw for a Chinese-language single-symbol US
stock trader was an incoherent zh/en patchwork — schema in Chinese,
role definition in English, hard constraints in English, custom prompt
back in Chinese — with crypto-flavored BTC/ETH vs Altcoin labelling that
made no sense for ARM-USDC. The LLM responded by being conservative and
boring. When it finally tried to open, the validator rejected the order
because the validator classified the stock as an altcoin (1x equity cap
= 112 USDT max) while the prompt said 5x cap (= 559 USDT).
- kernel/engine_prompt.go (BuildSystemPrompt): all eight prompt sections
now respect e.GetLanguage() consistently. For single-symbol
Hyperliquid XYZ assets (US stocks, commodities, forex) we additionally
force the language to English regardless of the strategy's stored
language — US-equity reasoning lands better in English and prevents
the language-mix incoherence. The Hard Constraints section drops the
BTC/ETH vs Altcoin two-tier split when the strategy trades a single
instrument and shows one Position Value Limit line tagged with the
actual symbol. The JSON example uses that symbol instead of the
legacy BTCUSDT/ETHUSDT. The legacy stored custom_prompt (which was
Chinese for stock quick-creates) is replaced for XYZ assets by
buildXYZStockCustomPrompt — a built-in English long-only stock
briefing that includes a Flat-Account Rule: when Current Positions
is None, the agent MUST open a long this cycle (size 40-60% probing
if technicals are mixed, 80-100% on a confirmed breakout). This is
the "be in the market, not on the sidelines" stance the quick-trade
flow needed; wait/hold are reserved for when a position already
exists.
- kernel/engine_position.go + trader/auto_trader_risk.go + agent/trade.go:
Hyperliquid XYZ assets now use the BTC/ETH higher tier rather than
the altcoin tier in all three position-value enforcement points. A
shared isMajorAsset / isMajorTradeSymbol helper treats BTC/ETH crypto
perps AND any IsXyzDexAsset symbol as the higher tier. With 5x
equity cap, the AI's confident-open decisions on US stocks now pass
validation instead of erroring out with "altcoin single coin position
value cannot exceed 112 USDT".
Net result: on a flat US-stock single-symbol trader, the agent opens
a sized position with stop-loss and take-profit on the very first
flat cycle, manages it (trail / partial / cut), and reports honestly
to the user. The "agent does nothing" complaint is closed.
The agent felt like an artificial idiot because the LLM almost never spoke
for itself: 14+ Go paths injected fmt.Sprintf canned replies, the frontend
filtered out tool-progress events so users saw three dots for 10-20s, the
main prompt told the LLM "be a trading partner" AND "answer only what's
asked", and the planner sliced the toolset by inferred domain so a "BTC
dropped, how much am I losing?" question couldn't see positions and market
at the same time.
- agent/central_brain.go: shouldTrustDeterministicSkillReply now always
returns false. Successful mutations (trader/strategy/model/exchange
create/update/start/stop/delete) flow through reviewTaskCompletion so the
LLM sees the real outcome JSON and writes the user-facing prose. The
trade-confirmation regex path (handleTradeConfirmation) was already
outside this code path and is unaffected.
- agent/agent.go: rewrite the Behavior section of the main system prompt.
Replace the contradictory "answer only what's asked / don't upsell" with
"lead with the direct answer, then optionally one relevant follow-up
only when (a) open risk, (b) missing config, or (c) the next step is
obvious — e.g. created, want me to start it?". Explicitly authorize
chaining ("if the user says create and start, do both this turn") and
ban "please wait / I'll get back to you" language because there is no
background job to come back from.
- agent/tools.go: plannerToolsForText always returns the full 22-tool set
(new __all__ domain). The old per-domain trimming hid manage_trader from
market questions and execute_trade from anything that didn't look like
an explicit trade — cross-domain reasoning was structurally blocked. The
compact-vs-full strategy schema switch is preserved so mutation intents
still see the full config schema.
- web/src/components/agent/{AgentStepPanel,ChatMessages}.tsx: stop
filtering tool: steps. Map raw tool names to friendly labels with emoji
("get_positions" → "📊 检查持仓") in zh/en/id. Users now see what the
agent is doing in real time instead of silence. central_brain routing
chatter still gets dropped.
- agent/planner_tools_test.go: tests updated to assert the new
full-toolset behavior and the compact-vs-full strategy schema switch.
- Add stock symbol panel and agent chat page wiring
- Update onboarding and tool visibility for focused trader flows
- Tighten related tests around configuration and trader scope
Clarify the rationale for not injecting conversation history in the
legacy loop comment, and extract plannerToolDomainForText result into
a named variable for readability.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove conversation history injection from thinkAndActLegacyWithStore.
Previously, the legacy loop appended all prior Q&A turns, causing the
LLM to re-answer topics from earlier conversations (e.g. strategy data
leaking into a wallet balance question). Each legacy-loop call is now
treated as a standalone request with domain-filtered tools.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: when planner fails (402 payment), legacy loop dumps all system
context to LLM which outputs everything. Also final response prompt was too
weak — LLM treated all observations as required output.
Changes:
- Strengthen system prompt: "answer ONLY what user asked", no tables/tutorials
unless requested, no self-intro repeats, no "next step" suggestions
- Add compact observation summary for final response (step summaries only,
no raw JSON blobs)
- Domain-filtered tool selection in legacy loop to prevent over-fetching
- Fix domain routing: "钱包/wallet" → account domain (not model), with
exchange configs included for wallet context
- Widen wallet fast-path: no longer requires "claw402" keyword
- Anti-repetition instructions in planner step selector
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Agent now uses mcp.NewAIClientByProvider() for claw402 provider, ensuring
x402 payment signing works correctly instead of generic HTTP client
- Added ReasoningContent field to Message/LLMResponse structs and wired
serialization/parsing so DeepSeek thinking models work in multi-turn
- Added Beta badge to Agent nav tab in HeaderBar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add nil checks for session.TargetRef in all four execute*Action
handlers (Trader/Exchange/Model/Strategy) to prevent panic on
corrupted sessions; bulk-delete and query actions are excluded
- Add ensureHistory() helper and call it in runPlannedAgentWithContextMode
to prevent nil panic when history is not initialized
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add stopCh check in runPostResponseMaintenanceAsync to respect agent
shutdown, preventing goroutine leak on Agent.Stop()
- Replace bare context.Background() in handleTraderDiagnosisSkill with
a 30s timeout context for proper deadline propagation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>