refactor(v2): remove trigger_credential_collection MCP tool

Drops the in-chat credential-collection flow introduced in e92b245. Agents
can no longer collect API keys via a secure modal — users must add secrets
through OneCLI directly. Keeps the OneCLI manual-approval handler and
threaded-routing work from the same commit intact.

Removed:
* container/agent-runner/src/mcp-tools/credentials.ts (MCP tool)
* src/credentials.ts (host-side modal/OneCLI pipeline)
* src/db/credentials.ts + migration 005 (pending_credentials table)
* src/onecli-secrets.ts (createSecret CLI facade, only caller was credentials.ts)
* findCredentialResponse from agent-runner DB layer
* PendingCredential types
* Four credential hooks from ChannelSetup (getCredentialForModal,
  onCredentialReject, onCredentialSubmit, onCredentialChannelUnsupported)
* Credential card/modal handling in chat-sdk-bridge (nccr/nccm prefixes,
  Modal/TextInput imports)
* credential_request text fallback in WhatsApp adapter
* request_credential system-action case in delivery.ts

Added:
* Migration 009 drops pending_credentials on existing installs.

Vercel skill now tells the agent to ask the user to register the token via
OneCLI instead of invoking the removed tool.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-04-16 21:41:41 +03:00
parent e55ed0f4e8
commit cc784ff94b
23 changed files with 29 additions and 823 deletions

View File

@@ -1,33 +0,0 @@
import type { PendingCredential, PendingCredentialStatus } from '../types.js';
import { getDb } from './connection.js';
export function createPendingCredential(c: PendingCredential): void {
getDb()
.prepare(
`INSERT INTO pending_credentials
(id, agent_group_id, session_id, name, type, host_pattern, path_pattern,
header_name, value_format, description, channel_type, platform_id,
platform_message_id, status, created_at)
VALUES
(@id, @agent_group_id, @session_id, @name, @type, @host_pattern, @path_pattern,
@header_name, @value_format, @description, @channel_type, @platform_id,
@platform_message_id, @status, @created_at)`,
)
.run(c);
}
export function getPendingCredential(id: string): PendingCredential | undefined {
return getDb().prepare('SELECT * FROM pending_credentials WHERE id = ?').get(id) as PendingCredential | undefined;
}
export function updatePendingCredentialStatus(id: string, status: PendingCredentialStatus): void {
getDb().prepare('UPDATE pending_credentials SET status = ? WHERE id = ?').run(status, id);
}
export function updatePendingCredentialMessageId(id: string, platformMessageId: string): void {
getDb().prepare('UPDATE pending_credentials SET platform_message_id = ? WHERE id = ?').run(platformMessageId, id);
}
export function deletePendingCredential(id: string): void {
getDb().prepare('DELETE FROM pending_credentials WHERE id = ?').run(id);
}

View File

@@ -58,10 +58,3 @@ export {
deletePendingApproval,
getPendingApprovalsByAction,
} from './sessions.js';
export {
createPendingCredential,
getPendingCredential,
updatePendingCredentialStatus,
updatePendingCredentialMessageId,
deletePendingCredential,
} from './credentials.js';

View File

@@ -1,34 +0,0 @@
import type { Migration } from './index.js';
/**
* `pending_credentials` — backs the trigger_credential_collection flow.
* One row per in-flight credential request; status transitions
* pending → submitted → saved | rejected | failed.
*/
export const migration005: Migration = {
version: 5,
name: 'pending-credentials',
up(db) {
db.exec(`
CREATE TABLE pending_credentials (
id TEXT PRIMARY KEY,
agent_group_id TEXT NOT NULL REFERENCES agent_groups(id),
session_id TEXT REFERENCES sessions(id),
name TEXT NOT NULL,
type TEXT NOT NULL,
host_pattern TEXT NOT NULL,
path_pattern TEXT,
header_name TEXT,
value_format TEXT,
description TEXT,
channel_type TEXT NOT NULL,
platform_id TEXT NOT NULL,
platform_message_id TEXT,
status TEXT NOT NULL DEFAULT 'pending',
created_at TEXT NOT NULL
);
CREATE INDEX idx_pending_credentials_status ON pending_credentials(status);
`);
},
};

View File

@@ -0,0 +1,13 @@
import type Database from 'better-sqlite3';
import type { Migration } from './index.js';
export const migration009: Migration = {
version: 9,
name: 'drop-pending-credentials',
up: (db: Database.Database) => {
db.exec(`
DROP INDEX IF EXISTS idx_pending_credentials_status;
DROP TABLE IF EXISTS pending_credentials;
`);
},
};

View File

@@ -5,9 +5,9 @@ import { migration001 } from './001-initial.js';
import { migration002 } from './002-chat-sdk-state.js';
import { migration003 } from './003-pending-approvals.js';
import { migration004 } from './004-agent-destinations.js';
import { migration005 } from './005-pending-credentials.js';
import { migration007 } from './007-pending-approvals-title-options.js';
import { migration008 } from './008-dropped-messages.js';
import { migration009 } from './009-drop-pending-credentials.js';
export interface Migration {
version: number;
@@ -20,9 +20,9 @@ const migrations: Migration[] = [
migration002,
migration003,
migration004,
migration005,
migration007,
migration008,
migration009,
];
export function runMigrations(db: Database.Database): void {

View File

@@ -169,9 +169,9 @@ CREATE TABLE IF NOT EXISTS destinations (
-- Default reply routing for this session. Single-row table (id=1).
-- Host overwrites on every container wake from the session's messaging_group
-- and thread_id. Container reads it in send_message / ask_user_question /
-- trigger_credential_collection to default the channel/thread of outbound
-- messages when the agent doesn't specify an explicit destination.
-- and thread_id. Container reads it in send_message / ask_user_question to
-- default the channel/thread of outbound messages when the agent doesn't
-- specify an explicit destination.
CREATE TABLE IF NOT EXISTS session_routing (
id INTEGER PRIMARY KEY CHECK (id = 1),
channel_type TEXT,