Merge remote-tracking branch 'origin/main' into feat/tanstack-query-migration
# Conflicts: # apps/web/app/(dashboard)/agents/page.tsx
This commit is contained in:
commit
8cf78b7a47
17 changed files with 36 additions and 803 deletions
|
|
@ -8,15 +8,10 @@ import {
|
|||
Monitor,
|
||||
Plus,
|
||||
ListTodo,
|
||||
Wrench,
|
||||
FileText,
|
||||
BookOpenText,
|
||||
MessageSquare,
|
||||
Timer,
|
||||
Trash2,
|
||||
Save,
|
||||
Key,
|
||||
Link2,
|
||||
Clock,
|
||||
CheckCircle2,
|
||||
XCircle,
|
||||
|
|
@ -35,9 +30,6 @@ import type {
|
|||
Agent,
|
||||
AgentStatus,
|
||||
AgentVisibility,
|
||||
AgentTool,
|
||||
AgentTrigger,
|
||||
AgentTriggerType,
|
||||
AgentTask,
|
||||
RuntimeDevice,
|
||||
CreateAgentRequest,
|
||||
|
|
@ -151,10 +143,6 @@ function CreateAgentDialog({
|
|||
description: description.trim(),
|
||||
runtime_id: selectedRuntime.id,
|
||||
visibility,
|
||||
triggers: [
|
||||
{ id: generateId(), type: "on_assign", enabled: true, config: {} },
|
||||
{ id: generateId(), type: "on_comment", enabled: true, config: {} },
|
||||
],
|
||||
});
|
||||
onClose();
|
||||
} catch (err) {
|
||||
|
|
@ -600,466 +588,6 @@ function SkillsTab({
|
|||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tools Tab
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function AddToolDialog({
|
||||
onClose,
|
||||
onAdd,
|
||||
}: {
|
||||
onClose: () => void;
|
||||
onAdd: (tool: AgentTool) => void;
|
||||
}) {
|
||||
const [name, setName] = useState("");
|
||||
const [description, setDescription] = useState("");
|
||||
const [authType, setAuthType] = useState<"oauth" | "api_key" | "none">("api_key");
|
||||
|
||||
const handleAdd = () => {
|
||||
if (!name.trim()) return;
|
||||
onAdd({
|
||||
id: generateId(),
|
||||
name: name.trim(),
|
||||
description: description.trim(),
|
||||
auth_type: authType,
|
||||
connected: false,
|
||||
config: {},
|
||||
});
|
||||
onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open onOpenChange={(v) => { if (!v) onClose(); }}>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-sm">Add Tool</DialogTitle>
|
||||
<DialogDescription className="text-xs">
|
||||
Connect an external tool for this agent to use.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">Tool Name</Label>
|
||||
<Input
|
||||
autoFocus
|
||||
type="text"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder="e.g. Google Search, Slack, GitHub"
|
||||
className="mt-1"
|
||||
onKeyDown={(e) => e.key === "Enter" && handleAdd()}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">Description</Label>
|
||||
<Input
|
||||
type="text"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
placeholder="What does this tool do?"
|
||||
className="mt-1"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">Authentication</Label>
|
||||
<div className="mt-1.5 flex gap-2">
|
||||
{(["api_key", "oauth", "none"] as const).map((type) => (
|
||||
<Button
|
||||
key={type}
|
||||
variant={authType === type ? "outline" : "ghost"}
|
||||
size="xs"
|
||||
onClick={() => setAuthType(type)}
|
||||
className={`flex-1 ${
|
||||
authType === type
|
||||
? "border-primary bg-primary/5 font-medium"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{type === "api_key" ? "API Key" : type === "oauth" ? "OAuth" : "None"}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="ghost" onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleAdd}
|
||||
disabled={!name.trim()}
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
function ToolsTab({
|
||||
agent,
|
||||
onSave,
|
||||
}: {
|
||||
agent: Agent;
|
||||
onSave: (tools: AgentTool[]) => Promise<void>;
|
||||
}) {
|
||||
const [tools, setTools] = useState<AgentTool[]>(agent.tools ?? []);
|
||||
const [showAdd, setShowAdd] = useState(false);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setTools(agent.tools ?? []);
|
||||
}, [agent.id, agent.tools]);
|
||||
|
||||
const isDirty = JSON.stringify(tools) !== JSON.stringify(agent.tools ?? []);
|
||||
|
||||
const handleSave = async () => {
|
||||
setSaving(true);
|
||||
try {
|
||||
await onSave(tools);
|
||||
} catch {
|
||||
// toast handled by parent
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleConnect = (toolId: string) => {
|
||||
setTools((prev) =>
|
||||
prev.map((t) => (t.id === toolId ? { ...t, connected: !t.connected } : t)),
|
||||
);
|
||||
};
|
||||
|
||||
const removeTool = (toolId: string) => {
|
||||
setTools((prev) => prev.filter((t) => t.id !== toolId));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold">Tools</h3>
|
||||
<p className="text-xs text-muted-foreground mt-0.5">
|
||||
External tools and APIs this agent can use during task execution.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{isDirty && (
|
||||
<Button
|
||||
onClick={handleSave}
|
||||
disabled={saving}
|
||||
size="xs"
|
||||
>
|
||||
<Save className="h-3 w-3" />
|
||||
{saving ? "Saving..." : "Save"}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="xs"
|
||||
onClick={() => setShowAdd(true)}
|
||||
>
|
||||
<Plus className="h-3 w-3" />
|
||||
Add Tool
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{tools.length === 0 ? (
|
||||
<div className="flex flex-col items-center justify-center rounded-lg border border-dashed py-12">
|
||||
<Wrench className="h-8 w-8 text-muted-foreground/40" />
|
||||
<p className="mt-3 text-sm text-muted-foreground">No tools configured</p>
|
||||
<Button
|
||||
onClick={() => setShowAdd(true)}
|
||||
size="xs"
|
||||
className="mt-3"
|
||||
>
|
||||
<Plus className="h-3 w-3" />
|
||||
Add Tool
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{tools.map((tool) => (
|
||||
<div
|
||||
key={tool.id}
|
||||
className="flex items-center gap-3 rounded-lg border px-4 py-3"
|
||||
>
|
||||
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-muted">
|
||||
{tool.auth_type === "oauth" ? (
|
||||
<Link2 className="h-4 w-4 text-muted-foreground" />
|
||||
) : tool.auth_type === "api_key" ? (
|
||||
<Key className="h-4 w-4 text-muted-foreground" />
|
||||
) : (
|
||||
<Wrench className="h-4 w-4 text-muted-foreground" />
|
||||
)}
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-sm font-medium">{tool.name}</div>
|
||||
{tool.description && (
|
||||
<div className="text-xs text-muted-foreground truncate">
|
||||
{tool.description}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="xs"
|
||||
onClick={() => toggleConnect(tool.id)}
|
||||
className={
|
||||
tool.connected
|
||||
? "bg-success/10 text-success"
|
||||
: "bg-muted text-muted-foreground hover:bg-accent"
|
||||
}
|
||||
>
|
||||
{tool.connected ? "Connected" : "Connect"}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-xs"
|
||||
onClick={() => removeTool(tool.id)}
|
||||
className="text-muted-foreground hover:text-destructive"
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showAdd && (
|
||||
<AddToolDialog
|
||||
onClose={() => setShowAdd(false)}
|
||||
onAdd={(tool) => setTools((prev) => [...prev, tool])}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Triggers Tab
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function TriggersTab({
|
||||
agent,
|
||||
onSave,
|
||||
}: {
|
||||
agent: Agent;
|
||||
onSave: (triggers: AgentTrigger[]) => Promise<void>;
|
||||
}) {
|
||||
const [triggers, setTriggers] = useState<AgentTrigger[]>(agent.triggers ?? []);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setTriggers(agent.triggers ?? []);
|
||||
}, [agent.id, agent.triggers]);
|
||||
|
||||
const isDirty = JSON.stringify(triggers) !== JSON.stringify(agent.triggers ?? []);
|
||||
|
||||
const handleSave = async () => {
|
||||
setSaving(true);
|
||||
try {
|
||||
await onSave(triggers);
|
||||
} catch {
|
||||
// toast handled by parent
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleTrigger = (triggerId: string) => {
|
||||
setTriggers((prev) =>
|
||||
prev.map((t) => (t.id === triggerId ? { ...t, enabled: !t.enabled } : t)),
|
||||
);
|
||||
};
|
||||
|
||||
const removeTrigger = (triggerId: string) => {
|
||||
setTriggers((prev) => prev.filter((t) => t.id !== triggerId));
|
||||
};
|
||||
|
||||
const addTrigger = (type: AgentTriggerType) => {
|
||||
const newTrigger: AgentTrigger = {
|
||||
id: generateId(),
|
||||
type,
|
||||
enabled: true,
|
||||
config: type === "scheduled" ? { cron: "0 9 * * 1-5", timezone: "UTC" } : {},
|
||||
};
|
||||
setTriggers((prev) => [...prev, newTrigger]);
|
||||
};
|
||||
|
||||
const updateTriggerConfig = (triggerId: string, config: Record<string, unknown>) => {
|
||||
setTriggers((prev) =>
|
||||
prev.map((t) => (t.id === triggerId ? { ...t, config } : t)),
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold">Triggers</h3>
|
||||
<p className="text-xs text-muted-foreground mt-0.5">
|
||||
Configure when this agent should start working.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{isDirty && (
|
||||
<Button
|
||||
onClick={handleSave}
|
||||
disabled={saving}
|
||||
size="xs"
|
||||
>
|
||||
<Save className="h-3 w-3" />
|
||||
{saving ? "Saving..." : "Save"}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
{triggers.map((trigger) => {
|
||||
const scheduledConfig = (trigger.config ?? {}) as {
|
||||
cron?: string;
|
||||
timezone?: string;
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
key={trigger.id}
|
||||
className="rounded-lg border px-4 py-3"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-muted">
|
||||
{trigger.type === "on_assign" ? (
|
||||
<Bot className="h-4 w-4 text-muted-foreground" />
|
||||
) : trigger.type === "on_comment" ? (
|
||||
<MessageSquare className="h-4 w-4 text-muted-foreground" />
|
||||
) : (
|
||||
<Timer className="h-4 w-4 text-muted-foreground" />
|
||||
)}
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-sm font-medium">
|
||||
{trigger.type === "on_assign"
|
||||
? "On Issue Assign"
|
||||
: trigger.type === "on_comment"
|
||||
? "On Comment"
|
||||
: "Scheduled"}
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{trigger.type === "on_assign"
|
||||
? "Runs when an issue is assigned to this agent"
|
||||
: trigger.type === "on_comment"
|
||||
? "Runs when a member comments on the agent's issue"
|
||||
: `Cron: ${scheduledConfig.cron ?? "Not set"}`}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => toggleTrigger(trigger.id)}
|
||||
className={`relative h-5 w-9 rounded-full transition-colors ${
|
||||
trigger.enabled ? "bg-primary" : "bg-muted"
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`absolute top-0.5 h-4 w-4 rounded-full bg-white shadow-sm transition-transform ${
|
||||
trigger.enabled ? "left-4.5" : "left-0.5"
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-xs"
|
||||
onClick={() => removeTrigger(trigger.id)}
|
||||
className="text-muted-foreground hover:text-destructive"
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{trigger.type === "scheduled" && (
|
||||
<div className="mt-3 grid grid-cols-2 gap-3 pl-12">
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Cron Expression
|
||||
</Label>
|
||||
<Input
|
||||
type="text"
|
||||
value={scheduledConfig.cron ?? ""}
|
||||
onChange={(e) =>
|
||||
updateTriggerConfig(trigger.id, {
|
||||
...(trigger.config ?? {}),
|
||||
cron: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="0 9 * * 1-5"
|
||||
className="mt-1 text-xs font-mono"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Timezone
|
||||
</Label>
|
||||
<Input
|
||||
type="text"
|
||||
value={scheduledConfig.timezone ?? ""}
|
||||
onChange={(e) =>
|
||||
updateTriggerConfig(trigger.id, {
|
||||
...(trigger.config ?? {}),
|
||||
timezone: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="UTC"
|
||||
className="mt-1 text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="xs"
|
||||
onClick={() => addTrigger("on_assign")}
|
||||
className="border-dashed text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<Bot className="h-3 w-3" />
|
||||
Add On Assign
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="xs"
|
||||
onClick={() => addTrigger("on_comment")}
|
||||
className="border-dashed text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<MessageSquare className="h-3 w-3" />
|
||||
Add On Comment
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="xs"
|
||||
onClick={() => addTrigger("scheduled")}
|
||||
className="border-dashed text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<Timer className="h-3 w-3" />
|
||||
Add Scheduled
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tasks Tab
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -1371,13 +899,11 @@ function SettingsTab({
|
|||
// Agent Detail
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type DetailTab = "instructions" | "skills" | "tools" | "triggers" | "tasks" | "settings";
|
||||
type DetailTab = "instructions" | "skills" | "tasks" | "settings";
|
||||
|
||||
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 },
|
||||
{ id: "tasks", label: "Tasks", icon: ListTodo },
|
||||
{ id: "settings", label: "Settings", icon: Settings },
|
||||
];
|
||||
|
|
@ -1491,18 +1017,6 @@ function AgentDetail({
|
|||
{activeTab === "skills" && (
|
||||
<SkillsTab agent={agent} />
|
||||
)}
|
||||
{activeTab === "tools" && (
|
||||
<ToolsTab
|
||||
agent={agent}
|
||||
onSave={(tools) => onUpdate(agent.id, { tools })}
|
||||
/>
|
||||
)}
|
||||
{activeTab === "triggers" && (
|
||||
<TriggersTab
|
||||
agent={agent}
|
||||
onSave={(triggers) => onUpdate(agent.id, { triggers })}
|
||||
/>
|
||||
)}
|
||||
{activeTab === "tasks" && <TasksTab agent={agent} />}
|
||||
{activeTab === "settings" && (
|
||||
<SettingsTab
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ export const en: LandingDict = {
|
|||
{
|
||||
title: "Create your first agent",
|
||||
description:
|
||||
"Give it a name, write instructions, attach skills, and set triggers. Choose when it activates: on assignment, on comment, or on mention.",
|
||||
"Give it a name, write instructions, and attach skills. Agents automatically activate on assignment, on comment, or on mention.",
|
||||
},
|
||||
{
|
||||
title: "Assign an issue and watch it work",
|
||||
|
|
@ -385,7 +385,7 @@ export const en: LandingDict = {
|
|||
title: "Core Platform",
|
||||
changes: [
|
||||
"Multi-workspace switching and creation",
|
||||
"Agent management UI with skills, tools, and triggers",
|
||||
"Agent management UI with skills",
|
||||
"Unified agent SDK supporting Claude Code and Codex backends",
|
||||
"Comment CRUD with real-time WebSocket updates",
|
||||
"Task service layer and daemon REST protocol",
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ export type AgentRuntimeMode = "local" | "cloud";
|
|||
|
||||
export type AgentVisibility = "workspace" | "private";
|
||||
|
||||
export type AgentTriggerType = "on_assign" | "on_comment" | "scheduled";
|
||||
|
||||
export interface RuntimeDevice {
|
||||
id: string;
|
||||
workspace_id: string;
|
||||
|
|
@ -23,22 +21,6 @@ export interface RuntimeDevice {
|
|||
|
||||
export type AgentRuntime = RuntimeDevice;
|
||||
|
||||
export interface AgentTool {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
auth_type: "oauth" | "api_key" | "none";
|
||||
connected: boolean;
|
||||
config: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface AgentTrigger {
|
||||
id: string;
|
||||
type: AgentTriggerType;
|
||||
enabled: boolean;
|
||||
config: Record<string, unknown> | null;
|
||||
}
|
||||
|
||||
export interface AgentTask {
|
||||
id: string;
|
||||
agent_id: string;
|
||||
|
|
@ -69,8 +51,6 @@ export interface Agent {
|
|||
max_concurrent_tasks: number;
|
||||
owner_id: string | null;
|
||||
skills: Skill[];
|
||||
tools: AgentTool[];
|
||||
triggers: AgentTrigger[];
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
archived_at: string | null;
|
||||
|
|
@ -86,8 +66,6 @@ export interface CreateAgentRequest {
|
|||
runtime_config?: Record<string, unknown>;
|
||||
visibility?: AgentVisibility;
|
||||
max_concurrent_tasks?: number;
|
||||
tools?: AgentTool[];
|
||||
triggers?: AgentTrigger[];
|
||||
}
|
||||
|
||||
export interface UpdateAgentRequest {
|
||||
|
|
@ -100,8 +78,6 @@ export interface UpdateAgentRequest {
|
|||
visibility?: AgentVisibility;
|
||||
status?: AgentStatus;
|
||||
max_concurrent_tasks?: number;
|
||||
tools?: AgentTool[];
|
||||
triggers?: AgentTrigger[];
|
||||
}
|
||||
|
||||
// Skills
|
||||
|
|
|
|||
|
|
@ -4,9 +4,6 @@ export type {
|
|||
AgentStatus,
|
||||
AgentRuntimeMode,
|
||||
AgentVisibility,
|
||||
AgentTriggerType,
|
||||
AgentTool,
|
||||
AgentTrigger,
|
||||
AgentTask,
|
||||
AgentRuntime,
|
||||
RuntimeDevice,
|
||||
|
|
|
|||
|
|
@ -58,8 +58,6 @@ export const mockAgents: Agent[] = [
|
|||
max_concurrent_tasks: 3,
|
||||
owner_id: null,
|
||||
skills: [],
|
||||
tools: [],
|
||||
triggers: [],
|
||||
created_at: "2026-01-01T00:00:00Z",
|
||||
updated_at: "2026-01-01T00:00:00Z",
|
||||
archived_at: null,
|
||||
|
|
|
|||
|
|
@ -139,9 +139,9 @@ func setupIntegrationTestFixture(ctx context.Context, pool *pgxpool.Pool) (strin
|
|||
if _, err := pool.Exec(ctx, `
|
||||
INSERT INTO agent (
|
||||
workspace_id, name, description, runtime_mode, runtime_config,
|
||||
runtime_id, visibility, max_concurrent_tasks, owner_id, tools, triggers
|
||||
runtime_id, visibility, max_concurrent_tasks, owner_id
|
||||
)
|
||||
VALUES ($1, $2, '', 'cloud', '{}'::jsonb, $3, 'workspace', 1, $4, '[]'::jsonb, '[]'::jsonb)
|
||||
VALUES ($1, $2, '', 'cloud', '{}'::jsonb, $3, 'workspace', 1, $4)
|
||||
`, workspaceID, "Integration Test Agent", runtimeID, userID); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@ type AgentResponse struct {
|
|||
MaxConcurrentTasks int32 `json:"max_concurrent_tasks"`
|
||||
OwnerID *string `json:"owner_id"`
|
||||
Skills []SkillResponse `json:"skills"`
|
||||
Tools any `json:"tools"`
|
||||
Triggers any `json:"triggers"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
ArchivedAt *string `json:"archived_at"`
|
||||
|
|
@ -45,22 +43,6 @@ func agentToResponse(a db.Agent) AgentResponse {
|
|||
rc = map[string]any{}
|
||||
}
|
||||
|
||||
var tools any
|
||||
if a.Tools != nil {
|
||||
json.Unmarshal(a.Tools, &tools)
|
||||
}
|
||||
if tools == nil {
|
||||
tools = []any{}
|
||||
}
|
||||
|
||||
var triggers any
|
||||
if a.Triggers != nil {
|
||||
json.Unmarshal(a.Triggers, &triggers)
|
||||
}
|
||||
if triggers == nil {
|
||||
triggers = []any{}
|
||||
}
|
||||
|
||||
return AgentResponse{
|
||||
ID: uuidToString(a.ID),
|
||||
WorkspaceID: uuidToString(a.WorkspaceID),
|
||||
|
|
@ -76,8 +58,6 @@ func agentToResponse(a db.Agent) AgentResponse {
|
|||
MaxConcurrentTasks: a.MaxConcurrentTasks,
|
||||
OwnerID: uuidToPtr(a.OwnerID),
|
||||
Skills: []SkillResponse{},
|
||||
Tools: tools,
|
||||
Triggers: triggers,
|
||||
CreatedAt: timestampToString(a.CreatedAt),
|
||||
UpdatedAt: timestampToString(a.UpdatedAt),
|
||||
ArchivedAt: timestampToPtr(a.ArchivedAt),
|
||||
|
|
@ -221,8 +201,6 @@ type CreateAgentRequest struct {
|
|||
RuntimeConfig any `json:"runtime_config"`
|
||||
Visibility string `json:"visibility"`
|
||||
MaxConcurrentTasks int32 `json:"max_concurrent_tasks"`
|
||||
Tools any `json:"tools"`
|
||||
Triggers any `json:"triggers"`
|
||||
}
|
||||
|
||||
func (h *Handler) CreateAgent(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -268,16 +246,6 @@ func (h *Handler) CreateAgent(w http.ResponseWriter, r *http.Request) {
|
|||
rc = []byte("{}")
|
||||
}
|
||||
|
||||
tools, _ := json.Marshal(req.Tools)
|
||||
if req.Tools == nil {
|
||||
tools = []byte("[]")
|
||||
}
|
||||
|
||||
triggers, _ := json.Marshal(req.Triggers)
|
||||
if req.Triggers == nil {
|
||||
triggers = defaultAgentTriggers()
|
||||
}
|
||||
|
||||
agent, err := h.Queries.CreateAgent(r.Context(), db.CreateAgentParams{
|
||||
WorkspaceID: parseUUID(workspaceID),
|
||||
Name: req.Name,
|
||||
|
|
@ -290,8 +258,6 @@ func (h *Handler) CreateAgent(w http.ResponseWriter, r *http.Request) {
|
|||
Visibility: req.Visibility,
|
||||
MaxConcurrentTasks: req.MaxConcurrentTasks,
|
||||
OwnerID: parseUUID(ownerID),
|
||||
Tools: tools,
|
||||
Triggers: triggers,
|
||||
})
|
||||
if err != nil {
|
||||
slog.Warn("create agent failed", append(logger.RequestAttrs(r), "error", err, "workspace_id", workspaceID)...)
|
||||
|
|
@ -323,8 +289,6 @@ type UpdateAgentRequest struct {
|
|||
Visibility *string `json:"visibility"`
|
||||
Status *string `json:"status"`
|
||||
MaxConcurrentTasks *int32 `json:"max_concurrent_tasks"`
|
||||
Tools any `json:"tools"`
|
||||
Triggers any `json:"triggers"`
|
||||
}
|
||||
|
||||
// canManageAgent checks whether the current user can update or archive an agent.
|
||||
|
|
@ -401,14 +365,6 @@ func (h *Handler) UpdateAgent(w http.ResponseWriter, r *http.Request) {
|
|||
if req.MaxConcurrentTasks != nil {
|
||||
params.MaxConcurrentTasks = pgtype.Int4{Int32: *req.MaxConcurrentTasks, Valid: true}
|
||||
}
|
||||
if req.Tools != nil {
|
||||
tools, _ := json.Marshal(req.Tools)
|
||||
params.Tools = tools
|
||||
}
|
||||
if req.Triggers != nil {
|
||||
triggers, _ := json.Marshal(req.Triggers)
|
||||
params.Triggers = triggers
|
||||
}
|
||||
|
||||
agent, err := h.Queries.UpdateAgent(r.Context(), params)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -418,10 +418,6 @@ func (h *Handler) enqueueMentionedAgentTasks(ctx context.Context, issue db.Issue
|
|||
}
|
||||
}
|
||||
}
|
||||
// Check if the agent has on_mention trigger enabled.
|
||||
if !agentHasTriggerEnabled(agent.Triggers, "on_mention") {
|
||||
continue
|
||||
}
|
||||
// Dedup: skip if this agent already has a pending task for this issue.
|
||||
hasPending, err := h.Queries.HasPendingTaskForIssueAndAgent(ctx, db.HasPendingTaskForIssueAndAgentParams{
|
||||
IssueID: issue.ID,
|
||||
|
|
|
|||
|
|
@ -118,9 +118,9 @@ func setupHandlerTestFixture(ctx context.Context, pool *pgxpool.Pool) (string, s
|
|||
if _, err := pool.Exec(ctx, `
|
||||
INSERT INTO agent (
|
||||
workspace_id, name, description, runtime_mode, runtime_config,
|
||||
runtime_id, visibility, max_concurrent_tasks, owner_id, tools, triggers
|
||||
runtime_id, visibility, max_concurrent_tasks, owner_id
|
||||
)
|
||||
VALUES ($1, $2, '', 'cloud', '{}'::jsonb, $3, 'workspace', 1, $4, '[]'::jsonb, '[]'::jsonb)
|
||||
VALUES ($1, $2, '', 'cloud', '{}'::jsonb, $3, 'workspace', 1, $4)
|
||||
`, workspaceID, "Handler Test Agent", runtimeID, userID); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,23 +39,6 @@ type IssueResponse struct {
|
|||
Attachments []AttachmentResponse `json:"attachments,omitempty"`
|
||||
}
|
||||
|
||||
type agentTriggerSnapshot struct {
|
||||
Type string `json:"type"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Config map[string]any `json:"config"`
|
||||
}
|
||||
|
||||
// defaultAgentTriggers returns the default trigger config for new agents:
|
||||
// all three triggers explicitly enabled.
|
||||
func defaultAgentTriggers() []byte {
|
||||
b, _ := json.Marshal([]agentTriggerSnapshot{
|
||||
{Type: "on_assign", Enabled: true},
|
||||
{Type: "on_comment", Enabled: true},
|
||||
{Type: "on_mention", Enabled: true},
|
||||
})
|
||||
return b
|
||||
}
|
||||
|
||||
func issueToResponse(i db.Issue, issuePrefix string) IssueResponse {
|
||||
identifier := issuePrefix + "-" + strconv.Itoa(int(i.Number))
|
||||
return IssueResponse{
|
||||
|
|
@ -549,8 +532,9 @@ func (h *Handler) canAssignAgent(ctx context.Context, r *http.Request, agentID,
|
|||
// the assigned agent. No status gate — assignment is an explicit human action,
|
||||
// so it should trigger regardless of issue status (e.g. assigning an agent to
|
||||
// a done issue to fix a discovered problem).
|
||||
// All trigger types (on_assign, on_comment, on_mention) are always enabled.
|
||||
func (h *Handler) shouldEnqueueAgentTask(ctx context.Context, issue db.Issue) bool {
|
||||
return h.isAgentTriggerEnabled(ctx, issue, "on_assign")
|
||||
return h.isAgentAssigneeReady(ctx, issue)
|
||||
}
|
||||
|
||||
// shouldEnqueueOnComment returns true if a member comment on this issue should
|
||||
|
|
@ -561,7 +545,7 @@ func (h *Handler) shouldEnqueueOnComment(ctx context.Context, issue db.Issue) bo
|
|||
if issue.Status == "done" || issue.Status == "cancelled" {
|
||||
return false
|
||||
}
|
||||
if !h.isAgentTriggerEnabled(ctx, issue, "on_comment") {
|
||||
if !h.isAgentAssigneeReady(ctx, issue) {
|
||||
return false
|
||||
}
|
||||
// Coalescing queue: allow enqueue when a task is running (so the agent
|
||||
|
|
@ -574,10 +558,9 @@ func (h *Handler) shouldEnqueueOnComment(ctx context.Context, issue db.Issue) bo
|
|||
return true
|
||||
}
|
||||
|
||||
// isAgentTriggerEnabled checks if an issue is assigned to an agent with a
|
||||
// specific trigger type enabled. Returns true if the agent has no triggers
|
||||
// configured (default-enabled behavior for backwards compatibility).
|
||||
func (h *Handler) isAgentTriggerEnabled(ctx context.Context, issue db.Issue, triggerType string) bool {
|
||||
// isAgentAssigneeReady checks if an issue is assigned to an active agent
|
||||
// with a valid runtime.
|
||||
func (h *Handler) isAgentAssigneeReady(ctx context.Context, issue db.Issue) bool {
|
||||
if !issue.AssigneeType.Valid || issue.AssigneeType.String != "agent" || !issue.AssigneeID.Valid {
|
||||
return false
|
||||
}
|
||||
|
|
@ -587,45 +570,9 @@ func (h *Handler) isAgentTriggerEnabled(ctx context.Context, issue db.Issue, tri
|
|||
return false
|
||||
}
|
||||
|
||||
return agentHasTriggerEnabled(agent.Triggers, triggerType)
|
||||
}
|
||||
|
||||
// isAgentMentionTriggerEnabled checks if a specific agent has the on_mention
|
||||
// trigger enabled. Unlike isAgentTriggerEnabled, this takes an explicit agent
|
||||
// ID rather than deriving it from the issue assignee.
|
||||
func (h *Handler) isAgentMentionTriggerEnabled(ctx context.Context, agentID pgtype.UUID) bool {
|
||||
agent, err := h.Queries.GetAgent(ctx, agentID)
|
||||
if err != nil || !agent.RuntimeID.Valid {
|
||||
return false
|
||||
}
|
||||
|
||||
return agentHasTriggerEnabled(agent.Triggers, "on_mention")
|
||||
}
|
||||
|
||||
// agentHasTriggerEnabled checks if a trigger type is enabled in the agent's
|
||||
// trigger config. Returns true (default-enabled) when the triggers list is
|
||||
// empty or does not contain the requested type — for backwards compatibility
|
||||
// with agents created before explicit trigger config was introduced.
|
||||
func agentHasTriggerEnabled(raw []byte, triggerType string) bool {
|
||||
if raw == nil || len(raw) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
var triggers []agentTriggerSnapshot
|
||||
if err := json.Unmarshal(raw, &triggers); err != nil {
|
||||
return false
|
||||
}
|
||||
if len(triggers) == 0 {
|
||||
return true // Empty array = default-enabled (backwards compat)
|
||||
}
|
||||
for _, trigger := range triggers {
|
||||
if trigger.Type == triggerType {
|
||||
return trigger.Enabled
|
||||
}
|
||||
}
|
||||
return true // Trigger type not configured = enabled by default
|
||||
}
|
||||
|
||||
func (h *Handler) DeleteIssue(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
issue, ok := h.loadIssueForUser(w, r, id)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
|
|
@ -268,119 +267,3 @@ func TestOnCommentTriggerDecision(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// agentHasTriggerEnabled
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
func TestAgentHasTriggerEnabled(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
raw []byte
|
||||
triggerType string
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "nil triggers → enabled (backwards compat)",
|
||||
raw: nil,
|
||||
triggerType: "on_comment",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "empty byte slice → enabled",
|
||||
raw: []byte{},
|
||||
triggerType: "on_comment",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "empty JSON array → enabled (backwards compat)",
|
||||
raw: []byte("[]"),
|
||||
triggerType: "on_comment",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "on_comment explicitly enabled",
|
||||
raw: mustJSON([]agentTriggerSnapshot{{Type: "on_comment", Enabled: true}}),
|
||||
triggerType: "on_comment",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "on_comment explicitly disabled",
|
||||
raw: mustJSON([]agentTriggerSnapshot{{Type: "on_comment", Enabled: false}}),
|
||||
triggerType: "on_comment",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "on_mention not configured but others are → enabled by default",
|
||||
raw: mustJSON([]agentTriggerSnapshot{{Type: "on_comment", Enabled: true}}),
|
||||
triggerType: "on_mention",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "invalid JSON → disabled (fail safe)",
|
||||
raw: []byte("{bad json"),
|
||||
triggerType: "on_comment",
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := agentHasTriggerEnabled(tt.raw, tt.triggerType)
|
||||
if got != tt.want {
|
||||
t.Errorf("agentHasTriggerEnabled() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// defaultAgentTriggers
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
func TestDefaultAgentTriggers(t *testing.T) {
|
||||
raw := defaultAgentTriggers()
|
||||
|
||||
var triggers []agentTriggerSnapshot
|
||||
if err := json.Unmarshal(raw, &triggers); err != nil {
|
||||
t.Fatalf("failed to unmarshal default triggers: %v", err)
|
||||
}
|
||||
|
||||
if len(triggers) != 3 {
|
||||
t.Fatalf("expected 3 default triggers, got %d", len(triggers))
|
||||
}
|
||||
|
||||
expected := map[string]bool{
|
||||
"on_assign": true,
|
||||
"on_comment": true,
|
||||
"on_mention": true,
|
||||
}
|
||||
for _, tr := range triggers {
|
||||
want, ok := expected[tr.Type]
|
||||
if !ok {
|
||||
t.Errorf("unexpected trigger type: %s", tr.Type)
|
||||
continue
|
||||
}
|
||||
if tr.Enabled != want {
|
||||
t.Errorf("trigger %s: enabled = %v, want %v", tr.Type, tr.Enabled, want)
|
||||
}
|
||||
delete(expected, tr.Type)
|
||||
}
|
||||
for typ := range expected {
|
||||
t.Errorf("missing trigger type: %s", typ)
|
||||
}
|
||||
|
||||
// Verify all triggers are enabled via agentHasTriggerEnabled
|
||||
for _, typ := range []string{"on_assign", "on_comment", "on_mention"} {
|
||||
if !agentHasTriggerEnabled(raw, typ) {
|
||||
t.Errorf("agentHasTriggerEnabled(default, %q) = false, want true", typ)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mustJSON(v any) []byte {
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
|
|
|||
|
|
@ -531,14 +531,6 @@ func agentToMap(a db.Agent) map[string]any {
|
|||
if a.RuntimeConfig != nil {
|
||||
json.Unmarshal(a.RuntimeConfig, &rc)
|
||||
}
|
||||
var tools any
|
||||
if a.Tools != nil {
|
||||
json.Unmarshal(a.Tools, &tools)
|
||||
}
|
||||
var triggers any
|
||||
if a.Triggers != nil {
|
||||
json.Unmarshal(a.Triggers, &triggers)
|
||||
}
|
||||
return map[string]any{
|
||||
"id": util.UUIDToString(a.ID),
|
||||
"workspace_id": util.UUIDToString(a.WorkspaceID),
|
||||
|
|
@ -553,8 +545,6 @@ func agentToMap(a db.Agent) map[string]any {
|
|||
"max_concurrent_tasks": a.MaxConcurrentTasks,
|
||||
"owner_id": util.UUIDToPtr(a.OwnerID),
|
||||
"skills": []any{},
|
||||
"tools": tools,
|
||||
"triggers": triggers,
|
||||
"created_at": util.TimestampToString(a.CreatedAt),
|
||||
"updated_at": util.TimestampToString(a.UpdatedAt),
|
||||
"archived_at": util.TimestampToPtr(a.ArchivedAt),
|
||||
|
|
|
|||
3
server/migrations/032_drop_agent_triggers.down.sql
Normal file
3
server/migrations/032_drop_agent_triggers.down.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
-- Re-add the triggers and tools columns to agent table.
|
||||
ALTER TABLE agent ADD COLUMN triggers JSONB NOT NULL DEFAULT '[]';
|
||||
ALTER TABLE agent ADD COLUMN tools JSONB NOT NULL DEFAULT '[]';
|
||||
5
server/migrations/032_drop_agent_triggers.up.sql
Normal file
5
server/migrations/032_drop_agent_triggers.up.sql
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
-- Remove the triggers and tools columns from agent table.
|
||||
-- Trigger behavior (on_assign, on_comment, on_mention) is now always enabled (hardcoded).
|
||||
-- Tools was a placeholder field never used at runtime.
|
||||
ALTER TABLE agent DROP COLUMN IF EXISTS triggers;
|
||||
ALTER TABLE agent DROP COLUMN IF EXISTS tools;
|
||||
|
|
@ -14,7 +14,7 @@ import (
|
|||
const archiveAgent = `-- name: ArchiveAgent :one
|
||||
UPDATE agent SET archived_at = now(), archived_by = $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, instructions, archived_at, archived_by
|
||||
RETURNING id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, runtime_id, instructions, archived_at, archived_by
|
||||
`
|
||||
|
||||
type ArchiveAgentParams struct {
|
||||
|
|
@ -39,8 +39,6 @@ func (q *Queries) ArchiveAgent(ctx context.Context, arg ArchiveAgentParams) (Age
|
|||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Description,
|
||||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
&i.ArchivedAt,
|
||||
|
|
@ -207,9 +205,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, 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, archived_at, archived_by
|
||||
instructions
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
RETURNING id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, runtime_id, instructions, archived_at, archived_by
|
||||
`
|
||||
|
||||
type CreateAgentParams struct {
|
||||
|
|
@ -223,8 +221,6 @@ type CreateAgentParams struct {
|
|||
Visibility string `json:"visibility"`
|
||||
MaxConcurrentTasks int32 `json:"max_concurrent_tasks"`
|
||||
OwnerID pgtype.UUID `json:"owner_id"`
|
||||
Tools []byte `json:"tools"`
|
||||
Triggers []byte `json:"triggers"`
|
||||
Instructions string `json:"instructions"`
|
||||
}
|
||||
|
||||
|
|
@ -240,8 +236,6 @@ func (q *Queries) CreateAgent(ctx context.Context, arg CreateAgentParams) (Agent
|
|||
arg.Visibility,
|
||||
arg.MaxConcurrentTasks,
|
||||
arg.OwnerID,
|
||||
arg.Tools,
|
||||
arg.Triggers,
|
||||
arg.Instructions,
|
||||
)
|
||||
var i Agent
|
||||
|
|
@ -259,8 +253,6 @@ func (q *Queries) CreateAgent(ctx context.Context, arg CreateAgentParams) (Agent
|
|||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Description,
|
||||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
&i.ArchivedAt,
|
||||
|
|
@ -392,7 +384,7 @@ func (q *Queries) FailStaleTasks(ctx context.Context, arg FailStaleTasksParams)
|
|||
}
|
||||
|
||||
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, instructions, archived_at, archived_by 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, runtime_id, instructions, archived_at, archived_by FROM agent
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
|
|
@ -413,8 +405,6 @@ func (q *Queries) GetAgent(ctx context.Context, id pgtype.UUID) (Agent, error) {
|
|||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Description,
|
||||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
&i.ArchivedAt,
|
||||
|
|
@ -424,7 +414,7 @@ func (q *Queries) GetAgent(ctx context.Context, id pgtype.UUID) (Agent, error) {
|
|||
}
|
||||
|
||||
const getAgentInWorkspace = `-- name: GetAgentInWorkspace :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, instructions, archived_at, archived_by 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, runtime_id, instructions, archived_at, archived_by FROM agent
|
||||
WHERE id = $1 AND workspace_id = $2
|
||||
`
|
||||
|
||||
|
|
@ -450,8 +440,6 @@ func (q *Queries) GetAgentInWorkspace(ctx context.Context, arg GetAgentInWorkspa
|
|||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Description,
|
||||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
&i.ArchivedAt,
|
||||
|
|
@ -650,7 +638,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, instructions, archived_at, archived_by 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, runtime_id, instructions, archived_at, archived_by FROM agent
|
||||
WHERE workspace_id = $1 AND archived_at IS NULL
|
||||
ORDER BY created_at ASC
|
||||
`
|
||||
|
|
@ -678,8 +666,6 @@ func (q *Queries) ListAgents(ctx context.Context, workspaceID pgtype.UUID) ([]Ag
|
|||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Description,
|
||||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
&i.ArchivedAt,
|
||||
|
|
@ -696,7 +682,7 @@ func (q *Queries) ListAgents(ctx context.Context, workspaceID pgtype.UUID) ([]Ag
|
|||
}
|
||||
|
||||
const listAllAgents = `-- name: ListAllAgents :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, instructions, archived_at, archived_by 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, runtime_id, instructions, archived_at, archived_by FROM agent
|
||||
WHERE workspace_id = $1
|
||||
ORDER BY created_at ASC
|
||||
`
|
||||
|
|
@ -724,8 +710,6 @@ func (q *Queries) ListAllAgents(ctx context.Context, workspaceID pgtype.UUID) ([
|
|||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Description,
|
||||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
&i.ArchivedAt,
|
||||
|
|
@ -830,7 +814,7 @@ func (q *Queries) ListTasksByIssue(ctx context.Context, issueID pgtype.UUID) ([]
|
|||
const restoreAgent = `-- name: RestoreAgent :one
|
||||
UPDATE agent SET archived_at = NULL, archived_by = NULL, 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, instructions, archived_at, archived_by
|
||||
RETURNING id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, runtime_id, instructions, archived_at, archived_by
|
||||
`
|
||||
|
||||
func (q *Queries) RestoreAgent(ctx context.Context, id pgtype.UUID) (Agent, error) {
|
||||
|
|
@ -850,8 +834,6 @@ func (q *Queries) RestoreAgent(ctx context.Context, id pgtype.UUID) (Agent, erro
|
|||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Description,
|
||||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
&i.ArchivedAt,
|
||||
|
|
@ -902,12 +884,10 @@ UPDATE agent SET
|
|||
visibility = COALESCE($8, visibility),
|
||||
status = COALESCE($9, status),
|
||||
max_concurrent_tasks = COALESCE($10, max_concurrent_tasks),
|
||||
tools = COALESCE($11, tools),
|
||||
triggers = COALESCE($12, triggers),
|
||||
instructions = COALESCE($13, instructions),
|
||||
instructions = COALESCE($11, 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, instructions, archived_at, archived_by
|
||||
RETURNING id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, runtime_id, instructions, archived_at, archived_by
|
||||
`
|
||||
|
||||
type UpdateAgentParams struct {
|
||||
|
|
@ -921,8 +901,6 @@ type UpdateAgentParams struct {
|
|||
Visibility pgtype.Text `json:"visibility"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
MaxConcurrentTasks pgtype.Int4 `json:"max_concurrent_tasks"`
|
||||
Tools []byte `json:"tools"`
|
||||
Triggers []byte `json:"triggers"`
|
||||
Instructions pgtype.Text `json:"instructions"`
|
||||
}
|
||||
|
||||
|
|
@ -938,8 +916,6 @@ func (q *Queries) UpdateAgent(ctx context.Context, arg UpdateAgentParams) (Agent
|
|||
arg.Visibility,
|
||||
arg.Status,
|
||||
arg.MaxConcurrentTasks,
|
||||
arg.Tools,
|
||||
arg.Triggers,
|
||||
arg.Instructions,
|
||||
)
|
||||
var i Agent
|
||||
|
|
@ -957,8 +933,6 @@ func (q *Queries) UpdateAgent(ctx context.Context, arg UpdateAgentParams) (Agent
|
|||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Description,
|
||||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
&i.ArchivedAt,
|
||||
|
|
@ -970,7 +944,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, instructions, archived_at, archived_by
|
||||
RETURNING id, workspace_id, name, avatar_url, runtime_mode, runtime_config, visibility, status, max_concurrent_tasks, owner_id, created_at, updated_at, description, runtime_id, instructions, archived_at, archived_by
|
||||
`
|
||||
|
||||
type UpdateAgentStatusParams struct {
|
||||
|
|
@ -995,8 +969,6 @@ func (q *Queries) UpdateAgentStatus(ctx context.Context, arg UpdateAgentStatusPa
|
|||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Description,
|
||||
&i.Tools,
|
||||
&i.Triggers,
|
||||
&i.RuntimeID,
|
||||
&i.Instructions,
|
||||
&i.ArchivedAt,
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@ type Agent struct {
|
|||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
Description string `json:"description"`
|
||||
Tools []byte `json:"tools"`
|
||||
Triggers []byte `json:"triggers"`
|
||||
RuntimeID pgtype.UUID `json:"runtime_id"`
|
||||
Instructions string `json:"instructions"`
|
||||
ArchivedAt pgtype.Timestamptz `json:"archived_at"`
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ WHERE id = $1 AND workspace_id = $2;
|
|||
INSERT INTO agent (
|
||||
workspace_id, name, description, avatar_url, runtime_mode,
|
||||
runtime_config, runtime_id, visibility, max_concurrent_tasks, owner_id,
|
||||
tools, triggers, instructions
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
|
||||
instructions
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateAgent :one
|
||||
|
|
@ -35,8 +35,6 @@ UPDATE agent SET
|
|||
visibility = COALESCE(sqlc.narg('visibility'), visibility),
|
||||
status = COALESCE(sqlc.narg('status'), status),
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue