Files
mesh-catalog/modules/mesh-hand-acts/cmd/mesh-hand-acts/tools.go
T
jschoubben e1cdeebcdf Add mesh-hand-acts, holder of the seat mesh-hand-acts, so the hand-act log has a home the controller's lease does not hold (issue 1953)
Acts are kept 400 days under the runtime-proven caller and said as act-recorded; a warrant is read from the router's own record and recorded once per ask; hand-acts answers over both logs. The act layout is a copy of mesh-sdk's until L5-S2 lands.
2026-10-29 21:54:21 +01:00

111 lines
4.3 KiB
Go

package main
// The seat's verbs (novox/hq ADR 0565 §10, §15): hand-act and warranted record, hand-acts reads both logs and, with
// warrants, every warrant recorded. A recovery is a call: a warrant whose act was lost is written again by asking
// warranted again, from the router's record.
import (
"encoding/json"
"fmt"
"sort"
"strings"
stdio "git.novox.be/novox/mesh-sdk/go"
)
// Verbs are the seat's verbs, as the manifest claims them.
var Verbs = []string{"hand-act", "hand-acts", "warranted"}
// Tool names.
const (
HandActTool = Seat + ".hand-act"
HandActsTool = Seat + ".hand-acts"
WarrantedTool = Seat + ".warranted"
)
func obj(props map[string]any, required ...string) map[string]any {
m := map[string]any{"type": "object", "properties": props}
if len(required) > 0 {
m["required"] = required
}
return m
}
func str(d string) map[string]any { return map[string]any{"type": "string", "description": d} }
// Tools are what the runtime serves.
func Tools(l *Log) []stdio.Tool {
return []stdio.Tool{
{Name: HandActTool,
Description: "Record one act done by hand (novox/hq ADR 0565 §10): what was done, why, its cause in a word or a " +
"condition's kind (the word a second act for the same reason uses, which is how a repair done twice is " +
"found) and the condition it addresses. Who did it is the caller the runtime proves. verb is the act's " +
"verb as the log names it: a repair when not given, `hand-act drill` for a drill, or a recorder's own " +
"(`conditions silence`, `config set`). Said as act-recorded.",
Input: obj(map[string]any{"what": str("what was done"), "why": str("why, in a sentence"),
"cause": str("the cause, in a word or a condition's kind"), "condition": str("the condition's key, if any"),
"verb": str("the act's verb in the log; a repair when not given")}, "what", "why"),
Run: func(a map[string]any) (any, error) {
return l.HandAct(stdio.CallerOf(a), arg(a, "verb"), arg(a, "what"), arg(a, "why"), arg(a, "cause"), arg(a, "condition"))
}},
{Name: HandActsTool,
Description: "What was done by hand lately, over both logs (this seat's and the controller's until its lease " +
"ends), newest first: each act with who, why, its cause and which log holds it, and the causes repaired by " +
"hand twice or more within a fortnight (a healer is wanted). Narrowed by cause and who; warrants=true lists " +
"every warrant recorded instead.",
Input: obj(map[string]any{"days": map[string]any{"type": "number", "description": "how many days back (default 14)"},
"cause": str("only this cause"), "who": str("only acts whose who contains this"),
"warrants": str("\"true\": every warrant recorded, `<asker>.<ask>` with its act")}),
Run: func(a map[string]any) (any, error) {
if strings.EqualFold(arg(a, "warrants"), "true") || a["warrants"] == true {
return l.Warrants()
}
return l.HandActs(days(a), arg(a, "cause"), arg(a, "who")), nil
}},
{Name: WarrantedTool,
Description: "Record an asker's act on the operator's warrant (ADR 0274, ADR 0259): read from the router's own " +
"record of that ask — who chose, through which channel, with which proofs and which answer — never from the " +
"caller, once per ask; refused for an ask still open, ended without a choice, or another asker's.",
Input: obj(map[string]any{"asker": str("the module that asked"), "ask": str("its ask's id")}, "asker", "ask"),
Run: func(a map[string]any) (any, error) {
return l.Warranted(stdio.CallerOf(a), arg(a, "asker"), arg(a, "ask"))
}},
}
}
// Warrants is every warrant recorded, by key.
func (l *Log) Warrants() (any, error) {
keys, err := l.Store.Keys(WarrantsState)
if err != nil {
return nil, fmt.Errorf("the warrants cannot be read: %w", err)
}
sort.Strings(keys)
rows := map[string]json.RawMessage{}
for _, k := range keys {
if raw, found, err := l.Store.Get(WarrantsState, k); err == nil && found {
rows[k] = raw
}
}
return map[string]any{"warrants": rows, "count": len(rows)}, nil
}
func arg(a map[string]any, k string) string {
s, _ := a[k].(string)
return strings.TrimSpace(s)
}
func days(a map[string]any) int {
switch v := a["days"].(type) {
case float64:
if v > 0 {
return int(v)
}
case string:
var n int
if _, err := fmt.Sscan(v, &n); err == nil && n > 0 {
return n
}
}
return 14
}