@geminixiang/mama 0.1.10 → 0.2.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +24 -7
  2. package/dist/adapter.d.ts +4 -4
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js.map +1 -1
  5. package/dist/adapters/slack/bot.d.ts +9 -1
  6. package/dist/adapters/slack/bot.d.ts.map +1 -1
  7. package/dist/adapters/slack/bot.js +30 -13
  8. package/dist/adapters/slack/bot.js.map +1 -1
  9. package/dist/adapters/slack/context.d.ts.map +1 -1
  10. package/dist/adapters/slack/context.js +5 -10
  11. package/dist/adapters/slack/context.js.map +1 -1
  12. package/dist/adapters/telegram/bot.d.ts +2 -0
  13. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  14. package/dist/adapters/telegram/bot.js +106 -42
  15. package/dist/adapters/telegram/bot.js.map +1 -1
  16. package/dist/adapters/telegram/context.d.ts +1 -1
  17. package/dist/adapters/telegram/context.d.ts.map +1 -1
  18. package/dist/adapters/telegram/context.js +71 -27
  19. package/dist/adapters/telegram/context.js.map +1 -1
  20. package/dist/agent.d.ts.map +1 -1
  21. package/dist/agent.js +179 -21
  22. package/dist/agent.js.map +1 -1
  23. package/dist/config.d.ts +3 -0
  24. package/dist/config.d.ts.map +1 -1
  25. package/dist/config.js +46 -13
  26. package/dist/config.js.map +1 -1
  27. package/dist/context.d.ts +2 -0
  28. package/dist/context.d.ts.map +1 -1
  29. package/dist/context.js +16 -7
  30. package/dist/context.js.map +1 -1
  31. package/dist/instrument.d.ts +2 -0
  32. package/dist/instrument.d.ts.map +1 -0
  33. package/dist/instrument.js +7 -0
  34. package/dist/instrument.js.map +1 -0
  35. package/dist/log.d.ts +1 -0
  36. package/dist/log.d.ts.map +1 -1
  37. package/dist/log.js +5 -4
  38. package/dist/log.js.map +1 -1
  39. package/dist/main.d.ts +1 -1
  40. package/dist/main.d.ts.map +1 -1
  41. package/dist/main.js +103 -50
  42. package/dist/main.js.map +1 -1
  43. package/dist/sentry.d.ts +31 -0
  44. package/dist/sentry.d.ts.map +1 -0
  45. package/dist/sentry.js +205 -0
  46. package/dist/sentry.js.map +1 -0
  47. package/dist/session-store.d.ts +76 -0
  48. package/dist/session-store.d.ts.map +1 -0
  49. package/dist/session-store.js +189 -0
  50. package/dist/session-store.js.map +1 -0
  51. package/package.json +2 -1
package/dist/agent.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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","sourcesContent":["import { Agent, type AgentEvent } from \"@mariozechner/pi-agent-core\";\nimport { getModel, type ImageContent } from \"@mariozechner/pi-ai\";\nimport {\n AgentSession,\n AuthStorage,\n convertToLlm,\n createExtensionRuntime,\n formatSkillsForPrompt,\n loadSkillsFromDir,\n ModelRegistry,\n type ResourceLoader,\n SessionManager,\n type Skill,\n} from \"@mariozechner/pi-coding-agent\";\nimport { existsSync, mkdirSync, readFileSync } from \"fs\";\nimport { mkdir, readFile, writeFile } from \"fs/promises\";\nimport { homedir } from \"os\";\nimport { join } from \"path\";\nimport type { ChatMessage, ChatResponseContext, PlatformInfo } from \"./adapter.js\";\nimport { loadAgentConfig } from \"./config.js\";\nimport { createMamaSettingsManager, syncLogToSessionManager } from \"./context.js\";\nimport * as log from \"./log.js\";\nimport { createExecutor, type SandboxConfig } from \"./sandbox.js\";\nimport { createMamaTools } from \"./tools/index.js\";\n\nexport interface PendingMessage {\n userName: string;\n text: string;\n attachments: { local: string }[];\n timestamp: number;\n}\n\nexport interface AgentRunner {\n run(\n message: ChatMessage,\n responseCtx: ChatResponseContext,\n platform: PlatformInfo,\n ): Promise<{ stopReason: string; errorMessage?: string }>;\n abort(): void;\n /** Get current step info (tool name, label) for debugging */\n getCurrentStep(): { toolName?: string; label?: string } | undefined;\n}\n\nconst IMAGE_MIME_TYPES: Record<string, string> = {\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n png: \"image/png\",\n gif: \"image/gif\",\n webp: \"image/webp\",\n};\n\nfunction getImageMimeType(filename: string): string | undefined {\n return IMAGE_MIME_TYPES[filename.toLowerCase().split(\".\").pop() || \"\"];\n}\n\nasync function getMemory(channelDir: string): Promise<string> {\n const parts: string[] = [];\n\n // Read workspace-level memory (shared across all channels)\n const workspaceMemoryPath = join(channelDir, \"..\", \"MEMORY.md\");\n if (existsSync(workspaceMemoryPath)) {\n try {\n const content = (await readFile(workspaceMemoryPath, \"utf-8\")).trim();\n if (content) {\n parts.push(`### Global Workspace Memory\\n${content}`);\n }\n } catch (error) {\n log.logWarning(\"Failed to read workspace memory\", `${workspaceMemoryPath}: ${error}`);\n }\n }\n\n // Read channel-specific memory\n const channelMemoryPath = join(channelDir, \"MEMORY.md\");\n if (existsSync(channelMemoryPath)) {\n try {\n const content = (await readFile(channelMemoryPath, \"utf-8\")).trim();\n if (content) {\n parts.push(`### Channel-Specific Memory\\n${content}`);\n }\n } catch (error) {\n log.logWarning(\"Failed to read channel memory\", `${channelMemoryPath}: ${error}`);\n }\n }\n\n if (parts.length === 0) {\n return \"(no working memory yet)\";\n }\n\n return parts.join(\"\\n\\n\");\n}\n\nfunction loadMamaSkills(channelDir: string, workspacePath: string): Skill[] {\n const skillMap = new Map<string, Skill>();\n\n // channelDir is the host path (e.g., /Users/.../data/C0A34FL8PMH)\n // hostWorkspacePath is the parent directory on host\n // workspacePath is the container path (e.g., /workspace)\n const hostWorkspacePath = join(channelDir, \"..\");\n\n // Helper to translate host paths to container paths\n const translatePath = (hostPath: string): string => {\n if (hostPath.startsWith(hostWorkspacePath)) {\n return workspacePath + hostPath.slice(hostWorkspacePath.length);\n }\n return hostPath;\n };\n\n // Load workspace-level skills (global)\n const workspaceSkillsDir = join(hostWorkspacePath, \"skills\");\n for (const skill of loadSkillsFromDir({ dir: workspaceSkillsDir, source: \"workspace\" }).skills) {\n // Translate paths to container paths for system prompt\n skill.filePath = translatePath(skill.filePath);\n skill.baseDir = translatePath(skill.baseDir);\n skillMap.set(skill.name, skill);\n }\n\n // Load channel-specific skills (override workspace skills on collision)\n const channelSkillsDir = join(channelDir, \"skills\");\n for (const skill of loadSkillsFromDir({ dir: channelSkillsDir, source: \"channel\" }).skills) {\n skill.filePath = translatePath(skill.filePath);\n skill.baseDir = translatePath(skill.baseDir);\n skillMap.set(skill.name, skill);\n }\n\n return Array.from(skillMap.values());\n}\n\nfunction buildSystemPrompt(\n workspacePath: string,\n channelId: string,\n memory: string,\n sandboxConfig: SandboxConfig,\n platform: PlatformInfo,\n skills: Skill[],\n): string {\n const channelPath = `${workspacePath}/${channelId}`;\n const isDocker = sandboxConfig.type === \"docker\";\n const isFirecracker = sandboxConfig.type === \"firecracker\";\n\n // Format channel mappings\n const channelMappings =\n platform.channels.length > 0\n ? platform.channels.map((c) => `${c.id}\\t#${c.name}`).join(\"\\n\")\n : \"(no channels loaded)\";\n\n // Format user mappings\n const userMappings =\n platform.users.length > 0\n ? platform.users.map((u) => `${u.id}\\t@${u.userName}\\t${u.displayName}`).join(\"\\n\")\n : \"(no users loaded)\";\n\n const envDescription = isDocker\n ? `You are running inside a Docker container (Alpine Linux).\n- Bash working directory: / (use cd or absolute paths)\n- Install tools with: apk add <package>\n- Your changes persist across sessions`\n : isFirecracker\n ? `You are running inside a Firecracker microVM.\n- Bash working directory: / (use cd or absolute paths)\n- Install tools with: apt-get install <package> (Debian-based)\n- Your changes persist across sessions`\n : `You are running directly on the host machine.\n- Bash working directory: ${process.cwd()}\n- Be careful with system modifications`;\n\n return `You are mama, a ${platform.name} bot assistant. Be concise. No emojis.\n\n## Context\n- For current date/time, use: date\n- You have access to previous conversation context including tool results from prior turns.\n- For older history beyond your context, search log.jsonl (contains user messages and your final responses, but not tool results).\n- User messages include a \\`[in-thread:TS]\\` marker when sent from within a Slack thread (TS is the root message timestamp). Without this marker, the message is a top-level channel message.\n\n${platform.formattingGuide}\n\n## Platform IDs\nChannels: ${channelMappings}\n\nUsers: ${userMappings}\n\nWhen mentioning users, use <@username> format (e.g., <@mario>).\n\n## Environment\n${envDescription}\n\n## Workspace Layout\n${workspacePath}/\n├── MEMORY.md # Global memory (all channels)\n├── skills/ # Global CLI tools you create\n└── ${channelId}/ # This channel\n ├── MEMORY.md # Channel-specific memory\n ├── log.jsonl # Message history (no tool results)\n ├── attachments/ # User-shared files\n ├── scratch/ # Your working directory\n └── skills/ # Channel-specific tools\n\n## Skills (Custom CLI Tools)\nYou can create reusable CLI tools for recurring tasks (email, APIs, data processing, etc.).\n\n### Creating Skills\nStore in \\`${workspacePath}/skills/<name>/\\` (global) or \\`${channelPath}/skills/<name>/\\` (channel-specific).\nEach skill directory needs a \\`SKILL.md\\` with YAML frontmatter:\n\n\\`\\`\\`markdown\n---\nname: skill-name\ndescription: Short description of what this skill does\n---\n\n# Skill Name\n\nUsage instructions, examples, etc.\nScripts are in: {baseDir}/\n\\`\\`\\`\n\n\\`name\\` and \\`description\\` are required. Use \\`{baseDir}\\` as placeholder for the skill's directory path.\n\n### Available Skills\n${skills.length > 0 ? formatSkillsForPrompt(skills) : \"(no skills installed yet)\"}\n\n## Events\nYou can schedule events that wake you up at specific times or when external things happen. Events are JSON files in \\`${workspacePath}/events/\\`.\n\n### Event Types\n\n**Immediate** - Triggers as soon as harness sees the file. Use in scripts/webhooks to signal external events.\n\\`\\`\\`json\n{\"type\": \"immediate\", \"platform\": \"${platform.name}\", \"channelId\": \"${channelId}\", \"text\": \"New GitHub issue opened\"}\n\\`\\`\\`\n\n**One-shot** - Triggers once at a specific time. Use for reminders.\n\\`\\`\\`json\n{\"type\": \"one-shot\", \"platform\": \"${platform.name}\", \"channelId\": \"${channelId}\", \"text\": \"Remind Mario about dentist\", \"at\": \"2025-12-15T09:00:00+01:00\"}\n\\`\\`\\`\n\n**Periodic** - Triggers on a cron schedule. Use for recurring tasks.\n\\`\\`\\`json\n{\"type\": \"periodic\", \"platform\": \"${platform.name}\", \"channelId\": \"${channelId}\", \"text\": \"Check inbox and summarize\", \"schedule\": \"0 9 * * 1-5\", \"timezone\": \"${Intl.DateTimeFormat().resolvedOptions().timeZone}\"}\n\\`\\`\\`\n\n### Cron Format\n\\`minute hour day-of-month month day-of-week\\`\n- \\`0 9 * * *\\` = daily at 9:00\n- \\`0 9 * * 1-5\\` = weekdays at 9:00\n- \\`30 14 * * 1\\` = Mondays at 14:30\n- \\`0 0 1 * *\\` = first of each month at midnight\n\n### Timezones\nAll \\`at\\` timestamps must include offset (e.g., \\`+01:00\\`). Periodic events use IANA timezone names. The harness runs in ${Intl.DateTimeFormat().resolvedOptions().timeZone}. When users mention times without timezone, assume ${Intl.DateTimeFormat().resolvedOptions().timeZone}.\n\n### Platform Routing\nSet \\`platform\\` to the target bot platform (\\`${platform.name}\\` for this conversation). When only one platform is running, omitting \\`platform\\` is allowed for backward compatibility, but include it by default to avoid ambiguity.\n\n### Creating Events\nUse unique filenames to avoid overwriting existing events. Include a timestamp or random suffix:\n\\`\\`\\`bash\ncat > ${workspacePath}/events/dentist-reminder-$(date +%s).json << 'EOF'\n{\"type\": \"one-shot\", \"platform\": \"${platform.name}\", \"channelId\": \"${channelId}\", \"text\": \"Dentist tomorrow\", \"at\": \"2025-12-14T09:00:00+01:00\"}\nEOF\n\\`\\`\\`\nOr check if file exists first before creating.\n\n### Managing Events\n- List: \\`ls ${workspacePath}/events/\\`\n- View: \\`cat ${workspacePath}/events/foo.json\\`\n- Delete/cancel: \\`rm ${workspacePath}/events/foo.json\\`\n\n### When Events Trigger\nYou receive a message like:\n\\`\\`\\`\n[EVENT:dentist-reminder.json:one-shot:2025-12-14T09:00:00+01:00] Dentist tomorrow\n\\`\\`\\`\nImmediate and one-shot events auto-delete after triggering. Periodic events persist until you delete them.\n\n### Silent Completion\nFor periodic events where there's nothing to report, respond with just \\`[SILENT]\\` (no other text). This deletes the status message and posts nothing to the platform. Use this to avoid spamming the channel when periodic checks find nothing actionable.\n\n### Debouncing\nWhen writing programs that create immediate events (email watchers, webhook handlers, etc.), always debounce. If 50 emails arrive in a minute, don't create 50 immediate events. Instead collect events over a window and create ONE immediate event summarizing what happened, or just signal \"new activity, check inbox\" rather than per-item events. Or simpler: use a periodic event to check for new items every N minutes instead of immediate events.\n\n### Limits\nMaximum 5 events can be queued. Don't create excessive immediate or periodic events.\n\n## Memory\nWrite to MEMORY.md files to persist context across conversations.\n- Global (${workspacePath}/MEMORY.md): skills, preferences, project info\n- Channel (${channelPath}/MEMORY.md): channel-specific decisions, ongoing work\nUpdate when you learn something important or when asked to remember something.\n\n### Current Memory\n${memory}\n\n## System Configuration Log\nMaintain ${workspacePath}/SYSTEM.md to log all environment modifications:\n- Installed packages (apk add, npm install, pip install)\n- Environment variables set\n- Config files modified (~/.gitconfig, cron jobs, etc.)\n- Skill dependencies installed\n\nUpdate this file whenever you modify the environment. On fresh container, read it first to restore your setup.\n\n## Log Queries (for older history)\nFormat: \\`{\"date\":\"...\",\"ts\":\"...\",\"user\":\"...\",\"userName\":\"...\",\"text\":\"...\",\"isBot\":false}\\`\nThe log contains user messages and your final responses (not tool calls/results).\n${isDocker ? \"Install jq: apk add jq\" : \"\"}\n${isFirecracker ? \"Install jq: apt-get install jq\" : \"\"}\n\n\\`\\`\\`bash\n# Recent messages\ntail -30 log.jsonl | jq -c '{date: .date[0:19], user: (.userName // .user), text}'\n\n# Search for specific topic\ngrep -i \"topic\" log.jsonl | jq -c '{date: .date[0:19], user: (.userName // .user), text}'\n\n# Messages from specific user\ngrep '\"userName\":\"mario\"' log.jsonl | tail -20 | jq -c '{date: .date[0:19], text}'\n\\`\\`\\`\n\n## Tools\n- bash: Run shell commands (primary tool). Install packages as needed.\n- read: Read files\n- write: Create/overwrite files\n- edit: Surgical file edits\n- attach: Share files to the platform\n\nEach tool requires a \"label\" parameter (shown to user).\n`;\n}\n\nfunction truncate(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n return `${text.substring(0, maxLen - 3)}...`;\n}\n\nfunction extractToolResultText(result: unknown): string {\n if (typeof result === \"string\") {\n return result;\n }\n\n if (\n result &&\n typeof result === \"object\" &&\n \"content\" in result &&\n Array.isArray((result as { content: unknown }).content)\n ) {\n const content = (result as { content: Array<{ type: string; text?: string }> }).content;\n const textParts: string[] = [];\n for (const part of content) {\n if (part.type === \"text\" && part.text) {\n textParts.push(part.text);\n }\n }\n if (textParts.length > 0) {\n return textParts.join(\"\\n\");\n }\n }\n\n return JSON.stringify(result);\n}\n\nfunction formatToolArgsForSlack(_toolName: string, args: Record<string, unknown>): string {\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(args)) {\n if (key === \"label\") continue;\n\n if (key === \"path\" && typeof value === \"string\") {\n const offset = args.offset as number | undefined;\n const limit = args.limit as number | undefined;\n if (offset !== undefined && limit !== undefined) {\n lines.push(`${value}:${offset}-${offset + limit}`);\n } else {\n lines.push(value);\n }\n continue;\n }\n\n if (key === \"offset\" || key === \"limit\") continue;\n\n if (typeof value === \"string\") {\n lines.push(value);\n } else {\n lines.push(JSON.stringify(value));\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n// ============================================================================\n// Agent runner\n// ============================================================================\n\n/**\n * Create a new AgentRunner for a channel.\n * Sets up the session and subscribes to events once.\n *\n * Runner caching is handled by the caller (channelStates in main.ts).\n * This is a stateless factory function.\n */\nexport async function createRunner(\n sandboxConfig: SandboxConfig,\n sessionKey: string,\n channelId: string,\n channelDir: string,\n workspaceDir: string,\n): Promise<AgentRunner> {\n const agentConfig = loadAgentConfig(workspaceDir);\n\n // Initialize logger with settings from config\n log.initLogger({\n logFormat: agentConfig.logFormat,\n logLevel: agentConfig.logLevel,\n });\n\n const executor = createExecutor(sandboxConfig);\n const workspacePath = executor.getWorkspacePath(channelDir.replace(`/${channelId}`, \"\"));\n\n // Create tools (per-runner, with per-runner upload function setter)\n const { tools, setUploadFunction } = createMamaTools(executor);\n\n // Resolve model from config\n // Use 'as any' cast because agentConfig.provider/model are plain strings,\n // while getModel() has constrained generic types for known providers.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const model = (getModel as any)(agentConfig.provider, agentConfig.model);\n\n // Initial system prompt (will be updated each run with fresh memory/channels/users/skills)\n const memory = await getMemory(channelDir);\n const skills = loadMamaSkills(channelDir, workspacePath);\n const emptyPlatform: PlatformInfo = {\n name: \"slack\",\n formattingGuide: \"\",\n channels: [],\n users: [],\n };\n const systemPrompt = buildSystemPrompt(\n workspacePath,\n channelId,\n memory,\n sandboxConfig,\n emptyPlatform,\n skills,\n );\n\n // Create session manager and settings manager\n // Per-session context file: {channelDir}/sessions/{rootTs}/context.jsonl\n const rootTs = sessionKey.includes(\":\") ? sessionKey.split(\":\").pop()! : sessionKey;\n const sessionDir = join(channelDir, \"sessions\", rootTs);\n mkdirSync(sessionDir, { recursive: true });\n const contextFile = join(sessionDir, \"context.jsonl\");\n const sessionManager = SessionManager.open(contextFile, channelDir);\n const settingsManager = createMamaSettingsManager(join(channelDir, \"..\"));\n\n // Create AuthStorage and ModelRegistry\n // Auth stored outside workspace so agent can't access it\n const authStorage = AuthStorage.create(join(homedir(), \".pi\", \"mama\", \"auth.json\"));\n const modelRegistry = new ModelRegistry(authStorage);\n\n // Create agent\n const agent = new Agent({\n initialState: {\n systemPrompt,\n model,\n thinkingLevel:\n (agentConfig.thinkingLevel as \"off\" | \"low\" | \"medium\" | \"high\" | undefined) ?? \"off\",\n tools,\n },\n convertToLlm,\n getApiKey: async () => {\n const key = await modelRegistry.getApiKeyForProvider(model.provider);\n if (!key)\n throw new Error(\n `No API key for provider \"${model.provider}\". Set the appropriate environment variable or configure via auth.json`,\n );\n return key;\n },\n });\n\n // Load existing messages\n const loadedSession = sessionManager.buildSessionContext();\n if (loadedSession.messages.length > 0) {\n agent.replaceMessages(loadedSession.messages);\n log.logInfo(\n `[${channelId}] Loaded ${loadedSession.messages.length} messages from context.jsonl`,\n );\n }\n\n const resourceLoader: ResourceLoader = {\n getExtensions: () => ({ extensions: [], errors: [], runtime: createExtensionRuntime() }),\n getSkills: () => ({ skills: [], diagnostics: [] }),\n getPrompts: () => ({ prompts: [], diagnostics: [] }),\n getThemes: () => ({ themes: [], diagnostics: [] }),\n getAgentsFiles: () => ({ agentsFiles: [] }),\n getSystemPrompt: () => systemPrompt,\n getAppendSystemPrompt: () => [],\n extendResources: () => {},\n reload: async () => {},\n };\n\n const baseToolsOverride = Object.fromEntries(tools.map((tool) => [tool.name, tool]));\n\n // Create AgentSession wrapper\n const session = new AgentSession({\n agent,\n sessionManager,\n settingsManager,\n cwd: process.cwd(),\n modelRegistry,\n resourceLoader,\n baseToolsOverride,\n });\n\n // Mutable per-run state - event handler references this\n const runState = {\n responseCtx: null as ChatResponseContext | null,\n logCtx: null as { channelId: string; userName?: string; channelName?: string } | null,\n queue: null as {\n enqueue(fn: () => Promise<void>, errorContext: string): void;\n enqueueMessage(\n text: string,\n target: \"main\" | \"thread\",\n errorContext: string,\n doLog?: boolean,\n ): void;\n } | null,\n pendingTools: new Map<string, { toolName: string; args: unknown; startTime: number }>(),\n totalUsage: {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n },\n stopReason: \"stop\",\n errorMessage: undefined as string | undefined,\n };\n\n // Subscribe to events ONCE\n session.subscribe(async (event) => {\n // Skip if no active run\n if (!runState.responseCtx || !runState.logCtx || !runState.queue) return;\n\n const { responseCtx, logCtx, queue, pendingTools } = runState;\n\n if (event.type === \"tool_execution_start\") {\n const agentEvent = event as AgentEvent & { type: \"tool_execution_start\" };\n const args = agentEvent.args as { label?: string };\n const label = args.label || agentEvent.toolName;\n\n pendingTools.set(agentEvent.toolCallId, {\n toolName: agentEvent.toolName,\n args: agentEvent.args,\n startTime: Date.now(),\n });\n\n log.logToolStart(\n logCtx,\n agentEvent.toolName,\n label,\n agentEvent.args as Record<string, unknown>,\n );\n // Tool labels are omitted from the main message to reduce Slack noise.\n // Tool execution details are still posted to the thread (see tool_execution_end).\n } else if (event.type === \"tool_execution_end\") {\n const agentEvent = event as AgentEvent & { type: \"tool_execution_end\" };\n const resultStr = extractToolResultText(agentEvent.result);\n const pending = pendingTools.get(agentEvent.toolCallId);\n pendingTools.delete(agentEvent.toolCallId);\n\n const durationMs = pending ? Date.now() - pending.startTime : 0;\n\n if (agentEvent.isError) {\n log.logToolError(logCtx, agentEvent.toolName, durationMs, resultStr);\n } else {\n log.logToolSuccess(logCtx, agentEvent.toolName, durationMs, resultStr);\n }\n\n // Post args + result to thread\n const label = pending?.args ? (pending.args as { label?: string }).label : undefined;\n const argsFormatted = pending\n ? formatToolArgsForSlack(agentEvent.toolName, pending.args as Record<string, unknown>)\n : \"(args not found)\";\n const duration = (durationMs / 1000).toFixed(1);\n let threadMessage = `*${agentEvent.isError ? \"✗\" : \"✓\"} ${agentEvent.toolName}*`;\n if (label) threadMessage += `: ${label}`;\n threadMessage += ` (${duration}s)\\n`;\n if (argsFormatted) threadMessage += `\\`\\`\\`\\n${argsFormatted}\\n\\`\\`\\`\\n`;\n threadMessage += `*Result:*\\n\\`\\`\\`\\n${resultStr}\\n\\`\\`\\``;\n\n // Only post thread details for tools with meaningful output (bash, attach).\n // Skip read/write/edit to reduce Slack noise — their results are in the log.\n const quietTools = new Set([\"read\", \"write\", \"edit\"]);\n if (!quietTools.has(agentEvent.toolName)) {\n queue.enqueueMessage(threadMessage, \"thread\", \"tool result thread\", false);\n }\n\n if (agentEvent.isError) {\n queue.enqueue(\n () => responseCtx.respond(`_Error: ${truncate(resultStr, 200)}_`),\n \"tool error\",\n );\n }\n } else if (event.type === \"message_start\") {\n const agentEvent = event as AgentEvent & { type: \"message_start\" };\n if (agentEvent.message.role === \"assistant\") {\n log.logResponseStart(logCtx);\n }\n } else if (event.type === \"message_end\") {\n const agentEvent = event as AgentEvent & { type: \"message_end\" };\n if (agentEvent.message.role === \"assistant\") {\n const assistantMsg = agentEvent.message as any;\n\n if (assistantMsg.stopReason) {\n runState.stopReason = assistantMsg.stopReason;\n }\n if (assistantMsg.errorMessage) {\n runState.errorMessage = assistantMsg.errorMessage;\n }\n\n if (assistantMsg.usage) {\n runState.totalUsage.input += assistantMsg.usage.input;\n runState.totalUsage.output += assistantMsg.usage.output;\n runState.totalUsage.cacheRead += assistantMsg.usage.cacheRead;\n runState.totalUsage.cacheWrite += assistantMsg.usage.cacheWrite;\n runState.totalUsage.cost.input += assistantMsg.usage.cost.input;\n runState.totalUsage.cost.output += assistantMsg.usage.cost.output;\n runState.totalUsage.cost.cacheRead += assistantMsg.usage.cost.cacheRead;\n runState.totalUsage.cost.cacheWrite += assistantMsg.usage.cost.cacheWrite;\n runState.totalUsage.cost.total += assistantMsg.usage.cost.total;\n }\n\n const content = agentEvent.message.content;\n const thinkingParts: string[] = [];\n const textParts: string[] = [];\n for (const part of content) {\n if (part.type === \"thinking\") {\n thinkingParts.push((part as any).thinking);\n } else if (part.type === \"text\") {\n textParts.push((part as any).text);\n }\n }\n\n const text = textParts.join(\"\\n\");\n\n for (const thinking of thinkingParts) {\n log.logThinking(logCtx, thinking);\n queue.enqueueMessage(`_${thinking}_`, \"main\", \"thinking main\");\n queue.enqueueMessage(`_${thinking}_`, \"thread\", \"thinking thread\", false);\n }\n\n if (text.trim()) {\n log.logResponse(logCtx, text);\n queue.enqueueMessage(text, \"main\", \"response main\");\n // Only overflow to thread for texts that will be truncated in main\n if (text.length > SLACK_MAX_LENGTH) {\n queue.enqueueMessage(text, \"thread\", \"response thread\", false);\n }\n }\n }\n } else if (event.type === \"compaction_start\") {\n log.logInfo(`Auto-compaction started (reason: ${(event as any).reason})`);\n queue.enqueue(() => responseCtx.respond(\"_Compacting context..._\"), \"compaction start\");\n } else if (event.type === \"compaction_end\") {\n const compEvent = event as any;\n if (compEvent.result) {\n log.logInfo(`Auto-compaction complete: ${compEvent.result.tokensBefore} tokens compacted`);\n } else if (compEvent.aborted) {\n log.logInfo(\"Auto-compaction aborted\");\n }\n } else if (event.type === \"auto_retry_start\") {\n const retryEvent = event as any;\n log.logWarning(\n `Retrying (${retryEvent.attempt}/${retryEvent.maxAttempts})`,\n retryEvent.errorMessage,\n );\n queue.enqueue(\n () =>\n responseCtx.respond(`_Retrying (${retryEvent.attempt}/${retryEvent.maxAttempts})..._`),\n \"retry\",\n );\n }\n });\n\n // Message limit constant\n const SLACK_MAX_LENGTH = 40000;\n const splitForSlack = (text: string): string[] => {\n if (text.length <= SLACK_MAX_LENGTH) return [text];\n const parts: string[] = [];\n let remaining = text;\n let partNum = 1;\n while (remaining.length > 0) {\n const chunk = remaining.substring(0, SLACK_MAX_LENGTH - 50);\n remaining = remaining.substring(SLACK_MAX_LENGTH - 50);\n const suffix = remaining.length > 0 ? `\\n_(continued ${partNum}...)_` : \"\";\n parts.push(chunk + suffix);\n partNum++;\n }\n return parts;\n };\n\n return {\n async run(\n message: ChatMessage,\n responseCtx: ChatResponseContext,\n platform: PlatformInfo,\n ): Promise<{ stopReason: string; errorMessage?: string }> {\n // Extract channelId from sessionKey (format: \"channelId:rootTs\" or just \"channelId\")\n const sessionChannel = message.sessionKey.split(\":\")[0];\n\n // Ensure channel directory exists\n await mkdir(channelDir, { recursive: true });\n\n // Sync messages from log.jsonl that arrived while we were offline or busy\n // Exclude the current message (it will be added via prompt())\n // Default sync range is 10 days (handled by syncLogToSessionManager)\n // Thread filter ensures only messages from this session's thread are synced\n const syncedCount = await syncLogToSessionManager(\n sessionManager,\n channelDir,\n message.id,\n undefined,\n { rootTs, threadTs: message.threadTs },\n );\n if (syncedCount > 0) {\n log.logInfo(`[${channelId}] Synced ${syncedCount} messages from log.jsonl`);\n }\n\n // Reload messages from context.jsonl\n // This picks up any messages synced above\n const reloadedSession = sessionManager.buildSessionContext();\n if (reloadedSession.messages.length > 0) {\n agent.replaceMessages(reloadedSession.messages);\n log.logInfo(\n `[${channelId}] Reloaded ${reloadedSession.messages.length} messages from context`,\n );\n }\n\n // Update system prompt with fresh memory, channel/user info, and skills\n const memory = await getMemory(channelDir);\n const skills = loadMamaSkills(channelDir, workspacePath);\n const systemPrompt = buildSystemPrompt(\n workspacePath,\n channelId,\n memory,\n sandboxConfig,\n platform,\n skills,\n );\n session.agent.setSystemPrompt(systemPrompt);\n\n // Set up file upload function\n setUploadFunction(async (filePath: string, title?: string) => {\n const hostPath = translateToHostPath(filePath, channelDir, workspacePath, channelId);\n await responseCtx.uploadFile(hostPath, title);\n });\n\n // Reset per-run state\n runState.responseCtx = responseCtx;\n runState.logCtx = {\n channelId: sessionChannel,\n userName: message.userName,\n channelName: undefined,\n };\n runState.pendingTools.clear();\n runState.totalUsage = {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n };\n runState.stopReason = \"stop\";\n runState.errorMessage = undefined;\n\n // Create queue for this run\n let queueChain = Promise.resolve();\n runState.queue = {\n enqueue(fn: () => Promise<void>, errorContext: string): void {\n queueChain = queueChain.then(async () => {\n try {\n await fn();\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n log.logWarning(`API error (${errorContext})`, errMsg);\n try {\n // Split long error messages to avoid msg_too_long\n const errParts = splitForSlack(`_Error: ${errMsg}_`);\n for (const part of errParts) {\n await responseCtx.respondInThread(part);\n }\n } catch {\n // Ignore\n }\n }\n });\n },\n enqueueMessage(\n text: string,\n target: \"main\" | \"thread\",\n errorContext: string,\n _doLog = true,\n ): void {\n const parts = splitForSlack(text);\n for (const part of parts) {\n this.enqueue(\n () =>\n target === \"main\" ? responseCtx.respond(part) : responseCtx.respondInThread(part),\n errorContext,\n );\n }\n },\n };\n\n // Log context info\n log.logInfo(\n `Context sizes - system: ${systemPrompt.length} chars, memory: ${memory.length} chars`,\n );\n log.logInfo(`Channels: ${platform.channels.length}, Users: ${platform.users.length}`);\n\n // Build user message with timestamp and username prefix\n // Format: \"[YYYY-MM-DD HH:MM:SS+HH:MM] [username]: message\" so LLM knows when and who\n const now = new Date();\n const pad = (n: number) => n.toString().padStart(2, \"0\");\n const offset = -now.getTimezoneOffset();\n const offsetSign = offset >= 0 ? \"+\" : \"-\";\n const offsetHours = pad(Math.floor(Math.abs(offset) / 60));\n const offsetMins = pad(Math.abs(offset) % 60);\n const timestamp = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}${offsetSign}${offsetHours}:${offsetMins}`;\n const threadContext = message.threadTs ? ` [in-thread:${message.threadTs}]` : \"\";\n let userMessage = `[${timestamp}] [${message.userName || \"unknown\"}]${threadContext}: ${message.text}`;\n\n const imageAttachments: ImageContent[] = [];\n const nonImagePaths: string[] = [];\n\n for (const a of message.attachments || []) {\n // a.localPath is the path relative to the workspace (same as old a.local)\n const fullPath = `${workspacePath}/${a.localPath}`;\n const mimeType = getImageMimeType(a.localPath);\n\n if (mimeType && existsSync(fullPath)) {\n try {\n imageAttachments.push({\n type: \"image\",\n mimeType,\n data: readFileSync(fullPath).toString(\"base64\"),\n });\n } catch {\n nonImagePaths.push(fullPath);\n }\n } else {\n nonImagePaths.push(fullPath);\n }\n }\n\n if (nonImagePaths.length > 0) {\n userMessage += `\\n\\n<slack_attachments>\\n${nonImagePaths.join(\"\\n\")}\\n</slack_attachments>`;\n }\n\n // Debug: write context to last_prompt.jsonl\n const debugContext = {\n systemPrompt,\n messages: session.messages,\n newUserMessage: userMessage,\n imageAttachmentCount: imageAttachments.length,\n };\n await writeFile(join(channelDir, \"last_prompt.jsonl\"), JSON.stringify(debugContext, null, 2));\n\n await session.prompt(\n userMessage,\n imageAttachments.length > 0 ? { images: imageAttachments } : undefined,\n );\n\n // Wait for queued messages\n await queueChain;\n\n // Handle error case - update main message and post error to thread\n if (runState.stopReason === \"error\" && runState.errorMessage) {\n try {\n await responseCtx.replaceResponse(\"_Sorry, something went wrong_\");\n // Split long error messages to avoid msg_too_long\n const errorParts = splitForSlack(`_Error: ${runState.errorMessage}_`);\n for (const part of errorParts) {\n await responseCtx.respondInThread(part);\n }\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n log.logWarning(\"Failed to post error message\", errMsg);\n }\n } else {\n // Final message update\n const messages = session.messages;\n const lastAssistant = messages.filter((m) => m.role === \"assistant\").pop();\n const finalText =\n lastAssistant?.content\n .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\\n\") || \"\";\n\n // Check for [SILENT] marker - delete message and thread instead of posting\n if (finalText.trim() === \"[SILENT]\" || finalText.trim().startsWith(\"[SILENT]\")) {\n try {\n await responseCtx.deleteResponse();\n log.logInfo(\"Silent response - deleted message and thread\");\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n log.logWarning(\"Failed to delete message for silent response\", errMsg);\n }\n } else if (finalText.trim()) {\n try {\n const mainText =\n finalText.length > SLACK_MAX_LENGTH\n ? `${finalText.substring(0, SLACK_MAX_LENGTH - 50)}\\n\\n_(see thread for full response)_`\n : finalText;\n await responseCtx.replaceResponse(mainText);\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n log.logWarning(\"Failed to replace message with final text\", errMsg);\n }\n }\n }\n\n // Log usage summary with context info\n if (runState.totalUsage.cost.total > 0) {\n // Get last non-aborted assistant message for context calculation\n const messages = session.messages;\n const lastAssistantMessage = messages\n .slice()\n .reverse()\n .find((m) => m.role === \"assistant\" && (m as any).stopReason !== \"aborted\") as any;\n\n const contextTokens = lastAssistantMessage\n ? lastAssistantMessage.usage.input +\n lastAssistantMessage.usage.output +\n lastAssistantMessage.usage.cacheRead +\n lastAssistantMessage.usage.cacheWrite\n : 0;\n const contextWindow = model.contextWindow || 200000;\n\n const summary = log.logUsageSummary(\n runState.logCtx!,\n runState.totalUsage,\n contextTokens,\n contextWindow,\n );\n // Split long summaries to avoid msg_too_long\n const summaryParts = splitForSlack(summary);\n for (const part of summaryParts) {\n runState.queue!.enqueue(\n () => responseCtx.respondInThread(part, { style: \"muted\" }),\n \"usage summary\",\n );\n }\n await queueChain;\n }\n\n // Clear run state\n runState.responseCtx = null;\n runState.logCtx = null;\n runState.queue = null;\n\n return { stopReason: runState.stopReason, errorMessage: runState.errorMessage };\n },\n\n abort(): void {\n session.abort();\n },\n\n getCurrentStep(): { toolName?: string; label?: string } | undefined {\n const pending = runState.pendingTools;\n if (pending.size === 0) return undefined;\n // Get the first pending tool\n const first = pending.values().next().value;\n if (!first) return undefined;\n return {\n toolName: first.toolName,\n label: (first.args as { label?: string })?.label,\n };\n },\n };\n}\n\n/**\n * Translate container path back to host path for file operations\n */\nfunction translateToHostPath(\n containerPath: string,\n channelDir: string,\n workspacePath: string,\n channelId: string,\n): string {\n if (workspacePath === \"/workspace\") {\n const prefix = `/workspace/${channelId}/`;\n if (containerPath.startsWith(prefix)) {\n return join(channelDir, containerPath.slice(prefix.length));\n }\n if (containerPath.startsWith(\"/workspace/\")) {\n return join(channelDir, \"..\", containerPath.slice(\"/workspace/\".length));\n }\n }\n return containerPath;\n}\n"]}
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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","sourcesContent":["import { Agent, type AgentEvent } from \"@mariozechner/pi-agent-core\";\nimport { getModel, type ImageContent } from \"@mariozechner/pi-ai\";\nimport {\n AgentSession,\n AuthStorage,\n convertToLlm,\n DefaultResourceLoader,\n formatSkillsForPrompt,\n loadSkillsFromDir,\n ModelRegistry,\n SessionManager,\n type Skill,\n} from \"@mariozechner/pi-coding-agent\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { mkdir, readFile, writeFile } from \"fs/promises\";\nimport { homedir } from \"os\";\nimport { join } from \"path\";\nimport type { ChatMessage, ChatResponseContext, PlatformInfo } from \"./adapter.js\";\nimport { loadAgentConfig } from \"./config.js\";\nimport { createMamaSettingsManager, syncLogToSessionManager } from \"./context.js\";\nimport * as log from \"./log.js\";\nimport { createExecutor, type SandboxConfig } from \"./sandbox.js\";\nimport { addLifecycleBreadcrumb, metricAttributes } from \"./sentry.js\";\nimport {\n createManagedSessionFileAtPath,\n extractSessionSuffix,\n extractSessionUuid,\n forkThreadSessionFile,\n getSessionDir,\n getThreadSessionFile,\n openManagedSession,\n resolveChannelSessionFile,\n resolveManagedSessionFile,\n tryResolveThreadSession,\n} from \"./session-store.js\";\nimport { createMamaTools } from \"./tools/index.js\";\nimport * as Sentry from \"@sentry/node\";\n\nexport interface PendingMessage {\n userName: string;\n text: string;\n attachments: { local: string }[];\n timestamp: number;\n}\n\nexport interface AgentRunner {\n run(\n message: ChatMessage,\n responseCtx: ChatResponseContext,\n platform: PlatformInfo,\n ): Promise<{ stopReason: string; errorMessage?: string }>;\n abort(): void;\n /** Get current step info (tool name, label) for debugging */\n getCurrentStep(): { toolName?: string; label?: string } | undefined;\n}\n\nconst IMAGE_MIME_TYPES: Record<string, string> = {\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n png: \"image/png\",\n gif: \"image/gif\",\n webp: \"image/webp\",\n};\n\nfunction getImageMimeType(filename: string): string | undefined {\n return IMAGE_MIME_TYPES[filename.toLowerCase().split(\".\").pop() || \"\"];\n}\n\nasync function getMemory(channelDir: string): Promise<string> {\n const parts: string[] = [];\n\n // Read workspace-level memory (shared across all channels)\n const workspaceMemoryPath = join(channelDir, \"..\", \"MEMORY.md\");\n if (existsSync(workspaceMemoryPath)) {\n try {\n const content = (await readFile(workspaceMemoryPath, \"utf-8\")).trim();\n if (content) {\n parts.push(`### Global Workspace Memory\\n${content}`);\n }\n } catch (error) {\n log.logWarning(\"Failed to read workspace memory\", `${workspaceMemoryPath}: ${error}`);\n }\n }\n\n // Read channel-specific memory\n const channelMemoryPath = join(channelDir, \"MEMORY.md\");\n if (existsSync(channelMemoryPath)) {\n try {\n const content = (await readFile(channelMemoryPath, \"utf-8\")).trim();\n if (content) {\n parts.push(`### Channel-Specific Memory\\n${content}`);\n }\n } catch (error) {\n log.logWarning(\"Failed to read channel memory\", `${channelMemoryPath}: ${error}`);\n }\n }\n\n if (parts.length === 0) {\n return \"(no working memory yet)\";\n }\n\n return parts.join(\"\\n\\n\");\n}\n\nfunction loadMamaSkills(channelDir: string, workspacePath: string): Skill[] {\n const skillMap = new Map<string, Skill>();\n\n // channelDir is the host path (e.g., /Users/.../data/C0A34FL8PMH)\n // hostWorkspacePath is the parent directory on host\n // workspacePath is the container path (e.g., /workspace)\n const hostWorkspacePath = join(channelDir, \"..\");\n\n // Helper to translate host paths to container paths\n const translatePath = (hostPath: string): string => {\n if (hostPath.startsWith(hostWorkspacePath)) {\n return workspacePath + hostPath.slice(hostWorkspacePath.length);\n }\n return hostPath;\n };\n\n // Load workspace-level skills (global)\n const workspaceSkillsDir = join(hostWorkspacePath, \"skills\");\n for (const skill of loadSkillsFromDir({ dir: workspaceSkillsDir, source: \"workspace\" }).skills) {\n // Translate paths to container paths for system prompt\n skill.filePath = translatePath(skill.filePath);\n skill.baseDir = translatePath(skill.baseDir);\n skillMap.set(skill.name, skill);\n }\n\n // Load channel-specific skills (override workspace skills on collision)\n const channelSkillsDir = join(channelDir, \"skills\");\n for (const skill of loadSkillsFromDir({ dir: channelSkillsDir, source: \"channel\" }).skills) {\n skill.filePath = translatePath(skill.filePath);\n skill.baseDir = translatePath(skill.baseDir);\n skillMap.set(skill.name, skill);\n }\n\n return Array.from(skillMap.values());\n}\n\nfunction buildSystemPrompt(\n workspacePath: string,\n channelId: string,\n memory: string,\n sandboxConfig: SandboxConfig,\n platform: PlatformInfo,\n skills: Skill[],\n): string {\n const channelPath = `${workspacePath}/${channelId}`;\n const isDocker = sandboxConfig.type === \"docker\";\n const isFirecracker = sandboxConfig.type === \"firecracker\";\n\n // Format channel mappings\n const channelMappings =\n platform.channels.length > 0\n ? platform.channels.map((c) => `${c.id}\\t#${c.name}`).join(\"\\n\")\n : \"(no channels loaded)\";\n\n // Format user mappings\n const userMappings =\n platform.users.length > 0\n ? platform.users.map((u) => `${u.id}\\t@${u.userName}\\t${u.displayName}`).join(\"\\n\")\n : \"(no users loaded)\";\n\n const envDescription = isDocker\n ? `You are running inside a Docker container (Alpine Linux).\n- Bash working directory: / (use cd or absolute paths)\n- Install tools with: apk add <package>\n- Your changes persist across sessions`\n : isFirecracker\n ? `You are running inside a Firecracker microVM.\n- Bash working directory: / (use cd or absolute paths)\n- Install tools with: apt-get install <package> (Debian-based)\n- Your changes persist across sessions`\n : `You are running directly on the host machine.\n- Bash working directory: ${process.cwd()}\n- Be careful with system modifications`;\n\n return `You are mama, a ${platform.name} bot assistant. Be concise. No emojis.\n\n## Context\n- For current date/time, use: date\n- You have access to previous conversation context including tool results from prior turns.\n- For older history beyond your context, search log.jsonl (contains user messages and your final responses, but not tool results).\n- User messages include a \\`[in-thread:TS]\\` marker when sent from within a Slack thread (TS is the root message timestamp). Without this marker, the message is a top-level channel message.\n\n${platform.formattingGuide}\n\n## Platform IDs\nChannels: ${channelMappings}\n\nUsers: ${userMappings}\n\nWhen mentioning users, use <@username> format (e.g., <@mario>).\n\n## Environment\n${envDescription}\n\n## Workspace Layout\n${workspacePath}/\n├── MEMORY.md # Global memory (all channels)\n├── skills/ # Global CLI tools you create\n└── ${channelId}/ # This channel\n ├── MEMORY.md # Channel-specific memory\n ├── log.jsonl # Message history (no tool results)\n ├── attachments/ # User-shared files\n ├── scratch/ # Your working directory\n └── skills/ # Channel-specific tools\n\n## Skills (Custom CLI Tools)\nYou can create reusable CLI tools for recurring tasks (email, APIs, data processing, etc.).\n\n### Creating Skills\nStore in \\`${workspacePath}/skills/<name>/\\` (global) or \\`${channelPath}/skills/<name>/\\` (channel-specific).\nEach skill directory needs a \\`SKILL.md\\` with YAML frontmatter:\n\n\\`\\`\\`markdown\n---\nname: skill-name\ndescription: Short description of what this skill does\n---\n\n# Skill Name\n\nUsage instructions, examples, etc.\nScripts are in: {baseDir}/\n\\`\\`\\`\n\n\\`name\\` and \\`description\\` are required. Use \\`{baseDir}\\` as placeholder for the skill's directory path.\n\n### Available Skills\n${skills.length > 0 ? formatSkillsForPrompt(skills) : \"(no skills installed yet)\"}\n\n## Events\nYou can schedule events that wake you up at specific times or when external things happen. Events are JSON files in \\`${workspacePath}/events/\\`.\n\n### Event Types\n\n**Immediate** - Triggers as soon as harness sees the file. Use in scripts/webhooks to signal external events.\n\\`\\`\\`json\n{\"type\": \"immediate\", \"platform\": \"${platform.name}\", \"channelId\": \"${channelId}\", \"text\": \"New GitHub issue opened\"}\n\\`\\`\\`\n\n**One-shot** - Triggers once at a specific time. Use for reminders.\n\\`\\`\\`json\n{\"type\": \"one-shot\", \"platform\": \"${platform.name}\", \"channelId\": \"${channelId}\", \"text\": \"Remind Mario about dentist\", \"at\": \"2025-12-15T09:00:00+01:00\"}\n\\`\\`\\`\n\n**Periodic** - Triggers on a cron schedule. Use for recurring tasks.\n\\`\\`\\`json\n{\"type\": \"periodic\", \"platform\": \"${platform.name}\", \"channelId\": \"${channelId}\", \"text\": \"Check inbox and summarize\", \"schedule\": \"0 9 * * 1-5\", \"timezone\": \"${Intl.DateTimeFormat().resolvedOptions().timeZone}\"}\n\\`\\`\\`\n\n### Cron Format\n\\`minute hour day-of-month month day-of-week\\`\n- \\`0 9 * * *\\` = daily at 9:00\n- \\`0 9 * * 1-5\\` = weekdays at 9:00\n- \\`30 14 * * 1\\` = Mondays at 14:30\n- \\`0 0 1 * *\\` = first of each month at midnight\n\n### Timezones\nAll \\`at\\` timestamps must include offset (e.g., \\`+01:00\\`). Periodic events use IANA timezone names. The harness runs in ${Intl.DateTimeFormat().resolvedOptions().timeZone}. When users mention times without timezone, assume ${Intl.DateTimeFormat().resolvedOptions().timeZone}.\n\n### Platform Routing\nSet \\`platform\\` to the target bot platform (\\`${platform.name}\\` for this conversation). When only one platform is running, omitting \\`platform\\` is allowed for backward compatibility, but include it by default to avoid ambiguity.\n\n### Creating Events\nUse unique filenames to avoid overwriting existing events. Include a timestamp or random suffix:\n\\`\\`\\`bash\ncat > ${workspacePath}/events/dentist-reminder-$(date +%s).json << 'EOF'\n{\"type\": \"one-shot\", \"platform\": \"${platform.name}\", \"channelId\": \"${channelId}\", \"text\": \"Dentist tomorrow\", \"at\": \"2025-12-14T09:00:00+01:00\"}\nEOF\n\\`\\`\\`\nOr check if file exists first before creating.\n\n### Managing Events\n- List: \\`ls ${workspacePath}/events/\\`\n- View: \\`cat ${workspacePath}/events/foo.json\\`\n- Delete/cancel: \\`rm ${workspacePath}/events/foo.json\\`\n\n### When Events Trigger\nYou receive a message like:\n\\`\\`\\`\n[EVENT:dentist-reminder.json:one-shot:2025-12-14T09:00:00+01:00] Dentist tomorrow\n\\`\\`\\`\nImmediate and one-shot events auto-delete after triggering. Periodic events persist until you delete them.\n\n### Silent Completion\nFor periodic events where there's nothing to report, respond with just \\`[SILENT]\\` (no other text). This deletes the status message and posts nothing to the platform. Use this to avoid spamming the channel when periodic checks find nothing actionable.\n\n### Debouncing\nWhen writing programs that create immediate events (email watchers, webhook handlers, etc.), always debounce. If 50 emails arrive in a minute, don't create 50 immediate events. Instead collect events over a window and create ONE immediate event summarizing what happened, or just signal \"new activity, check inbox\" rather than per-item events. Or simpler: use a periodic event to check for new items every N minutes instead of immediate events.\n\n### Limits\nMaximum 5 events can be queued. Don't create excessive immediate or periodic events.\n\n## Memory\nWrite to MEMORY.md files to persist context across conversations.\n- Global (${workspacePath}/MEMORY.md): skills, preferences, project info\n- Channel (${channelPath}/MEMORY.md): channel-specific decisions, ongoing work\nUpdate when you learn something important or when asked to remember something.\n\n### Current Memory\n${memory}\n\n## System Configuration Log\nMaintain ${workspacePath}/SYSTEM.md to log all environment modifications:\n- Installed packages (apk add, npm install, pip install)\n- Environment variables set\n- Config files modified (~/.gitconfig, cron jobs, etc.)\n- Skill dependencies installed\n\nUpdate this file whenever you modify the environment. On fresh container, read it first to restore your setup.\n\n## Log Queries (for older history)\nFormat: \\`{\"date\":\"...\",\"ts\":\"...\",\"user\":\"...\",\"userName\":\"...\",\"text\":\"...\",\"isBot\":false}\\`\nThe log contains user messages and your final responses (not tool calls/results).\n${isDocker ? \"Install jq: apk add jq\" : \"\"}\n${isFirecracker ? \"Install jq: apt-get install jq\" : \"\"}\n\n\\`\\`\\`bash\n# Recent messages\ntail -30 log.jsonl | jq -c '{date: .date[0:19], user: (.userName // .user), text}'\n\n# Search for specific topic\ngrep -i \"topic\" log.jsonl | jq -c '{date: .date[0:19], user: (.userName // .user), text}'\n\n# Messages from specific user\ngrep '\"userName\":\"mario\"' log.jsonl | tail -20 | jq -c '{date: .date[0:19], text}'\n\\`\\`\\`\n\n## Tools\n- bash: Run shell commands (primary tool). Install packages as needed.\n- read: Read files\n- write: Create/overwrite files\n- edit: Surgical file edits\n- attach: Share files to the platform\n\nEach tool requires a \"label\" parameter (shown to user).\n`;\n}\n\nfunction truncate(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n return `${text.substring(0, maxLen - 3)}...`;\n}\n\nfunction extractToolResultText(result: unknown): string {\n if (typeof result === \"string\") {\n return result;\n }\n\n if (\n result &&\n typeof result === \"object\" &&\n \"content\" in result &&\n Array.isArray((result as { content: unknown }).content)\n ) {\n const content = (result as { content: Array<{ type: string; text?: string }> }).content;\n const textParts: string[] = [];\n for (const part of content) {\n if (part.type === \"text\" && part.text) {\n textParts.push(part.text);\n }\n }\n if (textParts.length > 0) {\n return textParts.join(\"\\n\");\n }\n }\n\n return JSON.stringify(result);\n}\n\nfunction formatToolArgsForSlack(_toolName: string, args: Record<string, unknown>): string {\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(args)) {\n if (key === \"label\") continue;\n\n if (key === \"path\" && typeof value === \"string\") {\n const offset = args.offset as number | undefined;\n const limit = args.limit as number | undefined;\n if (offset !== undefined && limit !== undefined) {\n lines.push(`${value}:${offset}-${offset + limit}`);\n } else {\n lines.push(value);\n }\n continue;\n }\n\n if (key === \"offset\" || key === \"limit\") continue;\n\n if (typeof value === \"string\") {\n lines.push(value);\n } else {\n lines.push(JSON.stringify(value));\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n// ============================================================================\n// Agent runner\n// ============================================================================\n\n/**\n * Create a new AgentRunner for a channel.\n * Sets up the session and subscribes to events once.\n *\n * Runner caching is handled by the caller (channelStates in main.ts).\n * This is a stateless factory function.\n */\nexport async function createRunner(\n sandboxConfig: SandboxConfig,\n sessionKey: string,\n channelId: string,\n channelDir: string,\n workspaceDir: string,\n): Promise<AgentRunner> {\n const agentConfig = loadAgentConfig(workspaceDir);\n\n // Initialize logger with settings from config\n log.initLogger({\n logFormat: agentConfig.logFormat,\n logLevel: agentConfig.logLevel,\n });\n\n const executor = createExecutor(sandboxConfig);\n const workspacePath = executor.getWorkspacePath(channelDir.replace(`/${channelId}`, \"\"));\n\n // Create tools (per-runner, with per-runner upload function setter)\n const { tools, setUploadFunction } = createMamaTools(executor);\n\n // Resolve model from config\n // Use 'as any' cast because agentConfig.provider/model are plain strings,\n // while getModel() has constrained generic types for known providers.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const model = (getModel as any)(agentConfig.provider, agentConfig.model);\n\n // Initial system prompt (will be updated each run with fresh memory/channels/users/skills)\n const memory = await getMemory(channelDir);\n const skills = loadMamaSkills(channelDir, workspacePath);\n const emptyPlatform: PlatformInfo = {\n name: \"slack\",\n formattingGuide: \"\",\n channels: [],\n users: [],\n };\n const systemPrompt = buildSystemPrompt(\n workspacePath,\n channelId,\n memory,\n sandboxConfig,\n emptyPlatform,\n skills,\n );\n\n // Create session manager and settings manager\n // Channel sessions use {channelDir}/sessions/current.\n // Thread sessions use fixed files: {channelDir}/sessions/{threadTs}.jsonl\n const sessionDir = getSessionDir(channelDir, sessionKey);\n const isThread = sessionKey.includes(\":\");\n\n let sessionManager!: SessionManager;\n let contextFile!: string;\n\n if (isThread) {\n const threadFile = getThreadSessionFile(channelDir, sessionKey);\n const existing = tryResolveThreadSession(threadFile);\n if (existing) {\n contextFile = existing;\n sessionManager = openManagedSession(contextFile, sessionDir, channelDir);\n } else {\n const channelSource = resolveChannelSessionFile(channelDir);\n if (channelSource) {\n try {\n contextFile = forkThreadSessionFile(channelSource, threadFile, channelDir);\n sessionManager = openManagedSession(contextFile, sessionDir, channelDir);\n } catch {\n contextFile = createManagedSessionFileAtPath(threadFile, channelDir);\n sessionManager = openManagedSession(contextFile, sessionDir, channelDir);\n }\n } else {\n contextFile = createManagedSessionFileAtPath(threadFile, channelDir);\n sessionManager = openManagedSession(contextFile, sessionDir, channelDir);\n }\n }\n } else {\n // Channel/DM session: normal resolve\n contextFile = resolveManagedSessionFile(sessionDir, channelDir);\n sessionManager = openManagedSession(contextFile, sessionDir, channelDir);\n }\n const sessionUuid = extractSessionUuid(contextFile);\n // Used for Slack thread filtering — for non-Slack platforms this is effectively a no-op\n const rootTs = extractSessionSuffix(sessionKey);\n const settingsManager = createMamaSettingsManager(join(channelDir, \"..\"));\n\n // Create AuthStorage and ModelRegistry\n // Auth stored outside workspace so agent can't access it\n const authStorage = AuthStorage.create(join(homedir(), \".pi\", \"mama\", \"auth.json\"));\n const modelRegistry = new ModelRegistry(authStorage);\n\n // Create agent\n const agent = new Agent({\n initialState: {\n systemPrompt,\n model,\n thinkingLevel:\n (agentConfig.thinkingLevel as \"off\" | \"low\" | \"medium\" | \"high\" | undefined) ?? \"off\",\n tools,\n },\n convertToLlm,\n getApiKey: async () => {\n const key = await modelRegistry.getApiKeyForProvider(model.provider);\n if (!key)\n throw new Error(\n `No API key for provider \"${model.provider}\". Set the appropriate environment variable or configure via auth.json`,\n );\n return key;\n },\n });\n\n // Load existing messages\n const loadedSession = sessionManager.buildSessionContext();\n if (loadedSession.messages.length > 0) {\n agent.replaceMessages(loadedSession.messages);\n log.logInfo(\n `[${channelId}] Loaded ${loadedSession.messages.length} messages from context.jsonl`,\n );\n }\n\n // Load extensions, skills, prompts, themes via DefaultResourceLoader\n // This reads ~/.pi/agent/settings.json (packages, extensions enable/disable)\n // and discovers resources from standard locations + npm/git packages.\n const resourceLoader = new DefaultResourceLoader({\n cwd: workspaceDir,\n systemPrompt,\n });\n try {\n await resourceLoader.reload();\n const extResult = resourceLoader.getExtensions();\n if (extResult.errors.length > 0) {\n for (const err of extResult.errors) {\n log.logWarning(`[${channelId}] Extension load error: ${err.path}`, err.error);\n }\n }\n log.logInfo(\n `[${channelId}] Loaded ${extResult.extensions.length} extension(s): ${extResult.extensions.map((e) => e.path).join(\", \")}`,\n );\n } catch (error) {\n log.logWarning(`[${channelId}] Failed to load resources`, String(error));\n }\n\n const baseToolsOverride = Object.fromEntries(tools.map((tool) => [tool.name, tool]));\n\n // Create AgentSession wrapper\n const session = new AgentSession({\n agent,\n sessionManager,\n settingsManager,\n cwd: workspaceDir,\n modelRegistry,\n resourceLoader,\n baseToolsOverride,\n });\n\n // Mutable per-run state - event handler references this\n const runState = {\n responseCtx: null as ChatResponseContext | null,\n logCtx: null as {\n channelId: string;\n userName?: string;\n channelName?: string;\n sessionId?: string;\n } | null,\n queue: null as {\n enqueue(fn: () => Promise<void>, errorContext: string): void;\n enqueueMessage(\n text: string,\n target: \"main\" | \"thread\",\n errorContext: string,\n doLog?: boolean,\n ): void;\n } | null,\n pendingTools: new Map<string, { toolName: string; args: unknown; startTime: number }>(),\n totalUsage: {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n },\n llmCallCount: 0,\n stopReason: \"stop\",\n errorMessage: undefined as string | undefined,\n };\n\n // Subscribe to events ONCE\n session.subscribe(async (event) => {\n // Skip if no active run\n if (!runState.responseCtx || !runState.logCtx || !runState.queue) return;\n\n const { responseCtx, logCtx, queue, pendingTools } = runState;\n const baseAttrs = { channel_id: logCtx.channelId, session_id: logCtx.sessionId };\n\n if (event.type === \"tool_execution_start\") {\n const agentEvent = event as AgentEvent & { type: \"tool_execution_start\" };\n const args = agentEvent.args as { label?: string };\n const label = args.label || agentEvent.toolName;\n\n pendingTools.set(agentEvent.toolCallId, {\n toolName: agentEvent.toolName,\n args: agentEvent.args,\n startTime: Date.now(),\n });\n addLifecycleBreadcrumb(\"agent.tool.started\", {\n tool: agentEvent.toolName,\n ...baseAttrs,\n });\n\n log.logToolStart(\n logCtx,\n agentEvent.toolName,\n label,\n agentEvent.args as Record<string, unknown>,\n );\n // Tool labels are omitted from the main message to reduce Slack noise.\n // Tool execution details are still posted to the thread (see tool_execution_end).\n } else if (event.type === \"tool_execution_end\") {\n const agentEvent = event as AgentEvent & { type: \"tool_execution_end\" };\n const resultStr = extractToolResultText(agentEvent.result);\n const pending = pendingTools.get(agentEvent.toolCallId);\n pendingTools.delete(agentEvent.toolCallId);\n\n const durationMs = pending ? Date.now() - pending.startTime : 0;\n\n Sentry.metrics.count(\"agent.tool.calls\", 1, {\n attributes: metricAttributes({\n tool: agentEvent.toolName,\n error: String(agentEvent.isError),\n ...baseAttrs,\n }),\n });\n Sentry.metrics.distribution(\"agent.tool.duration\", durationMs, {\n unit: \"millisecond\",\n attributes: metricAttributes({\n tool: agentEvent.toolName,\n ...baseAttrs,\n }),\n });\n addLifecycleBreadcrumb(\"agent.tool.completed\", {\n tool: agentEvent.toolName,\n error: agentEvent.isError,\n duration_ms: durationMs,\n ...baseAttrs,\n });\n\n if (agentEvent.isError) {\n log.logToolError(logCtx, agentEvent.toolName, durationMs, resultStr);\n } else {\n log.logToolSuccess(logCtx, agentEvent.toolName, durationMs, resultStr);\n }\n\n // Post args + result to thread\n const label = pending?.args ? (pending.args as { label?: string }).label : undefined;\n const argsFormatted = pending\n ? formatToolArgsForSlack(agentEvent.toolName, pending.args as Record<string, unknown>)\n : \"(args not found)\";\n const duration = (durationMs / 1000).toFixed(1);\n let threadMessage = `*${agentEvent.isError ? \"✗\" : \"✓\"} ${agentEvent.toolName}*`;\n if (label) threadMessage += `: ${label}`;\n threadMessage += ` (${duration}s)\\n`;\n if (argsFormatted) threadMessage += `\\`\\`\\`\\n${argsFormatted}\\n\\`\\`\\`\\n`;\n threadMessage += `*Result:*\\n\\`\\`\\`\\n${resultStr}\\n\\`\\`\\``;\n\n // Only post thread details for tools with meaningful output (bash, attach).\n // Skip read/write/edit to reduce Slack noise — their results are in the log.\n const quietTools = new Set([\"read\", \"write\", \"edit\"]);\n if (!quietTools.has(agentEvent.toolName)) {\n queue.enqueueMessage(threadMessage, \"thread\", \"tool result thread\", false);\n }\n\n if (agentEvent.isError) {\n queue.enqueue(\n () => responseCtx.respond(`_Error: ${truncate(resultStr, 200)}_`),\n \"tool error\",\n );\n }\n } else if (event.type === \"message_start\") {\n const agentEvent = event as AgentEvent & { type: \"message_start\" };\n if (agentEvent.message.role === \"assistant\") {\n runState.llmCallCount += 1;\n addLifecycleBreadcrumb(\"agent.llm.call.started\", {\n call_index: runState.llmCallCount,\n provider: model.provider,\n model: agentConfig.model,\n ...baseAttrs,\n });\n log.logResponseStart(logCtx);\n }\n } else if (event.type === \"message_end\") {\n const agentEvent = event as AgentEvent & { type: \"message_end\" };\n if (agentEvent.message.role === \"assistant\") {\n const assistantMsg = agentEvent.message as any;\n\n if (assistantMsg.stopReason) {\n runState.stopReason = assistantMsg.stopReason;\n }\n if (assistantMsg.errorMessage) {\n runState.errorMessage = assistantMsg.errorMessage;\n }\n\n if (assistantMsg.usage) {\n runState.totalUsage.input += assistantMsg.usage.input;\n runState.totalUsage.output += assistantMsg.usage.output;\n runState.totalUsage.cacheRead += assistantMsg.usage.cacheRead;\n runState.totalUsage.cacheWrite += assistantMsg.usage.cacheWrite;\n runState.totalUsage.cost.input += assistantMsg.usage.cost.input;\n runState.totalUsage.cost.output += assistantMsg.usage.cost.output;\n runState.totalUsage.cost.cacheRead += assistantMsg.usage.cost.cacheRead;\n runState.totalUsage.cost.cacheWrite += assistantMsg.usage.cost.cacheWrite;\n runState.totalUsage.cost.total += assistantMsg.usage.cost.total;\n\n // Per-turn LLM metrics\n const llmAttributes = metricAttributes({\n provider: model.provider,\n model: agentConfig.model,\n ...baseAttrs,\n stop_reason: assistantMsg.stopReason,\n error: Boolean(assistantMsg.errorMessage),\n });\n Sentry.metrics.count(\"agent.llm.calls\", 1, { attributes: llmAttributes });\n Sentry.metrics.distribution(\"agent.llm.tokens_in\", assistantMsg.usage.input, {\n attributes: llmAttributes,\n });\n Sentry.metrics.distribution(\"agent.llm.tokens_out\", assistantMsg.usage.output, {\n attributes: llmAttributes,\n });\n if (assistantMsg.usage.cacheRead > 0) {\n Sentry.metrics.distribution(\"agent.llm.cache_read\", assistantMsg.usage.cacheRead, {\n attributes: llmAttributes,\n });\n }\n if (assistantMsg.usage.cacheWrite > 0) {\n Sentry.metrics.distribution(\"agent.llm.cache_write\", assistantMsg.usage.cacheWrite, {\n attributes: llmAttributes,\n });\n }\n Sentry.metrics.distribution(\"agent.llm.cost_per_turn\", assistantMsg.usage.cost.total, {\n attributes: llmAttributes,\n });\n addLifecycleBreadcrumb(\"agent.llm.call.completed\", {\n call_index: runState.llmCallCount,\n provider: model.provider,\n model: agentConfig.model,\n stop_reason: assistantMsg.stopReason,\n error: Boolean(assistantMsg.errorMessage),\n input_tokens: assistantMsg.usage.input,\n output_tokens: assistantMsg.usage.output,\n cost_total_usd: assistantMsg.usage.cost.total,\n });\n }\n\n const content = agentEvent.message.content;\n const thinkingParts: string[] = [];\n const textParts: string[] = [];\n for (const part of content) {\n if (part.type === \"thinking\") {\n thinkingParts.push((part as any).thinking);\n } else if (part.type === \"text\") {\n textParts.push((part as any).text);\n }\n }\n\n const text = textParts.join(\"\\n\");\n\n for (const thinking of thinkingParts) {\n log.logThinking(logCtx, thinking);\n queue.enqueueMessage(`_${thinking}_`, \"main\", \"thinking main\");\n queue.enqueueMessage(`_${thinking}_`, \"thread\", \"thinking thread\", false);\n }\n\n if (text.trim()) {\n log.logResponse(logCtx, text);\n queue.enqueueMessage(text, \"main\", \"response main\");\n // Only overflow to thread for texts that will be truncated in main\n if (text.length > SLACK_MAX_LENGTH) {\n queue.enqueueMessage(text, \"thread\", \"response thread\", false);\n }\n }\n }\n } else if (event.type === \"compaction_start\") {\n log.logInfo(`Auto-compaction started (reason: ${(event as any).reason})`);\n queue.enqueue(() => responseCtx.respond(\"_Compacting context..._\"), \"compaction start\");\n } else if (event.type === \"compaction_end\") {\n const compEvent = event as any;\n if (compEvent.result) {\n log.logInfo(`Auto-compaction complete: ${compEvent.result.tokensBefore} tokens compacted`);\n } else if (compEvent.aborted) {\n log.logInfo(\"Auto-compaction aborted\");\n }\n } else if (event.type === \"auto_retry_start\") {\n const retryEvent = event as any;\n log.logWarning(\n `Retrying (${retryEvent.attempt}/${retryEvent.maxAttempts})`,\n retryEvent.errorMessage,\n );\n queue.enqueue(\n () =>\n responseCtx.respond(`_Retrying (${retryEvent.attempt}/${retryEvent.maxAttempts})..._`),\n \"retry\",\n );\n }\n });\n\n // Message limit constant\n const SLACK_MAX_LENGTH = 40000;\n const splitForSlack = (text: string): string[] => {\n if (text.length <= SLACK_MAX_LENGTH) return [text];\n const parts: string[] = [];\n let remaining = text;\n let partNum = 1;\n while (remaining.length > 0) {\n const chunk = remaining.substring(0, SLACK_MAX_LENGTH - 50);\n remaining = remaining.substring(SLACK_MAX_LENGTH - 50);\n const suffix = remaining.length > 0 ? `\\n_(continued ${partNum}...)_` : \"\";\n parts.push(chunk + suffix);\n partNum++;\n }\n return parts;\n };\n\n return {\n async run(\n message: ChatMessage,\n responseCtx: ChatResponseContext,\n platform: PlatformInfo,\n ): Promise<{ stopReason: string; errorMessage?: string }> {\n // Extract channelId from sessionKey (format: \"channelId:rootTs\" or just \"channelId\")\n const sessionChannel = message.sessionKey.split(\":\")[0];\n\n // Ensure channel directory exists\n await mkdir(channelDir, { recursive: true });\n\n // Sync messages from log.jsonl that arrived while we were offline or busy\n // Exclude the current message (it will be added via prompt())\n // Default sync range is 10 days (handled by syncLogToSessionManager)\n // Thread filter ensures only messages from this session's thread are synced\n const threadFilter = message.sessionKey.includes(\":\")\n ? { scope: \"thread\" as const, rootTs, threadTs: message.threadTs }\n : { scope: \"top-level\" as const, rootTs };\n const syncedCount = await syncLogToSessionManager(\n sessionManager,\n channelDir,\n message.id,\n undefined,\n threadFilter,\n );\n if (syncedCount > 0) {\n log.logInfo(`[${channelId}] Synced ${syncedCount} messages from log.jsonl`);\n }\n\n // Reload messages from context.jsonl\n // This picks up any messages synced above\n const reloadedSession = sessionManager.buildSessionContext();\n if (reloadedSession.messages.length > 0) {\n agent.replaceMessages(reloadedSession.messages);\n log.logInfo(\n `[${channelId}] Reloaded ${reloadedSession.messages.length} messages from context`,\n );\n }\n\n // Update system prompt with fresh memory, channel/user info, and skills\n const memory = await getMemory(channelDir);\n const skills = loadMamaSkills(channelDir, workspacePath);\n const systemPrompt = buildSystemPrompt(\n workspacePath,\n channelId,\n memory,\n sandboxConfig,\n platform,\n skills,\n );\n session.agent.setSystemPrompt(systemPrompt);\n\n // Set up file upload function\n setUploadFunction(async (filePath: string, title?: string) => {\n const hostPath = translateToHostPath(filePath, channelDir, workspacePath, channelId);\n await responseCtx.uploadFile(hostPath, title);\n });\n\n // Reset per-run state\n runState.responseCtx = responseCtx;\n runState.logCtx = {\n channelId: sessionChannel,\n userName: message.userName,\n channelName: undefined,\n sessionId: sessionUuid,\n };\n runState.pendingTools.clear();\n runState.totalUsage = {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n };\n runState.llmCallCount = 0;\n runState.stopReason = \"stop\";\n runState.errorMessage = undefined;\n\n // Create queue for this run\n let queueChain = Promise.resolve();\n runState.queue = {\n enqueue(fn: () => Promise<void>, errorContext: string): void {\n queueChain = queueChain.then(async () => {\n try {\n await fn();\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n log.logWarning(`API error (${errorContext})`, errMsg);\n try {\n // Split long error messages to avoid msg_too_long\n const errParts = splitForSlack(`_Error: ${errMsg}_`);\n for (const part of errParts) {\n await responseCtx.respondInThread(part);\n }\n } catch {\n // Ignore\n }\n }\n });\n },\n enqueueMessage(\n text: string,\n target: \"main\" | \"thread\",\n errorContext: string,\n _doLog = true,\n ): void {\n const parts = splitForSlack(text);\n for (const part of parts) {\n this.enqueue(\n () =>\n target === \"main\" ? responseCtx.respond(part) : responseCtx.respondInThread(part),\n errorContext,\n );\n }\n },\n };\n\n // Log context info\n log.logInfo(\n `Context sizes - system: ${systemPrompt.length} chars, memory: ${memory.length} chars`,\n );\n log.logInfo(`Channels: ${platform.channels.length}, Users: ${platform.users.length}`);\n\n // Build user message with timestamp and username prefix\n // Format: \"[YYYY-MM-DD HH:MM:SS+HH:MM] [username]: message\" so LLM knows when and who\n const now = new Date();\n const pad = (n: number) => n.toString().padStart(2, \"0\");\n const offset = -now.getTimezoneOffset();\n const offsetSign = offset >= 0 ? \"+\" : \"-\";\n const offsetHours = pad(Math.floor(Math.abs(offset) / 60));\n const offsetMins = pad(Math.abs(offset) % 60);\n const timestamp = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}${offsetSign}${offsetHours}:${offsetMins}`;\n const threadContext = message.threadTs ? ` [in-thread:${message.threadTs}]` : \"\";\n let userMessage = `[${timestamp}] [${message.userName || \"unknown\"}]${threadContext}: ${message.text}`;\n\n const imageAttachments: ImageContent[] = [];\n const nonImagePaths: string[] = [];\n\n for (const a of message.attachments || []) {\n // a.localPath is the path relative to the workspace (same as old a.local)\n const fullPath = `${workspacePath}/${a.localPath}`;\n const mimeType = getImageMimeType(a.localPath);\n\n if (mimeType && existsSync(fullPath)) {\n try {\n imageAttachments.push({\n type: \"image\",\n mimeType,\n data: readFileSync(fullPath).toString(\"base64\"),\n });\n } catch {\n nonImagePaths.push(fullPath);\n }\n } else {\n nonImagePaths.push(fullPath);\n }\n }\n\n if (nonImagePaths.length > 0) {\n userMessage += `\\n\\n<slack_attachments>\\n${nonImagePaths.join(\"\\n\")}\\n</slack_attachments>`;\n }\n\n // Debug: write context to last_prompt.jsonl\n const debugContext = {\n systemPrompt,\n messages: session.messages,\n newUserMessage: userMessage,\n imageAttachmentCount: imageAttachments.length,\n };\n await writeFile(join(channelDir, \"last_prompt.jsonl\"), JSON.stringify(debugContext, null, 2));\n addLifecycleBreadcrumb(\"agent.prompt.sent\", {\n provider: model.provider,\n model: agentConfig.model,\n channel_id: sessionChannel,\n session_id: sessionUuid,\n attachment_count: message.attachments?.length ?? 0,\n image_attachment_count: imageAttachments.length,\n });\n\n await session.prompt(\n userMessage,\n imageAttachments.length > 0 ? { images: imageAttachments } : undefined,\n );\n\n // Wait for queued messages\n await queueChain;\n\n // Handle error case - update main message and post error to thread\n if (runState.stopReason === \"error\" && runState.errorMessage) {\n try {\n await responseCtx.replaceResponse(\"_Sorry, something went wrong_\");\n // Split long error messages to avoid msg_too_long\n const errorParts = splitForSlack(`_Error: ${runState.errorMessage}_`);\n for (const part of errorParts) {\n await responseCtx.respondInThread(part);\n }\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n log.logWarning(\"Failed to post error message\", errMsg);\n }\n } else {\n // Final message update\n const messages = session.messages;\n const lastAssistant = messages.filter((m) => m.role === \"assistant\").pop();\n const finalText =\n lastAssistant?.content\n .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\\n\") || \"\";\n\n // Check for [SILENT] marker - delete message and thread instead of posting\n if (finalText.trim() === \"[SILENT]\" || finalText.trim().startsWith(\"[SILENT]\")) {\n try {\n await responseCtx.deleteResponse();\n log.logInfo(\"Silent response - deleted message and thread\");\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n log.logWarning(\"Failed to delete message for silent response\", errMsg);\n }\n } else if (finalText.trim()) {\n try {\n const mainText =\n finalText.length > SLACK_MAX_LENGTH\n ? `${finalText.substring(0, SLACK_MAX_LENGTH - 50)}\\n\\n_(see thread for full response)_`\n : finalText;\n await responseCtx.replaceResponse(mainText);\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n log.logWarning(\"Failed to replace message with final text\", errMsg);\n }\n }\n }\n\n // Log usage summary with context info\n if (runState.totalUsage.cost.total > 0) {\n // Get last non-aborted assistant message for context calculation\n const messages = session.messages;\n const lastAssistantMessage = messages\n .slice()\n .reverse()\n .find((m) => m.role === \"assistant\" && (m as any).stopReason !== \"aborted\") as any;\n\n const contextTokens = lastAssistantMessage\n ? lastAssistantMessage.usage.input +\n lastAssistantMessage.usage.output +\n lastAssistantMessage.usage.cacheRead +\n lastAssistantMessage.usage.cacheWrite\n : 0;\n const contextWindow = model.contextWindow || 200000;\n\n // Run-level Sentry metrics\n const { totalUsage } = runState;\n const runMetricAttributes = metricAttributes({\n provider: model.provider,\n model: agentConfig.model,\n channel_id: sessionChannel,\n session_id: sessionUuid,\n stop_reason: runState.stopReason,\n llm_calls: runState.llmCallCount,\n });\n Sentry.metrics.distribution(\"agent.run.tokens_in\", totalUsage.input, {\n attributes: runMetricAttributes,\n });\n Sentry.metrics.distribution(\"agent.run.tokens_out\", totalUsage.output, {\n attributes: runMetricAttributes,\n });\n Sentry.metrics.distribution(\"agent.run.cache_read\", totalUsage.cacheRead, {\n attributes: runMetricAttributes,\n });\n Sentry.metrics.distribution(\"agent.run.cache_write\", totalUsage.cacheWrite, {\n attributes: runMetricAttributes,\n });\n Sentry.metrics.distribution(\"agent.run.cost\", totalUsage.cost.total, {\n attributes: runMetricAttributes,\n });\n Sentry.metrics.gauge(\"agent.context.utilization\", contextTokens / contextWindow, {\n unit: \"ratio\",\n attributes: runMetricAttributes,\n });\n\n const summary = log.logUsageSummary(\n runState.logCtx!,\n runState.totalUsage,\n contextTokens,\n contextWindow,\n );\n // Split long summaries to avoid msg_too_long\n const summaryParts = splitForSlack(summary);\n for (const part of summaryParts) {\n runState.queue!.enqueue(\n () => responseCtx.respondInThread(part, { style: \"muted\" }),\n \"usage summary\",\n );\n }\n await queueChain;\n }\n\n // Clear run state\n runState.responseCtx = null;\n runState.logCtx = null;\n runState.queue = null;\n\n return { stopReason: runState.stopReason, errorMessage: runState.errorMessage };\n },\n\n abort(): void {\n session.abort();\n },\n\n getCurrentStep(): { toolName?: string; label?: string } | undefined {\n const pending = runState.pendingTools;\n if (pending.size === 0) return undefined;\n // Get the first pending tool\n const first = pending.values().next().value;\n if (!first) return undefined;\n return {\n toolName: first.toolName,\n label: (first.args as { label?: string })?.label,\n };\n },\n };\n}\n\n/**\n * Translate container path back to host path for file operations\n */\nfunction translateToHostPath(\n containerPath: string,\n channelDir: string,\n workspacePath: string,\n channelId: string,\n): string {\n if (workspacePath === \"/workspace\") {\n const prefix = `/workspace/${channelId}/`;\n if (containerPath.startsWith(prefix)) {\n return join(channelDir, containerPath.slice(prefix.length));\n }\n if (containerPath.startsWith(\"/workspace/\")) {\n return join(channelDir, \"..\", containerPath.slice(\"/workspace/\".length));\n }\n }\n return containerPath;\n}\n"]}
package/dist/config.d.ts CHANGED
@@ -5,7 +5,10 @@ export interface AgentConfig {
5
5
  sessionScope?: "thread" | "channel";
6
6
  logFormat?: "console" | "json";
7
7
  logLevel?: "trace" | "debug" | "info" | "warn" | "error";
8
+ sentryDsn?: string;
8
9
  }
9
10
  export declare function loadAgentConfig(workspaceDir: string): AgentConfig;
11
+ export declare function resolveWorkspaceDirFromArgv(args?: string[]): string | undefined;
12
+ export declare function resolveSentryDsn(workspaceDir?: string): string | undefined;
10
13
  export declare function saveAgentConfig(workspaceDir: string, config: Partial<AgentConfig>): void;
11
14
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IACpC,SAAS,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAC1D;AAWD,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,WAAW,CAwBjE;AAED,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAwBxF","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\n\nexport interface AgentConfig {\n provider: string;\n model: string;\n thinkingLevel?: string;\n sessionScope?: \"thread\" | \"channel\";\n logFormat?: \"console\" | \"json\";\n logLevel?: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n}\n\nconst DEFAULTS: AgentConfig = {\n provider: \"anthropic\",\n model: \"claude-sonnet-4-5\",\n thinkingLevel: \"off\",\n sessionScope: \"thread\",\n logFormat: \"console\",\n logLevel: \"info\",\n};\n\nexport function loadAgentConfig(workspaceDir: string): AgentConfig {\n const settingsPath = join(workspaceDir, \"settings.json\");\n\n let fromFile: Partial<AgentConfig> = {};\n if (existsSync(settingsPath)) {\n try {\n const raw = readFileSync(settingsPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n fromFile = parsed as Partial<AgentConfig>;\n }\n } catch {\n // Ignore parse errors, fall through to env/defaults\n }\n }\n\n const provider = fromFile.provider || process.env.MOM_AI_PROVIDER || DEFAULTS.provider;\n const model = fromFile.model || process.env.MOM_AI_MODEL || DEFAULTS.model;\n const thinkingLevel = fromFile.thinkingLevel ?? DEFAULTS.thinkingLevel;\n const sessionScope = fromFile.sessionScope ?? DEFAULTS.sessionScope;\n const logFormat = fromFile.logFormat ?? DEFAULTS.logFormat;\n const logLevel = fromFile.logLevel ?? DEFAULTS.logLevel;\n\n return { provider, model, thinkingLevel, sessionScope, logFormat, logLevel };\n}\n\nexport function saveAgentConfig(workspaceDir: string, config: Partial<AgentConfig>): void {\n const settingsPath = join(workspaceDir, \"settings.json\");\n\n let existing: Partial<AgentConfig> = {};\n if (existsSync(settingsPath)) {\n try {\n const raw = readFileSync(settingsPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n existing = parsed as Partial<AgentConfig>;\n }\n } catch {\n // Start fresh if file is malformed\n }\n }\n\n const merged = { ...existing, ...config };\n\n const dir = dirname(settingsPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n writeFileSync(settingsPath, JSON.stringify(merged, null, 2), \"utf-8\");\n}\n"]}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IACpC,SAAS,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA+BD,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,WAAW,CAYjE;AAED,wBAAgB,2BAA2B,CAAC,IAAI,WAAwB,GAAG,MAAM,GAAG,SAAS,CAuB5F;AAED,wBAAgB,gBAAgB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAS1E;AAED,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAwBxF","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\n\nexport interface AgentConfig {\n provider: string;\n model: string;\n thinkingLevel?: string;\n sessionScope?: \"thread\" | \"channel\";\n logFormat?: \"console\" | \"json\";\n logLevel?: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n sentryDsn?: string;\n}\n\nconst DEFAULTS: AgentConfig = {\n provider: \"anthropic\",\n model: \"claude-sonnet-4-5\",\n thinkingLevel: \"off\",\n sessionScope: \"thread\",\n logFormat: \"console\",\n logLevel: \"info\",\n};\n\nfunction loadRawAgentConfig(workspaceDir: string): Partial<AgentConfig> {\n const settingsPath = join(workspaceDir, \"settings.json\");\n\n if (!existsSync(settingsPath)) {\n return {};\n }\n\n try {\n const raw = readFileSync(settingsPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n return parsed as Partial<AgentConfig>;\n }\n } catch {\n // Ignore parse errors, fall through to env/defaults\n }\n\n return {};\n}\n\nexport function loadAgentConfig(workspaceDir: string): AgentConfig {\n const fromFile = loadRawAgentConfig(workspaceDir);\n\n const provider = fromFile.provider || process.env.MOM_AI_PROVIDER || DEFAULTS.provider;\n const model = fromFile.model || process.env.MOM_AI_MODEL || DEFAULTS.model;\n const thinkingLevel = fromFile.thinkingLevel ?? DEFAULTS.thinkingLevel;\n const sessionScope = fromFile.sessionScope ?? DEFAULTS.sessionScope;\n const logFormat = fromFile.logFormat ?? DEFAULTS.logFormat;\n const logLevel = fromFile.logLevel ?? DEFAULTS.logLevel;\n const sentryDsn = fromFile.sentryDsn ?? process.env.SENTRY_DSN;\n\n return { provider, model, thinkingLevel, sessionScope, logFormat, logLevel, sentryDsn };\n}\n\nexport function resolveWorkspaceDirFromArgv(args = process.argv.slice(2)): string | undefined {\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === \"--sandbox\" || arg === \"--download\") {\n i += 1;\n continue;\n }\n\n if (arg === \"--version\" || arg === \"-v\" || arg === \"-V\") {\n continue;\n }\n\n if (arg.startsWith(\"--sandbox=\") || arg.startsWith(\"--download=\")) {\n continue;\n }\n\n if (!arg.startsWith(\"-\")) {\n return arg;\n }\n }\n\n return undefined;\n}\n\nexport function resolveSentryDsn(workspaceDir?: string): string | undefined {\n if (workspaceDir) {\n const fromFile = loadRawAgentConfig(workspaceDir);\n if (fromFile.sentryDsn) {\n return fromFile.sentryDsn;\n }\n }\n\n return process.env.SENTRY_DSN;\n}\n\nexport function saveAgentConfig(workspaceDir: string, config: Partial<AgentConfig>): void {\n const settingsPath = join(workspaceDir, \"settings.json\");\n\n let existing: Partial<AgentConfig> = {};\n if (existsSync(settingsPath)) {\n try {\n const raw = readFileSync(settingsPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n existing = parsed as Partial<AgentConfig>;\n }\n } catch {\n // Start fresh if file is malformed\n }\n }\n\n const merged = { ...existing, ...config };\n\n const dir = dirname(settingsPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n writeFileSync(settingsPath, JSON.stringify(merged, null, 2), \"utf-8\");\n}\n"]}
package/dist/config.js CHANGED
@@ -8,28 +8,61 @@ const DEFAULTS = {
8
8
  logFormat: "console",
9
9
  logLevel: "info",
10
10
  };
11
- export function loadAgentConfig(workspaceDir) {
11
+ function loadRawAgentConfig(workspaceDir) {
12
12
  const settingsPath = join(workspaceDir, "settings.json");
13
- let fromFile = {};
14
- if (existsSync(settingsPath)) {
15
- try {
16
- const raw = readFileSync(settingsPath, "utf-8");
17
- const parsed = JSON.parse(raw);
18
- if (parsed && typeof parsed === "object") {
19
- fromFile = parsed;
20
- }
21
- }
22
- catch {
23
- // Ignore parse errors, fall through to env/defaults
13
+ if (!existsSync(settingsPath)) {
14
+ return {};
15
+ }
16
+ try {
17
+ const raw = readFileSync(settingsPath, "utf-8");
18
+ const parsed = JSON.parse(raw);
19
+ if (parsed && typeof parsed === "object") {
20
+ return parsed;
24
21
  }
25
22
  }
23
+ catch {
24
+ // Ignore parse errors, fall through to env/defaults
25
+ }
26
+ return {};
27
+ }
28
+ export function loadAgentConfig(workspaceDir) {
29
+ const fromFile = loadRawAgentConfig(workspaceDir);
26
30
  const provider = fromFile.provider || process.env.MOM_AI_PROVIDER || DEFAULTS.provider;
27
31
  const model = fromFile.model || process.env.MOM_AI_MODEL || DEFAULTS.model;
28
32
  const thinkingLevel = fromFile.thinkingLevel ?? DEFAULTS.thinkingLevel;
29
33
  const sessionScope = fromFile.sessionScope ?? DEFAULTS.sessionScope;
30
34
  const logFormat = fromFile.logFormat ?? DEFAULTS.logFormat;
31
35
  const logLevel = fromFile.logLevel ?? DEFAULTS.logLevel;
32
- return { provider, model, thinkingLevel, sessionScope, logFormat, logLevel };
36
+ const sentryDsn = fromFile.sentryDsn ?? process.env.SENTRY_DSN;
37
+ return { provider, model, thinkingLevel, sessionScope, logFormat, logLevel, sentryDsn };
38
+ }
39
+ export function resolveWorkspaceDirFromArgv(args = process.argv.slice(2)) {
40
+ for (let i = 0; i < args.length; i++) {
41
+ const arg = args[i];
42
+ if (arg === "--sandbox" || arg === "--download") {
43
+ i += 1;
44
+ continue;
45
+ }
46
+ if (arg === "--version" || arg === "-v" || arg === "-V") {
47
+ continue;
48
+ }
49
+ if (arg.startsWith("--sandbox=") || arg.startsWith("--download=")) {
50
+ continue;
51
+ }
52
+ if (!arg.startsWith("-")) {
53
+ return arg;
54
+ }
55
+ }
56
+ return undefined;
57
+ }
58
+ export function resolveSentryDsn(workspaceDir) {
59
+ if (workspaceDir) {
60
+ const fromFile = loadRawAgentConfig(workspaceDir);
61
+ if (fromFile.sentryDsn) {
62
+ return fromFile.sentryDsn;
63
+ }
64
+ }
65
+ return process.env.SENTRY_DSN;
33
66
  }
34
67
  export function saveAgentConfig(workspaceDir, config) {
35
68
  const settingsPath = join(workspaceDir, "settings.json");
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\n\nexport interface AgentConfig {\n provider: string;\n model: string;\n thinkingLevel?: string;\n sessionScope?: \"thread\" | \"channel\";\n logFormat?: \"console\" | \"json\";\n logLevel?: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n}\n\nconst DEFAULTS: AgentConfig = {\n provider: \"anthropic\",\n model: \"claude-sonnet-4-5\",\n thinkingLevel: \"off\",\n sessionScope: \"thread\",\n logFormat: \"console\",\n logLevel: \"info\",\n};\n\nexport function loadAgentConfig(workspaceDir: string): AgentConfig {\n const settingsPath = join(workspaceDir, \"settings.json\");\n\n let fromFile: Partial<AgentConfig> = {};\n if (existsSync(settingsPath)) {\n try {\n const raw = readFileSync(settingsPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n fromFile = parsed as Partial<AgentConfig>;\n }\n } catch {\n // Ignore parse errors, fall through to env/defaults\n }\n }\n\n const provider = fromFile.provider || process.env.MOM_AI_PROVIDER || DEFAULTS.provider;\n const model = fromFile.model || process.env.MOM_AI_MODEL || DEFAULTS.model;\n const thinkingLevel = fromFile.thinkingLevel ?? DEFAULTS.thinkingLevel;\n const sessionScope = fromFile.sessionScope ?? DEFAULTS.sessionScope;\n const logFormat = fromFile.logFormat ?? DEFAULTS.logFormat;\n const logLevel = fromFile.logLevel ?? DEFAULTS.logLevel;\n\n return { provider, model, thinkingLevel, sessionScope, logFormat, logLevel };\n}\n\nexport function saveAgentConfig(workspaceDir: string, config: Partial<AgentConfig>): void {\n const settingsPath = join(workspaceDir, \"settings.json\");\n\n let existing: Partial<AgentConfig> = {};\n if (existsSync(settingsPath)) {\n try {\n const raw = readFileSync(settingsPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n existing = parsed as Partial<AgentConfig>;\n }\n } catch {\n // Start fresh if file is malformed\n }\n }\n\n const merged = { ...existing, ...config };\n\n const dir = dirname(settingsPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n writeFileSync(settingsPath, JSON.stringify(merged, null, 2), \"utf-8\");\n}\n"]}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\n\nexport interface AgentConfig {\n provider: string;\n model: string;\n thinkingLevel?: string;\n sessionScope?: \"thread\" | \"channel\";\n logFormat?: \"console\" | \"json\";\n logLevel?: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n sentryDsn?: string;\n}\n\nconst DEFAULTS: AgentConfig = {\n provider: \"anthropic\",\n model: \"claude-sonnet-4-5\",\n thinkingLevel: \"off\",\n sessionScope: \"thread\",\n logFormat: \"console\",\n logLevel: \"info\",\n};\n\nfunction loadRawAgentConfig(workspaceDir: string): Partial<AgentConfig> {\n const settingsPath = join(workspaceDir, \"settings.json\");\n\n if (!existsSync(settingsPath)) {\n return {};\n }\n\n try {\n const raw = readFileSync(settingsPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n return parsed as Partial<AgentConfig>;\n }\n } catch {\n // Ignore parse errors, fall through to env/defaults\n }\n\n return {};\n}\n\nexport function loadAgentConfig(workspaceDir: string): AgentConfig {\n const fromFile = loadRawAgentConfig(workspaceDir);\n\n const provider = fromFile.provider || process.env.MOM_AI_PROVIDER || DEFAULTS.provider;\n const model = fromFile.model || process.env.MOM_AI_MODEL || DEFAULTS.model;\n const thinkingLevel = fromFile.thinkingLevel ?? DEFAULTS.thinkingLevel;\n const sessionScope = fromFile.sessionScope ?? DEFAULTS.sessionScope;\n const logFormat = fromFile.logFormat ?? DEFAULTS.logFormat;\n const logLevel = fromFile.logLevel ?? DEFAULTS.logLevel;\n const sentryDsn = fromFile.sentryDsn ?? process.env.SENTRY_DSN;\n\n return { provider, model, thinkingLevel, sessionScope, logFormat, logLevel, sentryDsn };\n}\n\nexport function resolveWorkspaceDirFromArgv(args = process.argv.slice(2)): string | undefined {\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === \"--sandbox\" || arg === \"--download\") {\n i += 1;\n continue;\n }\n\n if (arg === \"--version\" || arg === \"-v\" || arg === \"-V\") {\n continue;\n }\n\n if (arg.startsWith(\"--sandbox=\") || arg.startsWith(\"--download=\")) {\n continue;\n }\n\n if (!arg.startsWith(\"-\")) {\n return arg;\n }\n }\n\n return undefined;\n}\n\nexport function resolveSentryDsn(workspaceDir?: string): string | undefined {\n if (workspaceDir) {\n const fromFile = loadRawAgentConfig(workspaceDir);\n if (fromFile.sentryDsn) {\n return fromFile.sentryDsn;\n }\n }\n\n return process.env.SENTRY_DSN;\n}\n\nexport function saveAgentConfig(workspaceDir: string, config: Partial<AgentConfig>): void {\n const settingsPath = join(workspaceDir, \"settings.json\");\n\n let existing: Partial<AgentConfig> = {};\n if (existsSync(settingsPath)) {\n try {\n const raw = readFileSync(settingsPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n existing = parsed as Partial<AgentConfig>;\n }\n } catch {\n // Start fresh if file is malformed\n }\n }\n\n const merged = { ...existing, ...config };\n\n const dir = dirname(settingsPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n writeFileSync(settingsPath, JSON.stringify(merged, null, 2), \"utf-8\");\n}\n"]}
package/dist/context.d.ts CHANGED
@@ -23,6 +23,8 @@ export interface TimeRange {
23
23
  * preventing cross-thread context contamination.
24
24
  */
25
25
  export interface ThreadFilter {
26
+ /** Filter mode: a specific thread, or top-level messages only for persistent channel/chat sessions */
27
+ scope?: "thread" | "top-level";
26
28
  /** The root message timestamp (user's original message ts, derived from sessionKey) */
27
29
  rootTs: string;
28
30
  /** The thread anchor timestamp (bot's first reply ts, used as thread_ts by Slack replies) */
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EACL,KAAK,cAAc,EAEnB,eAAe,EAChB,MAAM,+BAA+B,CAAC;AASvC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAiBD;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;IACf,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAC3C,cAAc,EAAE,cAAc,EAC9B,UAAU,EAAE,MAAM,EAClB,cAAc,CAAC,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,SAAS,EACrB,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,MAAM,CAAC,CAiGjB;AASD,wBAAgB,yBAAyB,CAAC,aAAa,EAAE,MAAM,GAAG,eAAe,CAEhF","sourcesContent":["/**\n * Context management for mama.\n *\n * Mama uses two files per channel:\n * - context.jsonl: Structured API messages for LLM context (same format as coding-agent sessions)\n * - log.jsonl: Human-readable channel history for grep (no tool results)\n *\n * This module provides:\n * - syncLogToSessionManager: Syncs messages from log.jsonl to SessionManager\n * - createMamaSettingsManager: Creates a SettingsManager backed by workspace settings.json\n */\n\nimport type { UserMessage } from \"@mariozechner/pi-ai\";\nimport {\n type SessionManager,\n type SessionMessageEntry,\n SettingsManager,\n} from \"@mariozechner/pi-coding-agent\";\nimport { existsSync } from \"fs\";\nimport { readFile } from \"fs/promises\";\nimport { join } from \"path\";\n\n// ============================================================================\n// Sync log.jsonl to SessionManager\n// ============================================================================\n\n/**\n * Time range for filtering log messages\n */\nexport interface TimeRange {\n start: number; // Unix timestamp in ms\n end: number;\n}\n\n/**\n * Default number of days to sync when no time range is specified\n */\nconst DEFAULT_SYNC_DAYS = 10;\n\ninterface LogMessage {\n date?: string;\n ts?: string;\n threadTs?: string;\n user?: string;\n userName?: string;\n text?: string;\n isBot?: boolean;\n}\n\n/**\n * Thread filter for scoping log sync to a specific thread session.\n * When provided, only messages belonging to this thread are synced,\n * preventing cross-thread context contamination.\n */\nexport interface ThreadFilter {\n /** The root message timestamp (user's original message ts, derived from sessionKey) */\n rootTs: string;\n /** The thread anchor timestamp (bot's first reply ts, used as thread_ts by Slack replies) */\n threadTs?: string;\n}\n\n/**\n * Sync user messages from log.jsonl to SessionManager.\n *\n * This ensures that messages logged while mama wasn't running (channel chatter,\n * backfilled messages, messages while busy) are added to the LLM context.\n *\n * @param sessionManager - The SessionManager to sync to\n * @param channelDir - Path to channel directory containing log.jsonl\n * @param excludeSlackTs - Slack timestamp of current message (will be added via prompt(), not sync)\n * @param timeRange - Optional time range to filter log entries (defaults to last 10 days)\n * @param threadFilter - Optional thread filter to scope sync to a specific thread\n * @returns Number of messages synced\n */\nexport async function syncLogToSessionManager(\n sessionManager: SessionManager,\n channelDir: string,\n excludeSlackTs?: string,\n timeRange?: TimeRange,\n threadFilter?: ThreadFilter,\n): Promise<number> {\n // Calculate default time range (last 10 days) if not provided\n const now = Date.now();\n const defaultStart = now - DEFAULT_SYNC_DAYS * 24 * 60 * 60 * 1000;\n const range = timeRange ?? { start: defaultStart, end: now };\n const logFile = join(channelDir, \"log.jsonl\");\n\n if (!existsSync(logFile)) return 0;\n\n // Build set of existing timestamps from session entries\n // We use ts (Slack timestamp) as the unique key instead of message content\n const existingTimestamps = new Set<string>();\n for (const entry of sessionManager.getEntries()) {\n if (entry.type === \"message\") {\n const msgEntry = entry as SessionMessageEntry;\n // SessionMessageEntry has a timestamp field (number, Unix ms)\n if (msgEntry.timestamp) {\n existingTimestamps.add(msgEntry.timestamp.toString());\n }\n }\n }\n\n // Read log.jsonl and find user messages not in context\n const logContent = await readFile(logFile, \"utf-8\");\n const logLines = logContent.trim().split(\"\\n\").filter(Boolean);\n\n const newMessages: Array<{ timestamp: number; message: UserMessage }> = [];\n\n for (const line of logLines) {\n try {\n const logMsg: LogMessage = JSON.parse(line);\n\n const slackTs = logMsg.ts;\n const date = logMsg.date;\n if (!slackTs || !date) continue;\n\n // Skip the current message being processed (will be added via prompt())\n if (excludeSlackTs && slackTs === excludeSlackTs) continue;\n\n // Skip bot messages - added through agent flow\n if (logMsg.isBot) continue;\n\n // Thread filtering: only sync messages belonging to this session's thread\n if (threadFilter) {\n if (logMsg.threadTs) {\n // Thread reply: only include if threadTs matches our thread anchor or rootTs\n if (\n logMsg.threadTs !== threadFilter.threadTs &&\n logMsg.threadTs !== threadFilter.rootTs\n ) {\n continue;\n }\n } else {\n // Top-level message: only include if it's this session's root message\n if (slackTs !== threadFilter.rootTs) {\n continue;\n }\n }\n }\n\n // Skip if this Slack timestamp is already in the session (dedupe by ts, not content)\n // Convert Slack ts (e.g., \"1234567890.123456\") to Unix ms for comparison\n const slackTsMs = Math.floor(parseFloat(slackTs) * 1000).toString();\n if (existingTimestamps.has(slackTsMs)) continue;\n\n // Build the message text as it would appear in context\n const threadContext = logMsg.threadTs ? ` [in-thread:${logMsg.threadTs}]` : \"\";\n const messageText = `[${logMsg.userName || logMsg.user || \"unknown\"}]${threadContext}: ${logMsg.text || \"\"}`;\n\n const msgTime = new Date(date).getTime() || Date.now();\n\n // Skip messages outside the time range\n if (msgTime < range.start || msgTime > range.end) continue;\n\n const userMessage: UserMessage = {\n role: \"user\",\n content: [{ type: \"text\", text: messageText }],\n timestamp: msgTime,\n };\n\n newMessages.push({ timestamp: msgTime, message: userMessage });\n existingTimestamps.add(slackTsMs); // Track to avoid duplicates within this sync\n } catch {\n // Skip malformed lines\n }\n }\n\n if (newMessages.length === 0) return 0;\n\n // Sort by timestamp and add to session\n newMessages.sort((a, b) => a.timestamp - b.timestamp);\n\n for (const { message } of newMessages) {\n sessionManager.appendMessage(message);\n }\n\n return newMessages.length;\n}\n\n// ============================================================================\n// Settings manager for mama\n// ============================================================================\n\n// Mama manages model/provider config through its own config.ts / settings.json.\n// We use an in-memory SettingsManager so AgentSession has valid defaults\n// without interfering with coding-agent's global settings files.\nexport function createMamaSettingsManager(_workspaceDir: string): SettingsManager {\n return SettingsManager.inMemory();\n}\n"]}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EACL,KAAK,cAAc,EAEnB,eAAe,EAChB,MAAM,+BAA+B,CAAC;AASvC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAiBD;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,sGAAsG;IACtG,KAAK,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC/B,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;IACf,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAC3C,cAAc,EAAE,cAAc,EAC9B,UAAU,EAAE,MAAM,EAClB,cAAc,CAAC,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,SAAS,EACrB,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,MAAM,CAAC,CAyGjB;AASD,wBAAgB,yBAAyB,CAAC,aAAa,EAAE,MAAM,GAAG,eAAe,CAEhF","sourcesContent":["/**\n * Context management for mama.\n *\n * Mama uses two files per channel:\n * - context.jsonl: Structured API messages for LLM context (same format as coding-agent sessions)\n * - log.jsonl: Human-readable channel history for grep (no tool results)\n *\n * This module provides:\n * - syncLogToSessionManager: Syncs messages from log.jsonl to SessionManager\n * - createMamaSettingsManager: Creates a SettingsManager backed by workspace settings.json\n */\n\nimport type { UserMessage } from \"@mariozechner/pi-ai\";\nimport {\n type SessionManager,\n type SessionMessageEntry,\n SettingsManager,\n} from \"@mariozechner/pi-coding-agent\";\nimport { existsSync } from \"fs\";\nimport { readFile } from \"fs/promises\";\nimport { join } from \"path\";\n\n// ============================================================================\n// Sync log.jsonl to SessionManager\n// ============================================================================\n\n/**\n * Time range for filtering log messages\n */\nexport interface TimeRange {\n start: number; // Unix timestamp in ms\n end: number;\n}\n\n/**\n * Default number of days to sync when no time range is specified\n */\nconst DEFAULT_SYNC_DAYS = 10;\n\ninterface LogMessage {\n date?: string;\n ts?: string;\n threadTs?: string;\n user?: string;\n userName?: string;\n text?: string;\n isBot?: boolean;\n}\n\n/**\n * Thread filter for scoping log sync to a specific thread session.\n * When provided, only messages belonging to this thread are synced,\n * preventing cross-thread context contamination.\n */\nexport interface ThreadFilter {\n /** Filter mode: a specific thread, or top-level messages only for persistent channel/chat sessions */\n scope?: \"thread\" | \"top-level\";\n /** The root message timestamp (user's original message ts, derived from sessionKey) */\n rootTs: string;\n /** The thread anchor timestamp (bot's first reply ts, used as thread_ts by Slack replies) */\n threadTs?: string;\n}\n\n/**\n * Sync user messages from log.jsonl to SessionManager.\n *\n * This ensures that messages logged while mama wasn't running (channel chatter,\n * backfilled messages, messages while busy) are added to the LLM context.\n *\n * @param sessionManager - The SessionManager to sync to\n * @param channelDir - Path to channel directory containing log.jsonl\n * @param excludeSlackTs - Slack timestamp of current message (will be added via prompt(), not sync)\n * @param timeRange - Optional time range to filter log entries (defaults to last 10 days)\n * @param threadFilter - Optional thread filter to scope sync to a specific thread\n * @returns Number of messages synced\n */\nexport async function syncLogToSessionManager(\n sessionManager: SessionManager,\n channelDir: string,\n excludeSlackTs?: string,\n timeRange?: TimeRange,\n threadFilter?: ThreadFilter,\n): Promise<number> {\n // Calculate default time range (last 10 days) if not provided\n const now = Date.now();\n const defaultStart = now - DEFAULT_SYNC_DAYS * 24 * 60 * 60 * 1000;\n const range = timeRange ?? { start: defaultStart, end: now };\n const logFile = join(channelDir, \"log.jsonl\");\n\n if (!existsSync(logFile)) return 0;\n\n // Build set of existing timestamps from session entries\n // We use ts (Slack timestamp) as the unique key instead of message content\n const existingTimestamps = new Set<string>();\n for (const entry of sessionManager.getEntries()) {\n if (entry.type === \"message\") {\n const msgEntry = entry as SessionMessageEntry;\n // SessionMessageEntry has a timestamp field (number, Unix ms)\n if (msgEntry.timestamp) {\n existingTimestamps.add(msgEntry.timestamp.toString());\n }\n }\n }\n\n // Read log.jsonl and find user messages not in context\n const logContent = await readFile(logFile, \"utf-8\");\n const logLines = logContent.trim().split(\"\\n\").filter(Boolean);\n\n const newMessages: Array<{ timestamp: number; message: UserMessage }> = [];\n\n for (const line of logLines) {\n try {\n const logMsg: LogMessage = JSON.parse(line);\n\n const slackTs = logMsg.ts;\n const date = logMsg.date;\n if (!slackTs || !date) continue;\n\n // Skip the current message being processed (will be added via prompt())\n if (excludeSlackTs && slackTs === excludeSlackTs) continue;\n\n // Skip bot messages - added through agent flow\n if (logMsg.isBot) continue;\n\n // Thread filtering: only sync messages belonging to this session's thread\n if (threadFilter) {\n if (threadFilter.scope === \"top-level\") {\n // Persistent channel/chat sessions should only ingest top-level messages.\n // This avoids pulling in unrelated replies from other threads.\n if (logMsg.threadTs) {\n continue;\n }\n } else {\n if (logMsg.threadTs) {\n // Thread reply: only include if threadTs matches our thread anchor or rootTs\n if (\n logMsg.threadTs !== threadFilter.threadTs &&\n logMsg.threadTs !== threadFilter.rootTs\n ) {\n continue;\n }\n } else {\n // Top-level message: only include if it's this session's root message\n if (slackTs !== threadFilter.rootTs) {\n continue;\n }\n }\n }\n }\n\n // Skip if this Slack timestamp is already in the session (dedupe by ts, not content)\n // Convert Slack ts (e.g., \"1234567890.123456\") to Unix ms for comparison\n const slackTsMs = Math.floor(parseFloat(slackTs) * 1000).toString();\n if (existingTimestamps.has(slackTsMs)) continue;\n\n // Build the message text as it would appear in context\n const threadContext = logMsg.threadTs ? ` [in-thread:${logMsg.threadTs}]` : \"\";\n const messageText = `[${logMsg.userName || logMsg.user || \"unknown\"}]${threadContext}: ${logMsg.text || \"\"}`;\n\n const msgTime = new Date(date).getTime() || Date.now();\n\n // Skip messages outside the time range\n if (msgTime < range.start || msgTime > range.end) continue;\n\n const userMessage: UserMessage = {\n role: \"user\",\n content: [{ type: \"text\", text: messageText }],\n timestamp: msgTime,\n };\n\n newMessages.push({ timestamp: msgTime, message: userMessage });\n existingTimestamps.add(slackTsMs); // Track to avoid duplicates within this sync\n } catch {\n // Skip malformed lines\n }\n }\n\n if (newMessages.length === 0) return 0;\n\n // Sort by timestamp and add to session\n newMessages.sort((a, b) => a.timestamp - b.timestamp);\n\n for (const { message } of newMessages) {\n sessionManager.appendMessage(message);\n }\n\n return newMessages.length;\n}\n\n// ============================================================================\n// Settings manager for mama\n// ============================================================================\n\n// Mama manages model/provider config through its own config.ts / settings.json.\n// We use an in-memory SettingsManager so AgentSession has valid defaults\n// without interfering with coding-agent's global settings files.\nexport function createMamaSettingsManager(_workspaceDir: string): SettingsManager {\n return SettingsManager.inMemory();\n}\n"]}
package/dist/context.js CHANGED
@@ -69,17 +69,26 @@ export async function syncLogToSessionManager(sessionManager, channelDir, exclud
69
69
  continue;
70
70
  // Thread filtering: only sync messages belonging to this session's thread
71
71
  if (threadFilter) {
72
- if (logMsg.threadTs) {
73
- // Thread reply: only include if threadTs matches our thread anchor or rootTs
74
- if (logMsg.threadTs !== threadFilter.threadTs &&
75
- logMsg.threadTs !== threadFilter.rootTs) {
72
+ if (threadFilter.scope === "top-level") {
73
+ // Persistent channel/chat sessions should only ingest top-level messages.
74
+ // This avoids pulling in unrelated replies from other threads.
75
+ if (logMsg.threadTs) {
76
76
  continue;
77
77
  }
78
78
  }
79
79
  else {
80
- // Top-level message: only include if it's this session's root message
81
- if (slackTs !== threadFilter.rootTs) {
82
- continue;
80
+ if (logMsg.threadTs) {
81
+ // Thread reply: only include if threadTs matches our thread anchor or rootTs
82
+ if (logMsg.threadTs !== threadFilter.threadTs &&
83
+ logMsg.threadTs !== threadFilter.rootTs) {
84
+ continue;
85
+ }
86
+ }
87
+ else {
88
+ // Top-level message: only include if it's this session's root message
89
+ if (slackTs !== threadFilter.rootTs) {
90
+ continue;
91
+ }
83
92
  }
84
93
  }
85
94
  }