Q96: connector action schemas reach the agent whole
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f6447319a3
commit
a9620eaa5a
2 files changed
+33
-13
No files matched your search
@@ -7,11 +7,8 @@ export interface ComposioToolSchema {
|
||||
name: string;
|
||||
description: string;
|
||||
toolkitSlug: string | null;
|
||||
parameters: {
|
||||
type: string;
|
||||
properties: Record<string, unknown>;
|
||||
required?: string[];
|
||||
};
|
||||
/** The action's input JSON Schema exactly as Composio validates it ($defs, combinations and limits kept). */
|
||||
parameters: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface ComposioAuthConfigSummary {
|
||||
@@ -214,17 +211,16 @@ export class ComposioClient {
|
||||
}
|
||||
|
||||
function normalizeToolSchema(raw: Record<string, unknown>): ComposioToolSchema {
|
||||
const params = raw.input_parameters ?? raw.parameters ?? raw.inputSchema ?? {};
|
||||
const schema = typeof params === "object" && params !== null ? params as Record<string, unknown> : {};
|
||||
const name = String(raw.slug ?? raw.name ?? "");
|
||||
const field = ["input_parameters", "parameters", "inputSchema"].find((key) => key in raw);
|
||||
const params = field === undefined ? undefined : raw[field];
|
||||
// An action without an input schema takes no input; anything else must be a schema object, passed on unchanged.
|
||||
if (params !== undefined && (typeof params !== "object" || params === null || Array.isArray(params))) throw new Error(`Composio action ${name} has an input schema that is not an object.`);
|
||||
const toolkit = (raw.toolkit ?? {}) as Record<string, unknown>;
|
||||
return {
|
||||
name: String(raw.slug ?? raw.name ?? ""),
|
||||
name,
|
||||
description: String(raw.description ?? "").slice(0, 300),
|
||||
toolkitSlug: typeof toolkit.slug === "string" ? toolkit.slug : null,
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: (schema.properties ?? {}) as Record<string, unknown>,
|
||||
required: Array.isArray(schema.required) ? schema.required as string[] : [],
|
||||
},
|
||||
parameters: params === undefined ? { type: "object", properties: {} } : params as Record<string, unknown>,
|
||||
};
|
||||
}
|
||||
@@ -109,4 +109,28 @@ describe("agents reach every action through search and run", () => {
|
||||
expect(h.connection.db.prepare("select count(*) as n from run_actions").get()).toEqual({ n: 0 });
|
||||
h.connection.close();
|
||||
});
|
||||
|
||||
test("an action's input schema reaches the agent whole: references, combinations and limits included", async () => {
|
||||
const input = {
|
||||
type: "object",
|
||||
$defs: { Reviewer: { type: "object", properties: { login: { type: "string" } }, required: ["login"] } },
|
||||
properties: {
|
||||
title: { type: "string", maxLength: 256 },
|
||||
reviewers: { type: "array", items: { $ref: "#/$defs/Reviewer" } },
|
||||
base: { anyOf: [{ type: "string" }, { type: "null" }] },
|
||||
},
|
||||
required: ["title"],
|
||||
additionalProperties: false,
|
||||
oneOf: [{ required: ["base"] }, { required: ["reviewers"] }],
|
||||
};
|
||||
pages.set("github:", { items: [{ ...tool("GITHUB_CREATE_A_PULL_REQUEST"), description: "Create a pull request", input_parameters: input }], next_cursor: null });
|
||||
const h = company("ak_schema");
|
||||
const found = JSON.parse(await h.call("composio_find_actions", { query: "pull request" })) as { matches: Array<{ input: unknown }> };
|
||||
expect(found.matches[0].input).toEqual(input);
|
||||
pages.set("github:", { items: [{ ...tool("GITHUB_BROKEN"), input_parameters: null }], next_cursor: null });
|
||||
const broken = company("ak_schema_null");
|
||||
expect(await broken.call("composio_find_actions", { query: "broken" })).toBe("ERROR: Composio action GITHUB_BROKEN has an input schema that is not an object.");
|
||||
broken.connection.close();
|
||||
h.connection.close();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user