Merge pull request #348 from ronyrus/mom-use-auth-json

make mom fetch apiKey from `authStorage`
This commit is contained in:
Mario Zechner 2025-12-29 13:35:39 +01:00 committed by GitHub
commit 193559bc65
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 34 additions and 17 deletions

View file

@ -64,8 +64,7 @@ export MOM_SLACK_APP_TOKEN=xapp-...
export MOM_SLACK_BOT_TOKEN=xoxb-... export MOM_SLACK_BOT_TOKEN=xoxb-...
# Option 1: Anthropic API key # Option 1: Anthropic API key
export ANTHROPIC_API_KEY=sk-ant-... export ANTHROPIC_API_KEY=sk-ant-...
# Option 2: Anthropic Pro/Max (use `claude setup-token`) # Option 2: use /login command in pi agent, then copy/link auth.json to ~/.pi/mom/
export ANTHROPIC_OAUTH_TOKEN=sk-ant-...
# Create Docker sandbox (recommended) # Create Docker sandbox (recommended)
docker run -d \ docker run -d \
@ -96,8 +95,24 @@ Options:
|----------|-------------| |----------|-------------|
| `MOM_SLACK_APP_TOKEN` | Slack app-level token (xapp-...) | | `MOM_SLACK_APP_TOKEN` | Slack app-level token (xapp-...) |
| `MOM_SLACK_BOT_TOKEN` | Slack bot token (xoxb-...) | | `MOM_SLACK_BOT_TOKEN` | Slack bot token (xoxb-...) |
| `ANTHROPIC_API_KEY` | Anthropic API key | | `ANTHROPIC_API_KEY` | (Optional) Anthropic API key |
| `ANTHROPIC_OAUTH_TOKEN` | Alternative: Anthropic OAuth token |
## Authentication
Mom needs credentials for Anthropic API. The options to set it are:
1. **Environment Variable**
```bash
export ANTHROPIC_API_KEY=sk-ant-...
```
2. **OAuth Login via coding agent command** (Recommended for Claude Pro/Max)
- run interactive coding agent session: `npx @mariozechner/pi-coding-agent`
- enter `/login` command
- choose "Anthropic" provider
- follow instructions in the browser
- link `auth.json` to mom: `ln -s ~/.pi/agent/auth.json ~/.pi/mom/auth.json`
## How Mom Works ## How Mom Works

View file

@ -39,10 +39,14 @@ export interface AgentRunner {
abort(): void; abort(): void;
} }
function getAnthropicApiKey(): string { async function getAnthropicApiKey(authStorage: AuthStorage): Promise<string> {
const key = process.env.ANTHROPIC_OAUTH_TOKEN || process.env.ANTHROPIC_API_KEY; const key = await authStorage.getApiKey("anthropic");
if (!key) { if (!key) {
throw new Error("ANTHROPIC_OAUTH_TOKEN or ANTHROPIC_API_KEY must be set"); throw new Error(
"No API key found for anthropic.\n\n" +
"Set an API key environment variable, or use /login with Anthropic and link to auth.json from " +
join(homedir(), ".pi", "mom", "auth.json"),
);
} }
return key; return key;
} }
@ -417,6 +421,11 @@ function createRunner(sandboxConfig: SandboxConfig, channelId: string, channelDi
const sessionManager = new MomSessionManager(channelDir); const sessionManager = new MomSessionManager(channelDir);
const settingsManager = new MomSettingsManager(join(channelDir, "..")); const settingsManager = new MomSettingsManager(join(channelDir, ".."));
// Create AuthStorage and ModelRegistry
// Auth stored outside workspace so agent can't access it
const authStorage = new AuthStorage(join(homedir(), ".pi", "mom", "auth.json"));
const modelRegistry = new ModelRegistry(authStorage);
// Create agent // Create agent
const agent = new Agent({ const agent = new Agent({
initialState: { initialState: {
@ -427,7 +436,7 @@ function createRunner(sandboxConfig: SandboxConfig, channelId: string, channelDi
}, },
messageTransformer, messageTransformer,
transport: new ProviderTransport({ transport: new ProviderTransport({
getApiKey: async () => getAnthropicApiKey(), getApiKey: async () => getAnthropicApiKey(authStorage),
}), }),
}); });
@ -438,11 +447,6 @@ function createRunner(sandboxConfig: SandboxConfig, channelId: string, channelDi
log.logInfo(`[${channelId}] Loaded ${loadedSession.messages.length} messages from context.jsonl`); log.logInfo(`[${channelId}] Loaded ${loadedSession.messages.length} messages from context.jsonl`);
} }
// Create AuthStorage and ModelRegistry for AgentSession
// Auth stored outside workspace so agent can't access it
const authStorage = new AuthStorage(join(homedir(), ".pi", "mom", "auth.json"));
const modelRegistry = new ModelRegistry(authStorage);
// Create AgentSession wrapper // Create AgentSession wrapper
const session = new AgentSession({ const session = new AgentSession({
agent, agent,

View file

@ -16,8 +16,6 @@ import { ChannelStore } from "./store.js";
const MOM_SLACK_APP_TOKEN = process.env.MOM_SLACK_APP_TOKEN; const MOM_SLACK_APP_TOKEN = process.env.MOM_SLACK_APP_TOKEN;
const MOM_SLACK_BOT_TOKEN = process.env.MOM_SLACK_BOT_TOKEN; const MOM_SLACK_BOT_TOKEN = process.env.MOM_SLACK_BOT_TOKEN;
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;
const ANTHROPIC_OAUTH_TOKEN = process.env.ANTHROPIC_OAUTH_TOKEN;
interface ParsedArgs { interface ParsedArgs {
workingDir?: string; workingDir?: string;
@ -74,8 +72,8 @@ if (!parsedArgs.workingDir) {
const { workingDir, sandbox } = { workingDir: parsedArgs.workingDir, sandbox: parsedArgs.sandbox }; const { workingDir, sandbox } = { workingDir: parsedArgs.workingDir, sandbox: parsedArgs.sandbox };
if (!MOM_SLACK_APP_TOKEN || !MOM_SLACK_BOT_TOKEN || (!ANTHROPIC_API_KEY && !ANTHROPIC_OAUTH_TOKEN)) { if (!MOM_SLACK_APP_TOKEN || !MOM_SLACK_BOT_TOKEN) {
console.error("Missing env: MOM_SLACK_APP_TOKEN, MOM_SLACK_BOT_TOKEN, ANTHROPIC_API_KEY or ANTHROPIC_OAUTH_TOKEN"); console.error("Missing env: MOM_SLACK_APP_TOKEN, MOM_SLACK_BOT_TOKEN");
process.exit(1); process.exit(1);
} }