Give modules the seat traffic and the contract to ask a person and answer on a channel (hq ADR 0259)

This commit is contained in:
jochen
2026-10-09 13:58:27 +02:00
committed by jschoubben
parent cd01c3701d
commit 3d0c8b02b2
6 changed files with 737 additions and 1 deletions
+62 -1
View File
@@ -64,6 +64,9 @@ type channel struct {
subscribed int
// watches are this bundle's state watches by the id each was asked with (ADR 0201).
watches map[string]func(StateChange) error
// takers and provers are this bundle's seat work and proof handlers, by worker and subject (ADR 0259).
takers map[string]func(Work) error
provers map[string]func(subject string, body json.RawMessage) (any, error)
}
type listener struct {
@@ -150,7 +153,8 @@ func ServeOn(name string, tools []Tool, in io.Reader, out io.Writer) error {
for _, t := range tools {
byName[t.Name] = t
}
c := &channel{enc: json.NewEncoder(out), waiting: map[string]chan message{}, watches: map[string]func(StateChange) error{}}
c := &channel{enc: json.NewEncoder(out), waiting: map[string]chan message{}, watches: map[string]func(StateChange) error{},
takers: map[string]func(Work) error{}, provers: map[string]func(string, json.RawMessage) (any, error){}}
currentMu.Lock()
current = c
currentMu.Unlock()
@@ -276,6 +280,63 @@ func ServeOn(name string, tools []Tool, in io.Reader, out io.Writer) error {
}
c.say(map[string]any{"id": id, "result": map[string]any{}})
}(id, *p.Change)
case "mesh/work":
// One piece of a seat's work this bundle takes (novox/hq ADR 0259): taken by an answer that is
// not an error, offered again after one. Beside the loop, like a tool call.
var p struct {
Work *Work `json:"work"`
}
if json.Unmarshal(m.Params, &p) != nil || p.Work == nil {
c.say(map[string]any{"id": id, "error": map[string]any{"code": -32602, "message": "mesh/work carries no work"}})
continue
}
c.mu.Lock()
handle := c.takers[p.Work.Worker]
if handle == nil && len(c.takers) == 1 {
for _, h := range c.takers {
handle = h
}
}
c.mu.Unlock()
go func(id any, w Work) {
if handle == nil {
c.say(map[string]any{"id": id, "error": map[string]any{"code": -32000, "message": "nothing here takes " + w.Subject}})
return
}
if err := handle(w); err != nil {
c.say(map[string]any{"id": id, "error": map[string]any{"code": -32000, "message": err.Error()}})
return
}
c.say(map[string]any{"id": id, "result": map[string]any{}})
}(id, *p.Work)
case "mesh/proof":
// One proof this bundle answers (novox/hq ADR 0259): what the handler returns is the answer; an
// error is answered in words, never as silence.
var p struct {
Subject string `json:"subject"`
Body json.RawMessage `json:"body"`
}
_ = json.Unmarshal(m.Params, &p)
c.mu.Lock()
var handle func(string, json.RawMessage) (any, error)
for pattern, h := range c.provers {
if subjectMatches(pattern, p.Subject) {
handle = h
}
}
c.mu.Unlock()
go func(id any, subject string, body json.RawMessage) {
if handle == nil {
c.say(map[string]any{"id": id, "error": map[string]any{"code": -32000, "message": "nothing here answers " + subject}})
return
}
out, err := handle(subject, body)
if err != nil {
c.say(map[string]any{"id": id, "error": map[string]any{"code": -32000, "message": err.Error()}})
return
}
c.say(map[string]any{"id": id, "result": out})
}(id, p.Subject, p.Body)
default:
if id != nil {
c.say(map[string]any{"id": id, "error": map[string]any{"code": -32601, "message": "no " + m.Method}})