Lesson 19: Using the Task API

This lesson introduces the Task API, a specialized interface for structured, non-chat interactions like code generation.

Code: lesson_19_task_api_usage.mjs

This script demonstrates how to get a list of available tasks and then execute a specific task (`code-generate:default`) using both the streaming (`.stream()`) and blocking (`.execute()`) methods.

// lesson_19_task_api_usage.mjs
// Merci SDK Tutorial: Lesson 19 - Using the Task API

// --- IMPORTS ---
import { MerciClient } from '../lib/merci.2.14.0.mjs';
import { token } from '../secret/token.mjs';

// A common task ID. We'll fetch the full list to ensure it's available.
const TASK_ID_TO_TEST = 'code-generate:default';

async function main() {
    console.log(`--- Merci SDK Tutorial: Lesson 19 - Using the Task API ---`);

    try {
        // --- STEP 1: INITIALIZE THE CLIENT ---
        console.log('[STEP 1] Initializing MerciClient...');
        const client = new MerciClient({ token });

        // --- STEP 2: GET THE ROSTER OF AVAILABLE TASKS ---
        console.log('
[STEP 2] Fetching the list of available tasks from the roster...');
        const roster = await client.tasks.roster();
        console.log('Available task IDs:', roster.ids);

        if (!roster.ids.includes(TASK_ID_TO_TEST)) {
            console.error(`\n[ERROR] The test task "${TASK_ID_TO_TEST}" is not available in the roster. Please choose another one.`);
            return;
        }
        console.log(`[INFO] Will use "${TASK_ID_TO_TEST}" for demonstration.`);

        // --- STEP 3: DEFINE TASK PARAMETERS ---
        console.log('
[STEP 3] Defining parameters for the code generation task...');
        const taskParameters = {
            instructions: "Write a simple JavaScript function that returns 'Hello, World!'.",
            language: "javascript",
            prefix: "",
            suffix: ""
        };
        console.log('Parameters:', JSON.stringify(taskParameters, null, 2));

        // --- STEP 4: EXECUTE THE TASK WITH THE STREAMING API ---
        console.log(`\n[STEP 4] Executing task "${TASK_ID_TO_TEST}" with .stream()...`);
        let streamedResponse = '';
        process.stdout.write('🤖 Task Output (Streaming) > ');

        const stream = client.tasks.stream(TASK_ID_TO_TEST, taskParameters);
        for await (const event of stream) {
            if (event.type === 'Content') {
                process.stdout.write(event.content);
                streamedResponse += event.content;
            } else {
                // Log other event types for observability
                console.log(`\n[STREAM EVENT: ${event.type}]`, event.data);
            }
        }
        process.stdout.write('\n');
        console.log('
[INFO] Stream finished.');

        // --- STEP 5: EXECUTE THE SAME TASK WITH THE BLOCKING API ---
        console.log(`\n[STEP 5] Executing task "${TASK_ID_TO_TEST}" with .execute()...`);
        const result = await client.tasks.execute(TASK_ID_TO_TEST, taskParameters);
        console.log('[INFO] Execution finished. Received aggregated result object.');

        // --- FINAL RESULT ---
        console.log('

--- FINAL RESULT ---');
        console.log('--- Streaming Response ---');
        console.log(streamedResponse);
        console.log('
--- Aggregated .execute() Response ---');
        console.log('Content:', result.content);
        console.log('Finish Metadata:', result.finishMetadata);
        console.log('--------------------');
        console.log('
Both methods produce the same content, but .stream() provides real-time feedback while .execute() returns a complete object after the task is done.');

    } catch (error) {
        console.error('

[FATAL ERROR] An error occurred during the operation.');
        console.error('  Message:', error.message);
        if (error.status) {
            console.error('  API Status:', error.status);
        }
        if (error.details) {
            console.error('  Details:', JSON.stringify(error.details, null, 2));
        }
        if (error.stack) {
            console.error('  Stack:', error.stack);
        }
        console.error('
  Possible causes: Invalid token, network issues, or an API service problem.');
        process.exit(1); // Exit with a non-zero code to indicate failure.
    }
}

main().catch(console.error);

Expected Output

The output shows the list of available tasks, the parameters used for the task, the real-time streaming output, and the final aggregated result from the `.execute()` call, demonstrating both ways to interact with the Task API.

--- Merci SDK Tutorial: Lesson 19 - Using the Task API ---
[STEP 1] Initializing MerciClient...
[STEP 2] Fetching the list of available tasks from the roster...
Available task IDs: ["code-generate:default", ... ]
[INFO] Will use "code-generate:default" for demonstration.
[STEP 3] Defining parameters for the code generation task...
Parameters: {
  "instructions": "Write a simple JavaScript function that returns 'Hello, World!'.",
  "language": "javascript",
  "prefix": "",
  "suffix": ""
}
[STEP 4] Executing task "code-generate:default" with .stream()...
🤖 Task Output (Streaming) > function hello() {
  return "Hello, World!";
}

[INFO] Stream finished.
[STEP 5] Executing task "code-generate:default" with .execute()...
[INFO] Execution finished. Received aggregated result object.

--- FINAL RESULT ---
--- Streaming Response ---
function hello() {
  return "Hello, World!";
}

--- Aggregated .execute() Response ---
Content: function hello() {
  return "Hello, World!";
}
Finish Metadata: { reason: "end_turn" }
--------------------

Both methods produce the same content, but .stream() provides real-time feedback while .execute() returns a complete object after the task is done.