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:
@@ -69,8 +69,16 @@ type Issue struct {
|
||||
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
|
||||
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"
|
||||
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"
|
||||
|
||||
// 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.
|
||||
@@ -165,6 +173,18 @@ func (i *Issue) ComputeContentHash() string {
|
||||
h.Write([]byte(waiter))
|
||||
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))
|
||||
}
|
||||
@@ -263,6 +283,10 @@ func (i *Issue) ValidateWithCustomStatuses(customStatuses []string) error {
|
||||
if i.Status != StatusTombstone && i.DeletedAt != nil {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -353,6 +377,30 @@ func (t IssueType) IsValid() bool {
|
||||
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
|
||||
type Dependency struct {
|
||||
IssueID string `json:"issue_id"`
|
||||
|
||||
Reference in New Issue
Block a user