Visibility internal Owner _ Approver _ Created _ Updated _
optimize.ts
| Field | Value |
|---|---|
| Type | TypeScript |
| Source | Forge/Skills/Forge_Optimizer/scripts/optimize.ts |
| Parent | Forge |
| GitHub | Forge/Skills/Forge_Optimizer/scripts/optimize.ts |
This page is auto-generated. Edit the source to change the content.
#!/usr/bin/env tsx
/**
* optimize.ts — Analyze a past Forge conversation for inefficiencies.
*
* Connects to MongoDB, builds a transcript, sends it to GPT-5.4 with
* Forge_Chat_Prompt.md context, and prints a structured analysis.
*
* Usage:
* npx tsx optimize.ts "Conversation Title"
* npx tsx optimize.ts --latest
* npx tsx optimize.ts --list
* npx tsx optimize.ts --project <ProjectName> [--model <model>]
*
* In project mode, saves the report to {Project}_Optimizer_Report.md
* in the project folder.
*
* Exit codes:
* 0 — Analysis printed successfully
* 1 — Error
*/
import { MongoClient } from 'mongodb';
import pg from 'pg';
import { readFileSync, writeFileSync, existsSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import { execSync } from 'child_process';
// ── Configuration ──────────────────────────────────────────────────────────────
const MONGO_URI = process.env['MONGO_URI'];
const DATABASE = 'test';
const DEFAULT_MODEL = 'gpt-5.4';
const PROJECT_MODEL = 'glm-5.1';
const MAX_OUTPUT_PER_TOOL = 1500; // chars of tool output to include
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
const SKILL_DIR = resolve(SCRIPT_DIR, '..');
const PROMPT_PATH = resolve(SKILL_DIR, 'references', 'extraction_prompt.md');
const FORGE_MD_PATH = resolve(SKILL_DIR, '..', '..', 'Configs', 'Agents', 'Forge_Chat_Prompt.md');
// Patterns to redact from transcripts
const REDACT_PATTERNS: RegExp[] = [
/(MONGO_URI|OPENAI_API_KEY|API_KEY|TOKEN|SECRET|PASSWORD|PRIVATE_KEY)=[^\s\x00"]+/g,
/mongodb:\/\/[^\s"]+/g,
/sk-[a-zA-Z0-9_-]{20,}/g,
];
// ── Types ──────────────────────────────────────────────────────────────────────
interface Conversation {
conversationId: string;
title?: string;
updatedAt?: unknown;
}
interface Message {
sender?: string;
text?: string;
content?: ContentItem[];
}
interface ContentItem {
type?: string;
text?: string;
tool_call?: {
name?: string;
args?: unknown;
output?: unknown;
};
}
interface OpenAIResponse {
choices: Array<{ message: { content: string } }>;
}
// ── MongoDB ────────────────────────────────────────────────────────────────────
async function connect(): Promise<{ client: MongoClient; db: ReturnType<MongoClient['db']> }> {
if (!MONGO_URI) {
console.error('Error: MONGO_URI not found in environment');
process.exit(1);
}
const client = new MongoClient(MONGO_URI);
await client.connect();
return { client, db: client.db(DATABASE) };
}
async function findConversation(
db: ReturnType<MongoClient['db']>,
title?: string,
latest?: boolean,
): Promise<Conversation | null> {
const coll = db.collection<Conversation>('conversations');
if (title) {
const doc = await coll.findOne({ title });
if (doc) return doc;
// Partial match fallback
const docs = await coll
.find(
{ title: { $regex: title, $options: 'i' } },
{ projection: { conversationId: 1, title: 1, updatedAt: 1 } },
)
.sort({ updatedAt: -1 })
.limit(5)
.toArray();
if (docs.length > 0) {
console.log(`No exact match for '${title}'. Partial matches:`);
for (const d of docs) console.log(` ${d.title} (${d.updatedAt})`);
} else {
console.log(`No conversation found matching '${title}'`);
}
return null;
}
if (latest) {
const docs = await coll
.find({}, { projection: { conversationId: 1, title: 1, updatedAt: 1 } })
.sort({ updatedAt: -1 })
.limit(5)
.toArray();
if (docs.length < 2) {
console.log('Not enough conversations to pick a non-current one');
return null;
}
const target = docs[1]; // skip most recent (likely current session)
const doc = await coll.findOne({ conversationId: target.conversationId });
console.log(`Selected: ${doc?.title ?? 'Untitled'} (${doc?.updatedAt})`);
return doc;
}
return null;
}
async function listConversations(
db: ReturnType<MongoClient['db']>,
limit = 15,
): Promise<void> {
const docs = await db
.collection<Conversation>('conversations')
.find({}, { projection: { title: 1, updatedAt: 1 } })
.sort({ updatedAt: -1 })
.limit(limit)
.toArray();
console.log('Recent conversations:');
for (const d of docs) {
console.log(` ${(d.title ?? 'Untitled').padEnd(55)} ${d.updatedAt}`);
}
}
// ── Transcript ─────────────────────────────────────────────────────────────────
function redact(text: string): string {
let result = text;
for (const pattern of REDACT_PATTERNS) {
result = result.replace(pattern, '[REDACTED]');
}
return result;
}
async function buildTranscript(
db: ReturnType<MongoClient['db']>,
conversation: Conversation,
): Promise<string> {
const msgs = await db
.collection<Message>('messages')
.find({ conversationId: conversation.conversationId })
.sort({ createdAt: 1 })
.toArray();
const parts: string[] = [];
for (const msg of msgs) {
const role = msg.sender ?? 'unknown';
const text = msg.text ?? '';
const content = msg.content ?? [];
const lines: string[] = [];
if (text) lines.push(redact(text));
for (const item of content) {
if (item.type === 'tool_call') {
const tc = item.tool_call ?? {};
const name = tc.name ?? 'unknown';
const args = redact(String(tc.args ?? ''));
let output = redact(String(tc.output ?? ''));
if (output.length > MAX_OUTPUT_PER_TOOL) {
output = output.slice(0, MAX_OUTPUT_PER_TOOL) + '\n[...truncated...]';
}
lines.push(`[TOOL CALL] ${name}\nArgs: ${args}\nOutput: ${output}`);
} else if (item.type === 'text') {
const txt = item.text ?? '';
if (txt) lines.push(redact(txt));
}
}
if (lines.length > 0) {
parts.push(`### ${role}\n` + lines.join('\n\n'));
}
}
return parts.join('\n\n---\n\n');
}
// ── LLM Analysis ──────────────────────────────────────────────────────────────
function getApiKey(): string {
const key = process.env['OPENAI_API_KEY'];
if (!key) {
console.error('Error: OPENAI_API_KEY not found');
process.exit(1);
}
return key;
}
function loadPrompt(transcript: string): string {
const raw = readFileSync(PROMPT_PATH, 'utf8');
// Strip YAML frontmatter (between first two --- lines)
const sections = raw.split('---\n');
const body = sections.length >= 3 ? sections.slice(2).join('---\n') : raw;
return body.replace('{transcript}', transcript);
}
async function analyze(transcript: string, apiKey: string, model: string): Promise<string> {
const prompt = loadPrompt(transcript);
const forgeMd = readFileSync(FORGE_MD_PATH, 'utf8');
const messages = [
{
role: 'system',
content:
'You are an expert AI operations analyst reviewing agentic execution ' +
'transcripts. You have the complete Forge operating rules below. ' +
"Your job is to find real problems — not to fill categories with noise.\n\n" +
'Forge_Chat_Prompt.md:\n' +
forgeMd,
},
{ role: 'user', content: prompt },
];
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({
model,
messages,
max_completion_tokens: 2000,
temperature: 0.2,
}),
signal: AbortSignal.timeout(120_000),
});
if (!response.ok) {
throw new Error(`OpenAI API error: ${response.status} ${response.statusText}`);
}
const result = (await response.json()) as OpenAIResponse;
return result.choices[0].message.content;
}
// ── Project mode ────────────────────────────────────────────────────────────
async function fetchProjectConversations(
pgPool: pg.Pool,
projectName: string,
): Promise<Array<{ conversationId: string; agentId: string; phase: string | null }>> {
const result = await pgPool.query(
`SELECT DISTINCT "conversationId", "agentId", phase FROM "AgentJob" WHERE project = $1 ORDER BY "conversationId"`,
[projectName],
);
return result.rows;
}
async function buildProjectTranscript(
db: ReturnType<MongoClient['db']>,
conversationIds: string[],
): Promise<string> {
const parts: string[] = [];
for (const convId of conversationIds) {
const conv = await db.collection('conversations').findOne({ conversationId: convId });
const title = (conv as any)?.title ?? 'Untitled';
parts.push(`## Conversation: ${title} (${convId})`);
const transcript = await buildTranscript(db, conv as Conversation);
parts.push(transcript);
}
return parts.join('\n\n---\n\n');
}
// ── Project report ──────────────────────────────────────────────────────────
function findProjectFolder(projectName: string): string | null {
const repoRoot = resolve(SCRIPT_DIR, '..', '..', '..', '..'); // scripts → repo root
try {
const result = execSync(
`find "${repoRoot}" -path "*/Projects/*" -name "${projectName}_Phase.md" -not -path "*/Archived/*" -not -path "*/.internal/*" -not -path "*/node_modules/*" -not -path "*/.generated/*" -not -path "*/dist/*"`,
{ encoding: 'utf8', timeout: 10_000 },
).trim();
if (result) {
return dirname(result.split('\n')[0]!);
}
} catch {
// find returned nothing or errored
}
return null;
}
function saveProjectReport(projectName: string, analysis: string): string | null {
const projectFolder = findProjectFolder(projectName);
if (!projectFolder) {
console.log(`Warning: Could not locate project folder for "${projectName}" — report not saved to file`);
return null;
}
const reportPath = resolve(projectFolder, `${projectName}_Optimizer_Report.md`);
const today = new Date().toISOString().slice(0, 10);
const runSection = `## Run — ${today}\n\n${analysis}`;
if (existsSync(reportPath)) {
// Append a new run section to the existing file
const existing = readFileSync(reportPath, 'utf8');
const updated = existing.trimEnd() + '\n\n---\n\n' + runSection + '\n';
writeFileSync(reportPath, updated, 'utf8');
console.log(`Appended optimizer report to: ${reportPath}`);
} else {
// Create new report file with frontmatter
const content =
`---\n` +
`title: "${projectName} Optimizer Report"\n` +
`status: published\n` +
`visibility: internal\n` +
`owner: "erik@uvilo.com"\n` +
`created: "${today}"\n` +
`updated: "${today}"\n` +
`---\n\n` +
`# ${projectName} Optimizer Report\n\n` +
`Automated analysis of project conversations, generated by the Forge Optimizer.\n\n` +
`${runSection}\n`;
writeFileSync(reportPath, content, 'utf8');
console.log(`Saved optimizer report to: ${reportPath}`);
}
return reportPath;
}
// ── Main ───────────────────────────────────────────────────────────────────────
async function main(): Promise<void> {
const args = process.argv.slice(2);
if (args.length === 0) {
console.log('Usage: npx tsx optimize.ts <title> | --latest | --list | --project <name> [--model <model>]');
process.exit(1);
}
// Parse arguments
let projectName: string | undefined;
let overrideModel: string | undefined;
let titleArg: string | undefined;
let isLatest = false;
let isList = false;
for (let i = 0; i < args.length; i++) {
if (args[i] === '--project' && args[i + 1]) {
projectName = args[++i];
} else if (args[i] === '--model' && args[i + 1]) {
overrideModel = args[++i];
} else if (args[i] === '--latest') {
isLatest = true;
} else if (args[i] === '--list') {
isList = true;
} else if (!args[i]!.startsWith('--')) {
titleArg = args[i];
}
}
const { client, db } = await connect();
try {
if (isList) {
await listConversations(db);
return;
}
// Project mode
if (projectName) {
const model = overrideModel ?? PROJECT_MODEL;
console.log(`Project mode: ${projectName}, model: ${model}`);
const forgeDbUrl = process.env['FORGE_DB_URL'];
if (!forgeDbUrl) {
console.error('Error: FORGE_DB_URL not found in environment');
process.exit(1);
}
const pgPool = new pg.Pool({ connectionString: forgeDbUrl });
try {
const jobs = await fetchProjectConversations(pgPool, projectName);
if (jobs.length === 0) {
console.log(`No AgentJob records found for project "${projectName}"`);
process.exit(0);
}
console.log(`Found ${jobs.length} conversation(s) for project "${projectName}"`);
const conversationIds = jobs.map((j) => j.conversationId);
const transcript = await buildProjectTranscript(db, conversationIds);
if (!transcript.trim()) {
console.error('Error: empty project transcript');
process.exit(1);
}
console.log(`Project transcript: ${transcript.length} chars, sending to ${model}...`);
const apiKey = getApiKey();
const analysis = await analyze(transcript, apiKey, model);
console.log(`\n${analysis}`);
// Save report to project folder as a workproduct file
saveProjectReport(projectName, analysis);
} finally {
await pgPool.end();
}
return;
}
// Single-conversation mode
const model = overrideModel ?? DEFAULT_MODEL;
const conv =
isLatest
? await findConversation(db, undefined, true)
: await findConversation(db, titleArg);
if (!conv) process.exit(1);
const title = conv.title ?? 'Untitled';
console.log(`Building transcript: ${title}`);
const transcript = await buildTranscript(db, conv);
if (!transcript.trim()) {
console.error('Error: empty transcript');
process.exit(1);
}
console.log(`Transcript: ${transcript.length} chars, sending to ${model}...`);
const apiKey = getApiKey();
const analysis = await analyze(transcript, apiKey, model);
console.log(`\n${analysis}`);
} finally {
await client.close();
}
}
main().catch((err) => {
console.error(err instanceof Error ? err.message : String(err));
process.exit(1);
});