import (
"context"
"crypto/sha256"
+ "encoding/hex"
"encoding/json"
"errors"
"fmt"
)
// NotifyInput is caller-supplied data. Its source label proves no identity or
-// authority. Source and ID together identify a retry of the same text.
+// authority. Source and ID together identify a retry of the same text. AgentID
+// selects a permanent agent. An empty AgentID selects the root.
type NotifyInput struct {
- Source string `json:"source"`
- ID string `json:"id"`
- Text string `json:"text"`
+ AgentID string `json:"agent_id,omitempty"`
+ Source string `json:"source"`
+ ID string `json:"id"`
+ Text string `json:"text"`
}
// NotifyReceipt keeps a retry key after its queued delivery finishes. Digest
-// binds the original text without retaining another copy of that text.
+// binds the original text without retaining another copy of that text. TargetID
+// binds the permanent agent identity. An empty TargetID selects the root.
type NotifyReceipt struct {
- Source string `json:"source"`
- ID string `json:"id"`
- Digest string `json:"digest"`
- Number int `json:"number"`
+ TargetID string `json:"target_id,omitempty"`
+ Source string `json:"source"`
+ ID string `json:"id"`
+ Digest string `json:"digest"`
+ Number int `json:"number"`
}
// notify submits a local event and prints only its acceptance receipt. The
// notifyValidate checks both CLI and direct socket inputs without echoing data.
func notifyValidate(input NotifyInput) error {
+ if input.AgentID != "" {
+ id, err := hex.DecodeString(input.AgentID)
+ if err != nil || len(id) != agentIDBytes {
+ return errors.New("notification agent ID is invalid")
+ }
+ }
+
if !notifyIdentifier(input.Source) || !notifyIdentifier(input.ID) {
return errors.New("notification source and ID must be 1 to 128 ASCII letters, digits, dots, underscores, or hyphens")
}