Skip to content

Commit 2f01557

Browse files
TwinsLeevincentkoc
authored andcommitted
fix(feishu): emit non-empty value schema for bitable write tools (#94547)
Type.Record(Type.String(), Type.Any()) serializes via TypeBox to an empty nested value schema (patternProperties: { "^.*$": {} }). AWS Bedrock's strict tool-schema validation rejects the empty sub-schema, breaking all agent turns for Bedrock-backed Anthropic users with Feishu bitable tools enabled. Replace the three affected free-form field maps (create_record, update_record, create_field) with an explicit non-empty FlexibleFieldValue value schema that still accepts any JSON value. Type.Unknown() is avoided because it also serializes to an empty schema. Adds regression coverage asserting the emitted value schema is non-empty.
1 parent bfffa95 commit 2f01557

2 files changed

Lines changed: 35 additions & 3 deletions

File tree

extensions/feishu/src/bitable.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,29 @@ describe("feishu bitable create app cleanup", () => {
172172
expect(client.bitable.appTableRecord.list).toHaveBeenCalledTimes(1);
173173
});
174174
});
175+
176+
describe("feishu bitable write tool schemas (#94547)", () => {
177+
it.each([
178+
["feishu_bitable_create_record", "fields"],
179+
["feishu_bitable_update_record", "fields"],
180+
["feishu_bitable_create_field", "property"],
181+
])("%s emits a non-empty value schema for %s", (toolName, propName) => {
182+
const { api, resolveTool } = createToolFactoryHarness(createConfig());
183+
registerFeishuBitableTools(api);
184+
185+
const tool = resolveTool(toolName) as unknown as {
186+
parameters?: {
187+
properties?: Record<
188+
string,
189+
{ patternProperties?: Record<string, Record<string, unknown>> }
190+
>;
191+
};
192+
};
193+
const patternSchemas = Object.values(
194+
tool.parameters?.properties?.[propName]?.patternProperties ?? {},
195+
);
196+
expect(patternSchemas).toEqual([
197+
{ type: ["string", "number", "boolean", "object", "array", "null"] },
198+
]);
199+
});
200+
});

extensions/feishu/src/bitable.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -517,12 +517,18 @@ const GetRecordSchema = Type.Object({
517517
record_id: Type.String({ description: "Record ID to retrieve" }),
518518
});
519519

520+
// TypeBox emits an empty schema for Any/Unknown, which Bedrock-backed validators
521+
// can reject inside patternProperties. Keep the existing any-JSON-value contract explicit.
522+
const BitableFieldValueSchema = Type.Unsafe<unknown>({
523+
type: ["string", "number", "boolean", "object", "array", "null"],
524+
});
525+
520526
const CreateRecordSchema = Type.Object({
521527
app_token: Type.String({
522528
description: "Bitable app token (use feishu_bitable_get_meta to get from URL)",
523529
}),
524530
table_id: Type.String({ description: "Table ID (from URL: ?table=YYY)" }),
525-
fields: Type.Record(Type.String(), Type.Any(), {
531+
fields: Type.Record(Type.String(), BitableFieldValueSchema, {
526532
description:
527533
"Field values keyed by field name. Format by type: Text='string', Number=123, SingleSelect='Option', MultiSelect=['A','B'], DateTime=timestamp_ms, User=[{id:'ou_xxx'}], URL={text:'Display',link:'https://...'}",
528534
}),
@@ -552,7 +558,7 @@ const CreateFieldSchema = Type.Object({
552558
minimum: 1,
553559
}),
554560
property: Type.Optional(
555-
Type.Record(Type.String(), Type.Any(), {
561+
Type.Record(Type.String(), BitableFieldValueSchema, {
556562
description: "Field-specific properties (e.g., options for SingleSelect, format for Number)",
557563
}),
558564
),
@@ -564,7 +570,7 @@ const UpdateRecordSchema = Type.Object({
564570
}),
565571
table_id: Type.String({ description: "Table ID (from URL: ?table=YYY)" }),
566572
record_id: Type.String({ description: "Record ID to update" }),
567-
fields: Type.Record(Type.String(), Type.Any(), {
573+
fields: Type.Record(Type.String(), BitableFieldValueSchema, {
568574
description: "Field values to update (same format as create_record)",
569575
}),
570576
});

0 commit comments

Comments
 (0)