feat: add disallowed interactive tools config for sessions

This commit is contained in:
cpacker
2026-02-10 13:21:58 -08:00
parent df18cba565
commit c1ca8a8080
4 changed files with 28 additions and 1 deletions

View File

@@ -14,6 +14,10 @@ LETTA_API_KEY=your_letta_api_key
# Allowed tools (comma-separated)
# ALLOWED_TOOLS=Read,Glob,Grep,Task,web_search,conversation_search
# Disallowed tools (comma-separated)
# Default blocks plan-mode interactive tools that can stall headless agents
# DISALLOWED_TOOLS=EnterPlanMode,ExitPlanMode
# ============================================
# Telegram (required: at least one channel)
# ============================================

View File

@@ -151,11 +151,20 @@ export class LettaBot implements AgentSession {
// =========================================================================
private get baseSessionOptions() {
const disallowedTools = this.config.disallowedTools || [];
return {
permissionMode: 'bypassPermissions' as const,
allowedTools: this.config.allowedTools,
disallowedTools,
cwd: this.config.workingDir,
canUseTool: (toolName: string, _toolInput: Record<string, unknown>) => {
if (disallowedTools.includes(toolName)) {
return {
behavior: 'deny' as const,
message: `Tool '${toolName}' is blocked by bot configuration`,
};
}
console.log(`[Bot] Tool approval requested: ${toolName} (should be auto-approved by bypassPermissions)`);
return { behavior: 'allow' as const };
},

View File

@@ -124,6 +124,7 @@ export interface BotConfig {
workingDir: string;
agentName?: string; // Name for the agent (set via API after creation)
allowedTools: string[];
disallowedTools?: string[];
// Display
displayName?: string; // Prefix outbound messages (e.g. "💜 Signo")

View File

@@ -397,10 +397,22 @@ function createGroupBatcher(
// Skills are installed to agent-scoped directory when agent is created (see core/bot.ts)
function parseCsvList(raw: string): string[] {
return raw
.split(',')
.map((item) => item.trim())
.filter((item) => item.length > 0);
}
// Global config (shared across all agents)
const globalConfig = {
workingDir: getWorkingDir(),
allowedTools: (process.env.ALLOWED_TOOLS || 'Bash,Read,Edit,Write,Glob,Grep,Task,web_search,conversation_search').split(','),
allowedTools: parseCsvList(
process.env.ALLOWED_TOOLS || 'Bash,Read,Edit,Write,Glob,Grep,Task,web_search,conversation_search',
),
disallowedTools: parseCsvList(
process.env.DISALLOWED_TOOLS || 'EnterPlanMode,ExitPlanMode',
),
attachmentsMaxBytes: resolveAttachmentsMaxBytes(),
attachmentsMaxAgeDays: resolveAttachmentsMaxAgeDays(),
cronEnabled: process.env.CRON_ENABLED === 'true', // Legacy env var fallback
@@ -472,6 +484,7 @@ async function main() {
workingDir: globalConfig.workingDir,
agentName: agentConfig.name,
allowedTools: globalConfig.allowedTools,
disallowedTools: globalConfig.disallowedTools,
displayName: agentConfig.displayName,
maxToolCalls: agentConfig.features?.maxToolCalls,
skills: {