Skip to main content

Handling Multiple Response Types

There are cases where your target could respond with multiple object types. This is usually the case when the target is blocked by a guardrail. For example,

{
"message": "Hello, world!"
}

or if it is blocked by a guardrail, it could return an error message:

{
"error": "The content you provided violates our policies."
}

Solution

For the simple case above you can use a response parser with a little bit of logic to handle the multiple response types.

- id: http://url.foryour.bot/chat
label: 'internal-chatbot'
config:
method: 'POST'
headers: { 'Content-Type': 'application/json' }
body: { 'message': '{{prompt}}' }
responseParser: json.response ?? json.error

For more complex cases, you can use a custom provider. See the custom provider docs.

For example, let's say the response will be return with a 400 status code.

const URL = 'enter your custom provider URL here';

class CustomApiProvider {
constructor(options) {
// The caller may override Provider ID (e.g. when using multiple instances of the same provider)
this.providerId = options.id || 'custom provider';

// The config object contains any options passed to the provider in the config file.
this.config = options.config;
}

id() {
return this.providerId;
}

async callApi(prompt) {
const body = {
message: prompt,
};

// Fetch the data from the API using promptfoo's cache. You can use your own fetch implementation if preferred.
const response = await fetch(
URL,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
},
10_000 /* 10 second timeout */,
);

let message = null;
if (response.status === 400) {
message = 'Request blocked by guardrail';
} else {
const data = await response.json();
message = data.message;
}

const ret = {
output: message,
tokenUsage: {
total: data.usage.total_tokens,
prompt: data.usage.prompt_tokens,
completion: data.usage.completion_tokens,
},
};
return ret;
}
}

module.exports = CustomApiProvider;