Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changeset/polite-paws-heal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
42 changes: 15 additions & 27 deletions server/src/addie/jobs/committee-document-indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
*/

import * as crypto from 'crypto';
import Anthropic from '@anthropic-ai/sdk';
import { logger } from '../../logger.js';
import { WorkingGroupDatabase } from '../../db/working-group-db.js';
import {
Expand All @@ -22,13 +21,11 @@ import {
GOOGLE_DOCS_ERROR_PREFIX,
GOOGLE_DOCS_ACCESS_DENIED_PREFIX,
} from '../mcp/google-docs.js';
import { isLLMConfigured, complete } from '../../utils/llm.js';
import type { CommitteeDocument, DocumentIndexStatus } from '../../types.js';

const workingGroupDb = new WorkingGroupDatabase();

// Use same model as main Addie assistant
const SUMMARIZER_MODEL = process.env.ADDIE_MODEL || 'claude-sonnet-4-20250514';

export interface DocumentIndexResult {
documentsChecked: number;
documentsChanged: number;
Expand Down Expand Up @@ -107,8 +104,7 @@ async function generateDocumentSummary(
content: string,
committeeContext?: string
): Promise<string> {
const apiKey = process.env.ANTHROPIC_API_KEY;
if (!apiKey) {
if (!isLLMConfigured()) {
throw new Error('ANTHROPIC_API_KEY not configured');
}

Expand All @@ -118,8 +114,6 @@ async function generateDocumentSummary(
? content.substring(0, maxContentLength) + '\n\n[Content truncated...]'
: content;

const client = new Anthropic({ apiKey });

const systemPrompt = `You are summarizing a document for a working group at AgenticAdvertising.org.
Generate a brief, informative summary (2-4 sentences) that captures the key points.
Focus on what the document covers and any important updates or decisions.
Expand All @@ -132,15 +126,15 @@ ${truncatedContent}

Write a brief summary (2-4 sentences) of this document.`;

const response = await client.messages.create({
model: SUMMARIZER_MODEL,
max_tokens: 300,
const result = await complete({
system: systemPrompt,
messages: [{ role: 'user', content: userPrompt }],
prompt: userPrompt,
maxTokens: 300,
model: 'primary',
operationName: 'document-summary',
});

const textContent = response.content.find(block => block.type === 'text');
return textContent?.text || 'Unable to generate summary.';
return result.text || 'Unable to generate summary.';
}

/**
Expand All @@ -151,8 +145,7 @@ async function generateChangeSummary(
oldContent: string,
newContent: string
): Promise<string> {
const apiKey = process.env.ANTHROPIC_API_KEY;
if (!apiKey) {
if (!isLLMConfigured()) {
return 'Document content was updated.';
}

Expand All @@ -165,20 +158,15 @@ async function generateChangeSummary(
? newContent.substring(0, maxLength) + '...'
: newContent;

const client = new Anthropic({ apiKey });

const response = await client.messages.create({
model: SUMMARIZER_MODEL,
max_tokens: 200,
const result = await complete({
system: 'Summarize the key changes between the old and new versions of this document in 1-2 sentences. Focus on substantive changes, not formatting.',
messages: [{
role: 'user',
content: `Document: "${title}"\n\nOLD VERSION:\n${truncatedOld}\n\nNEW VERSION:\n${truncatedNew}\n\nWhat changed?`,
}],
prompt: `Document: "${title}"\n\nOLD VERSION:\n${truncatedOld}\n\nNEW VERSION:\n${truncatedNew}\n\nWhat changed?`,
maxTokens: 200,
model: 'primary',
operationName: 'document-change-summary',
});

const textContent = response.content.find(block => block.type === 'text');
return textContent?.text || 'Document was updated.';
return result.text || 'Document was updated.';
}

/**
Expand Down
22 changes: 8 additions & 14 deletions server/src/addie/jobs/committee-summary-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,14 @@
* - 'changes': Summary of what changed since last update
*/

import Anthropic from '@anthropic-ai/sdk';
import { logger } from '../../logger.js';
import { getPool } from '../../db/client.js';
import { WorkingGroupDatabase } from '../../db/working-group-db.js';
import { isLLMConfigured, complete } from '../../utils/llm.js';
import type { CommitteeSummaryType } from '../../types.js';

const workingGroupDb = new WorkingGroupDatabase();

// Use same model as main Addie assistant
const SUMMARIZER_MODEL = process.env.ADDIE_MODEL || 'claude-sonnet-4-20250514';

export interface SummaryGeneratorResult {
committeesProcessed: number;
summariesGenerated: number;
Expand Down Expand Up @@ -64,13 +61,10 @@ async function generateActivitySummary(
posts: Array<{ title: string; excerpt?: string; published_at?: Date }>,
activity: Array<{ activity_type: string; change_summary?: string; detected_at: Date; document_title?: string }>
): Promise<string> {
const apiKey = process.env.ANTHROPIC_API_KEY;
if (!apiKey) {
if (!isLLMConfigured()) {
throw new Error('ANTHROPIC_API_KEY not configured');
}

const client = new Anthropic({ apiKey });

// Build context about the committee
const documentsSection = documents.length > 0
? `\nTracked Documents:\n${documents.map(d =>
Expand Down Expand Up @@ -105,15 +99,15 @@ ${documentsSection}${postsSection}${changesSection}

Generate a brief activity summary for this committee.`;

const response = await client.messages.create({
model: SUMMARIZER_MODEL,
max_tokens: 400,
const result = await complete({
prompt: userPrompt,
system: systemPrompt,
messages: [{ role: 'user', content: userPrompt }],
maxTokens: 400,
model: 'primary',
operationName: 'committee-summary',
});

const textContent = response.content.find(block => block.type === 'text');
return textContent?.text || 'No activity summary available.';
return result.text || 'No activity summary available.';
}

/**
Expand Down
40 changes: 16 additions & 24 deletions server/src/addie/jobs/insight-synthesizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
* focused knowledge rules.
*/

import Anthropic from '@anthropic-ai/sdk';
import { createLogger } from '../../logger.js';
import { complete } from '../../utils/llm.js';
import { ModelConfig } from '../../config/models.js';
import {
AddieDatabase,
type InsightSource,
Expand All @@ -18,7 +19,6 @@ import {
type AddieRule,
type RuleType,
} from '../../db/addie-db.js';
import { ModelConfig } from '../../config/models.js';
import {
getOrCreateConfigVersion,
invalidateConfigCache,
Expand Down Expand Up @@ -102,7 +102,6 @@ Prefer fewer, higher-quality rules over many mediocre ones.`;
*/
export async function synthesizeInsights(
db: AddieDatabase,
anthropicApiKey: string,
options: SynthesisOptions = {}
): Promise<SynthesisResult> {
const {
Expand All @@ -128,14 +127,12 @@ export async function synthesizeInsights(
const topicsIncluded = Object.keys(byTopic);

// 3. Synthesize each topic group
const anthropic = new Anthropic({ apiKey: anthropicApiKey });
const allProposedRules: ProposedRule[] = [];
const allGaps: string[] = [];
let totalTokens = 0;

for (const [topicName, topicSources] of Object.entries(byTopic)) {
const { rules, gaps, tokensUsed } = await synthesizeTopic(
anthropic,
topicName,
topicSources
);
Expand Down Expand Up @@ -165,7 +162,6 @@ export async function synthesizeInsights(
try {
preview = await previewSynthesizedRules(
db,
anthropic,
allProposedRules,
previewSampleSize
);
Expand Down Expand Up @@ -301,21 +297,21 @@ function groupByTopic(sources: InsightSource[]): Record<string, InsightSource[]>
* Synthesize a single topic's sources into rules
*/
async function synthesizeTopic(
anthropic: Anthropic,
topic: string,
sources: InsightSource[]
): Promise<{ rules: ProposedRule[]; gaps: string[]; tokensUsed: number }> {
const prompt = buildSynthesisPrompt(topic, sources);

const response = await anthropic.messages.create({
model: ModelConfig.primary,
max_tokens: 4096,
const result = await complete({
prompt,
system: SYNTHESIS_SYSTEM_PROMPT,
messages: [{ role: 'user', content: prompt }],
maxTokens: 4096,
model: 'primary',
operationName: 'insight-synthesis',
});

const tokensUsed = response.usage.input_tokens + response.usage.output_tokens;
const responseText = response.content[0].type === 'text' ? response.content[0].text : '';
const tokensUsed = (result.inputTokens || 0) + (result.outputTokens || 0);
const responseText = result.text;

// Parse response
let parsed: ClaudeSynthesisResponse;
Expand Down Expand Up @@ -377,7 +373,6 @@ Now synthesize these sources into 1-3 focused knowledge rules. Remember:
*/
async function previewSynthesizedRules(
db: AddieDatabase,
anthropic: Anthropic,
proposedRules: ProposedRule[],
sampleSize: number
): Promise<SynthesisPreviewResults> {
Expand Down Expand Up @@ -411,12 +406,8 @@ async function previewSynthesizedRules(

for (const interaction of sampled) {
try {
const response = await anthropic.messages.create({
model: ModelConfig.fast,
max_tokens: 512,
messages: [{
role: 'user',
content: `You are evaluating how new knowledge rules would affect an AI assistant's response.
const result = await complete({
prompt: `You are evaluating how new knowledge rules would affect an AI assistant's response.

## New Rules Being Added

Expand All @@ -437,12 +428,13 @@ Would the new rules improve this response? Output JSON:
"predicted_change": "Brief description of how response would change (or 'No significant change')",
"improvement_score": 0.5, // -1 (worse) to 1 (better), 0 = no change
"confidence": 0.8
}`
}],
}`,
maxTokens: 512,
model: 'fast',
operationName: 'synthesis-preview',
});

const responseText = response.content[0].type === 'text' ? response.content[0].text : '';
const jsonMatch = responseText.match(/\{[\s\S]*\}/);
const jsonMatch = result.text.match(/\{[\s\S]*\}/);
if (jsonMatch) {
const parsed = JSON.parse(jsonMatch[0]);
predictions.push({
Expand Down
Loading