@openagentpack/sdk 0.7.3 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -816,7 +816,21 @@ var toolsSchema = z.object({
816
816
  });
817
817
  var multiagentSchema = z.object({
818
818
  type: z.literal("coordinator"),
819
- agents: z.array(z.string())
819
+ agents: z.array(z.union([z.string().min(1), z.object({ agent_id: z.string().trim().min(1) })])).min(1)
820
+ }).superRefine((multiagent, ctx) => {
821
+ const seen = /* @__PURE__ */ new Set();
822
+ for (const [index, member] of multiagent.agents.entries()) {
823
+ const key = typeof member === "string" ? `logical:${member}` : `external:${member.agent_id}`;
824
+ if (seen.has(key)) {
825
+ const label = typeof member === "string" ? member : member.agent_id;
826
+ ctx.addIssue({
827
+ code: "custom",
828
+ path: ["agents", index],
829
+ message: `duplicates member '${label}'`
830
+ });
831
+ }
832
+ seen.add(key);
833
+ }
820
834
  });
821
835
  var agentSkillRefSchema = z.object({
822
836
  type: z.enum(["official", "custom"]),
@@ -1344,6 +1358,86 @@ function extractCreatedEventId(res) {
1344
1358
  return void 0;
1345
1359
  }
1346
1360
 
1361
+ // src/internal/multiagent/reverse-index.ts
1362
+ function buildReverseIndex(agents, project) {
1363
+ const index = /* @__PURE__ */ new Map();
1364
+ for (const raw of agents) {
1365
+ const id = raw.id;
1366
+ if (typeof id !== "string") continue;
1367
+ const metadata = raw.metadata;
1368
+ const owned = metadata?.["agents.project"] === project;
1369
+ const resource = metadata?.["agents.resource"];
1370
+ const logicalName = owned && typeof resource === "string" && resource.trim() ? resource.trim() : void 0;
1371
+ index.set(id, {
1372
+ logical_name: logicalName,
1373
+ archived: raw.archived_at != null,
1374
+ owned
1375
+ });
1376
+ }
1377
+ return index;
1378
+ }
1379
+ function memberDeclResolver(index) {
1380
+ const claims = /* @__PURE__ */ new Map();
1381
+ for (const entry of index.values()) {
1382
+ if (!entry.logical_name) continue;
1383
+ claims.set(entry.logical_name, (claims.get(entry.logical_name) ?? 0) + 1);
1384
+ }
1385
+ return (memberId) => {
1386
+ const entry = index.get(memberId);
1387
+ if (!entry) {
1388
+ throw new UserError(
1389
+ `sync.multiagent.member.unresolved: roster member '${memberId}' is missing from the /agents listing.`
1390
+ );
1391
+ }
1392
+ if (!entry.owned) return { agent_id: memberId };
1393
+ if (entry.archived) {
1394
+ throw new UserError(
1395
+ `sync.multiagent.member.archived: roster member '${memberId}' is archived; restore it before syncing.`
1396
+ );
1397
+ }
1398
+ const name = entry.logical_name;
1399
+ if (!name) {
1400
+ throw new UserError(
1401
+ `sync.multiagent.member.unresolved: roster member '${memberId}' carries no agents.resource metadata.`
1402
+ );
1403
+ }
1404
+ if ((claims.get(name) ?? 0) > 1) {
1405
+ throw new UserError(
1406
+ `sync.multiagent.member.ambiguous: logical name '${name}' is claimed by multiple remote agents.`
1407
+ );
1408
+ }
1409
+ return name;
1410
+ };
1411
+ }
1412
+ function reverseMultiagentDecl(raw, resolveMember) {
1413
+ if (raw === null || raw === void 0) return void 0;
1414
+ if (typeof raw !== "object") return void 0;
1415
+ const roster = raw;
1416
+ if (roster.type !== void 0 && roster.type !== "coordinator") {
1417
+ throw new UserError(
1418
+ `sync.multiagent.member.unresolved: remote multi-agent type '${String(roster.type)}' cannot be represented (coordinator only).`
1419
+ );
1420
+ }
1421
+ if (!Array.isArray(roster.agents) || roster.agents.length === 0) return void 0;
1422
+ if (!resolveMember) {
1423
+ throw new UserError(
1424
+ "sync.multiagent.member.unresolved: reverse-mapping a multi-agent roster requires a member name resolver."
1425
+ );
1426
+ }
1427
+ return {
1428
+ type: "coordinator",
1429
+ agents: roster.agents.map((member) => resolveMember(rosterMemberId(member)))
1430
+ };
1431
+ }
1432
+ function rosterMemberId(member) {
1433
+ if (typeof member === "string") return member;
1434
+ if (typeof member === "object" && member !== null) {
1435
+ const m = member;
1436
+ if (m.type === "agent" && typeof m.id === "string") return m.id;
1437
+ }
1438
+ throw new UserError("sync.multiagent.member.unresolved: roster member is not a representable agent reference.");
1439
+ }
1440
+
1347
1441
  // src/internal/providers/session-vault.ts
1348
1442
  function extractVaultIds(res) {
1349
1443
  const top = res.vault_ids;
@@ -1419,7 +1513,7 @@ function buildSessionInfo(res, memoryStoreIds) {
1419
1513
  attributes: res
1420
1514
  };
1421
1515
  }
1422
- async function exportRemoteResources(client, type, mappers) {
1516
+ async function exportRemoteResources(client, type, mappers, projectName) {
1423
1517
  if (type === "environment") {
1424
1518
  const envs = await client.getAllPaged("/environments");
1425
1519
  return envs.map((env) => {
@@ -1458,9 +1552,11 @@ async function exportRemoteResources(client, type, mappers) {
1458
1552
  }
1459
1553
  if (type === "agent") {
1460
1554
  const agents = await client.getAllPaged("/agents");
1555
+ const resolveMember = memberDeclResolver(buildReverseIndex(agents, projectName ?? ""));
1461
1556
  return agents.filter((agent) => !agent.archived_at).map((agent) => {
1462
1557
  const agentId = agent.id;
1463
- return { name: agentId, decl: mappers.agentToDecl(agent) };
1558
+ const name = resourceNameFromMetadata(agent.metadata, agent.name ?? agentId, agentId);
1559
+ return { name, decl: mappers.agentToDecl(agent, resolveMember) };
1464
1560
  });
1465
1561
  }
1466
1562
  return [];
@@ -1684,11 +1780,10 @@ function envToDecl(raw) {
1684
1780
  metadata: stripAgentsMetadata(raw.metadata)
1685
1781
  });
1686
1782
  }
1687
- function agentToDecl(raw) {
1783
+ function agentToDecl(raw, resolveMember) {
1688
1784
  const tools = raw.tools;
1689
1785
  const mcpServers = raw.mcp_servers;
1690
1786
  const skills = raw.skills;
1691
- const multiagent = raw.multiagent;
1692
1787
  let builtinTools;
1693
1788
  let builtinPermissions;
1694
1789
  let allToolsEnabled = false;
@@ -1720,10 +1815,6 @@ function agentToDecl(raw) {
1720
1815
  skill_id: s.skill_id
1721
1816
  }));
1722
1817
  }
1723
- let multiagentDecl;
1724
- if (multiagent && multiagent.agents?.length) {
1725
- multiagentDecl = { type: "coordinator", agents: multiagent.agents };
1726
- }
1727
1818
  let toolsDecl;
1728
1819
  if (builtinTools?.length) {
1729
1820
  toolsDecl = { builtin: builtinTools, permissions: builtinPermissions };
@@ -1740,7 +1831,7 @@ function agentToDecl(raw) {
1740
1831
  tools: toolsDecl,
1741
1832
  mcp_servers: mcpServerDecls,
1742
1833
  skills: skillDecls,
1743
- multiagent: multiagentDecl,
1834
+ multiagent: reverseMultiagentDecl(raw.multiagent, resolveMember),
1744
1835
  metadata: stripAgentsMetadata(raw.metadata)
1745
1836
  });
1746
1837
  }
@@ -1823,10 +1914,10 @@ function mapAgent(name, decl, refs, version, projectName) {
1823
1914
  skill_id: s.skill_id
1824
1915
  }));
1825
1916
  }
1826
- if (decl.multiagent && refs.multiagent_agent_ids?.length) {
1917
+ if (decl.multiagent && refs.multiagent) {
1827
1918
  body.multiagent = {
1828
1919
  type: "coordinator",
1829
- agents: refs.multiagent_agent_ids
1920
+ agents: refs.multiagent.members.map((member) => member.remote_id)
1830
1921
  };
1831
1922
  }
1832
1923
  return body;
@@ -2164,13 +2255,18 @@ var ClaudeAdapter = class _ClaudeAdapter {
2164
2255
  await this.client.delete(`/vaults/${id}`);
2165
2256
  }
2166
2257
  async exportResources(type) {
2167
- return exportRemoteResources(this.client, type, {
2168
- envToDecl,
2169
- vaultToDecl,
2170
- fileToDecl,
2171
- skillToDecl,
2172
- agentToDecl
2173
- });
2258
+ return exportRemoteResources(
2259
+ this.client,
2260
+ type,
2261
+ {
2262
+ envToDecl,
2263
+ vaultToDecl,
2264
+ fileToDecl,
2265
+ skillToDecl,
2266
+ agentToDecl
2267
+ },
2268
+ this.projectName
2269
+ );
2174
2270
  }
2175
2271
  async createSkill(name, _decl, files) {
2176
2272
  const formData = buildClaudeSkillFormData(name, files);
@@ -2539,6 +2635,31 @@ import { readFileSync as readFileSync2 } from "fs";
2539
2635
  import { basename as basename3, dirname as dirname5, resolve as resolve5 } from "path";
2540
2636
  import JSZip2 from "jszip";
2541
2637
 
2638
+ // src/internal/multiagent/comparable.ts
2639
+ function canonicalizeRemoteRoster(raw, materialization) {
2640
+ if (raw === null || raw === void 0) return { supported: true };
2641
+ if (typeof raw !== "object") return { supported: false };
2642
+ const roster = raw;
2643
+ if (roster.type !== "coordinator") return { supported: false };
2644
+ if (!Array.isArray(roster.agents)) return { supported: false };
2645
+ if (roster.agents.length === 0) return { supported: true };
2646
+ const memberIds = [];
2647
+ for (const entry of roster.agents) {
2648
+ if (typeof entry !== "object" || entry === null) return { supported: false };
2649
+ const member = entry;
2650
+ if (member.type !== "agent") return { supported: false };
2651
+ const id = materialization === "forward" ? member.template_id : member.id;
2652
+ if (typeof id !== "string") return { supported: false };
2653
+ memberIds.push(id);
2654
+ }
2655
+ return { supported: true, roster: { type: "coordinator", member_ids: [...new Set(memberIds)].sort() } };
2656
+ }
2657
+ function comparableMultiagentField(raw, materialization) {
2658
+ const canonical = canonicalizeRemoteRoster(raw, materialization);
2659
+ if (!canonical.supported) return { type: "unsupported" };
2660
+ return canonical.roster;
2661
+ }
2662
+
2542
2663
  // src/internal/providers/qoder/client.ts
2543
2664
  var QoderClient = class extends BaseApiClient {
2544
2665
  baseUrl;
@@ -2688,7 +2809,7 @@ function skillToDecl2(raw, name) {
2688
2809
  description: raw.description
2689
2810
  });
2690
2811
  }
2691
- function agentToDecl2(raw) {
2812
+ function agentToDecl2(raw, resolveMember) {
2692
2813
  const tools = raw.tools;
2693
2814
  const mcpServers = raw.mcp_servers;
2694
2815
  const skills = raw.skills;
@@ -2727,6 +2848,7 @@ function agentToDecl2(raw) {
2727
2848
  tools: builtinTools?.length ? { builtin: builtinTools, permissions: builtinPermissions } : void 0,
2728
2849
  mcp_servers: mcpServerDecls,
2729
2850
  skills: skillDecls,
2851
+ multiagent: reverseMultiagentDecl(raw.multiagent, resolveMember),
2730
2852
  metadata: stripAgentsMetadata(raw.metadata)
2731
2853
  });
2732
2854
  }
@@ -2835,7 +2957,7 @@ function mapDeploymentResources2(decl, refs, uploadedFiles) {
2835
2957
  }
2836
2958
  return resources;
2837
2959
  }
2838
- function mapAgent2(name, decl, refs, version, projectName) {
2960
+ function mapAgent2(name, decl, refs, version, projectName, operation = "create") {
2839
2961
  let model;
2840
2962
  if (typeof decl.model === "string") {
2841
2963
  model = decl.model;
@@ -2898,9 +3020,17 @@ function mapAgent2(name, decl, refs, version, projectName) {
2898
3020
  type: s.type === "official" ? "qoder" : s.type,
2899
3021
  skill_id: s.skill_id
2900
3022
  }));
3023
+ if (refs.multiagent) {
3024
+ body.multiagent = {
3025
+ type: "coordinator",
3026
+ agents: refs.multiagent.members.map(({ remote_id }) => ({ type: "agent", id: remote_id }))
3027
+ };
3028
+ } else if (operation === "update") {
3029
+ body.multiagent = null;
3030
+ }
2901
3031
  return body;
2902
3032
  }
2903
- function mapForwardTemplate(name, decl, refs, projectName) {
3033
+ function mapForwardTemplate(name, decl, refs, projectName, operation = "create") {
2904
3034
  let model;
2905
3035
  if (typeof decl.model === "string") {
2906
3036
  model = decl.model;
@@ -2962,6 +3092,14 @@ function mapForwardTemplate(name, decl, refs, projectName) {
2962
3092
  ...skill.version ? { version: skill.version } : {},
2963
3093
  enabled: true
2964
3094
  }));
3095
+ if (refs.multiagent) {
3096
+ body.multiagent = {
3097
+ type: "coordinator",
3098
+ agents: refs.multiagent.members.map(({ remote_id }) => ({ type: "agent", template_id: remote_id }))
3099
+ };
3100
+ } else if (operation === "update") {
3101
+ body.multiagent = null;
3102
+ }
2965
3103
  return body;
2966
3104
  }
2967
3105
  function mapSendMessage2(text) {
@@ -3307,7 +3445,7 @@ var QoderAdapter = class _QoderAdapter {
3307
3445
  if (!metadata || typeof metadata !== "object") return false;
3308
3446
  return metadata["agents.project"] === this.projectName && metadata["agents.resource"] === displayName;
3309
3447
  }
3310
- normalizeDesiredResource(type, name, decl) {
3448
+ normalizeDesiredResource(type, name, decl, refs) {
3311
3449
  if (type === "environment") {
3312
3450
  return this.normalizeRemote(
3313
3451
  type,
@@ -3317,10 +3455,16 @@ var QoderAdapter = class _QoderAdapter {
3317
3455
  if (type === "agent") {
3318
3456
  return this.normalizeRemote(
3319
3457
  type,
3320
- mapAgent2(name, decl, { skill_ids: [] }, void 0, this.projectName)
3458
+ mapAgent2(name, decl, refs ?? { skill_ids: [] }, void 0, this.projectName)
3459
+ );
3460
+ }
3461
+ if (type === "template") {
3462
+ if (!refs) return null;
3463
+ return this.normalizeRemote(
3464
+ type,
3465
+ mapForwardTemplate(name, decl, refs, this.projectName)
3321
3466
  );
3322
3467
  }
3323
- if (type === "template") return null;
3324
3468
  if (type === "identity") {
3325
3469
  const identity = decl;
3326
3470
  if (identity.identity_id) return null;
@@ -3348,10 +3492,10 @@ var QoderAdapter = class _QoderAdapter {
3348
3492
  description: raw.description,
3349
3493
  model: raw.model,
3350
3494
  system: raw.system,
3351
- tools: raw.tools,
3352
- mcp_servers: raw.mcp_servers,
3495
+ tools: normalizeQoderTools(raw.tools),
3496
+ mcp_servers: normalizeQoderMcpServers(raw.mcp_servers),
3353
3497
  skills: raw.skills,
3354
- multiagent: raw.multiagent,
3498
+ multiagent: comparableMultiagentField(raw.multiagent, "forward"),
3355
3499
  environment_id: raw.environment_id,
3356
3500
  tunnel_id: raw.tunnel_id,
3357
3501
  vault_ids: Array.isArray(raw.vault_ids) ? raw.vault_ids : Object.keys(raw.vaults ?? {}),
@@ -3393,6 +3537,7 @@ var QoderAdapter = class _QoderAdapter {
3393
3537
  instructions: raw.system,
3394
3538
  tools: normalizeQoderTools(raw.tools),
3395
3539
  mcp_servers: normalizeQoderMcpServers(raw.mcp_servers),
3540
+ multiagent: comparableMultiagentField(raw.multiagent, "managed"),
3396
3541
  metadata: stripAgentsMetadata(raw.metadata)
3397
3542
  });
3398
3543
  }
@@ -3471,13 +3616,18 @@ var QoderAdapter = class _QoderAdapter {
3471
3616
  await (mode === "forward" ? this.forwardClient : this.client).delete(`/vaults/${id}`);
3472
3617
  }
3473
3618
  async exportResources(type) {
3474
- return exportRemoteResources(this.client, type, {
3475
- envToDecl: envToDecl2,
3476
- vaultToDecl: vaultToDecl2,
3477
- fileToDecl: fileToDecl2,
3478
- skillToDecl: skillToDecl2,
3479
- agentToDecl: agentToDecl2
3480
- });
3619
+ return exportRemoteResources(
3620
+ this.client,
3621
+ type,
3622
+ {
3623
+ envToDecl: envToDecl2,
3624
+ vaultToDecl: vaultToDecl2,
3625
+ fileToDecl: fileToDecl2,
3626
+ skillToDecl: skillToDecl2,
3627
+ agentToDecl: agentToDecl2
3628
+ },
3629
+ this.projectName
3630
+ );
3481
3631
  }
3482
3632
  async createSkill(name, decl, files, mode = "managed") {
3483
3633
  const formData = await buildSkillFormData(name, decl, files);
@@ -3499,13 +3649,13 @@ var QoderAdapter = class _QoderAdapter {
3499
3649
  await (mode === "forward" ? this.forwardClient : this.client).delete(`/skills/${id}`);
3500
3650
  }
3501
3651
  async createAgent(name, decl, refs) {
3502
- const body = mapAgent2(name, decl, refs, void 0, this.projectName);
3652
+ const body = mapAgent2(name, decl, refs, void 0, this.projectName, "create");
3503
3653
  const res = await this.client.post("/agents", body);
3504
3654
  return toRemoteResource(res);
3505
3655
  }
3506
3656
  async updateAgent(id, name, decl, refs) {
3507
3657
  const current = await this.client.get(`/agents/${id}`);
3508
- const body = mapAgent2(name, decl, refs, current.version, this.projectName);
3658
+ const body = mapAgent2(name, decl, refs, current.version, this.projectName, "update");
3509
3659
  const res = await this.client.put(`/agents/${id}`, body);
3510
3660
  return toRemoteResource(res);
3511
3661
  }
@@ -3513,13 +3663,13 @@ var QoderAdapter = class _QoderAdapter {
3513
3663
  await this.client.delete(`/agents/${id}`);
3514
3664
  }
3515
3665
  async createTemplate(name, decl, refs) {
3516
- const body = mapForwardTemplate(name, decl, refs, this.projectName);
3666
+ const body = mapForwardTemplate(name, decl, refs, this.projectName, "create");
3517
3667
  const res = await this.forwardClient.post("/templates", body);
3518
3668
  await this.reconcileForwardMemoryMounts(res.id, refs);
3519
3669
  return toRemoteResource(res);
3520
3670
  }
3521
3671
  async updateTemplate(id, name, decl, refs) {
3522
- const body = mapForwardTemplate(name, decl, refs, this.projectName);
3672
+ const body = mapForwardTemplate(name, decl, refs, this.projectName, "update");
3523
3673
  if (!refs.tunnel_id) body.tunnel_id = null;
3524
3674
  const res = await this.forwardClient.post(`/templates/${id}`, body);
3525
3675
  await this.reconcileForwardMemoryMounts(id, refs);
@@ -4118,11 +4268,7 @@ var QODER_CAPABILITIES = {
4118
4268
  template: { tier: "native", reason: "Forward Templates API" },
4119
4269
  memory_store: { tier: "native", reason: "memory_stores API" },
4120
4270
  mcp_server: { tier: "native", reason: "mcp_servers field on agent" },
4121
- multiagent: {
4122
- tier: "unsupported",
4123
- reason: "no multiagent primitive on Qoder",
4124
- remediation: "deploy agents independently and orchestrate via MCP"
4125
- },
4271
+ multiagent: { tier: "native", reason: "coordinator + roster topology" },
4126
4272
  deployment: {
4127
4273
  tier: "native",
4128
4274
  reason: "deployments API with scheduled and manual runs"
@@ -4297,7 +4443,7 @@ function envToDecl3(raw) {
4297
4443
  metadata: stripAgentsMetadata(raw.metadata)
4298
4444
  });
4299
4445
  }
4300
- function agentToDecl3(raw) {
4446
+ function agentToDecl3(raw, resolveMember) {
4301
4447
  const tools = raw.tools;
4302
4448
  const mcpServers = raw.mcp_servers;
4303
4449
  const skills = raw.skills;
@@ -4334,10 +4480,11 @@ function agentToDecl3(raw) {
4334
4480
  tools: builtinTools?.length ? { builtin: builtinTools } : void 0,
4335
4481
  mcp_servers: mcpServerDecls,
4336
4482
  skills: skillDecls,
4483
+ multiagent: reverseMultiagentDecl(raw.multiagent, resolveMember),
4337
4484
  metadata: stripAgentsMetadata(raw.metadata)
4338
4485
  });
4339
4486
  }
4340
- function mapAgent3(name, decl, refs, version, projectName, skillVersions) {
4487
+ function mapAgent3(name, decl, refs, version, projectName, skillVersions, operation = "create") {
4341
4488
  let modelId;
4342
4489
  if (typeof decl.model === "string") {
4343
4490
  modelId = decl.model;
@@ -4358,7 +4505,17 @@ function mapAgent3(name, decl, refs, version, projectName, skillVersions) {
4358
4505
  } else if (decl.metadata) {
4359
4506
  body.metadata = decl.metadata;
4360
4507
  }
4361
- const BAILIAN_BUILTINS = /* @__PURE__ */ new Set(["bash", "read", "write", "edit", "glob", "grep", "download_file"]);
4508
+ const BAILIAN_BUILTINS = /* @__PURE__ */ new Set([
4509
+ "bash",
4510
+ "read",
4511
+ "write",
4512
+ "edit",
4513
+ "glob",
4514
+ "grep",
4515
+ "web_search",
4516
+ "web_fetch",
4517
+ "mark_artifacts"
4518
+ ]);
4362
4519
  if (decl.tools) {
4363
4520
  const toolConfigs = resolveBuiltinTools(decl.tools, {
4364
4521
  supportedWireNames: BAILIAN_BUILTINS
@@ -4412,6 +4569,15 @@ function mapAgent3(name, decl, refs, version, projectName, skillVersions) {
4412
4569
  // the latest active remote version, then the common initial version.
4413
4570
  version: s.version ?? skillVersions?.[s.skill_id] ?? "1.0"
4414
4571
  }));
4572
+ if (refs.multiagent) {
4573
+ body.multiagent = {
4574
+ type: "coordinator",
4575
+ // No version: Bailian resolves the child Thread on first creation.
4576
+ agents: refs.multiagent.members.map(({ remote_id }) => ({ type: "agent", id: remote_id }))
4577
+ };
4578
+ } else if (operation === "update") {
4579
+ body.multiagent = { type: "coordinator", agents: [] };
4580
+ }
4415
4581
  return body;
4416
4582
  }
4417
4583
  function mapSession3(bindings) {
@@ -4547,7 +4713,7 @@ var BailianAdapter = class _BailianAdapter {
4547
4713
  snapshot: comparable
4548
4714
  };
4549
4715
  }
4550
- normalizeDesiredResource(type, name, decl) {
4716
+ normalizeDesiredResource(type, name, decl, refs) {
4551
4717
  if (type === "environment") {
4552
4718
  return this.normalizeRemote(
4553
4719
  type,
@@ -4557,7 +4723,7 @@ var BailianAdapter = class _BailianAdapter {
4557
4723
  if (type === "agent") {
4558
4724
  return this.normalizeRemote(
4559
4725
  type,
4560
- mapAgent3(name, decl, { skill_ids: [] }, void 0, this.projectName)
4726
+ mapAgent3(name, decl, refs ?? { skill_ids: [] }, void 0, this.projectName)
4561
4727
  );
4562
4728
  }
4563
4729
  return null;
@@ -4582,17 +4748,23 @@ var BailianAdapter = class _BailianAdapter {
4582
4748
  instructions: raw.system,
4583
4749
  tools: normalizeBailianTools(raw.tools),
4584
4750
  mcp_servers: normalizeBailianMcpServers(raw.mcp_servers),
4751
+ multiagent: comparableMultiagentField(raw.multiagent, "managed"),
4585
4752
  metadata: stripAgentsMetadata(raw.metadata)
4586
4753
  });
4587
4754
  }
4588
4755
  async exportResources(type) {
4589
- return exportRemoteResources(this.client, type, {
4590
- envToDecl: envToDecl3,
4591
- vaultToDecl: vaultToDecl3,
4592
- fileToDecl: fileToDecl3,
4593
- skillToDecl: skillToDecl3,
4594
- agentToDecl: agentToDecl3
4595
- });
4756
+ return exportRemoteResources(
4757
+ this.client,
4758
+ type,
4759
+ {
4760
+ envToDecl: envToDecl3,
4761
+ vaultToDecl: vaultToDecl3,
4762
+ fileToDecl: fileToDecl3,
4763
+ skillToDecl: skillToDecl3,
4764
+ agentToDecl: agentToDecl3
4765
+ },
4766
+ this.projectName
4767
+ );
4596
4768
  }
4597
4769
  // --- Environment ---
4598
4770
  async createEnvironment(name, decl) {
@@ -4623,14 +4795,14 @@ var BailianAdapter = class _BailianAdapter {
4623
4795
  // --- Agent ---
4624
4796
  async createAgent(name, decl, refs) {
4625
4797
  const skillVersions = await this.fetchSkillVersions(refs);
4626
- const body = mapAgent3(name, decl, refs, void 0, this.projectName, skillVersions);
4798
+ const body = mapAgent3(name, decl, refs, void 0, this.projectName, skillVersions, "create");
4627
4799
  const res = await this.client.post("/agents", body);
4628
4800
  return toRemoteResource(res);
4629
4801
  }
4630
4802
  async updateAgent(id, name, decl, refs) {
4631
4803
  const current = await this.client.get(`/agents/${id}`);
4632
4804
  const skillVersions = await this.fetchSkillVersions(refs);
4633
- const body = mapAgent3(name, decl, refs, current.version, this.projectName, skillVersions);
4805
+ const body = mapAgent3(name, decl, refs, current.version, this.projectName, skillVersions, "update");
4634
4806
  const res = await this.client.post(`/agents/${id}`, body);
4635
4807
  return toRemoteResource(res);
4636
4808
  }
@@ -5352,11 +5524,7 @@ var BAILIAN_CAPABILITIES = {
5352
5524
  reason: "no memory store primitive on Bailian"
5353
5525
  },
5354
5526
  mcp_server: { tier: "native", reason: "mcp_servers field on agent (official servers)" },
5355
- multiagent: {
5356
- tier: "unsupported",
5357
- reason: "no multiagent primitive on Bailian",
5358
- remediation: "deploy agents independently and orchestrate via MCP"
5359
- },
5527
+ multiagent: { tier: "native", reason: "coordinator + roster topology" },
5360
5528
  deployment: {
5361
5529
  tier: "native",
5362
5530
  reason: "deployments API with cron schedules, manual runs, pause/unpause and archive"
@@ -5509,11 +5677,10 @@ function envToDecl4(raw) {
5509
5677
  metadata: stripAgentsMetadata(raw.metadata)
5510
5678
  });
5511
5679
  }
5512
- function agentToDecl4(raw) {
5680
+ function agentToDecl4(raw, resolveMember) {
5513
5681
  const tools = raw.tools;
5514
5682
  const mcpServers = raw.mcp_servers;
5515
5683
  const skills = raw.skills;
5516
- const multiagent = raw.multiagent;
5517
5684
  let builtinTools;
5518
5685
  let builtinPermissions;
5519
5686
  let allToolsEnabled = false;
@@ -5545,14 +5712,6 @@ function agentToDecl4(raw) {
5545
5712
  skill_id: s.skill_id
5546
5713
  }));
5547
5714
  }
5548
- let multiagentDecl;
5549
- if (multiagent) {
5550
- const rawAgents = multiagent.agents;
5551
- if (rawAgents?.length) {
5552
- const ids = rawAgents.map((a) => typeof a === "string" ? a : a.id).filter(Boolean);
5553
- if (ids.length) multiagentDecl = { type: "coordinator", agents: ids };
5554
- }
5555
- }
5556
5715
  let toolsDecl;
5557
5716
  if (builtinTools?.length) {
5558
5717
  toolsDecl = { builtin: builtinTools, permissions: builtinPermissions };
@@ -5569,7 +5728,7 @@ function agentToDecl4(raw) {
5569
5728
  tools: toolsDecl,
5570
5729
  mcp_servers: mcpServerDecls,
5571
5730
  skills: skillDecls,
5572
- multiagent: multiagentDecl,
5731
+ multiagent: reverseMultiagentDecl(raw.multiagent, resolveMember),
5573
5732
  metadata: stripAgentsMetadata(raw.metadata)
5574
5733
  });
5575
5734
  }
@@ -5653,10 +5812,10 @@ function mapAgent4(name, decl, refs, version, projectName) {
5653
5812
  skill_id: s.skill_id
5654
5813
  }));
5655
5814
  }
5656
- if (decl.multiagent && refs.multiagent_agent_ids?.length) {
5815
+ if (decl.multiagent && refs.multiagent) {
5657
5816
  body.multiagent = {
5658
5817
  type: "coordinator",
5659
- agents: refs.multiagent_agent_ids.map((id) => ({ type: "agent", id }))
5818
+ agents: refs.multiagent.members.map(({ remote_id }) => ({ type: "agent", id: remote_id }))
5660
5819
  };
5661
5820
  }
5662
5821
  return body;
@@ -5908,13 +6067,18 @@ var ArkAdapter = class _ArkAdapter {
5908
6067
  }
5909
6068
  async exportResources(type) {
5910
6069
  if (type === "skill") return [];
5911
- return exportRemoteResources(this.client, type, {
5912
- envToDecl: envToDecl4,
5913
- vaultToDecl: vaultToDecl4,
5914
- fileToDecl: fileToDecl4,
5915
- skillToDecl: skillToDecl4,
5916
- agentToDecl: agentToDecl4
5917
- });
6070
+ return exportRemoteResources(
6071
+ this.client,
6072
+ type,
6073
+ {
6074
+ envToDecl: envToDecl4,
6075
+ vaultToDecl: vaultToDecl4,
6076
+ fileToDecl: fileToDecl4,
6077
+ skillToDecl: skillToDecl4,
6078
+ agentToDecl: agentToDecl4
6079
+ },
6080
+ this.projectName
6081
+ );
5918
6082
  }
5919
6083
  // Ark skills support create + get + attach only. There is no list/update/delete endpoint
5920
6084
  // (GET /skills, PUT /skills/{id}, DELETE /skills/{id} all return 404 on real probe), so:
@@ -6229,6 +6393,50 @@ function severityIcon(s) {
6229
6393
  }
6230
6394
  }
6231
6395
 
6396
+ // src/internal/multiagent/topology.ts
6397
+ var MULTIAGENT_MEMBER_LIMIT = 20;
6398
+ function collectMultiagentTopologyDiagnostics(config, diagnostics) {
6399
+ const agents = config.agents ?? {};
6400
+ const names = Object.keys(agents).sort();
6401
+ for (const name of names) {
6402
+ const decl = agents[name];
6403
+ if (!decl?.multiagent) continue;
6404
+ for (const member of decl.multiagent.agents) {
6405
+ if (typeof member !== "string") continue;
6406
+ if (agents[member]?.multiagent) {
6407
+ diagnostics.error(
6408
+ "config.agent.multiagent.nested",
6409
+ `agent.${name}: multiagent member '${member}' is itself a coordinator; nested coordinators are not supported`
6410
+ );
6411
+ }
6412
+ }
6413
+ }
6414
+ const state = /* @__PURE__ */ new Map();
6415
+ const path = [];
6416
+ const visit2 = (name) => {
6417
+ if (state.get(name) === "done") return;
6418
+ state.set(name, "visiting");
6419
+ path.push(name);
6420
+ const members = agents[name]?.multiagent?.agents ?? [];
6421
+ for (const member of members) {
6422
+ if (typeof member !== "string") continue;
6423
+ if (!agents[member]) continue;
6424
+ if (state.get(member) === "visiting") {
6425
+ const cycle = [...path.slice(path.indexOf(member)), member];
6426
+ diagnostics.error(
6427
+ "config.agent.multiagent.cycle",
6428
+ `agent.${name}: multiagent cycle detected: ${cycle.join(" -> ")}`
6429
+ );
6430
+ continue;
6431
+ }
6432
+ visit2(member);
6433
+ }
6434
+ path.pop();
6435
+ state.set(name, "done");
6436
+ };
6437
+ for (const name of names) visit2(name);
6438
+ }
6439
+
6232
6440
  // src/internal/validation/bailian.ts
6233
6441
  function findMissingBailianMcpToolConfigs(config, providerName = "bailian") {
6234
6442
  if (providerName !== "bailian") return [];
@@ -6330,6 +6538,7 @@ function collectReferenceDiagnostics(config, diagnostics) {
6330
6538
  }
6331
6539
  if (agent.multiagent) {
6332
6540
  for (const subAgent of agent.multiagent.agents) {
6541
+ if (typeof subAgent !== "string") continue;
6333
6542
  if (!agentNames.has(subAgent)) {
6334
6543
  diagnostics.error(
6335
6544
  "config.agent.multiagent.unknown",
@@ -6342,6 +6551,7 @@ function collectReferenceDiagnostics(config, diagnostics) {
6342
6551
  }
6343
6552
  }
6344
6553
  }
6554
+ collectMultiagentTopologyDiagnostics(config, diagnostics);
6345
6555
  for (const [name, deployment] of Object.entries(config.deployments ?? {})) {
6346
6556
  if (deployment.tunnel && !tunnelNames.has(deployment.tunnel)) {
6347
6557
  diagnostics.error(
@@ -6663,15 +6873,44 @@ function collectProviderCapabilities(config, providers, diagnostics) {
6663
6873
  { type: "template", name, provider: providerName }
6664
6874
  );
6665
6875
  }
6666
- if (agent.multiagent) {
6876
+ }
6877
+ if (providerName === "qoder" && agent.multiagent) {
6878
+ const coordinatorMode = resolveAgentMaterialization(providerName, agent).mode;
6879
+ for (const memberName of agent.multiagent.agents) {
6880
+ if (typeof memberName !== "string") {
6881
+ if (coordinatorMode === "forward") {
6882
+ diagnostics.error(
6883
+ "qoder.template.multiagent.external_member",
6884
+ `agent.${name}: Qoder Forward coordinator cannot reference external Managed Agent '${memberName.agent_id}'.`,
6885
+ { type: "template", name, provider: providerName }
6886
+ );
6887
+ }
6888
+ continue;
6889
+ }
6890
+ const memberDecl = config.agents?.[memberName];
6891
+ if (!memberDecl) continue;
6892
+ const memberMode = resolveAgentMaterialization(providerName, memberDecl).mode;
6893
+ if (memberMode === coordinatorMode) continue;
6667
6894
  diagnostics.error(
6668
- "qoder.template.multiagent.unsupported",
6669
- `agent.${name}: multiagent is not yet supported by Qoder Forward Template delivery.`,
6670
- { type: "template", name, provider: providerName }
6895
+ "qoder.template.multiagent.member_materialization",
6896
+ `agent.${name}: multiagent member '${memberName}' uses ${memberMode} delivery but the coordinator uses ${coordinatorMode}; Qoder multiagent members must match the coordinator's delivery type.`,
6897
+ { type: coordinatorMode === "forward" ? "template" : "agent", name, provider: providerName }
6671
6898
  );
6672
6899
  }
6673
6900
  }
6674
6901
  }
6902
+ if (providerName === "qoder" || providerName === "bailian") {
6903
+ for (const [name, agent] of Object.entries(config.agents ?? {})) {
6904
+ if (agent.provider && agent.provider !== providerName) continue;
6905
+ const size = agent.multiagent?.agents.length ?? 0;
6906
+ if (size <= MULTIAGENT_MEMBER_LIMIT) continue;
6907
+ diagnostics.error(
6908
+ `${providerName}.agent.multiagent.member_limit`,
6909
+ `agent.${name}: provider '${providerName}' supports at most ${MULTIAGENT_MEMBER_LIMIT} multiagent members; got ${size}.`,
6910
+ { type: resolveAgentMaterialization(providerName, agent).resourceType, name, provider: providerName }
6911
+ );
6912
+ }
6913
+ }
6675
6914
  if (providerName === "qoder") {
6676
6915
  for (const [name, deployment] of Object.entries(config.deployments ?? {})) {
6677
6916
  if (deployment.provider && deployment.provider !== providerName) continue;