Files
Agentic-Compaction-and-Pipl…/agent-system/integrations/claude-code.ts
admin c629646b9f Complete Agent Pipeline System with Claude Code & OpenClaw Integration
- Added Claude Code integration with full context compaction support
- Added OpenClaw integration with deterministic pipeline support
- Implemented parallel agent execution (4 projects x 3 roles pattern)
- Added workspace isolation with permissions and quotas
- Implemented Lobster-compatible YAML workflow parser
- Added persistent memory store for cross-session context
- Created comprehensive README with hero section

This project was 100% autonomously built by Z.AI GLM-5
2026-03-03 13:12:14 +00:00

655 lines
19 KiB
TypeScript

/**
* Claude Code Integration
*
* Provides seamless integration with Claude Code CLI and IDE extensions.
* Enables context compaction, subagent spawning, and task orchestration
* within Claude Code workflows.
*/
import { ContextManager, ContextManagerConfig } from '../core/context-manager';
import { TokenCounter } from '../core/token-counter';
import { Summarizer, SummarizerOptions } from '../core/summarizer';
import { Orchestrator, OrchestratorConfig, Task } from '../core/orchestrator';
import { SubagentSpawner, SubagentType } from '../core/subagent-spawner';
import { MemoryStore } from '../storage/memory-store';
// ============================================================================
// Types
// ============================================================================
export interface ClaudeCodeConfig {
/** Maximum tokens for context (default: 200000 for Claude models) */
maxContextTokens?: number;
/** Reserve tokens for response generation */
reserveTokens?: number;
/** Compaction strategy */
compactionStrategy?: 'sliding-window' | 'summarize-old' | 'priority-retention' | 'hybrid';
/** Priority keywords for retention */
priorityKeywords?: string[];
/** Enable automatic compaction */
autoCompact?: boolean;
/** Compaction threshold percentage (0-1) */
compactionThreshold?: number;
/** Model identifier for Claude */
model?: string;
/** Enable subagent spawning */
enableSubagents?: boolean;
/** Max concurrent subagents */
maxSubagents?: number;
/** Working directory for Claude Code */
workingDirectory?: string;
/** Enable persistent memory */
persistentMemory?: boolean;
/** Memory store path */
memoryStorePath?: string;
}
export interface ClaudeMessage {
role: 'user' | 'assistant' | 'system';
content: string;
metadata?: {
timestamp?: number;
tokens?: number;
priority?: number;
toolUse?: boolean;
fileReferences?: string[];
};
}
export interface ClaudeToolDefinition {
name: string;
description: string;
input_schema: {
type: 'object';
properties: Record<string, any>;
required?: string[];
};
}
export interface ClaudeCodeSession {
id: string;
createdAt: Date;
lastActivity: Date;
messageCount: number;
tokenUsage: number;
status: 'active' | 'compacted' | 'idle' | 'error';
}
export interface CompactionResult {
success: boolean;
tokensBefore: number;
tokensAfter: number;
tokensSaved: number;
messagesRemoved: number;
summary?: string;
keyPoints?: string[];
decisions?: string[];
}
export interface SubagentTask {
type: SubagentType;
prompt: string;
context?: Record<string, any>;
timeout?: number;
priority?: 'low' | 'medium' | 'high';
}
export interface SubagentResult {
success: boolean;
output: string;
tokens: number;
duration: number;
filesModified?: string[];
artifacts?: Record<string, any>;
}
// ============================================================================
// Claude Code Integration Class
// ============================================================================
export class ClaudeCodeIntegration {
private contextManager: ContextManager;
private tokenCounter: TokenCounter;
private summarizer: Summarizer;
private orchestrator: Orchestrator | null = null;
private subagentSpawner: SubagentSpawner | null = null;
private memoryStore: MemoryStore | null = null;
private config: Required<ClaudeCodeConfig>;
private sessionId: string;
private messages: ClaudeMessage[] = [];
private toolDefinitions: ClaudeToolDefinition[] = [];
private compactionHistory: CompactionResult[] = [];
constructor(config: ClaudeCodeConfig = {}) {
this.config = {
maxContextTokens: config.maxContextTokens ?? 200000,
reserveTokens: config.reserveTokens ?? 40000,
compactionStrategy: config.compactionStrategy ?? 'hybrid',
priorityKeywords: config.priorityKeywords ?? [
'error', 'important', 'decision', 'critical', 'remember', 'todo', 'fixme'
],
autoCompact: config.autoCompact ?? true,
compactionThreshold: config.compactionThreshold ?? 0.8,
model: config.model ?? 'claude-sonnet-4-20250514',
enableSubagents: config.enableSubagents ?? true,
maxSubagents: config.maxSubagents ?? 6,
workingDirectory: config.workingDirectory ?? process.cwd(),
persistentMemory: config.persistentMemory ?? true,
memoryStorePath: config.memoryStorePath ?? '.claude-code/memory'
};
// Initialize core components
this.tokenCounter = new TokenCounter(this.config.maxContextTokens);
this.summarizer = new Summarizer();
this.contextManager = new ContextManager(
this.tokenCounter,
this.summarizer,
{
maxTokens: this.config.maxContextTokens - this.config.reserveTokens,
compactionStrategy: this.config.compactionStrategy,
priorityKeywords: this.config.priorityKeywords,
reserveTokens: this.config.reserveTokens
}
);
// Initialize orchestrator if subagents enabled
if (this.config.enableSubagents) {
this.orchestrator = new Orchestrator({
maxAgents: this.config.maxSubagents,
taskTimeout: 300000,
retryAttempts: 3
});
this.subagentSpawner = new SubagentSpawner();
}
// Initialize memory store if persistent
if (this.config.persistentMemory) {
this.memoryStore = new MemoryStore(this.config.memoryStorePath);
}
this.sessionId = this.generateSessionId();
this.registerDefaultTools();
}
// ============================================================================
// Session Management
// ============================================================================
private generateSessionId(): string {
return `claude-code-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
getSessionId(): string {
return this.sessionId;
}
getSessionInfo(): ClaudeCodeSession {
const usage = this.tokenCounter.getUsagePercentage();
return {
id: this.sessionId,
createdAt: new Date(parseInt(this.sessionId.split('-')[2])),
lastActivity: new Date(),
messageCount: this.messages.length,
tokenUsage: this.tokenCounter.getCurrentUsage(),
status: usage > this.config.compactionThreshold ? 'compacted' :
this.messages.length === 0 ? 'idle' : 'active'
};
}
// ============================================================================
// Message Handling
// ============================================================================
/**
* Add a message to the context
*/
addMessage(message: ClaudeMessage): void {
// Estimate tokens for this message
const tokens = this.tokenCounter.countTokens(message.content);
message.metadata = {
...message.metadata,
timestamp: message.metadata?.timestamp ?? Date.now(),
tokens
};
this.messages.push(message);
this.tokenCounter.addUsage(tokens);
// Add to context manager
this.contextManager.addMessage({
role: message.role,
content: message.content,
priority: message.metadata?.priority,
timestamp: message.metadata?.timestamp
});
// Check for auto-compaction
if (this.config.autoCompact && this.needsCompaction()) {
this.compact();
}
}
/**
* Get all messages in context
*/
getMessages(): ClaudeMessage[] {
return [...this.messages];
}
/**
* Get context for Claude API call
*/
getContextForAPI(): { messages: ClaudeMessage[]; systemPrompt?: string } {
const activeContext = this.contextManager.getActiveContext();
const messages: ClaudeMessage[] = activeContext.messages.map(m => ({
role: m.role as 'user' | 'assistant',
content: m.content,
metadata: {
timestamp: m.timestamp,
priority: m.priority
}
}));
return {
messages,
systemPrompt: activeContext.summary ?
`[Previous Context Summary]\n${activeContext.summary}\n\n[End of Summary]` :
undefined
};
}
// ============================================================================
// Context Compaction
// ============================================================================
/**
* Check if compaction is needed
*/
needsCompaction(): boolean {
return this.tokenCounter.getUsagePercentage() >= this.config.compactionThreshold;
}
/**
* Perform context compaction
*/
async compact(): Promise<CompactionResult> {
const tokensBefore = this.tokenCounter.getCurrentUsage();
try {
const result = await this.contextManager.compact();
// Update local messages to match compacted context
const activeContext = this.contextManager.getActiveContext();
this.messages = activeContext.messages.map(m => ({
role: m.role as 'user' | 'assistant',
content: m.content,
metadata: {
timestamp: m.timestamp,
priority: m.priority
}
}));
// Reset token counter and recalculate
this.tokenCounter.reset();
const newTokens = this.messages.reduce(
(sum, m) => sum + this.tokenCounter.countTokens(m.content),
0
);
this.tokenCounter.addUsage(newTokens);
const compactionResult: CompactionResult = {
success: true,
tokensBefore,
tokensAfter: this.tokenCounter.getCurrentUsage(),
tokensSaved: tokensBefore - this.tokenCounter.getCurrentUsage(),
messagesRemoved: result.messagesRemoved,
summary: result.summary,
keyPoints: result.keyPoints,
decisions: result.decisions
};
this.compactionHistory.push(compactionResult);
return compactionResult;
} catch (error) {
return {
success: false,
tokensBefore,
tokensAfter: tokensBefore,
tokensSaved: 0,
messagesRemoved: 0
};
}
}
/**
* Get compaction history
*/
getCompactionHistory(): CompactionResult[] {
return [...this.compactionHistory];
}
/**
* Get current token usage stats
*/
getTokenStats(): {
used: number;
total: number;
remaining: number;
percentage: number;
} {
return {
used: this.tokenCounter.getCurrentUsage(),
total: this.config.maxContextTokens,
remaining: this.tokenCounter.getRemainingBudget(),
percentage: this.tokenCounter.getUsagePercentage() * 100
};
}
// ============================================================================
// Tool Registration
// ============================================================================
private registerDefaultTools(): void {
// Register context management tools
this.registerTool({
name: 'compact_context',
description: 'Compact the conversation context to save tokens while preserving important information',
input_schema: {
type: 'object',
properties: {
force: {
type: 'boolean',
description: 'Force compaction even if threshold not reached'
}
}
}
});
// Register subagent tools
if (this.config.enableSubagents) {
this.registerTool({
name: 'spawn_explorer',
description: 'Spawn an explorer agent to quickly search and navigate the codebase',
input_schema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Search query or file pattern to explore'
}
},
required: ['query']
}
});
this.registerTool({
name: 'spawn_researcher',
description: 'Spawn a researcher agent to deeply analyze and research a topic',
input_schema: {
type: 'object',
properties: {
topic: {
type: 'string',
description: 'Topic to research'
},
depth: {
type: 'string',
enum: ['shallow', 'medium', 'deep'],
description: 'Research depth level'
}
},
required: ['topic']
}
});
this.registerTool({
name: 'spawn_coder',
description: 'Spawn a coder agent to implement or modify code',
input_schema: {
type: 'object',
properties: {
task: {
type: 'string',
description: 'Coding task description'
},
files: {
type: 'array',
items: { type: 'string' },
description: 'Files to work on'
}
},
required: ['task']
}
});
this.registerTool({
name: 'spawn_reviewer',
description: 'Spawn a reviewer agent to review code quality and suggest improvements',
input_schema: {
type: 'object',
properties: {
files: {
type: 'array',
items: { type: 'string' },
description: 'Files to review'
},
focus: {
type: 'string',
description: 'Review focus area (security, performance, style, all)'
}
},
required: ['files']
}
});
}
}
/**
* Register a custom tool
*/
registerTool(tool: ClaudeToolDefinition): void {
this.toolDefinitions.push(tool);
}
/**
* Get all registered tools
*/
getTools(): ClaudeToolDefinition[] {
return [...this.toolDefinitions];
}
// ============================================================================
// Subagent Spawning
// ============================================================================
/**
* Spawn a subagent for a specific task
*/
async spawnSubagent(task: SubagentTask): Promise<SubagentResult> {
if (!this.subagentSpawner || !this.orchestrator) {
throw new Error('Subagents are not enabled in this configuration');
}
const startTime = Date.now();
try {
// Create subagent
const agent = this.subagentSpawner.spawn(task.type, {
taskId: `${this.sessionId}-${task.type}-${Date.now()}`,
memory: this.memoryStore || undefined
});
// Execute task
const result = await agent.execute({
prompt: task.prompt,
...task.context
});
const duration = Date.now() - startTime;
const outputTokens = this.tokenCounter.countTokens(result.output || '');
return {
success: result.success !== false,
output: result.output || '',
tokens: outputTokens,
duration,
filesModified: result.filesModified,
artifacts: result.artifacts
};
} catch (error) {
return {
success: false,
output: `Subagent error: ${error instanceof Error ? error.message : 'Unknown error'}`,
tokens: 0,
duration: Date.now() - startTime
};
}
}
/**
* Execute multiple subagent tasks in parallel
*/
async executeParallelSubagents(tasks: SubagentTask[]): Promise<SubagentResult[]> {
return Promise.all(tasks.map(task => this.spawnSubagent(task)));
}
// ============================================================================
// Memory Management
// ============================================================================
/**
* Store a value in persistent memory
*/
async remember(key: string, value: any): Promise<void> {
if (this.memoryStore) {
await this.memoryStore.set(`session:${this.sessionId}:${key}`, value);
}
}
/**
* Retrieve a value from persistent memory
*/
async recall<T>(key: string): Promise<T | null> {
if (this.memoryStore) {
return this.memoryStore.get<T>(`session:${this.sessionId}:${key}`);
}
return null;
}
/**
* Store important context for cross-session persistence
*/
async saveContext(name: string): Promise<void> {
if (this.memoryStore) {
await this.memoryStore.set(`context:${name}`, {
sessionId: this.sessionId,
messages: this.messages,
createdAt: Date.now()
});
}
}
/**
* Load a previously saved context
*/
async loadContext(name: string): Promise<boolean> {
if (this.memoryStore) {
const saved = await this.memoryStore.get<{
sessionId: string;
messages: ClaudeMessage[];
}>(`context:${name}`);
if (saved) {
this.messages = saved.messages;
this.tokenCounter.reset();
for (const msg of this.messages) {
this.tokenCounter.addUsage(this.tokenCounter.countTokens(msg.content));
}
return true;
}
}
return false;
}
// ============================================================================
// Utility Methods
// ============================================================================
/**
* Reset the session
*/
reset(): void {
this.messages = [];
this.tokenCounter.reset();
this.contextManager = new ContextManager(
this.tokenCounter,
this.summarizer,
{
maxTokens: this.config.maxContextTokens - this.config.reserveTokens,
compactionStrategy: this.config.compactionStrategy,
priorityKeywords: this.config.priorityKeywords,
reserveTokens: this.config.reserveTokens
}
);
this.sessionId = this.generateSessionId();
this.compactionHistory = [];
}
/**
* Export session data
*/
exportSession(): {
sessionId: string;
config: Required<ClaudeCodeConfig>;
messages: ClaudeMessage[];
compactionHistory: CompactionResult[];
toolDefinitions: ClaudeToolDefinition[];
} {
return {
sessionId: this.sessionId,
config: this.config,
messages: this.messages,
compactionHistory: this.compactionHistory,
toolDefinitions: this.toolDefinitions
};
}
/**
* Import session data
*/
importSession(data: ReturnType<typeof this.exportSession>): void {
this.sessionId = data.sessionId;
this.messages = data.messages;
this.compactionHistory = data.compactionHistory;
this.toolDefinitions = data.toolDefinitions;
// Rebuild token counter state
this.tokenCounter.reset();
for (const msg of this.messages) {
this.tokenCounter.addUsage(this.tokenCounter.countTokens(msg.content));
}
}
}
// ============================================================================
// Factory Function
// ============================================================================
/**
* Create a Claude Code integration instance with sensible defaults
*/
export function createClaudeCodeIntegration(
config?: ClaudeCodeConfig
): ClaudeCodeIntegration {
return new ClaudeCodeIntegration(config);
}
// ============================================================================
// Export
// ============================================================================
export default ClaudeCodeIntegration;