Add agent-specific fields to bead schema (gt-v2gkv)
Agent identity fields on Issue struct: - HookBead: reference to current work (0..1 cardinality) - RoleBead: reference to role definition bead - AgentState: self-reported state (idle|spawning|running|working|stuck|done|stopped|dead) - LastActivity: timestamp for heartbeat/timeout detection - RoleType: agent type (polecat|crew|witness|refinery|mayor|deacon) - Rig: rig name (empty for town-level agents) Also adds: - AgentState type with IsValid() method - Validation for agent state in Issue.Validate() - Agent fields included in content hash This enables the agent-as-bead architecture where agents are tracked as first-class beads with self-reported state. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+50
-2
@@ -69,8 +69,16 @@ type Issue struct {
|
|||||||
Waiters []string `json:"waiters,omitempty"` // Mail addresses to notify when gate clears
|
Waiters []string `json:"waiters,omitempty"` // Mail addresses to notify when gate clears
|
||||||
|
|
||||||
// Source tracing fields (gt-8tmz.18): track where this issue came from during cooking
|
// Source tracing fields (gt-8tmz.18): track where this issue came from during cooking
|
||||||
SourceFormula string `json:"source_formula,omitempty"` // Formula name where this step was defined
|
SourceFormula string `json:"source_formula,omitempty"` // Formula name where this step was defined
|
||||||
SourceLocation string `json:"source_location,omitempty"` // Path within source: "steps[0]", "advice[0].after"
|
SourceLocation string `json:"source_location,omitempty"` // Path within source: "steps[0]", "advice[0].after"
|
||||||
|
|
||||||
|
// Agent identity fields (gt-v2gkv): agent-as-bead support
|
||||||
|
HookBead string `json:"hook_bead,omitempty"` // Current work attached to agent's hook (0..1)
|
||||||
|
RoleBead string `json:"role_bead,omitempty"` // Role definition bead (required for agents)
|
||||||
|
AgentState AgentState `json:"agent_state,omitempty"` // Agent-reported state (idle|running|stuck|stopped)
|
||||||
|
LastActivity *time.Time `json:"last_activity,omitempty"` // Updated on each agent action (for timeout detection)
|
||||||
|
RoleType string `json:"role_type,omitempty"` // Agent role: polecat|crew|witness|refinery|mayor|deacon
|
||||||
|
Rig string `json:"rig,omitempty"` // Rig name (empty for town-level agents like mayor/deacon)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ComputeContentHash creates a deterministic hash of the issue's content.
|
// ComputeContentHash creates a deterministic hash of the issue's content.
|
||||||
@@ -165,6 +173,18 @@ func (i *Issue) ComputeContentHash() string {
|
|||||||
h.Write([]byte(waiter))
|
h.Write([]byte(waiter))
|
||||||
h.Write([]byte{0})
|
h.Write([]byte{0})
|
||||||
}
|
}
|
||||||
|
// Hash agent identity fields (gt-v2gkv)
|
||||||
|
h.Write([]byte(i.HookBead))
|
||||||
|
h.Write([]byte{0})
|
||||||
|
h.Write([]byte(i.RoleBead))
|
||||||
|
h.Write([]byte{0})
|
||||||
|
h.Write([]byte(i.AgentState))
|
||||||
|
h.Write([]byte{0})
|
||||||
|
h.Write([]byte(i.RoleType))
|
||||||
|
h.Write([]byte{0})
|
||||||
|
h.Write([]byte(i.Rig))
|
||||||
|
h.Write([]byte{0})
|
||||||
|
// Note: LastActivity is a timestamp, excluded from hash like other timestamps
|
||||||
|
|
||||||
return fmt.Sprintf("%x", h.Sum(nil))
|
return fmt.Sprintf("%x", h.Sum(nil))
|
||||||
}
|
}
|
||||||
@@ -263,6 +283,10 @@ func (i *Issue) ValidateWithCustomStatuses(customStatuses []string) error {
|
|||||||
if i.Status != StatusTombstone && i.DeletedAt != nil {
|
if i.Status != StatusTombstone && i.DeletedAt != nil {
|
||||||
return fmt.Errorf("non-tombstone issues cannot have deleted_at timestamp")
|
return fmt.Errorf("non-tombstone issues cannot have deleted_at timestamp")
|
||||||
}
|
}
|
||||||
|
// Validate agent state if set (gt-v2gkv)
|
||||||
|
if !i.AgentState.IsValid() {
|
||||||
|
return fmt.Errorf("invalid agent state: %s", i.AgentState)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,6 +377,30 @@ func (t IssueType) IsValid() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AgentState represents the self-reported state of an agent (gt-v2gkv)
|
||||||
|
type AgentState string
|
||||||
|
|
||||||
|
// Agent state constants
|
||||||
|
const (
|
||||||
|
StateIdle AgentState = "idle" // Agent is waiting for work
|
||||||
|
StateSpawning AgentState = "spawning" // Agent is starting up
|
||||||
|
StateRunning AgentState = "running" // Agent is executing (general)
|
||||||
|
StateWorking AgentState = "working" // Agent is actively working on a task
|
||||||
|
StateStuck AgentState = "stuck" // Agent is blocked and needs help
|
||||||
|
StateDone AgentState = "done" // Agent completed its current work
|
||||||
|
StateStopped AgentState = "stopped" // Agent has cleanly shut down
|
||||||
|
StateDead AgentState = "dead" // Agent died without clean shutdown (timeout detection)
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsValid checks if the agent state value is valid
|
||||||
|
func (s AgentState) IsValid() bool {
|
||||||
|
switch s {
|
||||||
|
case StateIdle, StateSpawning, StateRunning, StateWorking, StateStuck, StateDone, StateStopped, StateDead, "":
|
||||||
|
return true // empty is valid (non-agent beads)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Dependency represents a relationship between issues
|
// Dependency represents a relationship between issues
|
||||||
type Dependency struct {
|
type Dependency struct {
|
||||||
IssueID string `json:"issue_id"`
|
IssueID string `json:"issue_id"`
|
||||||
|
|||||||
Reference in New Issue
Block a user