repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | /** |
| #2 | * leviathan/src/memory/clawd.ts |
| #3 | * |
| #4 | * Bridge from the Leviathan runtime into Clawd Memory. |
| #5 | * The source of truth is the Python ClawdBrain layer in ../MemeBRain. |
| #6 | */ |
| #7 | |
| #8 | import { existsSync } from 'node:fs'; |
| #9 | import { dirname, join, resolve } from 'node:path'; |
| #10 | import { fileURLToPath } from 'node:url'; |
| #11 | import { promisify } from 'node:util'; |
| #12 | import { execFile } from 'node:child_process'; |
| #13 | import type { |
| #14 | ClawState, |
| #15 | ClawdMemoryOptions, |
| #16 | ClawdMemoryRecallInput, |
| #17 | ClawdMemoryRememberInput, |
| #18 | } from '../types.js'; |
| #19 | |
| #20 | const execFileAsync = promisify(execFile); |
| #21 | |
| #22 | export interface ClawdMemoryCommandResult { |
| #23 | ok: boolean; |
| #24 | data?: unknown; |
| #25 | error?: string; |
| #26 | command: string[]; |
| #27 | } |
| #28 | |
| #29 | export interface LeviathanMemoryContext { |
| #30 | query: string; |
| #31 | text: string; |
| #32 | raw?: unknown; |
| #33 | available: boolean; |
| #34 | error?: string; |
| #35 | } |
| #36 | |
| #37 | function moduleDir(): string { |
| #38 | return dirname(fileURLToPath(import.meta.url)); |
| #39 | } |
| #40 | |
| #41 | export function resolveClawdBrainRoot(opts: ClawdMemoryOptions = {}): string | null { |
| #42 | const candidates = [ |
| #43 | opts.brainRoot, |
| #44 | process.env['CLAWD_BRAIN_ROOT'], |
| #45 | join(process.cwd(), 'MemeBRain'), |
| #46 | join(process.cwd(), '..', 'MemeBRain'), |
| #47 | join(process.cwd(), '..', '..', 'MemeBRain'), |
| #48 | join(moduleDir(), '..', '..', '..', 'MemeBRain'), |
| #49 | join(moduleDir(), '..', '..', '..', '..', 'MemeBRain'), |
| #50 | ].filter(Boolean) as string[]; |
| #51 | |
| #52 | for (const candidate of candidates) { |
| #53 | const root = resolve(candidate); |
| #54 | if (existsSync(join(root, 'mnemosyne', 'clawd_brain.py'))) return root; |
| #55 | } |
| #56 | |
| #57 | return null; |
| #58 | } |
| #59 | |
| #60 | async function runClawdBrain(args: string[], opts: ClawdMemoryOptions = {}): Promise<ClawdMemoryCommandResult> { |
| #61 | const root = resolveClawdBrainRoot(opts); |
| #62 | const command = ['-m', 'mnemosyne.clawd_brain', ...args]; |
| #63 | |
| #64 | if (!root) { |
| #65 | return { ok: false, error: 'MemeBRain root not found. Set CLAWD_BRAIN_ROOT.', command }; |
| #66 | } |
| #67 | |
| #68 | const pythonBin = opts.pythonBin ?? process.env['CLAWD_BRAIN_PYTHON'] ?? 'python3'; |
| #69 | const env = { ...process.env }; |
| #70 | if (opts.vault) env['CLAWD_BRAIN_VAULT'] = opts.vault; |
| #71 | |
| #72 | const bankArgs = opts.bank ? ['--bank', opts.bank] : []; |
| #73 | const vaultArgs = opts.vault ? ['--vault', opts.vault] : []; |
| #74 | const fullArgs = ['-m', 'mnemosyne.clawd_brain', ...bankArgs, ...vaultArgs, ...args]; |
| #75 | |
| #76 | try { |
| #77 | const { stdout } = await execFileAsync(pythonBin, fullArgs, { |
| #78 | cwd: root, |
| #79 | env, |
| #80 | timeout: opts.timeoutMs ?? 12_000, |
| #81 | maxBuffer: 1024 * 1024, |
| #82 | }); |
| #83 | const text = stdout.trim(); |
| #84 | return { ok: true, data: text ? JSON.parse(text) : null, command: fullArgs }; |
| #85 | } catch (err) { |
| #86 | const message = err instanceof Error ? err.message : String(err); |
| #87 | return { ok: false, error: message, command: fullArgs }; |
| #88 | } |
| #89 | } |
| #90 | |
| #91 | export async function initClawdMemory(opts: ClawdMemoryOptions = {}): Promise<ClawdMemoryCommandResult> { |
| #92 | return runClawdBrain(['init'], opts); |
| #93 | } |
| #94 | |
| #95 | export async function recallClawdMemory( |
| #96 | input: ClawdMemoryRecallInput, |
| #97 | opts: ClawdMemoryOptions = {}, |
| #98 | ): Promise<ClawdMemoryCommandResult> { |
| #99 | return runClawdBrain(['recall', input.query, '--top-k', String(input.topK ?? 8)], opts); |
| #100 | } |
| #101 | |
| #102 | export async function rememberClawdMemory( |
| #103 | input: ClawdMemoryRememberInput, |
| #104 | opts: ClawdMemoryOptions = {}, |
| #105 | ): Promise<ClawdMemoryCommandResult> { |
| #106 | const args = [ |
| #107 | 'remember', |
| #108 | input.title, |
| #109 | input.content, |
| #110 | '--kind', |
| #111 | input.kind ?? 'note', |
| #112 | '--source', |
| #113 | input.source ?? 'leviathan', |
| #114 | '--importance', |
| #115 | String(input.importance ?? 0.7), |
| #116 | ]; |
| #117 | |
| #118 | for (const tag of input.tags ?? []) args.push('--tag', tag); |
| #119 | return runClawdBrain(args, opts); |
| #120 | } |
| #121 | |
| #122 | export async function researchClawdMemory( |
| #123 | target: string, |
| #124 | tags: string[] = [], |
| #125 | opts: ClawdMemoryOptions = {}, |
| #126 | ): Promise<ClawdMemoryCommandResult> { |
| #127 | const args = ['research', target]; |
| #128 | for (const tag of tags) args.push('--tag', tag); |
| #129 | return runClawdBrain(args, opts); |
| #130 | } |
| #131 | |
| #132 | function compact(value: unknown, max = 1600): string { |
| #133 | const text = typeof value === 'string' ? value : JSON.stringify(value, null, 2); |
| #134 | return text.length > max ? `${text.slice(0, max)}...` : text; |
| #135 | } |
| #136 | |
| #137 | export function buildLeviathanMemoryQuery(state: ClawState, strikeHistory: unknown[]): string { |
| #138 | const pieces = [ |
| #139 | state.identity.name, |
| #140 | state.identity.pubkey, |
| #141 | `depth ${state.depth}`, |
| #142 | `shell v${state.identity.shellVersion}`, |
| #143 | state.shellMd, |
| #144 | compact(strikeHistory, 700), |
| #145 | ]; |
| #146 | return pieces.join('\n'); |
| #147 | } |
| #148 | |
| #149 | export async function loadLeviathanMemoryContext( |
| #150 | state: ClawState, |
| #151 | strikeHistory: unknown[], |
| #152 | opts: ClawdMemoryOptions = {}, |
| #153 | ): Promise<LeviathanMemoryContext> { |
| #154 | const query = buildLeviathanMemoryQuery(state, strikeHistory); |
| #155 | const result = await recallClawdMemory({ query, topK: 6 }, opts); |
| #156 | |
| #157 | if (!result.ok) { |
| #158 | return { |
| #159 | query, |
| #160 | available: false, |
| #161 | text: `Clawd Memory unavailable: ${result.error}`, |
| #162 | error: result.error, |
| #163 | }; |
| #164 | } |
| #165 | |
| #166 | return { |
| #167 | query, |
| #168 | raw: result.data, |
| #169 | available: true, |
| #170 | text: compact(result.data, 2400), |
| #171 | }; |
| #172 | } |
| #173 | |
| #174 | export async function rememberLeviathanStrike( |
| #175 | state: ClawState, |
| #176 | strike: unknown, |
| #177 | opts: ClawdMemoryOptions = {}, |
| #178 | ): Promise<ClawdMemoryCommandResult> { |
| #179 | const title = `Leviathan Tick ${state.tickCount + 1} - ${state.identity.name}`; |
| #180 | const content = [ |
| #181 | `Leviathan ${state.identity.name} (${state.identity.pubkey}) completed a tail-flick.`, |
| #182 | `Depth: ${state.depth}`, |
| #183 | `Shell version: ${state.identity.shellVersion}`, |
| #184 | `Strike: ${compact(strike, 1800)}`, |
| #185 | ].join('\n'); |
| #186 | |
| #187 | return rememberClawdMemory({ |
| #188 | title, |
| #189 | content, |
| #190 | kind: 'agent', |
| #191 | source: 'leviathan', |
| #192 | tags: ['clawd', 'leviathan', 'tail-flick', state.depth], |
| #193 | importance: 0.62, |
| #194 | }, opts); |
| #195 | } |
| #196 |