feat: add disallowed interactive tools config for sessions
This commit is contained in:
@@ -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)
|
||||
# ============================================
|
||||
|
||||
@@ -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 };
|
||||
},
|
||||
|
||||
@@ -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")
|
||||
|
||||
15
src/main.ts
15
src/main.ts
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user