/** * User-facing configuration shape for `anima.config.ts`. * * Example: * * import { defineConfig } from '@s0nderlabs/anima-core' * * export default defineConfig({ * identity: { iNFT: null }, // iNFT token id once minted * network: '0g-mainnet', // or '0g-testnet' * storage: { network: '0g-mainnet' }, * brain: { provider: '0xd9966e...' }, // chosen at `anima init` * plugins: ['onchain', 'comms', 'system'], * tools: { 'defi.*': false, 'shell.run': false }, * imports: { claudeCode: true }, * }) */ export type AnimaNetwork = '0g-mainnet' | '0g-testnet' export type AnimaPlugin = 'onchain' | 'comms' | 'system' | 'telegram' | 'webapp' export interface INFTRef { /** ERC-7857 contract address. */ contract: string /** Token id minted to the owner at `anima init`. */ tokenId: string /** Network where the iNFT lives. */ network: AnimaNetwork /** * Block at which the iNFT was minted. Used as the floor for Transfer-event * discovery scans (`chain.balance` no-arg). Optional for backward compat; * pre-Phase-10 configs lack this and the harness backfills lazily by * scanning ERC-721 Transfer logs for the tokenId. */ mintBlock?: string } export type OperatorSourceKind = 'walletconnect' | 'keychain' | 'keystore-file' | 'raw-privkey' /** * Persisted hint about which operator source to use when commands like * `anima` (chat), `anima topup`, and `anima restore` need to talk to the * operator wallet again. Stores enough metadata to reconstruct the signer * without re-prompting the user from scratch (passphrases / QR scans still * happen because they're per-session). */ export interface OperatorSourceHint { source: OperatorSourceKind /** Only for `keychain`: the macOS Keychain service name to read. */ keychainService?: string /** Only for `keystore-file`: absolute or `~`-prefixed path to the JSON keystore. */ keystorePath?: string } export interface AnimaConfig { identity: { iNFT: INFTRef | null /** Operator wallet address that owns the iNFT (section 22.1). */ operator: string | null /** Agent EOA address (separate key, pays infra gas). */ agent: string | null } network: AnimaNetwork storage: { network: AnimaNetwork } brain: { provider: string | null model: string | null /** * v2 (Router brain): which inference "door" this agent uses. * - `'direct'` (default, or ABSENT): the 0G serving-broker path, the agent * wallet signs EIP-712 vouchers per request, `provider` is the on-chain * provider EOA, `model` resolves from that provider's metadata. * - `'router'`: the 0G Router (OpenAI-compatible gateway, `Bearer sk-`). * `model` is the Router model id (e.g. `minimax-m3`); `provider` is unused. * * Absent === `'direct'`. There is no zod/schema validation and * `findAndLoadConfig` returns the raw module, so the build path MUST * coalesce `config.brain.providerKind ?? 'direct'` itself rather than rely * on `defineConfig` defaults having run. */ providerKind?: 'direct' | 'router' /** * Router-only settings (ignored unless `providerKind === 'router'`). This * NEVER holds the `sk-` secret, that is sealed in a sibling encrypted blob * (`router-secrets.encrypted`) co-located with the keystore custody and is * regenerable via headless SIWE. `managementKeyRef` is a non-secret label. */ router?: { /** OpenAI-compatible base URL. Default `https://router-api.0g.ai/v1`. */ baseUrl?: string /** Payment Layer contract address override (defaults per network). */ paymentLayer?: string /** Non-secret label/ref for the sealed management-key blob. */ managementKeyRef?: string } /** * v0.20.0: max assistant output tokens per turn. Default 4096 (was 1024). */ maxOutputTokens?: number /** * v0.20.0: model context window. Used for auto-compaction trigger. * Default 1_000_000 (Qwen 1M target). Override for smaller models. */ contextWindow?: number /** * v0.20.0: pre-flight summarize-fold of older history when running * estimate breaches `threshold * contextWindow`. Set to `null` to * disable. Default: { threshold: 0.5, keepRecent: 8 }. */ compaction?: { threshold?: number keepRecent?: number } | null /** * v0.20.0: persist channel histories to JSONL under * `~/.anima/agents//conversations/`. Loaded on boot, appended per * turn, atomically rewritten on compaction. Default true. */ persistConversations?: boolean } plugins: AnimaPlugin[] /** Glob-level tool allow/deny. Right-most match wins. */ tools: Record imports: { claudeCode: boolean } /** * Phase 6.6: which operator source to use when reconnecting. Optional so * legacy v0.5.0 configs still parse; commands fall back to the interactive * picker when this is missing. */ operator?: OperatorSourceHint | null /** * Phase 7: the agent's `