Execute AOPs

This example shows how to execute Agent Operating Procedures (AOPs) using the TypeScript SDK. AOPs are pre-configured AI workflows that can perform complex tasks like research, analysis, and content generation with optional user inputs for customization.

Key features:

  • Execute pre-built AI workflows with custom parameters
  • Support for both synchronous and asynchronous execution
  • Full TypeScript support with type safety
  • Track execution progress with thread monitoring
  • Proper error handling for production use
1

Install Package

$pnpm add athena-intelligence
2

Set Up Client

1import type { AthenaIntelligence } from 'athena-intelligence';
2import { AthenaIntelligenceClient, AthenaIntelligenceError } from 'athena-intelligence';
3
4// Basic client setup (uses default production API)
5const client = new AthenaIntelligenceClient({
6 apiKey: process.env.ATHENA_API_KEY,
7});
8
9// Override baseUrl for custom API endpoints
10const customClient = new AthenaIntelligenceClient({
11 apiKey: process.env.ATHENA_API_KEY,
12 baseUrl: 'https://your-custom-api.example.com', // Custom API endpoint
13});
14
15// Use with local development server
16const devClient = new AthenaIntelligenceClient({
17 apiKey: process.env.ATHENA_API_KEY,
18 baseUrl: 'http://localhost:8000', // Local development
19});
3

Basic AOP Execution

Execute an AOP synchronously and wait for completion:

1const aopRequest: AthenaIntelligence.AopExecuteRequestIn = {
2 asset_id: 'asset_9249292-d118-42d3-95b4-00eccfe0754f',
3 user_inputs: {
4 company: 'Acme Corp',
5 quarter: 'Q1 2024',
6 },
7};
8
9try {
10 console.log('🚀 Executing AOP...');
11 const response = await client.aop.execute(aopRequest);
12
13 console.log('✅ AOP execution completed');
14 console.log('Status:', response.status);
15 console.log('AOP Title:', response.aop_title);
16
17 // Access the conversation result
18 if (response.conversation) {
19 console.log('Last Assistant Message:', response.conversation.last_assistant_message?.content);
20 console.log('Total Messages:', response.conversation.num_messages);
21 }
22} catch (error) {
23 if (error instanceof AthenaIntelligenceError) {
24 console.error(`AOP execution failed: ${error.statusCode} - ${error.message}`);
25 } else {
26 console.error('Unexpected error:', error);
27 }
28}
4

Asynchronous AOP Execution

For long-running workflows, use async execution to avoid timeouts:

1const asyncAopRequest: AthenaIntelligence.AopExecuteRequestIn = {
2 asset_id: 'asset_9249292-d118-42d3-95b4-00eccfe0754f',
3 user_inputs: {
4 company: 'TechStartup Inc',
5 analysis_type: 'comprehensive',
6 time_period: '2024',
7 },
8};
9
10try {
11 console.log('🚀 Starting async AOP execution...');
12 const asyncResponse = await client.aop.executeAsync(asyncAopRequest);
13
14 console.log('✅ AOP execution started');
15 console.log('Thread ID:', asyncResponse.thread_id);
16 console.log('Status:', asyncResponse.status);
17 console.log('Sync Server:', asyncResponse.sync_server);
18
19 // Store the thread_id to track progress
20 const threadId = asyncResponse.thread_id;
21
22 // Poll for completion (see monitoring section below)
23 await monitorExecution(threadId);
24} catch (error) {
25 if (error instanceof AthenaIntelligenceError) {
26 console.error(`Async AOP execution failed: ${error.statusCode} - ${error.message}`);
27 } else {
28 console.error('Unexpected error:', error);
29 }
30}
5

Monitor Execution Progress

Track the progress of asynchronous AOP executions:

1async function monitorExecution(threadId: string): Promise<void> {
2 const maxAttempts = 30; // Maximum polling attempts
3 const pollInterval = 5000; // 5 seconds between polls
4
5 for (let attempt = 1; attempt <= maxAttempts; attempt++) {
6 try {
7 console.log(`📊 Checking execution status (attempt ${attempt}/${maxAttempts})...`);
8
9 const statusResponse = await client.threads.getStatus(threadId);
10
11 console.log('Current status:', statusResponse.status);
12 console.log('Updated at:', statusResponse.updated_at);
13
14 if (statusResponse.status === 'completed') {
15 console.log('🎉 AOP execution completed successfully!');
16
17 // Access the final conversation results
18 if (statusResponse.conversation_asset) {
19 console.log('Final result available in conversation asset:', statusResponse.conversation_asset.conversation_asset_id);
20
21 if (statusResponse.conversation_asset.last_message) {
22 console.log('Final message:', statusResponse.conversation_asset.last_message.content);
23 }
24 }
25 break;
26 } else if (statusResponse.status === 'failed') {
27 console.error('❌ AOP execution failed');
28 break;
29 } else {
30 console.log(`⏳ Still running... (${statusResponse.status})`);
31
32 // Wait before next poll
33 await new Promise(resolve => setTimeout(resolve, pollInterval));
34 }
35 } catch (error) {
36 if (error instanceof AthenaIntelligenceError) {
37 console.error(`Status check failed: ${error.statusCode} - ${error.message}`);
38 } else {
39 console.error('Unexpected error during status check:', error);
40 }
41 break;
42 }
43 }
44}
6

AOP with Custom Parameters

AOPs can accept various user inputs to customize their behavior:

1// Market research AOP with detailed parameters
2const marketResearchRequest: AthenaIntelligence.AopExecuteRequestIn = {
3 asset_id: 'asset_market_research_aop',
4 user_inputs: {
5 company: 'Tesla Inc',
6 industry: 'Electric Vehicles',
7 time_frame: '2023-2024',
8 analysis_depth: 'comprehensive',
9 include_competitors: 'true',
10 target_market: 'North America',
11 },
12};
13
14// Financial analysis AOP
15const financialAnalysisRequest: AthenaIntelligence.AopExecuteRequestIn = {
16 asset_id: 'asset_financial_analysis_aop',
17 user_inputs: {
18 ticker: 'TSLA',
19 period: 'quarterly',
20 metrics: 'revenue,profit,growth',
21 comparison: 'industry_average',
22 },
23};
24
25// Execute multiple AOPs in parallel
26const [marketResult, financialResult] = await Promise.all([
27 client.aop.execute(marketResearchRequest),
28 client.aop.execute(financialAnalysisRequest),
29]);
30
31console.log('Market Analysis:', marketResult.conversation?.last_assistant_message?.content);
32console.log('Financial Analysis:', financialResult.conversation?.last_assistant_message?.content);
7

Understanding AOP Responses

AOP responses contain extensive metadata and the complete conversation history. Here’s how to access all the data:

1// Execute an AOP and get the full response
2const response = await client.aop.execute({
3 asset_id: 'asset_market_research_aop',
4 user_inputs: {
5 company: 'Nvidia Corporation',
6 quarter: 'Q3 2024',
7 analysis_type: 'comprehensive',
8 },
9}) as AopExecuteResponse;
10
11console.log('=== AOP Execution Metadata ===');
12console.log(`AOP Title: ${response.aop_title}`);
13console.log(`Asset ID: ${response.aop_asset_id}`);
14console.log(`Status: ${response.status}`);
15console.log(`Thread ID: ${response.thread_id}`);
16console.log(`Trigger Type: ${response.trigger_type}`);
17console.log(`Sync Server: ${response.sync_server}`);
18
19console.log('\n=== Prompt Information ===');
20console.log('Base Prompt:');
21console.log(response.base_prompt);
22console.log('\nFinal Prompt (with user inputs):');
23console.log(response.final_prompt);
24
25console.log('\n=== AOP Configuration ===');
26console.log(JSON.stringify(response.aop_config, null, 2));
27
28// Access the complete conversation
29if (response.conversation) {
30 const conv = response.conversation;
31
32 console.log('\n=== Conversation Summary ===');
33 console.log(`Conversation ID: ${conv.conversation_id}`);
34 console.log(`Title: ${conv.title}`);
35 console.log(`Total Messages: ${conv.num_messages}`);
36 console.log(`Messages Source: ${conv.messages_source}`);
37 console.log(`Created: ${conv.created_at}`);
38 console.log(`Last Updated: ${conv.updated_at}`);
39
40 console.log('\n=== Complete Message History ===');
41 conv.messages.forEach((message, index) => {
42 console.log(`\n--- Message ${index + 1} ---`);
43 console.log(`ID: ${message.id}`);
44 console.log(`Role: ${message.role}`);
45 console.log(`Content Type: ${typeof message.content}`);
46
47 // Handle different content types
48 if (typeof message.content === 'string') {
49 console.log(`Content: ${message.content.length > 200 ? message.content.substring(0, 200) + '...' : message.content}`);
50 } else if (Array.isArray(message.content)) {
51 console.log(`Multimodal Content (${message.content.length} parts):`);
52 message.content.forEach((part, partIndex) => {
53 if (part.type === 'text') {
54 const truncated = part.text.length > 100 ? part.text.substring(0, 100) + '...' : part.text;
55 console.log(` Part ${partIndex + 1} [text]: ${truncated}`);
56 } else if (part.type === 'image_url') {
57 console.log(` Part ${partIndex + 1} [image]: ${JSON.stringify(part.image_url)}`);
58 }
59 });
60 }
61
62 // Show additional message metadata
63 if (message.additional_kwargs && Object.keys(message.additional_kwargs).length > 0) {
64 console.log(`Additional Kwargs: ${JSON.stringify(message.additional_kwargs, null, 2)}`);
65 }
66
67 if (message.tool_calls && message.tool_calls.length > 0) {
68 console.log(`Tool Calls (${message.tool_calls.length}):`);
69 message.tool_calls.forEach((toolCall, toolIndex) => {
70 console.log(` Tool ${toolIndex + 1}: ${JSON.stringify(toolCall, null, 2)}`);
71 });
72 }
73
74 if (message.response_metadata) {
75 console.log(`Response Metadata: ${JSON.stringify(message.response_metadata, null, 2)}`);
76 }
77
78 if (message.usage_metadata) {
79 console.log(`Usage Metadata: ${JSON.stringify(message.usage_metadata, null, 2)}`);
80 }
81 });
82
83 // Check for final assistant response (nullable)
84 if (conv.last_assistant_message) {
85 console.log('\n=== Final Assistant Response ===');
86 const finalMsg = conv.last_assistant_message;
87 console.log(`Message ID: ${finalMsg.id}`);
88 console.log(`Role: ${finalMsg.role}`);
89
90 if (typeof finalMsg.content === 'string') {
91 console.log('Final Content:');
92 console.log(finalMsg.content);
93 } else if (Array.isArray(finalMsg.content)) {
94 console.log('Final Multimodal Content:');
95 finalMsg.content.forEach((part, index) => {
96 if (part.type === 'text') {
97 console.log(`Text Part ${index + 1}: ${part.text}`);
98 } else if (part.type === 'image_url') {
99 console.log(`Image Part ${index + 1}: ${JSON.stringify(part.image_url, null, 2)}`);
100 }
101 });
102 }
103
104 if (finalMsg.tool_calls && finalMsg.tool_calls.length > 0) {
105 console.log(`Final Message Tool Calls: ${JSON.stringify(finalMsg.tool_calls, null, 2)}`);
106 }
107
108 if (finalMsg.usage_metadata) {
109 console.log(`Token Usage: ${JSON.stringify(finalMsg.usage_metadata, null, 2)}`);
110 }
111 } else {
112 console.log('\n=== No Final Assistant Response Available ===');
113 console.log('The conversation may still be running or may not have assistant responses yet.');
114 }
115}
116
117// Handle errors in the response
118if (response.error) {
119 console.error('\n=== Execution Error ===');
120 console.error(response.error);
121}
8

Working with Conversation Data

Extract and process conversation data for further use:

1// Function to extract all text content from a conversation
2function extractConversationText(conversation: ConversationResult): string[] {
3 return conversation.messages
4 .map(message => {
5 if (typeof message.content === 'string') {
6 return message.content;
7 } else if (Array.isArray(message.content)) {
8 return message.content
9 .filter(part => part.type === 'text')
10 .map(part => (part as TextContent).text)
11 .join('\n');
12 }
13 return '';
14 })
15 .filter(content => content.length > 0);
16}
17
18// Function to get conversation summary
19function getConversationSummary(conversation: ConversationResult) {
20 return {
21 id: conversation.conversation_id,
22 title: conversation.title,
23 messageCount: conversation.num_messages,
24 duration: new Date(conversation.updated_at).getTime() - new Date(conversation.created_at).getTime(),
25 finalResponse: conversation.last_assistant_message?.content || null, // Handle nullable
26 allTextContent: extractConversationText(conversation),
27 hasFinalAssistantMessage: !!conversation.last_assistant_message,
28 };
29}
30
31// Function to analyze conversation for insights
32function analyzeConversation(conversation: ConversationResult) {
33 const userMessages = conversation.messages.filter(m => m.role === 'user');
34 const assistantMessages = conversation.messages.filter(m => m.role === 'assistant');
35 const toolCalls = conversation.messages.flatMap(m => m.tool_calls || []);
36
37 return {
38 userMessageCount: userMessages.length,
39 assistantMessageCount: assistantMessages.length,
40 totalToolCalls: toolCalls.length,
41 averageResponseLength: assistantMessages.reduce((sum, msg) => {
42 const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
43 return sum + content.length;
44 }, 0) / assistantMessages.length,
45 conversationDuration: new Date(conversation.updated_at).getTime() - new Date(conversation.created_at).getTime(),
46 hasMultimodalContent: conversation.messages.some(m =>
47 Array.isArray(m.content) && m.content.some(part => part.type === 'image_url')
48 ),
49 };
50}
51
52// Usage examples
53const aopResult = await client.aop.execute({
54 asset_id: 'asset_analysis_aop',
55 user_inputs: { company: 'Microsoft', focus: 'cloud_services' },
56}) as AopExecuteResponse;
57
58if (aopResult.conversation) {
59 // Get summary
60 const summary = getConversationSummary(aopResult.conversation);
61 console.log('Conversation Summary:', summary);
62
63 // Analyze conversation
64 const analysis = analyzeConversation(aopResult.conversation);
65 console.log('Conversation Analysis:', analysis);
66
67 // Extract all text for further processing
68 const allText = extractConversationText(aopResult.conversation);
69 console.log('All conversation text extracted:', allText.length, 'segments');
70}
9

Error Handling and Best Practices

Implement comprehensive error handling for production applications:

1async function executeAopSafely(
2 assetId: string,
3 userInputs?: Record<string, string>
4): Promise<AthenaIntelligence.AopExecuteResponseOut | null> {
5 try {
6 // Validate inputs
7 if (!assetId) {
8 throw new Error('Asset ID is required');
9 }
10
11 const request: AthenaIntelligence.AopExecuteRequestIn = {
12 asset_id: assetId,
13 user_inputs: userInputs,
14 };
15
16 console.log('Executing AOP with inputs:', JSON.stringify(userInputs, null, 2));
17
18 const response = await client.aop.execute(request);
19
20 // Validate response
21 if (!response.conversation && response.status === 'completed') {
22 console.warn('AOP completed but no conversation data available');
23 }
24
25 return response;
26 } catch (error) {
27 if (error instanceof AthenaIntelligenceError) {
28 // Handle specific API errors
29 switch (error.statusCode) {
30 case 401:
31 console.error('Authentication failed - check your API key');
32 break;
33 case 404:
34 console.error('AOP asset not found - check the asset_id');
35 break;
36 case 400:
37 console.error('Invalid request - check your user_inputs format');
38 break;
39 default:
40 console.error(`AOP execution failed: ${error.statusCode} - ${error.message}`);
41 }
42 } else {
43 console.error('Unexpected error during AOP execution:', error);
44 }
45 return null;
46 }
47}
48
49// Usage
50const result = await executeAopSafely(
51 'asset_9249292-d118-42d3-95b4-00eccfe0754f',
52 { company: 'Example Corp', quarter: 'Q1 2024' }
53);
10

Complete Working Example

Here’s a complete example demonstrating both sync and async AOP execution:

1import type { AthenaIntelligence } from 'athena-intelligence';
2import { AthenaIntelligenceClient, AthenaIntelligenceError } from 'athena-intelligence';
3
4async function runAopExample() {
5 try {
6 const client = new AthenaIntelligenceClient({
7 apiKey: process.env.ATHENA_API_KEY,
8 });
9
10 // Example 1: Synchronous execution for quick tasks
11 console.log('=== Synchronous AOP Execution ===');
12
13 const syncRequest: AthenaIntelligence.AopExecuteRequestIn = {
14 asset_id: 'asset_quick_analysis_aop',
15 user_inputs: {
16 topic: 'AI market trends',
17 focus: 'investment analysis',
18 },
19 };
20
21 const syncResponse = await client.aop.execute(syncRequest);
22
23 // Safe access to conversation result
24 if (syncResponse.conversation?.last_assistant_message?.content) {
25 console.log('Sync Result:', syncResponse.conversation.last_assistant_message.content);
26 } else {
27 console.log('Sync Result: No final assistant message available');
28 console.log('Response status:', syncResponse.status);
29 }
30
31 // Example 2: Asynchronous execution for complex workflows
32 console.log('\n=== Asynchronous AOP Execution ===');
33
34 const asyncRequest: AthenaIntelligence.AopExecuteRequestIn = {
35 asset_id: 'asset_comprehensive_research_aop',
36 user_inputs: {
37 company: 'Microsoft Corporation',
38 analysis_type: 'full_competitive_analysis',
39 time_horizon: '2024-2025',
40 include_financials: 'true',
41 },
42 };
43
44 const asyncResponse = await client.aop.executeAsync(asyncRequest);
45 console.log('Async execution started with thread:', asyncResponse.thread_id);
46
47 // Monitor the async execution
48 await monitorAsyncExecution(client, asyncResponse.thread_id);
49
50 } catch (error) {
51 if (error instanceof AthenaIntelligenceError) {
52 console.error(`AOP example failed: ${error.statusCode} - ${error.message}`);
53 } else {
54 console.error('Unexpected error:', error);
55 }
56 }
57}
58
59async function monitorAsyncExecution(
60 client: AthenaIntelligenceClient,
61 threadId: string
62): Promise<void> {
63 const maxAttempts = 24; // 2 minutes with 5-second intervals
64 const pollInterval = 5000;
65
66 for (let attempt = 1; attempt <= maxAttempts; attempt++) {
67 try {
68 const status = await client.threads.getStatus(threadId);
69
70 console.log(`[${attempt}/${maxAttempts}] Status: ${status.status} (Updated: ${status.updated_at})`);
71
72 if (status.status === 'completed') {
73 console.log('🎉 AOP execution completed successfully!');
74
75 if (status.conversation_asset?.last_message) {
76 console.log('Final Result:');
77 console.log(status.conversation_asset.last_message.content);
78 }
79 return;
80 } else if (status.status === 'failed') {
81 console.error('❌ AOP execution failed');
82 return;
83 }
84
85 // Continue polling
86 await new Promise(resolve => setTimeout(resolve, pollInterval));
87 } catch (error) {
88 console.error('Status check failed:', error);
89 return;
90 }
91 }
92
93 console.warn('⏰ Polling timeout reached - execution may still be running');
94}
95
96runAopExample();
11

Working with Different AOP Types

AOPs can be designed for various use cases. Here are examples for common scenarios:

1// Research and Analysis AOP
2const researchAop: AthenaIntelligence.AopExecuteRequestIn = {
3 asset_id: 'asset_research_aop',
4 user_inputs: {
5 research_topic: 'Quantum computing breakthroughs',
6 depth: 'comprehensive',
7 sources: 'academic,industry,news',
8 time_range: 'last_12_months',
9 },
10};
11
12// Content Generation AOP
13const contentAop: AthenaIntelligence.AopExecuteRequestIn = {
14 asset_id: 'asset_content_generator_aop',
15 user_inputs: {
16 content_type: 'blog_post',
17 topic: 'AI in healthcare',
18 tone: 'professional',
19 length: '1500_words',
20 target_audience: 'healthcare_professionals',
21 },
22};
23
24// Data Analysis AOP
25const dataAnalysisAop: AthenaIntelligence.AopExecuteRequestIn = {
26 asset_id: 'asset_data_analysis_aop',
27 user_inputs: {
28 dataset_id: 'sales_q1_2024',
29 analysis_type: 'trend_analysis',
30 metrics: 'revenue,growth,customer_acquisition',
31 visualization: 'charts_and_tables',
32 },
33};
34
35// Execute different AOPs based on use case
36const results = await Promise.allSettled([
37 client.aop.execute(researchAop),
38 client.aop.execute(contentAop),
39 client.aop.execute(dataAnalysisAop),
40]);
41
42results.forEach((result, index) => {
43 const aopNames = ['Research', 'Content', 'Data Analysis'];
44
45 if (result.status === 'fulfilled') {
46 console.log(`${aopNames[index]} AOP completed:`, result.value.status);
47 } else {
48 console.error(`${aopNames[index]} AOP failed:`, result.reason);
49 }
50});
12

Advanced Configuration

Some AOPs may require specific configuration or have optional parameters:

1// AOP with minimal inputs
2const minimalRequest: AthenaIntelligence.AopExecuteRequestIn = {
3 asset_id: 'asset_simple_aop',
4 // No user_inputs required for this AOP
5};
6
7// AOP with complex nested inputs
8const complexRequest: AthenaIntelligence.AopExecuteRequestIn = {
9 asset_id: 'asset_advanced_aop',
10 user_inputs: {
11 // Simple parameters
12 company_name: 'OpenAI',
13 analysis_date: '2024-01-15',
14
15 // JSON-stringified complex parameters
16 search_criteria: JSON.stringify({
17 industries: ['technology', 'ai', 'saas'],
18 market_cap_min: 1000000000,
19 regions: ['north_america', 'europe'],
20 }),
21
22 // Configuration flags
23 include_charts: 'true',
24 export_format: 'pdf',
25 email_results: 'false',
26 },
27};
28
29const complexResponse = await client.aop.execute(complexRequest);
13

TypeScript Type Definitions

For better type safety, define comprehensive interfaces that match the full API response structure:

1// Content types for messages
2interface TextContent {
3 type: 'text';
4 text: string;
5}
6
7interface ImageUrlContent {
8 type: 'image_url';
9 image_url: Record<string, string>;
10}
11
12type MessageContent = string | (TextContent | ImageUrlContent)[];
13
14// Message structure
15interface ConversationMessage {
16 id: string;
17 role: 'user' | 'assistant' | 'system' | 'tool';
18 content: MessageContent;
19 additional_kwargs?: Record<string, any>;
20 name?: string;
21 tool_calls?: Record<string, any>[];
22 tool_call_id?: string;
23 response_metadata?: Record<string, any>;
24 usage_metadata?: Record<string, any>;
25}
26
27// Complete conversation result structure
28interface ConversationResult {
29 conversation_id: string;
30 created_at: string;
31 updated_at: string;
32 title: string;
33 num_messages: number;
34 messages_source: string;
35 messages: ConversationMessage[];
36 last_assistant_message?: ConversationMessage; // Optional - may not always be present
37}
38
39// Conversation asset information (from OpenAPI ConversationAssetInfo)
40interface ConversationAssetInfo {
41 conversation_asset_id: string;
42 title: string;
43 created_at: string;
44 updated_at: string;
45 created_by: string;
46 workspace_id: string;
47 state: string | null;
48 start_channel: string | null;
49 last_channel: string | null;
50 num_messages: number | null;
51 last_message: ConversationMessage | null; // Explicitly nullable in schema
52 linked_aops: Record<string, any>[] | null;
53 linked_projects: Record<string, any>[] | null;
54 agent: string | null;
55 model: string | null;
56 athena_metadata: Record<string, any> | null;
57 messages: ConversationMessage[] | null; // Nullable in schema - may not always be loaded
58}
59
60// Complete AOP execution response
61interface AopExecuteResponse {
62 status: string;
63 thread_id: string;
64 sync_server: string;
65 trigger_type: string;
66 aop_asset_id: string;
67 aop_title: string;
68 base_prompt: string;
69 final_prompt: string;
70 aop_config: Record<string, any>;
71 conversation?: ConversationResult | null;
72 error?: string | null;
73}
74
75// Async AOP response
76interface AopAsyncExecuteResponse {
77 status: string;
78 thread_id: string;
79 sync_server: string;
80 trigger_type: string;
81 message: string;
82 aop_asset_id: string;
83 aop_title: string;
84 base_prompt: string;
85 final_prompt: string;
86 aop_config: Record<string, any>;
87}
88
89// Thread status response
90interface ThreadStatusResponse {
91 thread_id: string;
92 status: string;
93 created_at: string;
94 updated_at: string;
95 conversation_asset: ConversationAssetInfo | null;
96}
97
98// AOP input types
99interface MarketResearchInputs {
100 company: string;
101 quarter: string;
102 analysis_depth?: 'basic' | 'comprehensive' | 'deep';
103 include_competitors?: 'true' | 'false';
104 target_market?: string;
105 industry?: string;
106 time_horizon?: string;
107}
108
109interface ContentGenerationInputs {
110 topic: string;
111 content_type: 'blog_post' | 'report' | 'summary' | 'presentation';
112 tone: 'professional' | 'casual' | 'technical' | 'friendly';
113 length: string;
114 target_audience: string;
115 keywords?: string;
116 outline_required?: 'true' | 'false';
117}
118
119interface DataAnalysisInputs {
120 dataset_id: string;
121 analysis_type: 'trend_analysis' | 'comparative' | 'predictive';
122 metrics: string;
123 time_period?: string;
124 visualization?: 'charts_and_tables' | 'dashboard' | 'report';
125 export_format?: 'json' | 'csv' | 'pdf';
126}
127
128// Type-safe AOP execution functions
129async function executeMarketResearchAop(
130 assetId: string,
131 inputs: MarketResearchInputs
132): Promise<AopExecuteResponse> {
133 const request: AthenaIntelligence.AopExecuteRequestIn = {
134 asset_id: assetId,
135 user_inputs: inputs as Record<string, string>,
136 };
137
138 const response = await client.aop.execute(request);
139 return response as AopExecuteResponse;
140}
141
142async function executeContentGenerationAop(
143 assetId: string,
144 inputs: ContentGenerationInputs
145): Promise<AopExecuteResponse> {
146 const request: AthenaIntelligence.AopExecuteRequestIn = {
147 asset_id: assetId,
148 user_inputs: inputs as Record<string, string>,
149 };
150
151 const response = await client.aop.execute(request);
152 return response as AopExecuteResponse;
153}
154
155// Type-safe async execution with monitoring
156async function executeAopAsync<T extends Record<string, string>>(
157 assetId: string,
158 inputs: T
159): Promise<{ response: AopAsyncExecuteResponse; finalResult: ThreadStatusResponse }> {
160 // Start async execution
161 const asyncResponse = await client.aop.executeAsync({
162 asset_id: assetId,
163 user_inputs: inputs,
164 }) as AopAsyncExecuteResponse;
165
166 // Monitor until completion
167 const finalResult = await monitorExecutionTyped(asyncResponse.thread_id);
168
169 return { response: asyncResponse, finalResult };
170}
171
172// Type-safe monitoring function
173async function monitorExecutionTyped(threadId: string): Promise<ThreadStatusResponse> {
174 const maxAttempts = 30;
175 const pollInterval = 5000;
176
177 for (let attempt = 1; attempt <= maxAttempts; attempt++) {
178 const status = await client.threads.getStatus(threadId) as ThreadStatusResponse;
179
180 console.log(`[${attempt}/${maxAttempts}] Status: ${status.status}`);
181
182 if (status.status === 'completed' || status.status === 'failed') {
183 return status;
184 }
185
186 await new Promise(resolve => setTimeout(resolve, pollInterval));
187 }
188
189 throw new Error('Monitoring timeout reached');
190}
191
192// Usage with full type safety and conversation access
193const marketResult = await executeMarketResearchAop(
194 'asset_market_research_aop',
195 {
196 company: 'Apple Inc',
197 quarter: 'Q4 2024',
198 analysis_depth: 'comprehensive',
199 include_competitors: 'true',
200 target_market: 'global',
201 industry: 'technology',
202 }
203);
204
205// Access typed conversation data
206if (marketResult.conversation) {
207 const conversation = marketResult.conversation;
208
209 console.log('Conversation Details:');
210 console.log(`- ID: ${conversation.conversation_id}`);
211 console.log(`- Title: ${conversation.title}`);
212 console.log(`- Messages: ${conversation.num_messages}`);
213 console.log(`- Created: ${conversation.created_at}`);
214 console.log(`- Updated: ${conversation.updated_at}`);
215
216 // Access all messages with type safety
217 conversation.messages.forEach((message, index) => {
218 console.log(`Message ${index + 1} (${message.role}):`);
219
220 if (typeof message.content === 'string') {
221 console.log(` Content: ${message.content}`);
222 } else if (Array.isArray(message.content)) {
223 message.content.forEach((part, partIndex) => {
224 if (part.type === 'text') {
225 console.log(` Text Part ${partIndex + 1}: ${part.text}`);
226 } else if (part.type === 'image_url') {
227 console.log(` Image Part ${partIndex + 1}: ${JSON.stringify(part.image_url)}`);
228 }
229 });
230 }
231
232 if (message.tool_calls && message.tool_calls.length > 0) {
233 console.log(` Tool Calls: ${message.tool_calls.length}`);
234 }
235
236 if (message.additional_kwargs) {
237 console.log(` Additional Data: ${JSON.stringify(message.additional_kwargs, null, 2)}`);
238 }
239 });
240
241 // Access the final assistant response (if available)
242 if (conversation.last_assistant_message) {
243 const finalMessage = conversation.last_assistant_message;
244 console.log('\nFinal Assistant Response:');
245 console.log(`- ID: ${finalMessage.id}`);
246 console.log(`- Role: ${finalMessage.role}`);
247 console.log(`- Content: ${typeof finalMessage.content === 'string' ? finalMessage.content : JSON.stringify(finalMessage.content)}`);
248
249 if (finalMessage.usage_metadata) {
250 console.log(`- Usage Metadata: ${JSON.stringify(finalMessage.usage_metadata, null, 2)}`);
251 }
252 } else {
253 console.log('\nNo final assistant message available');
254 }
255}
256
257// Example with async execution and full conversation access
258const asyncResult = await executeAopAsync('asset_comprehensive_analysis_aop', {
259 company: 'Tesla Inc',
260 analysis_type: 'full_market_analysis',
261 time_period: '2024',
262 include_forecasts: 'true',
263});
264
265console.log('Async Execution Started:', asyncResult.response.thread_id);
266console.log('Final Status:', asyncResult.finalResult.status);
267
268// Access the full conversation from the final result (handle nullable messages)
269if (asyncResult.finalResult.conversation_asset?.messages) {
270 const messages = asyncResult.finalResult.conversation_asset.messages;
271
272 console.log(`\nFull Conversation (${messages.length} messages):`);
273
274 messages.forEach((msg, index) => {
275 console.log(`${index + 1}. [${msg.role}] ${typeof msg.content === 'string' ? msg.content.substring(0, 100) + '...' : '[Complex Content]'}`);
276 });
277} else if (asyncResult.finalResult.conversation_asset?.last_message) {
278 // If full messages aren't available, show at least the last message
279 const lastMsg = asyncResult.finalResult.conversation_asset.last_message;
280 console.log(`\nLast Message Available: [${lastMsg.role}] ${typeof lastMsg.content === 'string' ? lastMsg.content.substring(0, 100) + '...' : '[Complex Content]'}`);
281} else {
282 console.log('\nNo conversation messages available - conversation may still be loading');
283}
14

Handling Nullable Fields and Conversation States

The API returns nullable fields in various scenarios. Always check for null values before accessing nested properties:

1// Safe conversation access function
2function safelyAccessConversation(response: AopExecuteResponse): void {
3 console.log('=== Safe Conversation Access ===');
4
5 // 1. Check if conversation exists at all
6 if (!response.conversation) {
7 console.log('❌ No conversation data available');
8 console.log('This may happen if:');
9 console.log(' - AOP execution failed before starting');
10 console.log(' - AOP is still initializing');
11 console.log(' - Response format changed');
12 return;
13 }
14
15 const conv = response.conversation;
16 console.log('✅ Conversation data available');
17
18 // 2. Check messages array
19 if (!conv.messages || conv.messages.length === 0) {
20 console.log('❌ No messages in conversation');
21 console.log('This may happen if:');
22 console.log(' - Conversation just started');
23 console.log(' - Messages not yet loaded from checkpoints');
24 } else {
25 console.log(`✅ ${conv.messages.length} messages available`);
26
27 // Process messages safely
28 conv.messages.forEach((msg, index) => {
29 console.log(`Message ${index + 1}: [${msg.role}]`);
30
31 // Safe content access
32 if (typeof msg.content === 'string') {
33 console.log(` Text: ${msg.content.substring(0, 100)}...`);
34 } else if (Array.isArray(msg.content)) {
35 console.log(` Multimodal content with ${msg.content.length} parts`);
36 } else {
37 console.log(' No content available');
38 }
39 });
40 }
41
42 // 3. Check last assistant message
43 if (!conv.last_assistant_message) {
44 console.log('❌ No final assistant message');
45 console.log('This may happen if:');
46 console.log(' - Conversation ended with user message');
47 console.log(' - Assistant response not yet generated');
48 console.log(' - Execution was interrupted');
49 } else {
50 console.log('✅ Final assistant message available');
51 const finalContent = conv.last_assistant_message.content;
52 if (typeof finalContent === 'string') {
53 console.log(`Final response: ${finalContent.substring(0, 150)}...`);
54 }
55 }
56
57 // 4. Show conversation metadata with safe access
58 console.log('\n=== Conversation Metadata ===');
59 console.log(`ID: ${conv.conversation_id}`);
60 console.log(`Title: ${conv.title}`);
61 console.log(`Message Count: ${conv.num_messages}`);
62 console.log(`Source: ${conv.messages_source}`);
63 console.log(`Created: ${conv.created_at}`);
64 console.log(`Updated: ${conv.updated_at}`);
65}
66
67// Safe thread status access
68function safelyAccessThreadStatus(status: ThreadStatusResponse): void {
69 console.log('=== Safe Thread Status Access ===');
70 console.log(`Thread ID: ${status.thread_id}`);
71 console.log(`Status: ${status.status}`);
72 console.log(`Created: ${status.created_at}`);
73 console.log(`Updated: ${status.updated_at}`);
74
75 // Check conversation asset (nullable)
76 if (!status.conversation_asset) {
77 console.log('❌ No conversation asset available');
78 return;
79 }
80
81 const asset = status.conversation_asset;
82 console.log('✅ Conversation asset available');
83
84 // Safe access to nullable fields
85 console.log(`Asset ID: ${asset.conversation_asset_id}`);
86 console.log(`Title: ${asset.title}`);
87 console.log(`State: ${asset.state || 'unknown'}`);
88 console.log(`Agent: ${asset.agent || 'not specified'}`);
89 console.log(`Model: ${asset.model || 'not specified'}`);
90 console.log(`Start Channel: ${asset.start_channel || 'unknown'}`);
91 console.log(`Last Channel: ${asset.last_channel || 'unknown'}`);
92 console.log(`Message Count: ${asset.num_messages ?? 'unknown'}`);
93
94 // Check last message (nullable)
95 if (asset.last_message) {
96 console.log('✅ Last message available');
97 console.log(`Last Message Role: ${asset.last_message.role}`);
98 const content = asset.last_message.content;
99 if (typeof content === 'string') {
100 console.log(`Last Message Content: ${content.substring(0, 100)}...`);
101 }
102 } else {
103 console.log('❌ No last message available');
104 }
105
106 // Check messages array (nullable)
107 if (asset.messages && asset.messages.length > 0) {
108 console.log(`✅ ${asset.messages.length} messages loaded from asset`);
109 } else {
110 console.log('❌ Messages not loaded in asset (use conversation field from sync response instead)');
111 }
112
113 // Check metadata (nullable)
114 if (asset.athena_metadata) {
115 console.log('✅ Athena metadata available:', Object.keys(asset.athena_metadata));
116 } else {
117 console.log('❌ No athena metadata');
118 }
119
120 // Check linked assets (nullable)
121 if (asset.linked_aops && asset.linked_aops.length > 0) {
122 console.log(`✅ ${asset.linked_aops.length} linked AOPs`);
123 }
124
125 if (asset.linked_projects && asset.linked_projects.length > 0) {
126 console.log(`✅ ${asset.linked_projects.length} linked projects`);
127 }
128}
129
130// Example usage with comprehensive null checking
131const aopResponse = await client.aop.execute({
132 asset_id: 'asset_example_aop',
133 user_inputs: { param: 'value' },
134}) as AopExecuteResponse;
135
136// Use safe access functions
137safelyAccessConversation(aopResponse);
138
139// For async executions
140const asyncResponse = await client.aop.executeAsync({
141 asset_id: 'asset_example_aop',
142 user_inputs: { param: 'value' },
143}) as AopAsyncExecuteResponse;
144
145// Monitor and safely access final status
146const finalStatus = await monitorExecutionTyped(asyncResponse.thread_id);
147safelyAccessThreadStatus(finalStatus);
15

Error Recovery and Retry Logic

Implement robust error handling with retry logic:

1async function executeAopWithRetry(
2 request: AthenaIntelligence.AopExecuteRequestIn,
3 maxRetries: number = 3
4): Promise<AthenaIntelligence.AopExecuteResponseOut | null> {
5 let lastError: Error | null = null;
6
7 for (let attempt = 1; attempt <= maxRetries; attempt++) {
8 try {
9 console.log(`Attempt ${attempt}/${maxRetries} for AOP execution...`);
10
11 const response = await client.aop.execute(request);
12 console.log(`✅ AOP execution successful on attempt ${attempt}`);
13 return response;
14
15 } catch (error) {
16 lastError = error as Error;
17
18 if (error instanceof AthenaIntelligenceError) {
19 // Don't retry on client errors (4xx)
20 if (error.statusCode && error.statusCode >= 400 && error.statusCode < 500) {
21 console.error(`Client error (${error.statusCode}): ${error.message}`);
22 break;
23 }
24
25 // Retry on server errors (5xx) or network issues
26 console.warn(`Server error on attempt ${attempt}: ${error.statusCode} - ${error.message}`);
27 } else {
28 console.warn(`Network error on attempt ${attempt}:`, error.message);
29 }
30
31 // Wait before retrying (exponential backoff)
32 if (attempt < maxRetries) {
33 const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
34 console.log(`Waiting ${delay}ms before retry...`);
35 await new Promise(resolve => setTimeout(resolve, delay));
36 }
37 }
38 }
39
40 console.error('❌ AOP execution failed after all retry attempts');
41 throw lastError;
42}
43
44// Usage with retry logic
45const retriedResult = await executeAopWithRetry({
46 asset_id: 'asset_important_aop',
47 user_inputs: { critical_param: 'value' },
48});