shipdeck
Version:
Ship MVPs in 48 hours. Fix bugs in 30 seconds. The command deck for developers who ship.
344 lines (294 loc) • 9.14 kB
JavaScript
/**
* Anthropic API Integration for Shipdeck Ultimate
* Complete production-ready integration with streaming, cost tracking, and agent execution
*/
const { AnthropicClient, MODEL_CONFIGS, DEFAULT_CONFIG } = require('./client');
const { AgentExecutor, AGENT_ROLES, ConversationContext } = require('./agent-executor');
const { ConfigManager } = require('./config-manager');
const { TokenManager, MODEL_LIMITS, TOKEN_ESTIMATION } = require('./token-manager');
/**
* Main Anthropic Integration Class
* Provides a unified interface for all Anthropic API operations
*/
class AnthropicIntegration {
constructor(options = {}) {
this.configManager = new ConfigManager();
// Initialize with config from file or options
const config = this.configManager.getConfig();
const anthropicOptions = {
apiKey: options.apiKey || config.anthropic?.apiKey || process.env.ANTHROPIC_API_KEY,
model: options.model || config.anthropic?.model,
config: {
...config.anthropic,
...options.config
}
};
this.client = new AnthropicClient(anthropicOptions);
this.executor = new AgentExecutor({
anthropic: anthropicOptions,
config: config.agents
});
this.tokenManager = new TokenManager(this.client.model);
// Track usage
this._setupUsageTracking();
}
/**
* Setup automatic usage tracking
*/
_setupUsageTracking() {
const originalCreateMessage = this.client.createMessage.bind(this.client);
this.client.createMessage = async (...args) => {
const result = await originalCreateMessage(...args);
if (result.usage) {
this.configManager.updateUsage({
inputTokens: result.usage.input_tokens,
outputTokens: result.usage.output_tokens,
requests: 1,
cost: result._metadata?.estimatedCost || 0,
errors: 0
});
}
return result;
};
}
/**
* Quick setup - configure API key and validate
*/
async setup(apiKey) {
if (!apiKey) {
throw new Error('API key is required for setup');
}
// Set API key
this.configManager.setApiKey(apiKey);
// Update client with new key
this.client.apiKey = apiKey;
this.client.client = new (require('@anthropic-ai/sdk'))({ apiKey });
// Validate key
const validation = await this.client.validateApiKey();
if (!validation.valid) {
throw new Error(`API key validation failed: ${validation.error}`);
}
return {
success: true,
message: 'Anthropic API integration configured successfully',
model: this.client.model,
limits: this.tokenManager.getModelInfo()
};
}
/**
* Execute an agent with prompt
*/
async execute(agentType, prompt, options = {}) {
// Check daily limits
const limitCheck = this.configManager.checkDailyLimit();
if (limitCheck.exceeded) {
throw new Error(`Daily spending limit of $${limitCheck.limit} exceeded. Current usage: $${limitCheck.current.toFixed(4)}`);
}
if (limitCheck.warning && !options.ignoreWarning) {
console.warn(`⚠️ Approaching daily limit: $${limitCheck.current.toFixed(4)} / $${limitCheck.limit}`);
}
return await this.executor.executeAgent(agentType, prompt, options);
}
/**
* Execute agent with streaming response
*/
async executeStream(agentType, prompt, options = {}) {
// Check daily limits
const limitCheck = this.configManager.checkDailyLimit();
if (limitCheck.exceeded) {
throw new Error(`Daily spending limit exceeded`);
}
return await this.executor.executeAgentStream(agentType, prompt, options);
}
/**
* Execute multiple agents in parallel
*/
async executeParallel(agentTasks) {
// Check limits for all tasks
const limitCheck = this.configManager.checkDailyLimit();
if (limitCheck.exceeded) {
throw new Error(`Daily spending limit exceeded`);
}
return await this.executor.executeAgentsParallel(agentTasks);
}
/**
* Direct API call (for custom prompts)
*/
async call(messages, options = {}) {
return await this.client.createMessage(messages, options);
}
/**
* Direct streaming API call
*/
async callStream(messages, options = {}) {
return await this.client.createStreamingMessage(messages, options);
}
/**
* Estimate cost for operation
*/
estimateCost(agentType, prompt, options = {}) {
return this.executor.estimateAgentCost(agentType, prompt, options);
}
/**
* Get usage statistics
*/
getUsage() {
return {
client: this.client.getUsage(),
config: this.configManager.getUsageSummary()
};
}
/**
* Get available agents
*/
getAgents() {
return this.executor.getAvailableAgents();
}
/**
* Get available models
*/
getModels() {
return this.client.getAvailableModels();
}
/**
* Get configuration
*/
getConfig() {
return this.configManager.getConfig();
}
/**
* Update configuration
*/
updateConfig(updates) {
return this.configManager.updateConfig(updates);
}
/**
* Set daily spending limit
*/
setDailyLimit(limitUSD, enabled = true) {
return this.configManager.setDailyLimit(limitUSD, enabled);
}
/**
* Reset usage statistics
*/
resetUsage() {
this.client.resetUsage();
return this.configManager.resetUsageStats();
}
/**
* Health check - validate setup and connectivity
*/
async healthCheck() {
const results = {
apiKey: false,
connectivity: false,
config: false,
usage: false,
overall: false
};
try {
// Check API key
results.apiKey = this.configManager.hasApiKey();
// Check connectivity
if (results.apiKey) {
const validation = await this.client.validateApiKey();
results.connectivity = validation.valid;
}
// Check config
const configValidation = this.configManager.validateConfig();
results.config = configValidation.valid;
results.configIssues = configValidation.issues;
// Check usage limits
const limitCheck = this.configManager.checkDailyLimit();
results.usage = !limitCheck.exceeded;
results.usageInfo = limitCheck;
// Overall status
results.overall = results.apiKey && results.connectivity && results.config && results.usage;
} catch (error) {
results.error = error.message;
}
return results;
}
/**
* Generate MVP workflow - specialized 48-hour development flow
*/
async generateMVP(requirements, options = {}) {
const mvpFlow = [
{
agent: 'backend-architect',
prompt: `Design the backend architecture for this MVP: ${requirements}. Focus on rapid deployment and scalability.`,
options: { sessionId: 'mvp-backend' }
},
{
agent: 'frontend-developer',
prompt: `Create the frontend structure for this MVP: ${requirements}. Prioritize user experience and rapid iteration.`,
options: { sessionId: 'mvp-frontend' }
},
{
agent: 'test-writer-fixer',
prompt: `Generate comprehensive test suite for MVP: ${requirements}. Focus on critical paths and user flows.`,
options: { sessionId: 'mvp-tests' }
},
{
agent: 'devops-automator',
prompt: `Create deployment pipeline for MVP: ${requirements}. Enable continuous deployment and monitoring.`,
options: { sessionId: 'mvp-deployment' }
}
];
const parallel = options.parallel !== false; // Default to parallel
if (parallel) {
return await this.executeParallel(mvpFlow);
} else {
const results = [];
for (const task of mvpFlow) {
const result = await this.execute(task.agent, task.prompt, task.options);
results.push({ success: true, agent: task.agent, result });
}
return results;
}
}
}
/**
* Quick factory function for common use cases
*/
function createAnthropicIntegration(options = {}) {
return new AnthropicIntegration(options);
}
// Export for CommonJS
module.exports = AnthropicIntegration;
module.exports.AnthropicIntegration = AnthropicIntegration;
module.exports.createAnthropicIntegration = createAnthropicIntegration;
/**
* Utility function to get API key from various sources
*/
function getApiKey() {
const configManager = new ConfigManager();
return configManager.getApiKey(false) || process.env.ANTHROPIC_API_KEY;
}
/**
* Validate API key format
*/
function validateApiKeyFormat(apiKey) {
return apiKey && typeof apiKey === 'string' && apiKey.startsWith('sk-ant-');
}
module.exports = {
// Main classes
AnthropicIntegration,
AnthropicClient,
AgentExecutor,
ConfigManager,
TokenManager,
ConversationContext,
// Constants
MODEL_CONFIGS,
DEFAULT_CONFIG,
AGENT_ROLES,
MODEL_LIMITS,
TOKEN_ESTIMATION,
// Utility functions
createAnthropicIntegration,
getApiKey,
validateApiKeyFormat,
// Default export
default: AnthropicIntegration
};