Skip to content
25 changes: 12 additions & 13 deletions packages/sdk/src/internal/providers/bailian/mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,19 +290,18 @@ export function mapAgent(
}
}

// Skills
if (refs.skill_ids.length) {
body.skills = refs.skill_ids.map((s) => ({
// Bailian's SkillType enum is "customer" | "official"; map the
// resolver's generic "custom" sentinel to "customer".
type: s.type === "custom" ? "customer" : s.type,
skill_id: s.skill_id,
// Bailian composes `{skill_id}@{version}` internally and rejects
// entries without a version. Prefer explicit external references, then
// the latest active remote version, then the common initial version.
version: s.version ?? skillVersions?.[s.skill_id] ?? "1.0",
}));
}
// Skills are an explicit replacement set. Keep an empty array in the full update
// payload so removing the last binding has the same declarative meaning everywhere.
body.skills = refs.skill_ids.map((s) => ({
// Bailian's SkillType enum is "customer" | "official"; map the
// resolver's generic "custom" sentinel to "customer".
type: s.type === "custom" ? "customer" : s.type,
skill_id: s.skill_id,
// Bailian composes `{skill_id}@{version}` internally and rejects
// entries without a version. Prefer explicit external references, then
// the latest active remote version, then the common initial version.
version: s.version ?? skillVersions?.[s.skill_id] ?? "1.0",
}));

return body;
}
Expand Down
13 changes: 6 additions & 7 deletions packages/sdk/src/internal/providers/qoder/mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,13 +466,12 @@ export function mapAgent(
}
}

// Skills
if (refs.skill_ids.length) {
body.skills = refs.skill_ids.map((s) => ({
type: s.type === "official" ? "qoder" : s.type,
skill_id: s.skill_id,
}));
}
// Skills are an explicit replacement set. Qoder agent updates use merge semantics,
// so omitting this field would retain remote bindings when the declaration is `skills: []`.
body.skills = refs.skill_ids.map((s) => ({
type: s.type === "official" ? "qoder" : s.type,
skill_id: s.skill_id,
}));

return body;
}
Expand Down
5 changes: 5 additions & 0 deletions packages/sdk/tests/unit/bailian.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,11 @@ describe("Bailian mapAgent", () => {
expect(body.skills).toEqual([{ type: "customer", skill_id: "skill_abc", version: "1.0" }]);
});

test("keeps an explicit empty skill replacement set", () => {
const body = mapAgent("helper", minimalDecl, emptyRefs) as Record<string, unknown>;
expect(body.skills).toEqual([]);
});

test("injects agents metadata when projectName provided", () => {
const body = mapAgent("helper", minimalDecl, emptyRefs, undefined, "my-project") as Record<string, unknown>;
const meta = body.metadata as Record<string, string>;
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/tests/unit/qoder-examples.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ test("qoder agent mapper preserves declared tool permission policies", () => {
],
},
]);
expect(body.skills).toEqual([]);
});

test("qoder permission overrides are case- and separator-insensitive", () => {
Expand Down
Loading