feat: simplify Claw402 autopilot trading flow

This commit is contained in:
tinkle-community
2026-06-27 00:37:59 +08:00
parent 961e016d33
commit 24f6421a73
151 changed files with 7453 additions and 41117 deletions

View File

@@ -1,103 +0,0 @@
package agent
import (
"encoding/json"
"testing"
"nofx/mcp"
)
// plannerToolsForText now always returns the FULL toolset (no per-domain
// trimming) so the LLM can cross-domain reason. The old "if market intent,
// hide manage_trader" filter was making cross-domain questions like "BTC
// dropped, how much am I losing?" impossible to answer because the agent
// couldn't see both market AND position tools in the same turn.
//
// We still trim the giant strategy schema for non-mutation intents because
// that one is genuinely huge and uninformative for read-only use.
func TestPlannerToolsExposeFullSetForMarketIntent(t *testing.T) {
tools := plannerToolsForText("看一下 BTCUSDT 行情和 K线")
names := toolNamesForTest(tools)
// Market tools must be present.
for _, expected := range []string{"get_market_snapshot", "get_market_price", "get_kline"} {
if !containsString(names, expected) {
t.Fatalf("expected market tool %q in %v", expected, names)
}
}
// Cross-domain tools (positions, balance, trader management) must ALSO be
// present so the agent can answer "how much am I losing" follow-ups
// without losing the market context.
for _, expected := range []string{"get_positions", "get_balance", "manage_trader"} {
if !containsString(names, expected) {
t.Fatalf("expected cross-domain tool %q in market context %v", expected, names)
}
}
}
func TestPlannerToolsExposeFullSetForExchangeIntent(t *testing.T) {
tools := plannerToolsForText("帮我添加 okx 交易所 API key")
names := toolNamesForTest(tools)
// At least the exchange management tools must show up.
for _, expected := range []string{"get_exchange_configs", "manage_exchange_config"} {
if !containsString(names, expected) {
t.Fatalf("expected exchange tool %q in %v", expected, names)
}
}
// And the agent still has the broader surface available — adding an
// exchange often leads to "now create a trader" so trader/strategy tools
// must be reachable in the same turn.
for _, expected := range []string{"manage_trader", "get_strategies"} {
if !containsString(names, expected) {
t.Fatalf("expected adjacent tool %q in exchange context %v", expected, names)
}
}
}
func TestPlannerToolsUseCompactManageStrategyForReadIntent(t *testing.T) {
tools := plannerToolsForText("列出我的策略")
tool := findToolForTest(tools, "manage_strategy")
if tool == nil {
t.Fatalf("expected manage_strategy in strategy tools")
}
raw, _ := json.Marshal(tool.Function.Parameters)
if len(raw) > 900 {
t.Fatalf("expected compact strategy schema, got %d bytes", len(raw))
}
if string(raw) == "" || !json.Valid(raw) {
t.Fatalf("expected valid strategy schema JSON")
}
}
func TestPlannerToolsKeepFullManageStrategyForMutationIntent(t *testing.T) {
tools := plannerToolsForText("创建一个 BTC 网格策略")
tool := findToolForTest(tools, "manage_strategy")
if tool == nil {
t.Fatalf("expected manage_strategy in strategy tools")
}
raw, _ := json.Marshal(tool.Function.Parameters)
if len(raw) < 1500 {
t.Fatalf("expected full strategy schema for mutation intent, got %d bytes", len(raw))
}
}
func toolNamesForTest(tools []mcp.Tool) []string {
names := make([]string, 0, len(tools))
for _, tool := range tools {
names = append(names, tool.Function.Name)
}
return names
}
func findToolForTest(tools []mcp.Tool, name string) *mcp.Tool {
for i := range tools {
if tools[i].Function.Name == name {
return &tools[i]
}
}
return nil
}