@multi-agent-protocol/sdk 0.1.9 → 0.1.11

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.
package/dist/server.js CHANGED
@@ -4637,6 +4637,11 @@ var InMemoryAgentStore = class {
4637
4637
  );
4638
4638
  if (!match) continue;
4639
4639
  }
4640
+ if (filter?.persistentId !== void 0) {
4641
+ if (agent.persistentIdentity?.persistentId !== filter.persistentId) {
4642
+ continue;
4643
+ }
4644
+ }
4640
4645
  results.push({ ...agent });
4641
4646
  }
4642
4647
  return results;
@@ -4765,7 +4770,8 @@ var AgentRegistryImpl = class {
4765
4770
  registeredAt: now,
4766
4771
  lastStateChange: now,
4767
4772
  capabilities: params.capabilities,
4768
- capabilityDescriptor: params.capabilityDescriptor
4773
+ capabilityDescriptor: params.capabilityDescriptor,
4774
+ persistentIdentity: params.persistentIdentity
4769
4775
  };
4770
4776
  this.store.save(agent);
4771
4777
  this.eventBus.emit({
@@ -4860,6 +4866,38 @@ var AgentRegistryImpl = class {
4860
4866
  });
4861
4867
  return updatedAgent;
4862
4868
  }
4869
+ /**
4870
+ * Resume an orphaned agent under a new session.
4871
+ * Updates sessionId, resets state to idle, optionally merges metadata,
4872
+ * and optionally updates the persistent identity (e.g., with fresh proof).
4873
+ * Emits agent.resumed event.
4874
+ */
4875
+ resume(id, newSessionId, metadata, persistentIdentity) {
4876
+ const agent = this.store.get(id);
4877
+ if (!agent) {
4878
+ throw new AgentNotFoundError(id);
4879
+ }
4880
+ const previousSessionId = agent.sessionId;
4881
+ const now = Date.now();
4882
+ const resumedAgent = {
4883
+ ...agent,
4884
+ sessionId: newSessionId,
4885
+ state: "idle",
4886
+ lastStateChange: now,
4887
+ metadata: metadata ? { ...agent.metadata, ...metadata } : agent.metadata,
4888
+ ...persistentIdentity && { persistentIdentity }
4889
+ };
4890
+ this.store.save(resumedAgent);
4891
+ this.eventBus.emit({
4892
+ type: "agent.resumed",
4893
+ data: {
4894
+ agent: resumedAgent,
4895
+ previousSessionId
4896
+ },
4897
+ source: { agentId: id, sessionId: newSessionId }
4898
+ });
4899
+ return resumedAgent;
4900
+ }
4863
4901
  /**
4864
4902
  * Unregister all agents for a session.
4865
4903
  * Used for cleanup when a session disconnects.
@@ -5166,17 +5204,137 @@ var MAPRequestError = class _MAPRequestError extends Error {
5166
5204
 
5167
5205
  // src/server/agents/handlers.ts
5168
5206
  function createAgentHandlers(options) {
5169
- const { agents, sessions, authManager } = options;
5207
+ const { agents, sessions, authManager, eventBus, identityVerifier, uniqueIdentity } = options;
5170
5208
  return {
5171
5209
  "map/agents/register": async (params, ctx) => {
5172
- const { name, role, metadata, capabilities, capabilityDescriptor } = params;
5210
+ const { name, role, metadata, capabilities, capabilityDescriptor, persistentIdentity, resumePersistentIdentity } = params;
5211
+ if (!name || typeof name !== "string" || name.trim() === "") {
5212
+ throw new Error("Agent name is required");
5213
+ }
5214
+ let resolvedIdentity = persistentIdentity;
5215
+ if (!resolvedIdentity) {
5216
+ const tokenData = ctx.session.providers?.["agent-iam"]?.providerData;
5217
+ if (tokenData?.persistentIdentity) {
5218
+ const pi = tokenData.persistentIdentity;
5219
+ if (pi.persistentId && pi.identityType) {
5220
+ resolvedIdentity = {
5221
+ persistentId: pi.persistentId,
5222
+ identityType: pi.identityType,
5223
+ publicKey: pi.publicKey,
5224
+ publicKeyJwk: pi.publicKeyJwk,
5225
+ // Token stores proof and challenge as separate strings;
5226
+ // map to AgentIdentityProof object
5227
+ proof: pi.proof && pi.challenge ? {
5228
+ challenge: pi.challenge,
5229
+ signature: pi.proof,
5230
+ provenAt: (/* @__PURE__ */ new Date()).toISOString()
5231
+ } : void 0,
5232
+ verificationStatus: "auth-derived"
5233
+ };
5234
+ }
5235
+ }
5236
+ }
5237
+ if (resolvedIdentity) {
5238
+ if (!resolvedIdentity.persistentId || typeof resolvedIdentity.persistentId !== "string" || resolvedIdentity.persistentId.trim() === "") {
5239
+ throw new Error("persistentIdentity.persistentId must be a non-empty string");
5240
+ }
5241
+ if (!resolvedIdentity.identityType || typeof resolvedIdentity.identityType !== "string") {
5242
+ throw new Error("persistentIdentity.identityType is required");
5243
+ }
5244
+ }
5245
+ if (resolvedIdentity && identityVerifier) {
5246
+ const verificationContext = {
5247
+ sessionId: ctx.session.id,
5248
+ agentName: name,
5249
+ isResumption: !!resumePersistentIdentity
5250
+ };
5251
+ try {
5252
+ const status = await identityVerifier.verify(resolvedIdentity, verificationContext);
5253
+ if (status) {
5254
+ resolvedIdentity = { ...resolvedIdentity, verificationStatus: status };
5255
+ }
5256
+ } catch (verifyError) {
5257
+ resolvedIdentity = { ...resolvedIdentity, verificationStatus: "unverified" };
5258
+ if (eventBus) {
5259
+ eventBus.emit({
5260
+ type: "agent.identity.verification.failed",
5261
+ data: {
5262
+ persistentId: resolvedIdentity.persistentId,
5263
+ identityType: resolvedIdentity.identityType,
5264
+ error: verifyError instanceof Error ? verifyError.message : String(verifyError)
5265
+ },
5266
+ source: { sessionId: ctx.session.id }
5267
+ });
5268
+ }
5269
+ }
5270
+ }
5271
+ const persistentId = resolvedIdentity?.persistentId;
5272
+ if (persistentId) {
5273
+ const existingAgents = agents.list({ persistentId });
5274
+ const activeAgents = existingAgents.filter((a) => a.state !== "stopped");
5275
+ if (resumePersistentIdentity && activeAgents.length > 0) {
5276
+ const sorted = activeAgents.sort((a, b) => b.lastStateChange - a.lastStateChange);
5277
+ const resumeTarget = sorted[0];
5278
+ try {
5279
+ if (sessions) {
5280
+ try {
5281
+ if (resumeTarget.sessionId !== ctx.session.id) {
5282
+ sessions.removeAgent(resumeTarget.sessionId, resumeTarget.id);
5283
+ }
5284
+ } catch {
5285
+ }
5286
+ sessions.addAgent(ctx.session.id, resumeTarget.id);
5287
+ } else {
5288
+ ctx.session.agentIds.push(resumeTarget.id);
5289
+ }
5290
+ const previousSessionId = resumeTarget.sessionId;
5291
+ const resumedAgent = agents.resume(
5292
+ resumeTarget.id,
5293
+ ctx.session.id,
5294
+ {
5295
+ ...metadata || {},
5296
+ resumedAt: Date.now(),
5297
+ resumedFromSession: previousSessionId
5298
+ },
5299
+ resolvedIdentity
5300
+ );
5301
+ return {
5302
+ agent: {
5303
+ id: resumedAgent.id,
5304
+ name: resumedAgent.name,
5305
+ role: resumedAgent.role,
5306
+ state: resumedAgent.state,
5307
+ metadata: resumedAgent.metadata,
5308
+ capabilities: resumedAgent.capabilities,
5309
+ capabilityDescriptor: resumedAgent.capabilityDescriptor,
5310
+ persistentIdentity: resumedAgent.persistentIdentity,
5311
+ visibility: "public"
5312
+ },
5313
+ resumed: true,
5314
+ resumedFrom: {
5315
+ previousSessionId
5316
+ }
5317
+ };
5318
+ } catch (resumeError) {
5319
+ if (resumeError instanceof AgentNotFoundError) ; else {
5320
+ throw resumeError;
5321
+ }
5322
+ }
5323
+ }
5324
+ if (uniqueIdentity && activeAgents.length > 0) {
5325
+ throw new Error(
5326
+ `An active agent with persistentId "${persistentId}" already exists. Use resumePersistentIdentity: true to resume it, or unregister the existing agent first.`
5327
+ );
5328
+ }
5329
+ }
5173
5330
  const registeredAgent = agents.register({
5174
5331
  name,
5175
5332
  role,
5176
5333
  metadata,
5177
5334
  sessionId: ctx.session.id,
5178
5335
  capabilities,
5179
- capabilityDescriptor
5336
+ capabilityDescriptor,
5337
+ persistentIdentity: resolvedIdentity
5180
5338
  });
5181
5339
  if (sessions) {
5182
5340
  sessions.addAgent(ctx.session.id, registeredAgent.id);
@@ -5192,6 +5350,7 @@ function createAgentHandlers(options) {
5192
5350
  metadata: registeredAgent.metadata,
5193
5351
  capabilities: registeredAgent.capabilities,
5194
5352
  capabilityDescriptor: registeredAgent.capabilityDescriptor,
5353
+ persistentIdentity: registeredAgent.persistentIdentity,
5195
5354
  visibility: "public"
5196
5355
  }
5197
5356
  };
@@ -5228,6 +5387,7 @@ function createAgentHandlers(options) {
5228
5387
  metadata: a.metadata,
5229
5388
  capabilities: a.capabilities,
5230
5389
  capabilityDescriptor: a.capabilityDescriptor,
5390
+ persistentIdentity: a.persistentIdentity,
5231
5391
  visibility: "public"
5232
5392
  }))
5233
5393
  };
@@ -5247,6 +5407,7 @@ function createAgentHandlers(options) {
5247
5407
  metadata: agent.metadata,
5248
5408
  capabilities: agent.capabilities,
5249
5409
  capabilityDescriptor: agent.capabilityDescriptor,
5410
+ persistentIdentity: agent.persistentIdentity,
5250
5411
  visibility: "public"
5251
5412
  }
5252
5413
  };
@@ -5272,6 +5433,7 @@ function createAgentHandlers(options) {
5272
5433
  metadata: agent.metadata,
5273
5434
  capabilities: agent.capabilities,
5274
5435
  capabilityDescriptor: agent.capabilityDescriptor,
5436
+ persistentIdentity: agent.persistentIdentity,
5275
5437
  visibility: "public"
5276
5438
  }
5277
5439
  };
@@ -5321,7 +5483,8 @@ function createAgentHandlers(options) {
5321
5483
  parentId: parent
5322
5484
  },
5323
5485
  sessionId: ctx.session.id,
5324
- capabilityDescriptor
5486
+ capabilityDescriptor,
5487
+ persistentIdentity: parentAgent.persistentIdentity
5325
5488
  });
5326
5489
  if (sessions) {
5327
5490
  sessions.addAgent(ctx.session.id, childAgent.id);
@@ -5354,6 +5517,7 @@ function createAgentHandlers(options) {
5354
5517
  state: childAgent.state,
5355
5518
  metadata: childAgent.metadata,
5356
5519
  capabilityDescriptor: childAgent.capabilityDescriptor,
5520
+ persistentIdentity: childAgent.persistentIdentity,
5357
5521
  visibility: "public"
5358
5522
  }
5359
5523
  };
@@ -7581,94 +7745,113 @@ function toScope(scopeId) {
7581
7745
  }
7582
7746
 
7583
7747
  // src/server/messages/handlers.ts
7748
+ function resolveRouteTarget(to) {
7749
+ if (typeof to === "string") {
7750
+ return { type: "string", value: to };
7751
+ }
7752
+ if (Array.isArray(to)) {
7753
+ return to.map((item) => resolveRouteTarget(item));
7754
+ }
7755
+ if (to && typeof to === "object") {
7756
+ const obj = to;
7757
+ if (typeof obj.agent === "string" && !obj.system) {
7758
+ return { type: "agent", id: obj.agent };
7759
+ }
7760
+ if (Array.isArray(obj.agents)) {
7761
+ return { type: "agents", ids: obj.agents };
7762
+ }
7763
+ if (typeof obj.scope === "string") {
7764
+ return { type: "scope", id: obj.scope };
7765
+ }
7766
+ if (obj.broadcast === true) {
7767
+ return { type: "broadcast" };
7768
+ }
7769
+ if (typeof obj.role === "string") {
7770
+ if (typeof obj.within === "string") {
7771
+ return { type: "scope", id: obj.within };
7772
+ }
7773
+ return { type: "broadcast" };
7774
+ }
7775
+ if (obj.system === true) {
7776
+ return { type: "broadcast" };
7777
+ }
7778
+ if (typeof obj.system === "string" && typeof obj.agent === "string") {
7779
+ return { type: "agent", id: obj.agent };
7780
+ }
7781
+ if (typeof obj.participant === "string") {
7782
+ return { type: "agent", id: obj.participant };
7783
+ }
7784
+ if (obj.participants === "all" || obj.participants === "agents") {
7785
+ return { type: "broadcast" };
7786
+ }
7787
+ if (obj.parent || obj.children || obj.ancestors || obj.descendants || obj.siblings) {
7788
+ return { type: "broadcast" };
7789
+ }
7790
+ }
7791
+ return { type: "string", value: String(to) };
7792
+ }
7584
7793
  function createMessageHandlers(options) {
7585
7794
  const { messages, scopes, agents, turns } = options;
7795
+ function sendToAgent(from, to, params) {
7796
+ return messages.sendToAgent({
7797
+ from,
7798
+ to,
7799
+ payload: params.payload,
7800
+ replyTo: params.replyTo,
7801
+ priority: params.priority,
7802
+ ttlMs: params.ttlMs,
7803
+ messageType: params.messageType
7804
+ });
7805
+ }
7806
+ function sendToScope(from, scopeId, params) {
7807
+ return messages.sendToScope({
7808
+ from,
7809
+ scopeId,
7810
+ payload: params.payload,
7811
+ excludeSender: true,
7812
+ messageType: params.messageType
7813
+ });
7814
+ }
7815
+ function resolveStringAddress(from, to, params) {
7816
+ if (isAddress(to)) {
7817
+ if (isScopeAddress(to)) {
7818
+ const message3 = sendToScope(from, extractId(to), params);
7819
+ return { messageId: message3.id };
7820
+ } else {
7821
+ const message3 = sendToAgent(from, extractId(to), params);
7822
+ return { messageId: message3.id };
7823
+ }
7824
+ }
7825
+ const scope = scopes.get(to);
7826
+ const agent = agents?.get(to);
7827
+ if (scope && agent) {
7828
+ throw new Error(
7829
+ `Ambiguous address "${to}" matches both an agent and a scope. Use "agent:${to}" or "scope:${to}" to disambiguate.`
7830
+ );
7831
+ }
7832
+ if (scope) {
7833
+ const message3 = sendToScope(from, to, params);
7834
+ return { messageId: message3.id };
7835
+ }
7836
+ const message2 = sendToAgent(from, to, params);
7837
+ return { messageId: message2.id };
7838
+ }
7586
7839
  return {
7587
7840
  "map/send": async (params, ctx) => {
7588
- const { to, payload, replyTo, priority, ttlMs, messageType, meta } = params;
7841
+ const sendParams = params;
7842
+ const { to: rawTo, meta } = sendParams;
7589
7843
  const from = ctx.session.agentIds[0] ?? ctx.session.id;
7844
+ const target = resolveRouteTarget(rawTo);
7590
7845
  let result;
7591
- if (Array.isArray(to)) {
7846
+ if (Array.isArray(target)) {
7592
7847
  const results = [];
7593
- for (const recipient of to) {
7594
- if (isScopeAddress(recipient)) {
7595
- const scopeId = extractId(recipient);
7596
- const message2 = messages.sendToScope({
7597
- from,
7598
- scopeId,
7599
- payload,
7600
- excludeSender: true,
7601
- messageType
7602
- });
7603
- results.push(message2.id);
7604
- } else {
7605
- const agentId = isAgentAddress(recipient) ? extractId(recipient) : recipient;
7606
- const message2 = messages.sendToAgent({
7607
- from,
7608
- to: agentId,
7609
- payload,
7610
- replyTo,
7611
- priority,
7612
- ttlMs,
7613
- messageType
7614
- });
7615
- results.push(message2.id);
7616
- }
7848
+ for (const t of target) {
7849
+ const { messageId } = routeSingle(from, t, sendParams);
7850
+ results.push(messageId);
7617
7851
  }
7618
7852
  result = { messageId: results[0], delivered: results };
7619
- } else if (isAddress(to)) {
7620
- if (isScopeAddress(to)) {
7621
- const scopeId = extractId(to);
7622
- const message2 = messages.sendToScope({
7623
- from,
7624
- scopeId,
7625
- payload,
7626
- excludeSender: true,
7627
- messageType
7628
- });
7629
- result = { messageId: message2.id };
7630
- } else {
7631
- const agentId = extractId(to);
7632
- const message2 = messages.sendToAgent({
7633
- from,
7634
- to: agentId,
7635
- payload,
7636
- replyTo,
7637
- priority,
7638
- ttlMs,
7639
- messageType
7640
- });
7641
- result = { messageId: message2.id };
7642
- }
7643
7853
  } else {
7644
- const scope = scopes.get(to);
7645
- const agent = agents?.get(to);
7646
- if (scope && agent) {
7647
- throw new Error(
7648
- `Ambiguous address "${to}" matches both an agent and a scope. Use "agent:${to}" or "scope:${to}" to disambiguate.`
7649
- );
7650
- }
7651
- if (scope) {
7652
- const message2 = messages.sendToScope({
7653
- from,
7654
- scopeId: to,
7655
- payload,
7656
- excludeSender: true,
7657
- messageType
7658
- });
7659
- result = { messageId: message2.id };
7660
- } else {
7661
- const message2 = messages.sendToAgent({
7662
- from,
7663
- to,
7664
- payload,
7665
- replyTo,
7666
- priority,
7667
- ttlMs,
7668
- messageType
7669
- });
7670
- result = { messageId: message2.id };
7671
- }
7854
+ result = routeSingle(from, target, sendParams);
7672
7855
  }
7673
7856
  if (turns && meta?.mail?.conversationId) {
7674
7857
  try {
@@ -7676,7 +7859,7 @@ function createMessageHandlers(options) {
7676
7859
  conversationId: meta.mail.conversationId,
7677
7860
  participant: from,
7678
7861
  contentType: "data",
7679
- content: payload,
7862
+ content: sendParams.payload,
7680
7863
  messageId: result.messageId,
7681
7864
  threadId: meta.mail.threadId,
7682
7865
  inReplyTo: meta.mail.inReplyTo,
@@ -7701,6 +7884,38 @@ function createMessageHandlers(options) {
7701
7884
  return { messageId: message2.id };
7702
7885
  }
7703
7886
  };
7887
+ function routeSingle(from, target, params) {
7888
+ switch (target.type) {
7889
+ case "agent": {
7890
+ const message2 = sendToAgent(from, target.id, params);
7891
+ return { messageId: message2.id };
7892
+ }
7893
+ case "agents": {
7894
+ const results = [];
7895
+ for (const agentId of target.ids) {
7896
+ const message2 = sendToAgent(from, agentId, params);
7897
+ results.push(message2.id);
7898
+ }
7899
+ return { messageId: results[0] };
7900
+ }
7901
+ case "scope": {
7902
+ const message2 = sendToScope(from, target.id, params);
7903
+ return { messageId: message2.id };
7904
+ }
7905
+ case "broadcast": {
7906
+ const message2 = messages.sendToAgent({
7907
+ from,
7908
+ to: "*",
7909
+ payload: params.payload,
7910
+ messageType: params.messageType
7911
+ });
7912
+ return { messageId: message2.id };
7913
+ }
7914
+ case "string": {
7915
+ return resolveStringAddress(from, target.value, params);
7916
+ }
7917
+ }
7918
+ }
7704
7919
  }
7705
7920
 
7706
7921
  // src/server/mail/stores/in-memory-conversation.ts
@@ -9975,6 +10190,9 @@ function createCredentialHandlers(options) {
9975
10190
  type: "credential.denied",
9976
10191
  data: {
9977
10192
  agentId: token.agentId,
10193
+ ...token.persistentIdentity?.persistentId && {
10194
+ persistentId: token.persistentIdentity.persistentId
10195
+ },
9978
10196
  scope,
9979
10197
  resource,
9980
10198
  reason: check2.error
@@ -9990,6 +10208,9 @@ function createCredentialHandlers(options) {
9990
10208
  type: "credential.issued",
9991
10209
  data: {
9992
10210
  agentId: token.agentId,
10211
+ ...token.persistentIdentity?.persistentId && {
10212
+ persistentId: token.persistentIdentity.persistentId
10213
+ },
9993
10214
  scope,
9994
10215
  resource,
9995
10216
  credentialType: credential.credentialType,
@@ -10917,6 +11138,7 @@ var AgentIAMProvider = class {
10917
11138
  const principal = {
10918
11139
  id: token.agentId,
10919
11140
  issuer: token.identity?.systemId ?? "agent-iam",
11141
+ persistentId: token.persistentIdentity?.persistentId,
10920
11142
  claims: {
10921
11143
  scopes: token.scopes,
10922
11144
  delegatable: token.delegatable,
@@ -10945,7 +11167,8 @@ var AgentIAMProvider = class {
10945
11167
  requestedScopes: spawnRequest.requestedScopes ?? parentToken.scopes,
10946
11168
  delegatable: true,
10947
11169
  ttlMinutes: spawnRequest.ttlMinutes,
10948
- inheritIdentity: spawnRequest.inheritIdentity ?? true
11170
+ inheritIdentity: spawnRequest.inheritIdentity ?? true,
11171
+ inheritPersistentIdentity: spawnRequest.inheritIdentity ?? true
10949
11172
  });
10950
11173
  const serialized = this.#tokenService.serialize(childToken);
10951
11174
  return {
@@ -11042,6 +11265,7 @@ var AgentIAMFederationGateway = class {
11042
11265
  const principal = {
11043
11266
  id: `federated:${sourceSystemId}:${deserializedToken.agentId}`,
11044
11267
  issuer: sourceSystemId,
11268
+ persistentId: deserializedToken.persistentIdentity?.persistentId,
11045
11269
  claims: {
11046
11270
  scopes: translatedScopes,
11047
11271
  federatedFrom: sourceSystemId,
@@ -11110,7 +11334,8 @@ var AgentIAMFederationGateway = class {
11110
11334
  requestedScopes: translatedScopes,
11111
11335
  delegatable: false,
11112
11336
  ttlMinutes: this.#federatedTTL,
11113
- inheritIdentity: true
11337
+ inheritIdentity: true,
11338
+ inheritPersistentIdentity: true
11114
11339
  });
11115
11340
  const withFederation = {
11116
11341
  ...delegated,
@@ -12835,6 +13060,13 @@ var FederatedAgentRegistry = class {
12835
13060
  }
12836
13061
  return unregisteredIds;
12837
13062
  }
13063
+ /**
13064
+ * Resume an orphaned agent under a new session.
13065
+ * Delegates to the local registry.
13066
+ */
13067
+ resume(id, newSessionId, metadata, persistentIdentity) {
13068
+ return this.local.resume(id, newSessionId, metadata, persistentIdentity);
13069
+ }
12838
13070
  /**
12839
13071
  * Check if an agent is remote.
12840
13072
  */