Files
clawdbot/src/agents/system-prompt-params.ts
2026-01-22 05:20:42 +00:00

106 lines
2.8 KiB
TypeScript

import fs from "node:fs";
import path from "node:path";
import type { ClawdbotConfig } from "../config/config.js";
import {
formatUserTime,
resolveUserTimeFormat,
resolveUserTimezone,
type ResolvedTimeFormat,
} from "./date-time.js";
export type RuntimeInfoInput = {
agentId?: string;
host: string;
os: string;
arch: string;
node: string;
model: string;
defaultModel?: string;
channel?: string;
capabilities?: string[];
/** Supported message actions for the current channel (e.g., react, edit, unsend) */
channelActions?: string[];
repoRoot?: string;
};
export type SystemPromptRuntimeParams = {
runtimeInfo: RuntimeInfoInput;
userTimezone: string;
userTime?: string;
userTimeFormat?: ResolvedTimeFormat;
};
export function buildSystemPromptParams(params: {
config?: ClawdbotConfig;
agentId?: string;
runtime: Omit<RuntimeInfoInput, "agentId">;
workspaceDir?: string;
cwd?: string;
}): SystemPromptRuntimeParams {
const repoRoot = resolveRepoRoot({
config: params.config,
workspaceDir: params.workspaceDir,
cwd: params.cwd,
});
const userTimezone = resolveUserTimezone(params.config?.agents?.defaults?.userTimezone);
const userTimeFormat = resolveUserTimeFormat(params.config?.agents?.defaults?.timeFormat);
const userTime = formatUserTime(new Date(), userTimezone, userTimeFormat);
return {
runtimeInfo: {
agentId: params.agentId,
...params.runtime,
repoRoot,
},
userTimezone,
userTime,
userTimeFormat,
};
}
function resolveRepoRoot(params: {
config?: ClawdbotConfig;
workspaceDir?: string;
cwd?: string;
}): string | undefined {
const configured = params.config?.agents?.defaults?.repoRoot?.trim();
if (configured) {
try {
const resolved = path.resolve(configured);
const stat = fs.statSync(resolved);
if (stat.isDirectory()) return resolved;
} catch {
// ignore invalid config path
}
}
const candidates = [params.workspaceDir, params.cwd]
.map((value) => value?.trim())
.filter(Boolean) as string[];
const seen = new Set<string>();
for (const candidate of candidates) {
const resolved = path.resolve(candidate);
if (seen.has(resolved)) continue;
seen.add(resolved);
const root = findGitRoot(resolved);
if (root) return root;
}
return undefined;
}
function findGitRoot(startDir: string): string | null {
let current = path.resolve(startDir);
for (let i = 0; i < 12; i += 1) {
const gitPath = path.join(current, ".git");
try {
const stat = fs.statSync(gitPath);
if (stat.isDirectory() || stat.isFile()) return current;
} catch {
// ignore missing .git at this level
}
const parent = path.dirname(current);
if (parent === current) break;
current = parent;
}
return null;
}