mirror of
https://github.com/letta-ai/claude-subconscious.git
synced 2026-04-25 17:04:56 +02:00
feat: restore LETTA_SDK_TOOLS=off as listen-only mode
off now means "no client-side tools" — Sub still receives transcripts via the SDK transport but can only use memory operations. Useful for listen-only agents that observe without filesystem access. Written by Cameron ◯ Letta Code "Listening is an art that requires attention over talent." - Dean Jackson
This commit is contained in:
@@ -111,7 +111,7 @@ export LETTA_BASE_URL="http://localhost:8283" # For self-hosted Letta
|
||||
export LETTA_MODEL="anthropic/claude-sonnet-4-5" # Model override
|
||||
export LETTA_CONTEXT_WINDOW="1048576" # Context window size (e.g. 1M tokens)
|
||||
export LETTA_HOME="$HOME" # Consolidate .letta state to ~/.letta/
|
||||
export LETTA_SDK_TOOLS="read-only" # Or "full"
|
||||
export LETTA_SDK_TOOLS="read-only" # Or "full", "off"
|
||||
```
|
||||
|
||||
- `LETTA_MODE` - Controls what gets injected. `whisper` (default, messages only), `full` (blocks + messages), `off` (disable). See [Modes](#modes).
|
||||
@@ -120,7 +120,7 @@ export LETTA_SDK_TOOLS="read-only" # Or "full"
|
||||
- `LETTA_MODEL` - Override the agent's model. Optional - the plugin auto-detects and selects from available models. See [Model Configuration](#model-configuration) below.
|
||||
- `LETTA_CONTEXT_WINDOW` - Override the agent's context window size (in tokens). Useful when `LETTA_MODEL` is set to a model with a large context window that differs from the server default. Example: `1048576` for 1M tokens.
|
||||
- `LETTA_HOME` - Base directory for plugin state files. Creates `{LETTA_HOME}/.letta/claude/` for session data and conversation mappings. Defaults to current working directory. Set to `$HOME` to consolidate all state in one location.
|
||||
- `LETTA_SDK_TOOLS` - Controls client-side tool access for the Subconscious agent. `read-only` (default) or `full`. See [SDK Tools](#sdk-tools).
|
||||
- `LETTA_SDK_TOOLS` - Controls client-side tool access for the Subconscious agent. `read-only` (default), `full`, or `off`. See [SDK Tools](#sdk-tools).
|
||||
|
||||
### Modes
|
||||
|
||||
@@ -288,6 +288,7 @@ By default, the Subconscious agent now gets **client-side tool access** via the
|
||||
|------|----------------|----------|
|
||||
| `read-only` (default) | `Read`, `Grep`, `Glob`, `web_search`, `fetch_webpage` | Safe background research and file reading |
|
||||
| `full` | All tools (Bash, Edit, Write, etc.) | Full autonomy — Sub can make changes |
|
||||
| `off` | None (memory-only) | Listen-only — Sub processes transcripts but has no client-side tools |
|
||||
|
||||
> **Note:** Requires `@letta-ai/letta-code-sdk` (installed as a dependency).
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ export function getTempStateDir(): string {
|
||||
// SDK Tools Configuration
|
||||
// ============================================
|
||||
|
||||
export type SdkToolsMode = 'read-only' | 'full';
|
||||
export type SdkToolsMode = 'read-only' | 'full' | 'off';
|
||||
|
||||
/** Read-only tool set: safe defaults for background Sub execution */
|
||||
export const SDK_TOOLS_READ_ONLY = ['Read', 'Grep', 'Glob', 'web_search', 'fetch_webpage'];
|
||||
@@ -75,10 +75,11 @@ export const SDK_TOOLS_BLOCKED = ['AskUserQuestion', 'EnterPlanMode', 'ExitPlanM
|
||||
* Get the SDK tools mode from LETTA_SDK_TOOLS env var.
|
||||
* - read-only (default): Sub can read files and search the web
|
||||
* - full: Sub has full tool access (use with caution)
|
||||
* - off: No client-side tools (listen-only, memory operations only)
|
||||
*/
|
||||
export function getSdkToolsMode(): SdkToolsMode {
|
||||
const mode = process.env.LETTA_SDK_TOOLS?.toLowerCase();
|
||||
if (mode === 'full') return mode;
|
||||
if (mode === 'full' || mode === 'off') return mode;
|
||||
return 'read-only';
|
||||
}
|
||||
|
||||
|
||||
@@ -56,15 +56,19 @@ async function sendViaSdk(payload: SdkPayload): Promise<boolean> {
|
||||
sleeptime: { trigger: 'off' }, // don't recurse sleeptime
|
||||
};
|
||||
|
||||
if (payload.sdkToolsMode === 'read-only') {
|
||||
if (payload.sdkToolsMode === 'off') {
|
||||
// Listen-only: block all client-side tools, Sub can only use memory operations
|
||||
sessionOptions.disallowedTools = [...blockedTools, ...readOnlyTools, 'Bash', 'Edit', 'Write', 'Task', 'Glob', 'Grep', 'Read'];
|
||||
} else if (payload.sdkToolsMode === 'read-only') {
|
||||
sessionOptions.allowedTools = readOnlyTools;
|
||||
}
|
||||
// 'full' mode: no allowedTools restriction (all tools available)
|
||||
|
||||
const toolsLabel = payload.sdkToolsMode === 'off' ? 'none' : payload.sdkToolsMode === 'read-only' ? readOnlyTools.join(', ') : 'all';
|
||||
log(`Creating SDK session for conversation ${payload.conversationId} (mode: ${payload.sdkToolsMode})`);
|
||||
log(` agent: ${payload.agentId}`);
|
||||
log(` cwd: ${payload.cwd}`);
|
||||
log(` allowedTools: ${payload.sdkToolsMode === 'read-only' ? readOnlyTools.join(', ') : 'all'}`);
|
||||
log(` allowedTools: ${toolsLabel}`);
|
||||
|
||||
const session = resumeSession(payload.conversationId, sessionOptions);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user