What the TypeScript SDK's stdio loop does, in Go: an empty name serves as MESH_SERVED_MODULE; each call runs beside the loop so a tool waiting on the runtime does not deadlock it; Emit asks the runtime (mesh/publish) with the same envelope and headers. README says how to install it and how releases are tagged.
69 lines
2.3 KiB
Go
69 lines
2.3 KiB
Go
package stdio
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"io"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// A Go bundle serves as the module the runtime names, answers calls concurrently, and emits through
|
|
// the runtime with the TypeScript SDK's envelope (novox/hq ADR 0193).
|
|
func TestABundleEmitsThroughTheRuntimeAndServesAsItsModule(t *testing.T) {
|
|
t.Setenv(ServedAs, "chime")
|
|
t.Setenv("MESH_MODULE", "chime")
|
|
t.Setenv("MESH_NODE", "anchor")
|
|
inR, inW := io.Pipe()
|
|
outR, outW := io.Pipe()
|
|
go func() {
|
|
_ = ServeOn("", []Tool{{Name: "ring", Description: "rings", Run: func(map[string]any) (any, error) {
|
|
if err := Emit("rang", map[string]any{"times": 1}); err != nil {
|
|
return nil, err
|
|
}
|
|
return map[string]any{"rang": true}, nil
|
|
}}}, inR, outW)
|
|
}()
|
|
lines := bufio.NewScanner(outR)
|
|
next := func() map[string]any {
|
|
done := make(chan map[string]any, 1)
|
|
go func() {
|
|
if lines.Scan() {
|
|
var m map[string]any
|
|
_ = json.Unmarshal(lines.Bytes(), &m)
|
|
done <- m
|
|
}
|
|
}()
|
|
select {
|
|
case m := <-done:
|
|
return m
|
|
case <-time.After(3 * time.Second):
|
|
t.Fatal("the bundle said nothing")
|
|
return nil
|
|
}
|
|
}
|
|
send := func(m map[string]any) { b, _ := json.Marshal(m); _, _ = inW.Write(append(b, '\n')) }
|
|
|
|
send(map[string]any{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": map[string]any{}})
|
|
if got := next()["result"].(map[string]any)["serverInfo"].(map[string]any)["name"]; got != "chime" {
|
|
t.Fatalf("served as %v, want the module the runtime named", got)
|
|
}
|
|
send(map[string]any{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": map[string]any{"name": "ring", "arguments": map[string]any{}}})
|
|
asked := next()
|
|
if asked["method"] != "mesh/publish" {
|
|
t.Fatalf("the tool's emit was not asked of the runtime: %v", asked)
|
|
}
|
|
p := asked["params"].(map[string]any)
|
|
h := p["headers"].(map[string]any)
|
|
if p["key"] != "rang" || p["node"] != "anchor" || h["x-source"] != "chime" || h["content-type"] != "application/json" || len(h["x-event-id"].(string)) != 36 {
|
|
t.Errorf("the envelope is not the SDK's: %v", p)
|
|
}
|
|
send(map[string]any{"jsonrpc": "2.0", "id": asked["id"], "result": map[string]any{}})
|
|
answered := next()
|
|
text := answered["result"].(map[string]any)["content"].([]any)[0].(map[string]any)["text"]
|
|
if answered["id"] != float64(2) || text != `{"rang":true}` {
|
|
t.Errorf("the call answered %v", answered)
|
|
}
|
|
_ = inW.Close()
|
|
}
|