From 5dc0983b779bde0547d9ee03703b4ff517e97f51 Mon Sep 17 00:00:00 2001 From: Virgil Date: Thu, 2 Apr 2026 08:26:02 +0000 Subject: [PATCH] feat(agentic): align model contracts with RFC Co-Authored-By: Virgil --- pkg/agentic/commands_plan.go | 1 + pkg/agentic/commands_platform_example_test.go | 2 +- pkg/agentic/message.go | 54 ++++++++++--------- pkg/agentic/plan.go | 53 ++++++++++++------ pkg/agentic/session.go | 15 ++++++ pkg/agentic/state.go | 1 + pkg/brain/direct.go | 19 +++---- pkg/brain/tools.go | 1 + 8 files changed, 95 insertions(+), 51 deletions(-) diff --git a/pkg/agentic/commands_plan.go b/pkg/agentic/commands_plan.go index 1564699..f98b049 100644 --- a/pkg/agentic/commands_plan.go +++ b/pkg/agentic/commands_plan.go @@ -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"), diff --git a/pkg/agentic/commands_platform_example_test.go b/pkg/agentic/commands_platform_example_test.go index 325648b..11bab4b 100644 --- a/pkg/agentic/commands_platform_example_test.go +++ b/pkg/agentic/commands_platform_example_test.go @@ -24,6 +24,6 @@ func ExamplePrepSubsystem_cmdAuthProvision() { result := s.cmdAuthProvision(core.NewOptions()) core.Println(result.OK) // Output: - // usage: core-agent auth provision [--name=codex] [--permissions=plans:read,plans:write] [--rate-limit=60] [--expires-at=2026-04-01T00:00:00Z] + // usage: core-agent auth provision [--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 } diff --git a/pkg/agentic/message.go b/pkg/agentic/message.go index f529d5c..f6c4081 100644 --- a/pkg/agentic/message.go +++ b/pkg/agentic/message.go @@ -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) diff --git a/pkg/agentic/plan.go b/pkg/agentic/plan.go index 8b2c50c..de33a8c 100644 --- a/pkg/agentic/plan.go +++ b/pkg/agentic/plan.go @@ -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) } diff --git a/pkg/agentic/session.go b/pkg/agentic/session.go index 5ce8b68..a3cc723 100644 --- a/pkg/agentic/session.go +++ b/pkg/agentic/session.go @@ -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 } diff --git a/pkg/agentic/state.go b/pkg/agentic/state.go index 7126993..3d16b62 100644 --- a/pkg/agentic/state.go +++ b/pkg/agentic/state.go @@ -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"` diff --git a/pkg/brain/direct.go b/pkg/brain/direct.go index b9c9e1c..e79fb4a 100644 --- a/pkg/brain/direct.go +++ b/pkg/brain/direct.go @@ -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 diff --git a/pkg/brain/tools.go b/pkg/brain/tools.go index 38c6bc0..99c9281 100644 --- a/pkg/brain/tools.go +++ b/pkg/brain/tools.go @@ -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"`