refactor(connectors): drop dead CLI command field after pi-mono migration
The CLI-adapter era `connector.command` field became vestigial once every provider dispatch went through pi-ai. The schema still required a non-empty command, so onboarding saveConnector silently rejected every Pi Mono row (which carries an empty default). Remove the field from the payload chain (renderer → IPC schema → DB CRUD → run dispatch → worker job), narrow RunJob.taskId to match EnqueueRunPayload, and drop the dead helper plus its test. Schema column stays NOT NULL for DB compatibility; seedConnectors writes a literal empty string so no migration is needed.
This commit is contained in:
1 parent
dac59f56c2
commit
88a1f8b334
29 files changed
+17
-171
No files matched your search
@@ -1,9 +0,0 @@
|
||||
/**
|
||||
* Normalise a CLI command value read from the connectors table or a user form.
|
||||
*
|
||||
* Collapses surrounding whitespace so CLI dispatch does not fork an empty
|
||||
* argument or pass leading/trailing spaces to spawn().
|
||||
*/
|
||||
export function normalizeCommandValue(value: string | null | undefined): string {
|
||||
return (value ?? "").trim();
|
||||
}
|
||||
@@ -16,53 +16,6 @@ export const ROLE_DEPARTMENT_HINTS: Record<string, TaskType> = {
|
||||
legal: "management",
|
||||
};
|
||||
|
||||
/**
|
||||
* Preferred provider ordering per task type. Resolved against `CONNECTORS` at
|
||||
* module load so `TASK_TYPE_PREFERENCE` stays in sync with the pi-mono catalog
|
||||
* without hard-coded id lists.
|
||||
*/
|
||||
const PROVIDER_PREFERENCE: Record<TaskType, string[]> = {
|
||||
code: ["anthropic", "openai", "xai", "groq", "google", "openrouter", "mistral", "cerebras"],
|
||||
research: ["google", "anthropic", "openai", "openrouter", "xai", "mistral", "groq"],
|
||||
content: ["anthropic", "openai", "google", "mistral", "openrouter", "groq", "xai"],
|
||||
management: ["anthropic", "openai", "google", "mistral", "openrouter", "groq", "xai"],
|
||||
general: ["anthropic", "openai", "google", "openrouter", "mistral", "xai", "groq"],
|
||||
};
|
||||
|
||||
function connectorsByProvider(provider: string): ConnectorId[] {
|
||||
return CONNECTORS.filter((c) => c.provider === provider).map((c) => c.id);
|
||||
}
|
||||
|
||||
function buildPreference(taskType: TaskType): ConnectorId[] {
|
||||
const preferred: ConnectorId[] = [];
|
||||
const seen = new Set<ConnectorId>();
|
||||
for (const provider of PROVIDER_PREFERENCE[taskType]) {
|
||||
for (const id of connectorsByProvider(provider)) {
|
||||
if (!seen.has(id)) {
|
||||
preferred.push(id);
|
||||
seen.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ensure every catalog entry appears in the preference list so callers can
|
||||
// always resolve to *some* connector even when the provider is not ranked.
|
||||
for (const connector of CONNECTORS) {
|
||||
if (!seen.has(connector.id)) {
|
||||
preferred.push(connector.id);
|
||||
seen.add(connector.id);
|
||||
}
|
||||
}
|
||||
return preferred;
|
||||
}
|
||||
|
||||
export const TASK_TYPE_PREFERENCE: Record<TaskType, ConnectorId[]> = {
|
||||
code: buildPreference("code"),
|
||||
research: buildPreference("research"),
|
||||
content: buildPreference("content"),
|
||||
management: buildPreference("management"),
|
||||
general: buildPreference("general"),
|
||||
};
|
||||
|
||||
export function inferTaskType(department: string | null | undefined): TaskType {
|
||||
if (!department) return "general";
|
||||
const lower = department.toLowerCase();
|
||||
|
||||
@@ -31,13 +31,6 @@ const PI_MONO_CAPABILITIES: CapabilityMatrix = {
|
||||
costAttribution: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Legacy `ConnectorRecord.command` column. Pi-mono has no CLI command — the
|
||||
* worker calls pi-ai directly — so this is an empty string that the UI
|
||||
* treats as "managed by pi-mono".
|
||||
*/
|
||||
const PI_MONO_DEFAULT_COMMAND = "";
|
||||
|
||||
export function getConnectorDefinition(id: string) {
|
||||
const definition = CONNECTORS.find((entry) => entry.id === id);
|
||||
if (!definition) {
|
||||
@@ -105,7 +98,6 @@ export function buildDefaultConnectorRows(existing: Array<Partial<ConnectorRecor
|
||||
label: definition.label,
|
||||
description: definition.description,
|
||||
status: existingRecord?.status ?? "not_installed",
|
||||
command: existingRecord?.command ?? PI_MONO_DEFAULT_COMMAND,
|
||||
version: existingRecord?.version ?? null,
|
||||
authState: existingRecord?.authState ?? "unknown",
|
||||
lastCheckedAt: existingRecord?.lastCheckedAt ?? null,
|
||||
|
||||
@@ -289,7 +289,7 @@ export class AppDatabaseBase {
|
||||
|
||||
// ─── Connectors ────────────────────────────────────────────────────────────
|
||||
|
||||
saveConnector(input: { id: ConnectorId; command: string; model: string | null; envBindingText: string; notes: string }) { this.connectorsCrud.saveConnector(input); }
|
||||
saveConnector(input: { id: ConnectorId; model: string | null; envBindingText: string; notes: string }) { this.connectorsCrud.saveConnector(input); }
|
||||
updateConnectorHealth(input: { id: ConnectorId; status: string; authState: string; version: string | null; lastError: string | null }) { this.connectorsCrud.updateConnectorHealth(input); }
|
||||
getConnector(id: ConnectorId) { return this.connectorsCrud.getConnector(id); }
|
||||
findConnector(id: ConnectorId) { return this.connectorsCrud.findConnector(id); }
|
||||
|
||||
@@ -3,7 +3,6 @@ import log from "electron-log/main.js";
|
||||
import type { ConnectorId, ConnectorRecord } from "@shared/types";
|
||||
import type { ReadAll } from "./helpers";
|
||||
import { nowIso } from "./helpers";
|
||||
import { normalizeCommandValue } from "../connector-helpers";
|
||||
import {
|
||||
CONNECTORS,
|
||||
getConnectorDefinition,
|
||||
@@ -20,11 +19,11 @@ export function buildConnectorMethods(
|
||||
function readConnectors(): ConnectorRecord[] {
|
||||
const rows = readAll<{
|
||||
id: string; label: string; description: string; status: ConnectorRecord["status"];
|
||||
command: string; version: string | null; auth_state: ConnectorRecord["authState"];
|
||||
version: string | null; auth_state: ConnectorRecord["authState"];
|
||||
last_checked_at: string | null; last_error: string | null; model: string | null;
|
||||
env_binding_text: string; notes: string;
|
||||
}>(
|
||||
"select id, label, description, status, command, version, auth_state, last_checked_at, last_error, model, env_binding_text, notes from connectors order by label asc",
|
||||
"select id, label, description, status, version, auth_state, last_checked_at, last_error, model, env_binding_text, notes from connectors order by label asc",
|
||||
);
|
||||
const result: ConnectorRecord[] = [];
|
||||
for (const row of rows) {
|
||||
@@ -40,7 +39,6 @@ export function buildConnectorMethods(
|
||||
label: row.label,
|
||||
description: row.description,
|
||||
status: row.status,
|
||||
command: normalizeCommandValue(row.command),
|
||||
version: row.version,
|
||||
authState: row.auth_state,
|
||||
lastCheckedAt: row.last_checked_at,
|
||||
@@ -60,17 +58,15 @@ export function buildConnectorMethods(
|
||||
|
||||
saveConnector(input: {
|
||||
id: ConnectorId;
|
||||
command: string;
|
||||
model: string | null;
|
||||
envBindingText: string;
|
||||
notes: string;
|
||||
}) {
|
||||
const normalizedCommand = normalizeCommandValue(input.command);
|
||||
getDb()
|
||||
.prepare(
|
||||
"update connectors set command = ?, model = ?, env_binding_text = ?, notes = ?, updated_at = ? where id = ?",
|
||||
"update connectors set model = ?, env_binding_text = ?, notes = ?, updated_at = ? where id = ?",
|
||||
)
|
||||
.run(normalizedCommand, input.model, input.envBindingText, input.notes, nowIso(), input.id);
|
||||
.run(input.model, input.envBindingText, input.notes, nowIso(), input.id);
|
||||
},
|
||||
|
||||
updateConnectorHealth(input: {
|
||||
@@ -90,7 +86,7 @@ export function buildConnectorMethods(
|
||||
findConnector(id: ConnectorId): ConnectorRecord | null {
|
||||
const row = getDb()
|
||||
.prepare(
|
||||
"select id, label, description, status, command, version, auth_state, last_checked_at, last_error, model, env_binding_text, notes from connectors where id = ?",
|
||||
"select id, label, description, status, version, auth_state, last_checked_at, last_error, model, env_binding_text, notes from connectors where id = ?",
|
||||
)
|
||||
.get(id) as
|
||||
| {
|
||||
@@ -98,7 +94,6 @@ export function buildConnectorMethods(
|
||||
label: string;
|
||||
description: string;
|
||||
status: ConnectorRecord["status"];
|
||||
command: string;
|
||||
version: string | null;
|
||||
auth_state: ConnectorRecord["authState"];
|
||||
last_checked_at: string | null;
|
||||
@@ -121,7 +116,6 @@ export function buildConnectorMethods(
|
||||
label: row.label,
|
||||
description: row.description,
|
||||
status: row.status,
|
||||
command: normalizeCommandValue(row.command),
|
||||
version: row.version,
|
||||
authState: row.auth_state,
|
||||
lastCheckedAt: row.last_checked_at,
|
||||
@@ -146,18 +140,21 @@ export function buildConnectorMethods(
|
||||
getDb().prepare(`delete from connectors where id not in (${validIds})`).run();
|
||||
|
||||
const currentRows = readAll<Partial<ConnectorRecord>>(
|
||||
"select id, label, description, status, command, version, auth_state as authState, last_checked_at as lastCheckedAt, last_error as lastError, model, env_binding_text as envBindingText, notes from connectors",
|
||||
"select id, label, description, status, version, auth_state as authState, last_checked_at as lastCheckedAt, last_error as lastError, model, env_binding_text as envBindingText, notes from connectors",
|
||||
);
|
||||
|
||||
const merged = buildDefaultConnectorRows(currentRows);
|
||||
// `command` column stays in the schema as NOT NULL for legacy reasons;
|
||||
// pi-mono has no CLI so we always write an empty string. Column is
|
||||
// never read by runtime code.
|
||||
const statement = getDb().prepare(
|
||||
"insert or replace into connectors (id, label, description, status, command, version, auth_state, last_checked_at, last_error, model, env_binding_text, notes, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
"insert or replace into connectors (id, label, description, status, command, version, auth_state, last_checked_at, last_error, model, env_binding_text, notes, updated_at) values (?, ?, ?, ?, '', ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
);
|
||||
const updatedAt = nowIso();
|
||||
for (const row of merged) {
|
||||
statement.run(
|
||||
row.id, row.label, row.description, row.status,
|
||||
row.command, row.version, row.authState, row.lastCheckedAt,
|
||||
row.version, row.authState, row.lastCheckedAt,
|
||||
row.lastError, row.model, row.envBindingText, row.notes, updatedAt,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -86,10 +86,6 @@ export function registerCoreAdminHandlers({
|
||||
|
||||
registerHandle(IPC_CHANNELS.saveConnector, async (_event, payload) => {
|
||||
const parsed = connectorInputSchema.parse(payload);
|
||||
const existingConnector = db.getConnector(parsed.id);
|
||||
if (parsed.command !== existingConnector.command) {
|
||||
return fail("CONNECTOR_COMMAND_LOCKED", `Connector command is managed by AgentCompany and must remain "${existingConnector.command}".`);
|
||||
}
|
||||
const connectorConfigValidation = validateConnectorConfigurationModel(parsed.id, parsed.model ?? null);
|
||||
if (!connectorConfigValidation.ok) {
|
||||
return fail("CONNECTOR_MODEL_NOT_ALLOWED", connectorConfigValidation.error);
|
||||
@@ -99,7 +95,6 @@ export function registerCoreAdminHandlers({
|
||||
// happens at run dispatch time where the company is known.
|
||||
db.saveConnector({
|
||||
...parsed,
|
||||
command: existingConnector.command,
|
||||
model: parsed.model ?? null,
|
||||
});
|
||||
db.addActivity({
|
||||
@@ -108,7 +103,7 @@ export function registerCoreAdminHandlers({
|
||||
action: "connector.updated",
|
||||
entityType: "connector",
|
||||
entityId: parsed.id,
|
||||
detail: existingConnector.command,
|
||||
detail: parsed.id,
|
||||
});
|
||||
publishDomainChanged();
|
||||
return ok(true);
|
||||
|
||||
@@ -360,7 +360,6 @@ export function buildRunPayload(params: RunDispatchParams, deps: TurnContextDeps
|
||||
workspaceId: workspaceMode === "exclusive" ? (workspace?.id ?? null) : null,
|
||||
workspacePath: workspace?.localPath ?? null,
|
||||
workspaceMode,
|
||||
command: connector.command,
|
||||
model: modelSelection.effectiveModel,
|
||||
thinkingEffort,
|
||||
env,
|
||||
|
||||
@@ -37,7 +37,6 @@ export interface EnqueueRunPayload {
|
||||
workspaceId: string | null;
|
||||
workspacePath: string | null;
|
||||
workspaceMode: WorkspaceLockMode;
|
||||
command: string;
|
||||
model: string | null;
|
||||
thinkingEffort: string | null;
|
||||
env: Record<string, string>;
|
||||
|
||||
@@ -3,7 +3,8 @@ import type { RunStatus } from "@shared/types";
|
||||
export interface RunJob {
|
||||
runId: string;
|
||||
companyId: string;
|
||||
taskId: string;
|
||||
/** Null for heartbeat runs with no assigned task. Must stay aligned with EnqueueRunPayload. */
|
||||
taskId: string | null;
|
||||
taskTitle: string;
|
||||
taskDescription: string;
|
||||
agentId: string;
|
||||
@@ -12,7 +13,6 @@ export interface RunJob {
|
||||
workspaceId: string | null;
|
||||
workspacePath: string | null;
|
||||
workspaceMode: "exclusive" | "shared" | "none";
|
||||
command: string;
|
||||
model: string | null;
|
||||
thinkingEffort: string | null;
|
||||
env: Record<string, string>;
|
||||
|
||||
@@ -22,7 +22,6 @@ export function useConnectorCallbacks(connectors: ProfileSnapshot["connectors"])
|
||||
try {
|
||||
unwrap(await window.agentCompany.saveConnector({
|
||||
id: connectorId as ConnectorId,
|
||||
command: connector.command,
|
||||
model,
|
||||
envBindingText,
|
||||
notes: notes ?? connector.notes,
|
||||
|
||||
@@ -132,7 +132,7 @@ export function ExecutionSections({ section }: ExecutionSectionsProps) {
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="min-w-0">
|
||||
<div className="text-[14px] font-medium text-foreground">{connector.label}</div>
|
||||
<div className="mt-1 truncate text-[11px] uppercase tracking-[0.12em] text-muted-foreground">{connector.command}</div>
|
||||
<div className="mt-1 truncate text-[11px] uppercase tracking-[0.12em] text-muted-foreground">{connector.id}</div>
|
||||
</div>
|
||||
<StatusPill status={connector.status} />
|
||||
</div>
|
||||
|
||||
@@ -53,7 +53,6 @@ export type ConnectorId = z.infer<typeof connectorIdEnum>;
|
||||
|
||||
export const connectorInputSchema = z.object({
|
||||
id: connectorIdEnum,
|
||||
command: z.string().min(1),
|
||||
model: z.string().nullable().optional(),
|
||||
envBindingText: z.string().default(""),
|
||||
notes: z.string().default(""),
|
||||
|
||||
@@ -43,7 +43,6 @@ export interface ConnectorRecord {
|
||||
label: string;
|
||||
description: string;
|
||||
status: ConnectorStatus;
|
||||
command: string;
|
||||
version: string | null;
|
||||
authState: "unknown" | "ok" | "required" | "error";
|
||||
lastCheckedAt: string | null;
|
||||
|
||||
Reference in new issue
Block a user