feat(agent): add instructions field for agent persona/identity
Add an `instructions` text field to the agent model, allowing users to define each agent's role, expertise, and working style. Instructions are injected into CLAUDE.md as an "Agent Identity" section so the agent knows who it is on every task execution. - Migration 021: add instructions column to agent table - Backend: create/update/get agent handlers support instructions - ClaimTask response includes instructions for daemon injection - execenv: inject instructions into CLAUDE.md meta-skill - Frontend: add Instructions tab to agent detail panel
This commit is contained in:
parent
ffda18c809
commit
5b2c61cfab
14 changed files with 159 additions and 27 deletions
|
|
@ -312,6 +312,73 @@ function AgentListItem({
|
|||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Instructions Tab
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function InstructionsTab({
|
||||
agent,
|
||||
onSave,
|
||||
}: {
|
||||
agent: Agent;
|
||||
onSave: (instructions: string) => Promise<void>;
|
||||
}) {
|
||||
const [value, setValue] = useState(agent.instructions ?? "");
|
||||
const [saving, setSaving] = useState(false);
|
||||
const isDirty = value !== (agent.instructions ?? "");
|
||||
|
||||
// Sync when switching between agents.
|
||||
useEffect(() => {
|
||||
setValue(agent.instructions ?? "");
|
||||
}, [agent.id, agent.instructions]);
|
||||
|
||||
const handleSave = async () => {
|
||||
setSaving(true);
|
||||
try {
|
||||
await onSave(value);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold">Agent Instructions</h3>
|
||||
<p className="text-xs text-muted-foreground mt-0.5">
|
||||
Define this agent's identity and working style. These instructions are
|
||||
injected into the agent's context for every task.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<textarea
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
placeholder={`Define this agent's role, expertise, and working style.\n\nExample:\nYou are a frontend engineer specializing in React and TypeScript.\n\n## Working Style\n- Write small, focused PRs — one commit per logical change\n- Prefer composition over inheritance\n- Always add unit tests for new components\n\n## Constraints\n- Do not modify shared/ types without explicit approval\n- Follow the existing component patterns in features/`}
|
||||
className="w-full min-h-[300px] rounded-md border bg-transparent px-3 py-2 text-sm font-mono placeholder:text-muted-foreground/50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring resize-y"
|
||||
/>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{value.length > 0 ? `${value.length} characters` : "No instructions set"}
|
||||
</span>
|
||||
<Button
|
||||
size="xs"
|
||||
onClick={handleSave}
|
||||
disabled={!isDirty || saving}
|
||||
>
|
||||
{saving ? (
|
||||
<Loader2 className="h-3 w-3 animate-spin" />
|
||||
) : (
|
||||
<Save className="h-3 w-3" />
|
||||
)}
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Skills Tab (picker — skills are managed on /skills page)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -976,9 +1043,10 @@ function TasksTab({ agent }: { agent: Agent }) {
|
|||
// Agent Detail
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type DetailTab = "skills" | "tools" | "triggers" | "tasks";
|
||||
type DetailTab = "instructions" | "skills" | "tools" | "triggers" | "tasks";
|
||||
|
||||
const detailTabs: { id: DetailTab; label: string; icon: typeof FileText }[] = [
|
||||
{ id: "instructions", label: "Instructions", icon: FileText },
|
||||
{ id: "skills", label: "Skills", icon: BookOpenText },
|
||||
{ id: "tools", label: "Tools", icon: Wrench },
|
||||
{ id: "triggers", label: "Triggers", icon: Timer },
|
||||
|
|
@ -998,7 +1066,7 @@ function AgentDetail({
|
|||
}) {
|
||||
const st = statusConfig[agent.status];
|
||||
const runtimeDevice = getRuntimeDevice(agent, runtimes);
|
||||
const [activeTab, setActiveTab] = useState<DetailTab>("skills");
|
||||
const [activeTab, setActiveTab] = useState<DetailTab>("instructions");
|
||||
const [confirmDelete, setConfirmDelete] = useState(false);
|
||||
|
||||
return (
|
||||
|
|
@ -1065,6 +1133,12 @@ function AgentDetail({
|
|||
|
||||
{/* Tab Content */}
|
||||
<div className="flex-1 overflow-y-auto p-6">
|
||||
{activeTab === "instructions" && (
|
||||
<InstructionsTab
|
||||
agent={agent}
|
||||
onSave={(instructions) => onUpdate(agent.id, { instructions })}
|
||||
/>
|
||||
)}
|
||||
{activeTab === "skills" && (
|
||||
<SkillsTab agent={agent} />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ export interface Agent {
|
|||
runtime_id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
instructions: string;
|
||||
avatar_url: string | null;
|
||||
runtime_mode: AgentRuntimeMode;
|
||||
runtime_config: Record<string, unknown>;
|
||||
|
|
@ -77,6 +78,7 @@ export interface Agent {
|
|||
export interface CreateAgentRequest {
|
||||
name: string;
|
||||
description?: string;
|
||||
instructions?: string;
|
||||
avatar_url?: string;
|
||||
runtime_id: string;
|
||||
runtime_config?: Record<string, unknown>;
|
||||
|
|
@ -89,6 +91,7 @@ export interface CreateAgentRequest {
|
|||
export interface UpdateAgentRequest {
|
||||
name?: string;
|
||||
description?: string;
|
||||
instructions?: string;
|
||||
avatar_url?: string;
|
||||
runtime_id?: string;
|
||||
runtime_config?: Record<string, unknown>;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ export const mockAgents: Agent[] = [
|
|||
runtime_id: "runtime-1",
|
||||
name: "Claude Agent",
|
||||
description: "",
|
||||
instructions: "",
|
||||
avatar_url: null,
|
||||
status: "idle",
|
||||
runtime_mode: "cloud",
|
||||
|
|
|
|||
|
|
@ -578,16 +578,19 @@ func (d *Daemon) runTask(ctx context.Context, task Task, provider string) (TaskR
|
|||
|
||||
agentName := "agent"
|
||||
var skills []SkillData
|
||||
var instructions string
|
||||
if task.Agent != nil {
|
||||
agentName = task.Agent.Name
|
||||
skills = task.Agent.Skills
|
||||
instructions = task.Agent.Instructions
|
||||
}
|
||||
|
||||
// Prepare isolated execution environment.
|
||||
taskCtx := execenv.TaskContextForEnv{
|
||||
IssueID: task.IssueID,
|
||||
AgentName: agentName,
|
||||
AgentSkills: convertSkillsForEnv(skills),
|
||||
IssueID: task.IssueID,
|
||||
AgentName: agentName,
|
||||
AgentInstructions: instructions,
|
||||
AgentSkills: convertSkillsForEnv(skills),
|
||||
}
|
||||
env, err := execenv.Prepare(execenv.PrepareParams{
|
||||
WorkspacesRoot: d.cfg.WorkspacesRoot,
|
||||
|
|
|
|||
|
|
@ -30,9 +30,10 @@ type PrepareParams struct {
|
|||
|
||||
// TaskContextForEnv is the subset of task context used for writing context files.
|
||||
type TaskContextForEnv struct {
|
||||
IssueID string
|
||||
AgentName string
|
||||
AgentSkills []SkillContextForEnv
|
||||
IssueID string
|
||||
AgentName string
|
||||
AgentInstructions string // agent identity/persona instructions, injected into CLAUDE.md
|
||||
AgentSkills []SkillContextForEnv
|
||||
}
|
||||
|
||||
// SkillContextForEnv represents a skill to be written into the execution environment.
|
||||
|
|
|
|||
|
|
@ -34,6 +34,13 @@ func buildMetaSkillContent(provider string, ctx TaskContextForEnv) string {
|
|||
b.WriteString("# Multica Agent Runtime\n\n")
|
||||
b.WriteString("You are a coding agent in the Multica platform. Use the `multica` CLI to interact with the platform.\n\n")
|
||||
|
||||
// Inject agent identity instructions before workflow commands.
|
||||
if ctx.AgentInstructions != "" {
|
||||
b.WriteString("## Agent Identity\n\n")
|
||||
b.WriteString(ctx.AgentInstructions)
|
||||
b.WriteString("\n\n")
|
||||
}
|
||||
|
||||
b.WriteString("## Available Commands\n\n")
|
||||
b.WriteString("### Read\n")
|
||||
b.WriteString("- `multica issue get <id>` — Get full issue details (title, description, status, priority, assignee)\n")
|
||||
|
|
|
|||
|
|
@ -27,9 +27,10 @@ type Task struct {
|
|||
|
||||
// AgentData holds agent details returned by the claim endpoint.
|
||||
type AgentData struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Skills []SkillData `json:"skills"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Instructions string `json:"instructions"`
|
||||
Skills []SkillData `json:"skills"`
|
||||
}
|
||||
|
||||
// SkillData represents a structured skill for task execution.
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ type AgentResponse struct {
|
|||
RuntimeID string `json:"runtime_id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Instructions string `json:"instructions"`
|
||||
AvatarURL *string `json:"avatar_url"`
|
||||
RuntimeMode string `json:"runtime_mode"`
|
||||
RuntimeConfig any `json:"runtime_config"`
|
||||
|
|
@ -64,6 +65,7 @@ func agentToResponse(a db.Agent) AgentResponse {
|
|||
RuntimeID: uuidToString(a.RuntimeID),
|
||||
Name: a.Name,
|
||||
Description: a.Description,
|
||||
Instructions: a.Instructions,
|
||||
AvatarURL: textToPtr(a.AvatarUrl),
|
||||
RuntimeMode: a.RuntimeMode,
|
||||
RuntimeConfig: rc,
|
||||
|
|
@ -97,11 +99,12 @@ type AgentTaskResponse struct {
|
|||
}
|
||||
|
||||
// TaskAgentData holds agent info included in claim responses so the daemon
|
||||
// can set up the execution environment (branch naming, skill files).
|
||||
// can set up the execution environment (branch naming, skill files, instructions).
|
||||
type TaskAgentData struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Skills []service.AgentSkillData `json:"skills,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Instructions string `json:"instructions"`
|
||||
Skills []service.AgentSkillData `json:"skills,omitempty"`
|
||||
}
|
||||
|
||||
func taskToResponse(t db.AgentTaskQueue) AgentTaskResponse {
|
||||
|
|
@ -200,6 +203,7 @@ func (h *Handler) GetAgent(w http.ResponseWriter, r *http.Request) {
|
|||
type CreateAgentRequest struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Instructions string `json:"instructions"`
|
||||
AvatarURL *string `json:"avatar_url"`
|
||||
RuntimeID string `json:"runtime_id"`
|
||||
RuntimeConfig any `json:"runtime_config"`
|
||||
|
|
@ -269,6 +273,7 @@ func (h *Handler) CreateAgent(w http.ResponseWriter, r *http.Request) {
|
|||
WorkspaceID: parseUUID(workspaceID),
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
Instructions: req.Instructions,
|
||||
AvatarUrl: ptrToText(req.AvatarURL),
|
||||
RuntimeMode: runtime.RuntimeMode,
|
||||
RuntimeConfig: rc,
|
||||
|
|
@ -301,6 +306,7 @@ func (h *Handler) CreateAgent(w http.ResponseWriter, r *http.Request) {
|
|||
type UpdateAgentRequest struct {
|
||||
Name *string `json:"name"`
|
||||
Description *string `json:"description"`
|
||||
Instructions *string `json:"instructions"`
|
||||
AvatarURL *string `json:"avatar_url"`
|
||||
RuntimeID *string `json:"runtime_id"`
|
||||
RuntimeConfig any `json:"runtime_config"`
|
||||
|
|
@ -336,6 +342,9 @@ func (h *Handler) UpdateAgent(w http.ResponseWriter, r *http.Request) {
|
|||
if req.Description != nil {
|
||||
params.Description = pgtype.Text{String: *req.Description, Valid: true}
|
||||
}
|
||||
if req.Instructions != nil {
|
||||
params.Instructions = pgtype.Text{String: *req.Instructions, Valid: true}
|
||||
}
|
||||
if req.AvatarURL != nil {
|
||||
params.AvatarUrl = pgtype.Text{String: *req.AvatarURL, Valid: true}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,9 +210,10 @@ func (h *Handler) ClaimTaskByRuntime(w http.ResponseWriter, r *http.Request) {
|
|||
if agent, err := h.Queries.GetAgent(r.Context(), task.AgentID); err == nil {
|
||||
skills := h.TaskService.LoadAgentSkills(r.Context(), task.AgentID)
|
||||
resp.Agent = &TaskAgentData{
|
||||
ID: uuidToString(agent.ID),
|
||||
Name: agent.Name,
|
||||
Skills: skills,
|
||||
ID: uuidToString(agent.ID),
|
||||
Name: agent.Name,
|
||||
Instructions: agent.Instructions,
|
||||
Skills: skills,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
1
server/migrations/021_agent_instructions.down.sql
Normal file
1
server/migrations/021_agent_instructions.down.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE agent DROP COLUMN instructions;
|
||||
1
server/migrations/021_agent_instructions.up.sql
Normal file
1
server/migrations/021_agent_instructions.up.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE agent ADD COLUMN instructions TEXT NOT NULL DEFAULT '';
|
||||
|
|
@ -116,9 +116,9 @@ const createAgent = `-- name: CreateAgent :one
|
|||
INSERT INTO agent (
|
||||
workspace_id, name, description, avatar_url, runtime_mode,
|
||||
runtime_config, runtime_id, visibility, max_concurrent_tasks, owner_id,
|
||||
tools, triggers
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
||||
RETURNING id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, tools, triggers, runtime_id
|
||||
tools, triggers, instructions
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
|
||||
RETURNING id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, tools, triggers, runtime_id, instructions
|
||||
`
|
||||
|
||||
type CreateAgentParams struct {
|
||||
|
|
@ -134,6 +134,7 @@ type CreateAgentParams struct {
|
|||
OwnerID pgtype.UUID `json:"owner_id"`
|
||||
Tools []byte `json:"tools"`
|
||||
Triggers []byte `json:"triggers"`
|
||||
Instructions string `json:"instructions"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateAgent(ctx context.Context, arg CreateAgentParams) (Agent, error) {
|
||||
|
|
@ -150,6 +151,7 @@ func (q *Queries) CreateAgent(ctx context.Context, arg CreateAgentParams) (Agent
|
|||
arg.OwnerID,
|
||||
arg.Tools,
|
||||
arg.Triggers,
|
||||
arg.Instructions,
|
||||
)
|
||||
var i Agent
|
||||
err := row.Scan(
|
||||
|
|
@ -169,6 +171,7 @@ func (q *Queries) CreateAgent(ctx context.Context, arg CreateAgentParams) (Agent
|
|||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
|
@ -259,7 +262,7 @@ func (q *Queries) FailAgentTask(ctx context.Context, arg FailAgentTaskParams) (A
|
|||
}
|
||||
|
||||
const getAgent = `-- name: GetAgent :one
|
||||
SELECT id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, tools, triggers, runtime_id FROM agent
|
||||
SELECT id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, tools, triggers, runtime_id, instructions FROM agent
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
|
|
@ -283,6 +286,7 @@ func (q *Queries) GetAgent(ctx context.Context, id pgtype.UUID) (Agent, error) {
|
|||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
|
@ -341,6 +345,19 @@ func (q *Queries) GetLastTaskSession(ctx context.Context, arg GetLastTaskSession
|
|||
return i, err
|
||||
}
|
||||
|
||||
const hasActiveTaskForIssue = `-- name: HasActiveTaskForIssue :one
|
||||
SELECT count(*) > 0 AS has_active FROM agent_task_queue
|
||||
WHERE issue_id = $1 AND status IN ('queued', 'dispatched', 'running')
|
||||
`
|
||||
|
||||
// Returns true if there is any queued, dispatched, or running task for the issue.
|
||||
func (q *Queries) HasActiveTaskForIssue(ctx context.Context, issueID pgtype.UUID) (bool, error) {
|
||||
row := q.db.QueryRow(ctx, hasActiveTaskForIssue, issueID)
|
||||
var has_active bool
|
||||
err := row.Scan(&has_active)
|
||||
return has_active, err
|
||||
}
|
||||
|
||||
const listAgentTasks = `-- name: ListAgentTasks :many
|
||||
SELECT id, agent_id, issue_id, status, priority, dispatched_at, started_at, completed_at, result, error, created_at, context, runtime_id, session_id, work_dir FROM agent_task_queue
|
||||
WHERE agent_id = $1
|
||||
|
|
@ -384,7 +401,7 @@ func (q *Queries) ListAgentTasks(ctx context.Context, agentID pgtype.UUID) ([]Ag
|
|||
}
|
||||
|
||||
const listAgents = `-- name: ListAgents :many
|
||||
SELECT id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, tools, triggers, runtime_id FROM agent
|
||||
SELECT id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, tools, triggers, runtime_id, instructions FROM agent
|
||||
WHERE workspace_id = $1
|
||||
ORDER BY created_at ASC
|
||||
`
|
||||
|
|
@ -415,6 +432,7 @@ func (q *Queries) ListAgents(ctx context.Context, workspaceID pgtype.UUID) ([]Ag
|
|||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -511,9 +529,10 @@ UPDATE agent SET
|
|||
max_concurrent_tasks = COALESCE($10, max_concurrent_tasks),
|
||||
tools = COALESCE($11, tools),
|
||||
triggers = COALESCE($12, triggers),
|
||||
instructions = COALESCE($13, instructions),
|
||||
updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, tools, triggers, runtime_id
|
||||
RETURNING id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, tools, triggers, runtime_id, instructions
|
||||
`
|
||||
|
||||
type UpdateAgentParams struct {
|
||||
|
|
@ -529,6 +548,7 @@ type UpdateAgentParams struct {
|
|||
MaxConcurrentTasks pgtype.Int4 `json:"max_concurrent_tasks"`
|
||||
Tools []byte `json:"tools"`
|
||||
Triggers []byte `json:"triggers"`
|
||||
Instructions pgtype.Text `json:"instructions"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateAgent(ctx context.Context, arg UpdateAgentParams) (Agent, error) {
|
||||
|
|
@ -545,6 +565,7 @@ func (q *Queries) UpdateAgent(ctx context.Context, arg UpdateAgentParams) (Agent
|
|||
arg.MaxConcurrentTasks,
|
||||
arg.Tools,
|
||||
arg.Triggers,
|
||||
arg.Instructions,
|
||||
)
|
||||
var i Agent
|
||||
err := row.Scan(
|
||||
|
|
@ -564,6 +585,7 @@ func (q *Queries) UpdateAgent(ctx context.Context, arg UpdateAgentParams) (Agent
|
|||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
|
@ -571,7 +593,7 @@ func (q *Queries) UpdateAgent(ctx context.Context, arg UpdateAgentParams) (Agent
|
|||
const updateAgentStatus = `-- name: UpdateAgentStatus :one
|
||||
UPDATE agent SET status = $2, updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, tools, triggers, runtime_id
|
||||
RETURNING id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, tools, triggers, runtime_id, instructions
|
||||
`
|
||||
|
||||
type UpdateAgentStatusParams struct {
|
||||
|
|
@ -599,6 +621,7 @@ func (q *Queries) UpdateAgentStatus(ctx context.Context, arg UpdateAgentStatusPa
|
|||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ type Agent struct {
|
|||
Tools []byte `json:"tools"`
|
||||
Triggers []byte `json:"triggers"`
|
||||
RuntimeID pgtype.UUID `json:"runtime_id"`
|
||||
Instructions string `json:"instructions"`
|
||||
}
|
||||
|
||||
type AgentRuntime struct {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ WHERE id = $1;
|
|||
INSERT INTO agent (
|
||||
workspace_id, name, description, avatar_url, runtime_mode,
|
||||
runtime_config, runtime_id, visibility, max_concurrent_tasks, owner_id,
|
||||
tools, triggers
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
||||
tools, triggers, instructions
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateAgent :one
|
||||
|
|
@ -28,6 +28,7 @@ UPDATE agent SET
|
|||
max_concurrent_tasks = COALESCE(sqlc.narg('max_concurrent_tasks'), max_concurrent_tasks),
|
||||
tools = COALESCE(sqlc.narg('tools'), tools),
|
||||
triggers = COALESCE(sqlc.narg('triggers'), triggers),
|
||||
instructions = COALESCE(sqlc.narg('instructions'), instructions),
|
||||
updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING *;
|
||||
|
|
@ -96,6 +97,11 @@ RETURNING *;
|
|||
SELECT count(*) FROM agent_task_queue
|
||||
WHERE agent_id = $1 AND status IN ('dispatched', 'running');
|
||||
|
||||
-- name: HasActiveTaskForIssue :one
|
||||
-- Returns true if there is any queued, dispatched, or running task for the issue.
|
||||
SELECT count(*) > 0 AS has_active FROM agent_task_queue
|
||||
WHERE issue_id = $1 AND status IN ('queued', 'dispatched', 'running');
|
||||
|
||||
-- name: ListPendingTasksByRuntime :many
|
||||
SELECT * FROM agent_task_queue
|
||||
WHERE runtime_id = $1 AND status IN ('queued', 'dispatched')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue