feat(agentic): align model contracts with RFC

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-02 08:26:02 +00:00
parent 4e82ec8da6
commit 5dc0983b77
8 changed files with 95 additions and 51 deletions

View file

@ -162,6 +162,7 @@ func (s *PrepSubsystem) cmdPlanCreate(options core.Options) core.Result {
Objective: objective,
Description: description,
Context: optionAnyMapValue(options, "context"),
AgentType: optionStringValue(options, "agent_type", "agent"),
Repo: optionStringValue(options, "repo"),
Org: optionStringValue(options, "org"),
Phases: planPhasesValue(options, "phases"),

View file

@ -24,6 +24,6 @@ func ExamplePrepSubsystem_cmdAuthProvision() {
result := s.cmdAuthProvision(core.NewOptions())
core.Println(result.OK)
// Output:
// usage: core-agent auth provision <oauth-user-id> [--name=codex] [--permissions=plans:read,plans:write] [--rate-limit=60] [--expires-at=2026-04-01T00:00:00Z]
// usage: core-agent auth provision <oauth-user-id> [--name=codex] [--permissions=plans:read,plans:write] [--ip-restrictions=10.0.0.0/8,192.168.0.0/16] [--rate-limit=60] [--expires-at=2026-04-01T00:00:00Z]
// false
}

View file

@ -14,23 +14,25 @@ import (
// message := agentic.AgentMessage{Workspace: "core/go-io/task-5", FromAgent: "codex", ToAgent: "claude", Subject: "Review", Content: "Please check the prompt."}
type AgentMessage struct {
ID string `json:"id"`
Workspace string `json:"workspace"`
FromAgent string `json:"from_agent"`
ToAgent string `json:"to_agent"`
Subject string `json:"subject,omitempty"`
Content string `json:"content"`
ReadAt string `json:"read_at,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
ID string `json:"id"`
WorkspaceID int `json:"workspace_id,omitempty"`
Workspace string `json:"workspace"`
FromAgent string `json:"from_agent"`
ToAgent string `json:"to_agent"`
Subject string `json:"subject,omitempty"`
Content string `json:"content"`
ReadAt string `json:"read_at,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
}
// input := agentic.MessageSendInput{Workspace: "core/go-io/task-5", FromAgent: "codex", ToAgent: "claude", Subject: "Review", Content: "Please check the prompt."}
type MessageSendInput struct {
Workspace string `json:"workspace"`
FromAgent string `json:"from_agent"`
ToAgent string `json:"to_agent"`
Subject string `json:"subject,omitempty"`
Content string `json:"content"`
WorkspaceID int `json:"workspace_id,omitempty"`
Workspace string `json:"workspace"`
FromAgent string `json:"from_agent"`
ToAgent string `json:"to_agent"`
Subject string `json:"subject,omitempty"`
Content string `json:"content"`
}
// input := agentic.MessageInboxInput{Workspace: "core/go-io/task-5", Agent: "claude"}
@ -71,11 +73,12 @@ type MessageListOutput struct {
// ))
func (s *PrepSubsystem) handleMessageSend(ctx context.Context, options core.Options) core.Result {
_, output, err := s.messageSend(ctx, nil, MessageSendInput{
Workspace: optionStringValue(options, "workspace", "_arg"),
FromAgent: optionStringValue(options, "from_agent", "from"),
ToAgent: optionStringValue(options, "to_agent", "to"),
Subject: optionStringValue(options, "subject"),
Content: optionStringValue(options, "content", "body"),
WorkspaceID: optionIntValue(options, "workspace_id", "workspace-id"),
Workspace: optionStringValue(options, "workspace", "_arg"),
FromAgent: optionStringValue(options, "from_agent", "from"),
ToAgent: optionStringValue(options, "to_agent", "to"),
Subject: optionStringValue(options, "subject"),
Content: optionStringValue(options, "content", "body"),
})
if err != nil {
return core.Result{Value: err, OK: false}
@ -196,13 +199,14 @@ func messageStoreSend(input MessageSendInput) (AgentMessage, error) {
now := time.Now().Format(time.RFC3339)
message := AgentMessage{
ID: messageID(),
Workspace: core.Trim(input.Workspace),
FromAgent: core.Trim(input.FromAgent),
ToAgent: core.Trim(input.ToAgent),
Subject: core.Trim(input.Subject),
Content: input.Content,
CreatedAt: now,
ID: messageID(),
WorkspaceID: input.WorkspaceID,
Workspace: core.Trim(input.Workspace),
FromAgent: core.Trim(input.FromAgent),
ToAgent: core.Trim(input.ToAgent),
Subject: core.Trim(input.Subject),
Content: input.Content,
CreatedAt: now,
}
messages = append(messages, message)

View file

@ -13,22 +13,25 @@ import (
// plan := &Plan{ID: "id-1-a3f2b1", Title: "Migrate Core", Status: "draft", Objective: "Replace raw process calls with Core.Process()"}
// r := writePlanResult(PlansRoot(), plan)
type Plan struct {
ID string `json:"id"`
Slug string `json:"slug,omitempty"`
Title string `json:"title"`
Status string `json:"status"`
Repo string `json:"repo,omitempty"`
Org string `json:"org,omitempty"`
Objective string `json:"objective"`
Description string `json:"description,omitempty"`
Context map[string]any `json:"context,omitempty"`
TemplateVersion PlanTemplateVersion `json:"template_version,omitempty"`
Phases []Phase `json:"phases,omitempty"`
Notes string `json:"notes,omitempty"`
Agent string `json:"agent,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ArchivedAt time.Time `json:"archived_at,omitempty"`
ID string `json:"id"`
WorkspaceID int `json:"workspace_id,omitempty"`
Slug string `json:"slug,omitempty"`
Title string `json:"title"`
Status string `json:"status"`
Repo string `json:"repo,omitempty"`
Org string `json:"org,omitempty"`
Objective string `json:"objective"`
Description string `json:"description,omitempty"`
AgentType string `json:"agent_type,omitempty"`
Context map[string]any `json:"context,omitempty"`
TemplateVersionID int `json:"template_version_id,omitempty"`
TemplateVersion PlanTemplateVersion `json:"template_version,omitempty"`
Phases []Phase `json:"phases,omitempty"`
Notes string `json:"notes,omitempty"`
Agent string `json:"agent,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ArchivedAt time.Time `json:"archived_at,omitempty"`
}
// AgentPlan is the RFC-named alias for Plan.
@ -36,6 +39,7 @@ type AgentPlan = Plan
// phase := agentic.Phase{Number: 1, Name: "Migrate strings", Status: "in_progress"}
type Phase struct {
AgentPlanID int `json:"agent_plan_id,omitempty"`
Number int `json:"number"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
@ -80,6 +84,7 @@ type PlanCreateInput struct {
Objective string `json:"objective,omitempty"`
Description string `json:"description,omitempty"`
Context map[string]any `json:"context,omitempty"`
AgentType string `json:"agent_type,omitempty"`
TemplateVersion PlanTemplateVersion `json:"template_version,omitempty"`
Repo string `json:"repo,omitempty"`
Org string `json:"org,omitempty"`
@ -114,6 +119,7 @@ type PlanUpdateInput struct {
Phases []Phase `json:"phases,omitempty"`
Notes string `json:"notes,omitempty"`
Agent string `json:"agent,omitempty"`
AgentType string `json:"agent_type,omitempty"`
}
type PlanUpdateOutput struct {
@ -159,6 +165,7 @@ func (s *PrepSubsystem) handlePlanCreate(ctx context.Context, options core.Optio
Objective: optionStringValue(options, "objective"),
Description: optionStringValue(options, "description"),
Context: optionAnyMapValue(options, "context"),
AgentType: optionStringValue(options, "agent_type", "agent"),
Repo: optionStringValue(options, "repo"),
Org: optionStringValue(options, "org"),
Phases: planPhasesValue(options, "phases"),
@ -200,6 +207,7 @@ func (s *PrepSubsystem) handlePlanUpdate(ctx context.Context, options core.Optio
Phases: planPhasesValue(options, "phases"),
Notes: optionStringValue(options, "notes"),
Agent: optionStringValue(options, "agent"),
AgentType: optionStringValue(options, "agent_type", "agent-type"),
})
if err != nil {
return core.Result{Value: err, OK: false}
@ -356,6 +364,7 @@ func (s *PrepSubsystem) planCreate(_ context.Context, _ *mcp.CallToolRequest, in
Org: input.Org,
Objective: objective,
Description: description,
AgentType: core.Trim(input.AgentType),
Context: input.Context,
TemplateVersion: input.TemplateVersion,
Phases: input.Phases,
@ -363,6 +372,9 @@ func (s *PrepSubsystem) planCreate(_ context.Context, _ *mcp.CallToolRequest, in
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
if plan.AgentType == "" {
plan.AgentType = core.Trim(plan.Agent)
}
plan = normalisePlan(plan)
writeResult := writePlanResult(PlansRoot(), &plan)
@ -465,6 +477,9 @@ func (s *PrepSubsystem) planUpdate(_ context.Context, _ *mcp.CallToolRequest, in
if input.Agent != "" {
plan.Agent = input.Agent
}
if input.AgentType != "" {
plan.AgentType = input.AgentType
}
*plan = normalisePlan(*plan)
plan.UpdatedAt = time.Now()
@ -994,6 +1009,12 @@ func normalisePlan(plan Plan) Plan {
if plan.Objective == "" {
plan.Objective = plan.Description
}
if plan.AgentType == "" {
plan.AgentType = plan.Agent
}
if plan.Agent == "" {
plan.Agent = plan.AgentType
}
for i := range plan.Phases {
plan.Phases[i] = normalisePhase(plan.Phases[i], i+1)
}

View file

@ -13,6 +13,9 @@ import (
// session := agentic.Session{SessionID: "ses_abc123", AgentType: "codex", Status: "active"}
type Session struct {
ID int `json:"id"`
WorkspaceID int `json:"workspace_id,omitempty"`
AgentPlanID int `json:"agent_plan_id,omitempty"`
AgentAPIKeyID int `json:"agent_api_key_id,omitempty"`
SessionID string `json:"session_id"`
Plan string `json:"plan,omitempty"`
PlanSlug string `json:"plan_slug,omitempty"`
@ -719,6 +722,9 @@ func parseSession(values map[string]any) Session {
return Session{
ID: intValue(values["id"]),
WorkspaceID: intValue(values["workspace_id"]),
AgentPlanID: intValue(values["agent_plan_id"]),
AgentAPIKeyID: intValue(values["agent_api_key_id"]),
SessionID: stringValue(values["session_id"]),
Plan: stringValue(values["plan"]),
PlanSlug: planSlug,
@ -971,6 +977,15 @@ func mergeSessionCache(session Session) (Session, error) {
if session.ID == 0 {
session.ID = existing.ID
}
if session.WorkspaceID == 0 {
session.WorkspaceID = existing.WorkspaceID
}
if session.AgentPlanID == 0 {
session.AgentPlanID = existing.AgentPlanID
}
if session.AgentAPIKeyID == 0 {
session.AgentAPIKeyID = existing.AgentAPIKeyID
}
if session.Plan == "" {
session.Plan = existing.Plan
}

View file

@ -12,6 +12,7 @@ import (
// state := agentic.WorkspaceState{Key: "pattern", Value: "observer", Type: "general", Description: "Shared across sessions"}
type WorkspaceState struct {
AgentPlanID int `json:"agent_plan_id,omitempty"`
Key string `json:"key"`
Value any `json:"value"`
Type string `json:"type,omitempty"`

View file

@ -250,15 +250,16 @@ func memoriesFromPayload(payload map[string]any) []Memory {
}
memory := Memory{
Content: stringField(memoryMap, "content"),
Type: stringField(memoryMap, "type"),
Project: stringField(memoryMap, "project"),
AgentID: stringField(memoryMap, "agent_id"),
Source: stringField(memoryMap, "source"),
CreatedAt: stringField(memoryMap, "created_at"),
UpdatedAt: stringField(memoryMap, "updated_at"),
ExpiresAt: stringField(memoryMap, "expires_at"),
DeletedAt: stringField(memoryMap, "deleted_at"),
Content: stringField(memoryMap, "content"),
Type: stringField(memoryMap, "type"),
Project: stringField(memoryMap, "project"),
WorkspaceID: stringField(memoryMap, "workspace_id"),
AgentID: stringField(memoryMap, "agent_id"),
Source: stringField(memoryMap, "source"),
CreatedAt: stringField(memoryMap, "created_at"),
UpdatedAt: stringField(memoryMap, "updated_at"),
ExpiresAt: stringField(memoryMap, "expires_at"),
DeletedAt: stringField(memoryMap, "deleted_at"),
}
if id, ok := memoryMap["id"].(string); ok {
memory.ID = id

View file

@ -73,6 +73,7 @@ type RecallOutput struct {
// }
type Memory struct {
ID string `json:"id"`
WorkspaceID string `json:"workspace_id,omitempty"`
AgentID string `json:"agent_id"`
Type string `json:"type"`
Content string `json:"content"`