Skip to content

Commit 38e5a90

Browse files
committed
set type of event given to resolve as unknown and use type assertion to verify it a bedrock event
1 parent 71f24b4 commit 38e5a90

File tree

3 files changed

+112
-7
lines changed

3 files changed

+112
-7
lines changed

packages/event-handler/src/bedrock-agent-function/BedrockAgentFunctionResolver.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
// TODO: rename folder to just bedrock-agent
2+
13
import { EnvironmentVariablesService } from '@aws-lambda-powertools/commons';
24
import type { Context } from 'aws-lambda';
35
import type {
4-
BedrockAgentFunctionEvent,
56
BedrockAgentFunctionResponse,
67
Configuration,
78
ParameterValue,
@@ -11,11 +12,10 @@ import type {
1112
ToolFunction,
1213
} from '../types/bedrock-agent-function.js';
1314
import type { GenericLogger } from '../types/common.js';
14-
import { isPrimitive } from './utils.js';
15+
import { assertBedrockAgentFunctionEvent, isPrimitive } from './utils.js';
1516

1617
export class BedrockAgentFunctionResolver {
17-
readonly #tools: Map<string, Tool<Record<string, ParameterValue>>> =
18-
new Map();
18+
readonly #tools: Map<string, Tool> = new Map();
1919
readonly #envService: EnvironmentVariablesService;
2020
readonly #logger: Pick<GenericLogger, 'debug' | 'warn' | 'error'>;
2121

@@ -124,7 +124,7 @@ export class BedrockAgentFunctionResolver {
124124
}
125125

126126
this.#tools.set(name, {
127-
handler: handler as ToolFunction<Record<string, ParameterValue>>,
127+
handler: handler as ToolFunction,
128128
config,
129129
});
130130
this.#logger.debug(`Tool ${name} has been registered.`);
@@ -160,9 +160,11 @@ export class BedrockAgentFunctionResolver {
160160
}
161161

162162
async resolve(
163-
event: BedrockAgentFunctionEvent,
163+
event: unknown,
164164
context: Context
165165
): Promise<BedrockAgentFunctionResponse> {
166+
assertBedrockAgentFunctionEvent(event);
167+
166168
const {
167169
function: toolName,
168170
parameters = [],
@@ -205,7 +207,7 @@ export class BedrockAgentFunctionResolver {
205207

206208
try {
207209
const res = (await tool.handler(toolParams, event, context)) ?? '';
208-
const body = isPrimitive(res) ? String(res) : JSON.stringify(res);
210+
const body = isPrimitive(res) ? String(res) : JSON.stringify(res); //TODO just use JSON.stringify
209211
return this.#buildResponse({
210212
actionGroup,
211213
function: toolName,

packages/event-handler/src/bedrock-agent-function/utils.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import type {
22
JSONPrimitive,
33
JSONValue,
44
} from '@aws-lambda-powertools/commons/types';
5+
import { isRecord, isString } from '@aws-lambda-powertools/commons/typeutils';
6+
import type { BedrockAgentFunctionEvent } from '../types/bedrock-agent-function.js';
57

68
export function isPrimitive(value: JSONValue): value is JSONPrimitive {
79
return (
@@ -12,3 +14,59 @@ export function isPrimitive(value: JSONValue): value is JSONPrimitive {
1214
typeof value === 'boolean'
1315
);
1416
}
17+
18+
/**
19+
* Asserts that the provided event is a BedrockAgentFunctionEvent.
20+
*
21+
* @param event - The incoming event to check
22+
* @throws Error if the event is not a valid BedrockAgentFunctionEvent
23+
*/
24+
export function assertBedrockAgentFunctionEvent(
25+
event: unknown
26+
): asserts event is BedrockAgentFunctionEvent {
27+
const isValid =
28+
typeof event === 'object' &&
29+
event !== null &&
30+
isRecord(event) &&
31+
'actionGroup' in event &&
32+
isString(event.actionGroup) &&
33+
'function' in event &&
34+
isString(event.function) &&
35+
(!('parameters' in event) ||
36+
event.parameters == null ||
37+
(Array.isArray(event.parameters) &&
38+
event.parameters.every(
39+
(param) =>
40+
isRecord(param) &&
41+
'name' in param &&
42+
isString(param.name) &&
43+
'type' in param &&
44+
isString(param.type) &&
45+
'value' in param &&
46+
isString(param.value)
47+
))) &&
48+
'messageVersion' in event &&
49+
isString(event.messageVersion) &&
50+
'agent' in event &&
51+
isRecord(event.agent) &&
52+
'name' in event.agent &&
53+
isString(event.agent.name) &&
54+
'id' in event.agent &&
55+
isString(event.agent.id) &&
56+
'alias' in event.agent &&
57+
isString(event.agent.alias) &&
58+
'version' in event.agent &&
59+
isString(event.agent.version) &&
60+
'inputText' in event &&
61+
isString(event.inputText) &&
62+
'sessionId' in event &&
63+
isString(event.sessionId) &&
64+
'sessionAttributes' in event &&
65+
isRecord(event.sessionAttributes) &&
66+
'promptSessionAttributes' in event &&
67+
isRecord(event.promptSessionAttributes);
68+
69+
if (!isValid) {
70+
throw new Error('Event is not a valid BedrockAgentFunctionEvent');
71+
}
72+
}

packages/event-handler/tests/unit/bedrock-agent/BedrockAgentFunctionResolver.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,51 @@ describe('Class: BedrockAgentFunctionResolver', () => {
3434
vi.unstubAllEnvs();
3535
});
3636

37+
it.each([
38+
{
39+
name: 'null event',
40+
invalidEvent: null,
41+
},
42+
{
43+
name: 'missing required fields',
44+
invalidEvent: {
45+
function: 'test-tool',
46+
},
47+
},
48+
{
49+
name: 'invalid parameters structure',
50+
invalidEvent: {
51+
function: 'test-tool',
52+
actionGroup: 'testGroup',
53+
messageVersion: '1.0',
54+
agent: {
55+
name: 'agentName',
56+
id: 'agentId',
57+
alias: 'agentAlias',
58+
version: '1',
59+
},
60+
inputText: 'test input',
61+
sessionId: 'session123',
62+
parameters: 'not an array',
63+
sessionAttributes: {},
64+
promptSessionAttributes: {},
65+
},
66+
},
67+
])('throws when given an invalid event: $name', async ({ invalidEvent }) => {
68+
// Prepare
69+
const app = new BedrockAgentFunctionResolver();
70+
71+
app.tool(async () => 'test', {
72+
name: 'test-tool',
73+
description: 'Test tool',
74+
});
75+
76+
// Act & Assert
77+
await expect(app.resolve(invalidEvent, context)).rejects.toThrow(
78+
'Event is not a valid BedrockAgentFunctionEvent'
79+
);
80+
});
81+
3782
it('uses a default logger with only warnings if none is provided', () => {
3883
// Prepare
3984
const app = new BedrockAgentFunctionResolver();

0 commit comments

Comments
 (0)