739eabc49a
Co-authored-by: ayattara <alassane.yattara@savoirfairelinux.com> Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
208 lines
11 KiB
Go
208 lines
11 KiB
Go
package models
|
|
|
|
import (
|
|
"time"
|
|
|
|
agentusage "github.com/kandev/kandev/internal/agent/usage"
|
|
taskmodels "github.com/kandev/kandev/internal/task/models"
|
|
)
|
|
|
|
// ProfileEnvVar is an environment variable entry on an agent profile.
|
|
type ProfileEnvVar = taskmodels.ProfileEnvVar
|
|
|
|
type Agent struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
WorkspaceID *string `json:"workspace_id,omitempty"`
|
|
SupportsMCP bool `json:"supports_mcp"`
|
|
MCPConfigPath string `json:"mcp_config_path,omitempty"`
|
|
TUIConfig *TUIConfigJSON `json:"tui_config,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
// TUIConfigJSON is the JSON schema stored in the tui_config column for custom TUI agents.
|
|
type TUIConfigJSON struct {
|
|
Command string `json:"command"`
|
|
DisplayName string `json:"display_name"`
|
|
Model string `json:"model,omitempty"`
|
|
Description string `json:"description,omitempty"`
|
|
CommandArgs []string `json:"command_args,omitempty"`
|
|
WaitForTerminal bool `json:"wait_for_terminal"`
|
|
// MCPStrategy selects how kandev injects its per-session MCP server into
|
|
// the wrapped CLI (mcpconfig.StrategyKey*). Empty — the value every row
|
|
// written before this field existed decodes to — means no injection.
|
|
// Stored here rather than as an agent column because it is part of the
|
|
// user's CLI definition, and because tui_config is JSON: adding the field
|
|
// needs no migration.
|
|
MCPStrategy string `json:"mcp_strategy,omitempty"`
|
|
}
|
|
|
|
type AgentProfile struct {
|
|
ID string `json:"id" db:"id"`
|
|
AgentID string `json:"agent_id" db:"agent_id"`
|
|
Name string `json:"name" db:"name"`
|
|
AgentDisplayName string `json:"agent_display_name" db:"agent_display_name"`
|
|
|
|
// BillingType is computed at read time from credential files — not stored in the DB.
|
|
// Values: "api_key" | "subscription".
|
|
BillingType string `json:"billing_type,omitempty" db:"-"`
|
|
|
|
// Model is the ACP model ID applied through session model selection at session start.
|
|
// Validated against the host utility capability cache by the reconciler.
|
|
Model string `json:"model" db:"model"`
|
|
|
|
// FallbackModel is the optional ACP model ID the runtime switches to when
|
|
// the start model (Model) becomes unavailable. Empty means "no explicit
|
|
// fallback". Ignored at runtime when AutoFallback is enabled.
|
|
FallbackModel string `json:"fallback_model,omitempty" db:"fallback_model"`
|
|
|
|
// AutoFallback opts the profile into the legacy automatic-fallback
|
|
// behavior: session-start model application is best-effort and office
|
|
// post-start failures re-dispatch to the next provider candidate. When
|
|
// enabled, FallbackModel is ignored and the UI hides its field.
|
|
AutoFallback bool `json:"auto_fallback" db:"auto_fallback"`
|
|
|
|
// RequireExactModel makes the configured model an explicit per-profile
|
|
// identity requirement. False preserves compatible pre-PR behavior.
|
|
RequireExactModel bool `json:"require_exact_model" db:"require_exact_model"`
|
|
|
|
// Mode is the optional ACP session mode applied via session/set_mode at
|
|
// session start. Empty when the agent does not advertise modes.
|
|
// The DB column is nullable; the settings repo handles the empty-string ↔ NULL
|
|
// conversion via sql.NullString in scan/insert paths, so callers see a
|
|
// regular string here.
|
|
Mode string `json:"mode,omitempty" db:"-"`
|
|
|
|
// ConfigOptions are dynamic ACP session config options applied through
|
|
// session/set_config_option at session start. Model and mode stay in their
|
|
// dedicated fields.
|
|
ConfigOptions map[string]string `json:"config_options,omitempty" db:"-"`
|
|
|
|
// MigratedFrom records the agent_id this profile was migrated from, if any.
|
|
// Same db:"-" treatment as Mode (nullable column, settings repo handles).
|
|
MigratedFrom string `json:"migrated_from,omitempty" db:"-"`
|
|
|
|
// CLIPassthrough enables TUI-passthrough execution style. Orthogonal to ACP.
|
|
CLIPassthrough bool `json:"cli_passthrough" db:"cli_passthrough"`
|
|
|
|
// Enabled gates the profile from new-work selection: when false, the
|
|
// profile is hidden from task/session creation pickers but keeps serving
|
|
// existing sessions and remains editable in settings. Independent of
|
|
// DeletedAt (soft delete) and the office Status column.
|
|
Enabled bool `json:"enabled" db:"enabled"`
|
|
|
|
// CommandPrefix is an optional launcher prefix prepended to the agent
|
|
// subprocess command. It lets a user wrap the ACP agent in a sandbox
|
|
// launcher (e.g. "greywall --" produces "greywall -- npx -y <pkg> …").
|
|
// The raw string is shell-tokenised at launch time, mirroring CLIFlags.
|
|
// Empty means the agent command runs unwrapped.
|
|
CommandPrefix string `json:"command_prefix" db:"command_prefix"`
|
|
|
|
// AllowIndexing is retained for backward compatibility with existing
|
|
// auggie profiles. The launch path no longer consults it — it is read
|
|
// only by the legacy migration shim that seeds CLIFlags on the first
|
|
// post-migration read. New code should use CLIFlags instead.
|
|
AllowIndexing bool `json:"allow_indexing" db:"allow_indexing"`
|
|
|
|
// CLIFlags is the user-configurable list of CLI flags passed to the agent
|
|
// subprocess. At profile creation the list is seeded from the agent's
|
|
// PermissionSettings(); users can toggle entries on/off, remove them, or
|
|
// add custom entries via the settings UI. Only entries with Enabled=true
|
|
// reach the subprocess argv. Stored as a JSON-encoded TEXT column;
|
|
// settings repo handles the conversion via manual scan.
|
|
CLIFlags []CLIFlag `json:"cli_flags" db:"-"`
|
|
|
|
// EnvVars are injected into the agent subprocess when this profile runs.
|
|
// Stored as a JSON-encoded TEXT column; settings repo handles conversion.
|
|
EnvVars []ProfileEnvVar `json:"env_vars,omitempty" db:"-"`
|
|
|
|
// AutoApprove enables Kandev agentctl-side ACP permission auto-approval at
|
|
// launch (AGENTCTL_AUTO_APPROVE_PERMISSIONS). DangerouslySkipPermissions is
|
|
// a deprecated legacy column retained so existing rows load cleanly.
|
|
AutoApprove bool `json:"auto_approve" db:"auto_approve"`
|
|
DangerouslySkipPermissions bool `json:"-" db:"dangerously_skip_permissions"`
|
|
|
|
UserModified bool `json:"user_modified" db:"user_modified"`
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
|
DeletedAt *time.Time `json:"deleted_at,omitempty" db:"deleted_at"`
|
|
|
|
// Office enrichment fields (ADR 0005 Wave A; collapsed with
|
|
// office.AgentInstance in Wave G). Empty / zero values mean the profile
|
|
// is a "shallow" kanban-flavour profile; populated values mark a "rich"
|
|
// office-flavour profile. Both flavours live in the same agent_profiles
|
|
// row, and office code references this struct via the
|
|
// office/models.AgentInstance type alias.
|
|
//
|
|
// WorkspaceID scopes the profile to a workspace. Empty = global / kanban-legacy.
|
|
WorkspaceID string `json:"workspace_id,omitempty" db:"workspace_id"`
|
|
// Role is the organisational role of an office agent. Empty for shallow
|
|
// kanban profiles. The DB column is TEXT NOT NULL DEFAULT ''.
|
|
Role AgentRole `json:"role,omitempty" db:"role"`
|
|
// Icon is an emoji or short string surfaced in the office UI.
|
|
Icon string `json:"icon,omitempty" db:"icon"`
|
|
// ReportsTo references another agent_profile.id (org chart).
|
|
ReportsTo string `json:"reports_to,omitempty" db:"reports_to"`
|
|
// SkillIDs is the JSON-array string of skill IDs (office.skills) the
|
|
// agent owns. Stored verbatim as a TEXT column to match the office
|
|
// repo's existing string-based handling.
|
|
SkillIDs string `json:"skill_ids,omitempty" db:"skill_ids"`
|
|
// DesiredSkills is the legacy office field listing skill slugs the
|
|
// agent wants when launched. JSON-array string (kept distinct from
|
|
// SkillIDs per the ADR — separate columns, separate semantics).
|
|
DesiredSkills string `json:"desired_skills,omitempty" db:"desired_skills"`
|
|
// CustomPrompt is deprecated: per-agent prompt addendums were removed in
|
|
// favour of multi-file instructions. The DB column remains for backward
|
|
// compatibility with existing rows but is never read or written by the
|
|
// UI/runtime. Slated for removal in a follow-up migration.
|
|
CustomPrompt string `json:"custom_prompt,omitempty" db:"custom_prompt"`
|
|
// Status is the runtime status of an office agent.
|
|
Status AgentStatus `json:"status,omitempty" db:"status"`
|
|
// PauseReason is a free-text explanation when Status == paused.
|
|
PauseReason string `json:"pause_reason,omitempty" db:"pause_reason"`
|
|
// LastRunFinishedAt is the wall-clock time of the most recent finished
|
|
// run. Used by cooldown gating.
|
|
LastRunFinishedAt *time.Time `json:"last_run_finished_at,omitempty" db:"last_run_finished_at"`
|
|
// MaxConcurrentSessions caps the number of in-flight sessions for the agent.
|
|
MaxConcurrentSessions int `json:"max_concurrent_sessions,omitempty" db:"max_concurrent_sessions"`
|
|
// CooldownSec is the minimum gap between successive runs.
|
|
CooldownSec int `json:"cooldown_sec,omitempty" db:"cooldown_sec"`
|
|
// SkipIdleRuns short-circuits scheduler ticks when the agent has nothing
|
|
// queued.
|
|
SkipIdleRuns bool `json:"skip_idle_runs,omitempty" db:"skip_idle_runs"`
|
|
// ConsecutiveFailures is the running count for auto-pause gating.
|
|
ConsecutiveFailures int `json:"consecutive_failures,omitempty" db:"consecutive_failures"`
|
|
// FailureThreshold is the per-agent override for the workspace-level
|
|
// auto-pause threshold. nil → use workspace default. The DB column is
|
|
// INTEGER NOT NULL DEFAULT 3; the office repo round-trips nil ↔ 0 via
|
|
// NULLIF / failureThresholdToColumn.
|
|
FailureThreshold *int `json:"failure_threshold,omitempty" db:"failure_threshold"`
|
|
// ExecutorPreference is a hint for which executor backend to prefer
|
|
// (free-form JSON or a simple type name).
|
|
ExecutorPreference string `json:"executor_preference,omitempty" db:"executor_preference"`
|
|
// BudgetMonthlyCents is the per-agent monthly budget cap.
|
|
BudgetMonthlyCents int `json:"budget_monthly_cents,omitempty" db:"budget_monthly_cents"`
|
|
// Settings is a free-form JSON object holding office fields not promoted
|
|
// to dedicated columns.
|
|
Settings string `json:"settings,omitempty" db:"settings"`
|
|
// Permissions is a free-form JSON object holding office permission
|
|
// flags (e.g. spawn_subagents, hire_agents, approve_budget). Stored as
|
|
// the raw JSON string so callers may unmarshal into their own shape.
|
|
// Empty / "{}" means "no special permissions".
|
|
Permissions string `json:"permissions,omitempty" db:"permissions"`
|
|
|
|
// Utilization is populated for subscription-billed agents only. nil
|
|
// for api_key billing. Computed at read time — not stored in the DB.
|
|
Utilization *agentusage.ProviderUsage `json:"utilization,omitempty" db:"-"`
|
|
}
|
|
|
|
// CLIFlag is a single user-configurable CLI argument on an AgentProfile.
|
|
// The raw Flag string is shell-tokenised at launch time: a single entry
|
|
// like "--add-dir /shared" becomes two argv tokens.
|
|
type CLIFlag struct {
|
|
Description string `json:"description"`
|
|
Flag string `json:"flag"`
|
|
Enabled bool `json:"enabled"`
|
|
}
|