moving
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled

This commit is contained in:
Oleg Maslov
2026-09-02 10:10:29 +02:00
commit 0c3e2ead3b
3841 changed files with 970576 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
import { eq, and, desc, gte, sql } from 'drizzle-orm';
import { agentJobs, teamResources, tasks, messages, teamMembers } from '../db/schema.js';
import type { Db } from '../db/connection.js';
export class HiveMindAgent {
constructor(private db: Db) {}
async generateWeeklyDigest(teamId: string): Promise<{ digest: WeeklyDigest; messageId: string }> {
const oneWeekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
// Aggregate metrics
const jobsCompleted = await this.db.select().from(agentJobs)
.where(and(
eq(agentJobs.teamId, teamId),
eq(agentJobs.status, 'completed'),
gte(agentJobs.completedAt, oneWeekAgo),
));
const tasksCompleted = await this.db.select().from(tasks)
.where(and(
eq(tasks.teamId, teamId),
eq(tasks.status, 'done'),
));
const resourcesShared = await this.db.select().from(teamResources)
.where(and(
eq(teamResources.teamId, teamId),
gte(teamResources.createdAt, oneWeekAgo),
));
const waggleMessages = await this.db.select().from(messages)
.where(and(
eq(messages.teamId, teamId),
gte(messages.createdAt, oneWeekAgo),
));
// Detect duplicate work (similar task titles by different users)
const duplicates = this.detectDuplicateWork(tasksCompleted);
// Find high-rated resources as best practices
const bestPractices = await this.db.select().from(teamResources)
.where(and(
eq(teamResources.teamId, teamId),
gte(teamResources.rating, sql`3.0`),
))
.orderBy(desc(teamResources.rating))
.limit(5);
const digest: WeeklyDigest = {
period: { from: oneWeekAgo, to: new Date() },
metrics: {
jobsCompleted: jobsCompleted.length,
tasksCompleted: tasksCompleted.length,
resourcesShared: resourcesShared.length,
waggleMessages: waggleMessages.length,
},
duplicateWork: duplicates,
bestPractices: bestPractices.map(r => ({ name: r.name, type: r.resourceType, rating: r.rating })),
recommendations: this.generateRecommendations(jobsCompleted, duplicates, bestPractices),
};
// Get a team member to attribute the broadcast to
const [firstMember] = await this.db.select().from(teamMembers)
.where(eq(teamMembers.teamId, teamId))
.limit(1);
const senderId = firstMember?.userId ?? '';
// Broadcast digest as Waggle Dance message
const [msg] = await this.db.insert(messages).values({
teamId,
senderId,
type: 'broadcast',
subtype: 'discovery',
content: { type: 'weekly_digest', digest },
}).returning();
return { digest, messageId: msg.id };
}
private detectDuplicateWork(tasksList: Array<{ title: string; createdBy: string }>): DuplicateWork[] {
// Group by similar titles (case-insensitive first 20 chars)
const groups = new Map<string, { titles: string[]; users: Set<string> }>();
for (const task of tasksList) {
const key = task.title.toLowerCase().substring(0, 20);
if (!groups.has(key)) groups.set(key, { titles: [], users: new Set() });
groups.get(key)!.titles.push(task.title);
groups.get(key)!.users.add(task.createdBy);
}
return Array.from(groups.values())
.filter(g => g.users.size > 1)
.map(g => ({ titles: g.titles, users: Array.from(g.users) }));
}
private generateRecommendations(jobs: unknown[], duplicates: DuplicateWork[], bestPractices: unknown[]): string[] {
const recommendations: string[] = [];
if (duplicates.length > 0) {
recommendations.push(`${duplicates.length} potential duplicate work detected. Consider checking the hive before starting tasks.`);
}
if (bestPractices.length > 0) {
recommendations.push(`${bestPractices.length} highly-rated resources available. Share them team-wide.`);
}
if (jobs.length > 50) {
recommendations.push('High job volume this week. Consider automating recurring tasks with cron schedules.');
}
return recommendations;
}
}
interface DuplicateWork {
titles: string[];
users: string[];
}
interface WeeklyDigest {
period: { from: Date; to: Date };
metrics: {
jobsCompleted: number;
tasksCompleted: number;
resourcesShared: number;
waggleMessages: number;
};
duplicateWork: DuplicateWork[];
bestPractices: Array<{ name: string; type: string; rating: number }>;
recommendations: string[];
}

View File

@@ -0,0 +1,121 @@
import { eq, and, desc } from 'drizzle-orm';
import { scoutFindings, agents, teamMembers, teamResources } from '../db/schema.js';
import type { Db } from '../db/connection.js';
interface Finding {
source: string;
category: string;
title: string;
summary: string;
relevanceScore: number;
url: string | null;
}
export class ScoutAgent {
constructor(private db: Db) {}
async scan(userId: string, teamId: string): Promise<Array<typeof scoutFindings.$inferSelect>> {
const findings: Finding[] = [];
// Source 1: Check team resources for newly shared items
findings.push(...await this.checkTeamResources(teamId));
// Source 2: Mock marketplace check (would check npm/MCP registry in production)
findings.push(...await this.checkMarketplace(userId));
// Score relevance based on user's agent configs and role
const scored = await this.scoreRelevance(findings, userId, teamId);
// Filter out findings with titles already dismissed by this user
const existingDismissed = await this.db.select().from(scoutFindings)
.where(and(
eq(scoutFindings.userId, userId),
eq(scoutFindings.status, 'dismissed'),
));
const dismissedTitles = new Set(existingDismissed.map(f => f.title));
const filtered = scored.filter(f => !dismissedTitles.has(f.title));
// Store findings
const stored = [];
for (const finding of filtered) {
const [entry] = await this.db.insert(scoutFindings).values({
userId,
teamId,
source: finding.source,
category: finding.category,
title: finding.title,
summary: finding.summary,
relevanceScore: finding.relevanceScore,
url: finding.url,
status: 'new',
}).returning();
stored.push(entry);
}
return stored;
}
private async checkTeamResources(teamId: string): Promise<Finding[]> {
const recent = await this.db.select().from(teamResources)
.where(eq(teamResources.teamId, teamId))
.orderBy(desc(teamResources.createdAt))
.limit(5);
return recent.map(r => ({
source: 'team' as const,
category: r.resourceType === 'skill' ? 'skill' : 'practice',
title: `New team resource: ${r.name}`,
summary: r.description ?? `A ${r.resourceType} shared by a team member`,
relevanceScore: 0.5,
url: null,
}));
}
private async checkMarketplace(_userId: string): Promise<Finding[]> {
// Mock: In production, would check npm registry for MCP packages, skill marketplace, etc.
return [];
}
private async scoreRelevance(findings: Finding[], userId: string, teamId: string): Promise<Finding[]> {
// Load user's agent configs for interest matching
const userAgents = await this.db.select().from(agents)
.where(eq(agents.userId, userId));
// Load member interests
const [membership] = await this.db.select().from(teamMembers)
.where(and(eq(teamMembers.teamId, teamId), eq(teamMembers.userId, userId)));
const interests = (membership?.interests as string[]) ?? [];
const agentTools = userAgents.flatMap(a => (a.tools as string[]) ?? []);
return findings.map(f => {
let score = f.relevanceScore;
// Boost if matches user interests
if (interests.some(i => f.title.toLowerCase().includes(i.toLowerCase()))) score += 0.3;
// Boost if matches agent tool names
if (agentTools.some(t => f.title.toLowerCase().includes(t.toLowerCase()))) score += 0.2;
return { ...f, relevanceScore: Math.min(score, 1.0) };
});
}
async adopt(findingId: string) {
const [updated] = await this.db.update(scoutFindings)
.set({ status: 'adopted' })
.where(eq(scoutFindings.id, findingId))
.returning();
return updated ?? null;
}
async dismiss(findingId: string) {
const [updated] = await this.db.update(scoutFindings)
.set({ status: 'dismissed' })
.where(eq(scoutFindings.id, findingId))
.returning();
return updated ?? null;
}
async listFindings(userId: string) {
return this.db.select().from(scoutFindings)
.where(eq(scoutFindings.userId, userId));
}
}

View File

@@ -0,0 +1,94 @@
import { eq, desc, and, sql } from 'drizzle-orm';
import { agentJobs, agentAuditLog } from '../db/schema.js';
import type { Db } from '../db/connection.js';
import { SUBCONSCIOUS_INTERACTION_THRESHOLD } from '@waggle/shared';
export class SubconsciousAgent {
constructor(private db: Db) {}
async shouldReflect(userId: string): Promise<boolean> {
// Count completed jobs since last reflection
const lastReflection = await this.db.select().from(agentAuditLog)
.where(and(
eq(agentAuditLog.userId, userId),
eq(agentAuditLog.actionType, 'subconscious_reflection'),
))
.orderBy(desc(agentAuditLog.createdAt))
.limit(1);
const since = lastReflection[0]?.createdAt ?? new Date(0);
const sinceIso = since.toISOString();
const recentJobs = await this.db.select().from(agentJobs)
.where(and(
eq(agentJobs.userId, userId),
eq(agentJobs.status, 'completed'),
sql`${agentJobs.completedAt} > ${sinceIso}::timestamptz`,
));
return recentJobs.length >= SUBCONSCIOUS_INTERACTION_THRESHOLD;
}
async reflect(userId: string): Promise<{ auditEntry: typeof agentAuditLog.$inferSelect; insights: Insight[] }> {
// Get recent completed jobs
const recentJobs = await this.db.select().from(agentJobs)
.where(and(
eq(agentJobs.userId, userId),
eq(agentJobs.status, 'completed'),
))
.orderBy(desc(agentJobs.completedAt))
.limit(20);
// Analyze patterns
const insights = this.analyzePatterns(recentJobs);
// Log the reflection
const [auditEntry] = await this.db.insert(agentAuditLog).values({
userId,
agentName: 'subconscious',
actionType: 'subconscious_reflection',
description: `Reflected on ${recentJobs.length} recent jobs. Found ${insights.length} insights.`,
afterState: { insights },
requiresApproval: insights.some(i => i.type === 'prompt_change'),
}).returning();
return { auditEntry, insights };
}
private analyzePatterns(jobs: Array<typeof agentJobs.$inferSelect>): Insight[] {
const insights: Insight[] = [];
// Pattern: repeated job types
const typeCounts = new Map<string, number>();
for (const job of jobs) {
typeCounts.set(job.jobType, (typeCounts.get(job.jobType) ?? 0) + 1);
}
for (const [type, count] of typeCounts) {
if (count >= 5) {
insights.push({
type: 'prompt_change',
description: `Job type "${type}" executed ${count} times recently`,
recommendation: `Consider optimizing the system prompt for ${type} tasks`,
});
}
}
// Pattern: failed jobs
const failedCount = jobs.filter(j => j.status === 'failed').length;
if (failedCount >= 3) {
insights.push({
type: 'tool_issue',
description: `${failedCount} jobs failed recently`,
recommendation: 'Review tool configurations and consider adding error handling',
});
}
return insights;
}
}
interface Insight {
type: string;
description: string;
recommendation: string;
}