Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: TypeScript version does not support async encoders for AWS Lambda agents #140

Open
giusedroid opened this issue Dec 4, 2024 · 0 comments
Labels
bug Something isn't working triage

Comments

@giusedroid
Copy link

Expected Behaviour

I can use promises or async functions when defining a custom encoder or custom decoder for AWS Lambda Agents. For example, I can use Bedrock to constrain the user input to JSON, or make use of APIs to adjust or hydrate my input.

Current Behaviour

Error during agent dispatch: TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received an instance of Promise
at Function.from (node:buffer:322:9)
at writeBody (/home/ec2-user/REDACTED/node_modules/@smithy/node-http-handler/dist-cjs/index.js:189:28)
at writeRequestBody (/home/ec2-user/REDACTED/node_modules/@smithy/node-http-handler/dist-cjs/index.js:170:5)
at /home/ec2-user/REDACTED/node_modules/@smithy/node-http-handler/dist-cjs/index.js:399:33
at new Promise ()
at _NodeHttpHandler.handle (/home/ec2-user/REDACTED/node_modules/@smithy/node-http-handler/dist-cjs/index.js:289:12)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async /home/ec2-user/REDACTED/node_modules/@smithy/middleware-serde/dist-cjs/index.js:33:24
at async /home/ec2-user/REDACTED/node_modules/@smithy/core/dist-cjs/index.js:168:18
at async /home/ec2-user/REDACTED/node_modules/@smithy/middleware-retry/dist-cjs/index.js:320:38 {
code: 'ERR_INVALID_ARG_TYPE',
'$metadata': { attempts: 1, totalRetryDelay: 0 }
}

Code snippet

import { MultiAgentOrchestrator, BedrockLLMAgent, LambdaAgent } from "multi-agent-orchestrator";
import { BedrockRuntimeClient, InvokeModelCommand } from "@aws-sdk/client-bedrock-runtime";

const encodingPrompt = `user input needs to be returned as a JSON object in the format
{"property":"value"}. RESPOND ONLY WITH JSON
`;

async function encodeUserInput(userInput) {
    // Initialize the Bedrock client
    const bedrockClient = new BedrockRuntimeClient({
        region: "us-east-1" // or your preferred region
    });

    // Construct the full prompt
    const fullPrompt = encodingPrompt + userInput;

    // Prepare the request body for Claude
    const body = {
        anthropic_version: "bedrock-2023-05-31",
        max_tokens: 1000,
        messages: [
            {
                role: "user",
                content: fullPrompt
            }
        ]
    };

    try {
        // Create the command
        const command = new InvokeModelCommand({
            modelId: "anthropic.claude-3-sonnet-20240229-v1:0", // Claude 3 Sonnet model ID
            body: JSON.stringify(body),
            contentType: "application/json",
            accept: "application/json",
        });

        // Invoke the model
        const response = await bedrockClient.send(command);

        // Parse the response
        const responseBody = JSON.parse(new TextDecoder().decode(response.body));
        
        // Extract the response content
        const result = responseBody?.content[0]?.text || "";

        // Parse the JSON response
        return JSON.parse(result);

    } catch (error) {
        console.error("Error invoking Bedrock:", error);
        throw error;
    }
}

const myCustomInputPayloadEncoder = async (input, chatHistory, userId, sessionId, additionalParams) => {
  const encoded = await encodeUserInput(input);
  return JSON.stringify({
    userQuestion: input,
    myCustomField: "Hello world!",
    history: chatHistory,
    user: userId,
    session: sessionId,
    intent:encoded.intent,
    prompt: encoded.prompt,
    text: encoded.text,
    ...additionalParams
  });
};

const options = {
  name: 'Custom Lambda Agent',
  description: 'An agent making use of lambda functions but requiring some interpretation of user input',
  functionName: 'MyLambdaFunctionName',
  functionRegion: 'us-east-1',
  inputPayloadEncoder: myCustomInputPayloadEncoder,
  outputPayloadDecoder: myCustomOutputPayloadDecoder
};


const CustomLambdaAgent = new LambdaAgent(options);

const orchestrator = new MultiAgentOrchestrator();

orchestrator.addAgent(CustomLambdaAgent);

const response = await orchestrator.routeRequest(
  "I want to know more about how to cook lasagna ",
  'user123',
  'session456'
);


// Handle the response (streaming or non-streaming)
if (response.streaming == true) {
    console.log("\n** RESPONSE STREAMING ** \n");
    // Send metadata immediately
    console.log(`> Agent ID: ${response.metadata.agentId}`);
    console.log(`> Agent Name: ${response.metadata.agentName}`);
    console.log(`> User Input: ${response.metadata.userInput}`);
    console.log(`> User ID: ${response.metadata.userId}`);
    console.log(`> Session ID: ${response.metadata.sessionId}`);
    console.log(
      `> Additional Parameters:`,
      response.metadata.additionalParams
    );
    console.log(`\n> Response: `);

    // Stream the content
    for await (const chunk of response.output) {
      if (typeof chunk === "string") {
        process.stdout.write(chunk);
      } else {
        console.error("Received unexpected chunk type:", typeof chunk);
      }
    }

} else {
    // Handle non-streaming response (AgentProcessingResult)
    console.log("\n** RESPONSE ** \n");
    console.log(`> Agent ID: ${response.metadata.agentId}`);
    console.log(`> Agent Name: ${response.metadata.agentName}`);
    console.log(`> User Input: ${response.metadata.userInput}`);
    console.log(`> User ID: ${response.metadata.userId}`);
    console.log(`> Session ID: ${response.metadata.sessionId}`);
    console.log(
      `> Additional Parameters:`,
      response.metadata.additionalParams
    );
    console.log(`\n> Response: ${response.output}`);
}

Possible Solution

No response

Steps to Reproduce

running the code above should be enough.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working triage
Projects
Development

No branches or pull requests

1 participant