feat(hyperguild): mode client-local writes routing headers
Plan 6 is now deployed; replace the _routing_pending placeholder in the routing MCP entry with a real headers block carrying X-Hyperguild-Mode: client-local. The pod treats absent or unknown values as client-local, so this is forward-compat for future modes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -115,9 +115,10 @@ Flags:
|
|||||||
Modes:
|
Modes:
|
||||||
|
|
||||||
- **cloud** — brain MCP only. Claude Code with no routing.
|
- **cloud** — brain MCP only. Claude Code with no routing.
|
||||||
- **client-local** — brain + routing placeholder. The routing entry's
|
- **client-local** — brain + routing pod. The `routing` entry points at
|
||||||
URL points at `koala:30310/mcp`; a `_routing_pending` field marks it
|
`koala:30310/mcp` (the routing pod, deployed in Plan 6). The
|
||||||
as awaiting Plan 6 of the hyperguild migration.
|
`X-Hyperguild-Mode: client-local` header is forward-compat for future
|
||||||
|
modes; the pod treats absent or unknown values as `client-local`.
|
||||||
- **sovereign** — brain only, with a `_mode_note` explaining that this
|
- **sovereign** — brain only, with a `_mode_note` explaining that this
|
||||||
mode primarily uses Crush + LiteLLM and the `.mcp.json` is a Claude
|
mode primarily uses Crush + LiteLLM and the `.mcp.json` is a Claude
|
||||||
Code fallback for emergency offline use.
|
Code fallback for emergency offline use.
|
||||||
|
|||||||
@@ -78,9 +78,11 @@ func modeClientLocal(brainURL string) map[string]any {
|
|||||||
"description": "Brain MCP — knowledge query, write, ingestion, session log",
|
"description": "Brain MCP — knowledge query, write, ingestion, session log",
|
||||||
},
|
},
|
||||||
"routing": map[string]any{
|
"routing": map[string]any{
|
||||||
"url": "http://koala:30310/mcp",
|
"url": "http://koala:30310/mcp",
|
||||||
"description": "Mode 2 routing pod — routes skill calls to LiteLLM/local",
|
"description": "Mode 2 routing pod — routes skill calls to LiteLLM/local",
|
||||||
"_routing_pending": "Plan 6 — routing pod not deployed yet; this URL is a placeholder",
|
"headers": map[string]any{
|
||||||
|
"X-Hyperguild-Mode": "client-local",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func TestRunMode_Cloud_Default(t *testing.T) {
|
|||||||
assert.NotContains(t, got, "_mode_note")
|
assert.NotContains(t, got, "_mode_note")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunMode_ClientLocal_HasRoutingPlaceholder(t *testing.T) {
|
func TestRunMode_ClientLocal_HasRoutingEntry(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
outPath := filepath.Join(dir, ".mcp.json")
|
outPath := filepath.Join(dir, ".mcp.json")
|
||||||
t.Setenv("BRAIN_URL", "http://koala:30330")
|
t.Setenv("BRAIN_URL", "http://koala:30330")
|
||||||
@@ -54,7 +54,32 @@ func TestRunMode_ClientLocal_HasRoutingPlaceholder(t *testing.T) {
|
|||||||
require.Contains(t, servers, "routing")
|
require.Contains(t, servers, "routing")
|
||||||
|
|
||||||
routing := servers["routing"].(map[string]any)
|
routing := servers["routing"].(map[string]any)
|
||||||
assert.Contains(t, routing, "_routing_pending")
|
assert.NotContains(t, routing, "_routing_pending", "placeholder should be removed once Plan 6 ships")
|
||||||
|
|
||||||
|
headers, ok := routing["headers"].(map[string]any)
|
||||||
|
require.True(t, ok, "routing entry should have headers block")
|
||||||
|
assert.Equal(t, "client-local", headers["X-Hyperguild-Mode"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestModeClientLocalHasRoutingHeader(t *testing.T) {
|
||||||
|
tmp := t.TempDir() + "/mcp.json"
|
||||||
|
out := &bytes.Buffer{}
|
||||||
|
stderr := &bytes.Buffer{}
|
||||||
|
require.NoError(t, runMode(context.Background(), []string{"client-local", "--out", tmp}, nil, out, stderr))
|
||||||
|
|
||||||
|
body, err := os.ReadFile(tmp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
var doc map[string]any
|
||||||
|
require.NoError(t, json.Unmarshal(body, &doc))
|
||||||
|
|
||||||
|
servers := doc["mcpServers"].(map[string]any)
|
||||||
|
routing := servers["routing"].(map[string]any)
|
||||||
|
assert.Equal(t, "http://koala:30310/mcp", routing["url"])
|
||||||
|
assert.NotContains(t, routing, "_routing_pending", "placeholder should be removed once Plan 6 ships")
|
||||||
|
|
||||||
|
headers, ok := routing["headers"].(map[string]any)
|
||||||
|
require.True(t, ok, "routing entry should have headers block")
|
||||||
|
assert.Equal(t, "client-local", headers["X-Hyperguild-Mode"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunMode_Sovereign_HasModeNote(t *testing.T) {
|
func TestRunMode_Sovereign_HasModeNote(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user