@topolo/sdk 0.16.0 → 0.17.1

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/index.cjs CHANGED
@@ -1381,6 +1381,7 @@ var NEGATIVE_CACHE_TTL_MS = 60 * 1e3;
1381
1381
  var TopoloClient = class _TopoloClient {
1382
1382
  credential;
1383
1383
  agent;
1384
+ actorContext;
1384
1385
  serviceUrls;
1385
1386
  environment;
1386
1387
  appIds;
@@ -1411,6 +1412,11 @@ var TopoloClient = class _TopoloClient {
1411
1412
  if (!options.agent?.clientName) throw new TopoloAuthError("agent.clientName is required");
1412
1413
  this.credential = options.credential;
1413
1414
  this.agent = options.agent;
1415
+ this.actorContext = options.actorContext ? {
1416
+ channel: options.actorContext.channel,
1417
+ taskId: options.actorContext.taskId ?? `task_${generateRequestId()}`,
1418
+ runId: options.actorContext.runId ?? `run_${generateRequestId()}`
1419
+ } : void 0;
1414
1420
  this.environment = options.environment;
1415
1421
  this.serviceUrls = options.environment ? topoloServiceOrigins(options.serviceUrls, options.environment) : options.serviceUrls;
1416
1422
  this.appIds = options.appIds;
@@ -2126,8 +2132,9 @@ var TopoloClient = class _TopoloClient {
2126
2132
  );
2127
2133
  }
2128
2134
  const mapped = mapActionInput(entry, input);
2129
- if (options.actorEnvelope) {
2130
- const actorEnvelope = parseActorEnvelope(options.actorEnvelope);
2135
+ const resolvedActorEnvelope = options.actorEnvelope ?? await this.buildVerifiedAgentActorEnvelope(entry.actionId, input, options.resource);
2136
+ if (resolvedActorEnvelope) {
2137
+ const actorEnvelope = parseActorEnvelope(resolvedActorEnvelope);
2131
2138
  if (actorEnvelope.action.actionId !== entry.actionId) {
2132
2139
  throw new TopoloSdkError("actor_envelope_action_mismatch", "Actor envelope actionId does not match the executed action.");
2133
2140
  }
@@ -2148,7 +2155,7 @@ var TopoloClient = class _TopoloClient {
2148
2155
  ...mapped.query ? { query: mapped.query } : {},
2149
2156
  ...mapped.body !== void 0 ? { body: mapped.body } : {},
2150
2157
  ...options.resource ? { resource: options.resource } : {},
2151
- ...options.actorEnvelope ? { actorEnvelope: options.actorEnvelope } : {},
2158
+ ...resolvedActorEnvelope ? { actorEnvelope: resolvedActorEnvelope } : {},
2152
2159
  headers: {
2153
2160
  [TOPOLO_ACTION_ID_HEADER]: entry.actionId,
2154
2161
  [TOPOLO_ACTION_NAME_HEADER]: entry.name
@@ -2157,6 +2164,56 @@ var TopoloClient = class _TopoloClient {
2157
2164
  });
2158
2165
  return redactActionResult(result);
2159
2166
  }
2167
+ async buildVerifiedAgentActorEnvelope(actionId, input, resource) {
2168
+ if (!this.actorContext) return void 0;
2169
+ const identity = await this.introspect();
2170
+ const principalType = identity.user.principalType;
2171
+ if (principalType !== "agent_employee" && principalType !== "external_agent") return void 0;
2172
+ if (!identity.organization || !identity.user.accountableUserId || !identity.user.principalId) {
2173
+ throw new TopoloSdkError(
2174
+ "incomplete_agent_identity",
2175
+ "Verified agent credentials must resolve an organization, accountable user, and principal id."
2176
+ );
2177
+ }
2178
+ const performer = principalType === "external_agent" ? {
2179
+ principalType: "external_agent",
2180
+ principalId: identity.user.principalId,
2181
+ installationId: identity.user.installationId ?? void 0,
2182
+ provider: identity.user.provider ?? void 0,
2183
+ model: identity.user.model ?? void 0
2184
+ } : {
2185
+ principalType: "managed_agent",
2186
+ principalId: identity.user.principalId,
2187
+ agentInstanceId: identity.user.agentInstanceId ?? void 0,
2188
+ model: identity.user.model ?? void 0
2189
+ };
2190
+ if (performer.principalType === "external_agent" && (!performer.installationId || !performer.provider) || performer.principalType === "managed_agent" && !performer.agentInstanceId) {
2191
+ throw new TopoloSdkError(
2192
+ "incomplete_agent_identity",
2193
+ "Verified agent credentials are missing the performer identity required for provenance."
2194
+ );
2195
+ }
2196
+ return parseActorEnvelope({
2197
+ schemaVersion: 1,
2198
+ organizationId: identity.organization.id,
2199
+ accountableSubject: { principalType: "human", principalId: identity.user.accountableUserId },
2200
+ performer,
2201
+ delegation: {
2202
+ taskId: this.actorContext.taskId,
2203
+ runId: this.actorContext.runId,
2204
+ lineage: [{ principalType: performer.principalType, principalId: performer.principalId }]
2205
+ },
2206
+ channel: this.actorContext.channel,
2207
+ assurance: { level: "workload_identity", methods: ["client_credentials"] },
2208
+ action: {
2209
+ requestId: generateRequestId(),
2210
+ actionId,
2211
+ ...resource ? resource : {},
2212
+ inputHash: await sha256CanonicalValue(input)
2213
+ },
2214
+ issuedAt: (/* @__PURE__ */ new Date()).toISOString()
2215
+ });
2216
+ }
2160
2217
  /**
2161
2218
  * Introspect the current credential. Returns the caller's resolved identity,
2162
2219
  * organization, and permission set. Used by CLI `whoami` and by MCP to gate
@@ -2184,7 +2241,18 @@ var TopoloClient = class _TopoloClient {
2184
2241
  email: user.email,
2185
2242
  name: user.name ?? null,
2186
2243
  role: user.role ?? (kind === "api_key" ? "service" : "member"),
2187
- permissions: payload.permissions ?? user.permissions ?? []
2244
+ permissions: payload.permissions ?? user.permissions ?? [],
2245
+ ...normalizeAgentPrincipalType(user.principalType) ? {
2246
+ principalId: readOptionalString(user.principalId),
2247
+ principalType: normalizeAgentPrincipalType(user.principalType),
2248
+ accountableUserId: readOptionalString(user.accountableUserId),
2249
+ agentInstanceId: readOptionalString(user.agentInstanceId),
2250
+ installationId: readOptionalString(user.installationId),
2251
+ provider: readOptionalString(user.provider),
2252
+ model: readOptionalString(user.model),
2253
+ serviceScopes: stringArray(user.serviceScopes),
2254
+ policyRef: readOptionalString(user.policyRef)
2255
+ } : {}
2188
2256
  },
2189
2257
  organization: organization ? {
2190
2258
  id: organization.id,
@@ -2549,6 +2617,9 @@ function normalizeCredentialAuthorizationMode(value, kind) {
2549
2617
  if (value === "context_rbac" || value === "oauth_scopes" || value === "session_rbac") return value;
2550
2618
  return "unknown";
2551
2619
  }
2620
+ function normalizeAgentPrincipalType(value) {
2621
+ return value === "agent_employee" || value === "external_agent" ? value : null;
2622
+ }
2552
2623
  function describeError(body, fallback) {
2553
2624
  if (body && typeof body === "object") {
2554
2625
  const maybe = body;
package/dist/index.d.cts CHANGED
@@ -146,6 +146,12 @@ declare function encodeTopoloActionBase64(bytes: Uint8Array): string;
146
146
  interface TopoloClientOptions {
147
147
  credential: TopoloCredential;
148
148
  agent: AgentIdentity;
149
+ /** Host surface used to attribute actions performed with verified agent credentials. */
150
+ actorContext?: {
151
+ channel: ActorChannel;
152
+ taskId?: string;
153
+ runId?: string;
154
+ };
149
155
  /** Per-service URL overrides. Useful for staging/dev. */
150
156
  serviceUrls?: Record<string, string>;
151
157
  /** Explicit environment used to reject cross-environment service and action origins. */
@@ -403,6 +409,7 @@ interface TopoloCatalogSearchOptions {
403
409
  declare class TopoloClient {
404
410
  private credential;
405
411
  private readonly agent;
412
+ private readonly actorContext?;
406
413
  private readonly serviceUrls?;
407
414
  private readonly environment?;
408
415
  private readonly appIds?;
@@ -534,6 +541,7 @@ declare class TopoloClient {
534
541
  actorEnvelope?: ActorEnvelope;
535
542
  }): Promise<T>;
536
543
  private executeResolvedAction;
544
+ private buildVerifiedAgentActorEnvelope;
537
545
  /**
538
546
  * Introspect the current credential. Returns the caller's resolved identity,
539
547
  * organization, and permission set. Used by CLI `whoami` and by MCP to gate
@@ -554,6 +562,15 @@ interface CredentialIntrospection {
554
562
  name: string | null;
555
563
  role: string;
556
564
  permissions: string[];
565
+ principalId?: string | null;
566
+ principalType?: 'agent_employee' | 'external_agent' | null;
567
+ accountableUserId?: string | null;
568
+ agentInstanceId?: string | null;
569
+ installationId?: string | null;
570
+ provider?: string | null;
571
+ model?: string | null;
572
+ serviceScopes?: string[];
573
+ policyRef?: string | null;
557
574
  };
558
575
  organization: {
559
576
  id: string;
package/dist/index.d.ts CHANGED
@@ -146,6 +146,12 @@ declare function encodeTopoloActionBase64(bytes: Uint8Array): string;
146
146
  interface TopoloClientOptions {
147
147
  credential: TopoloCredential;
148
148
  agent: AgentIdentity;
149
+ /** Host surface used to attribute actions performed with verified agent credentials. */
150
+ actorContext?: {
151
+ channel: ActorChannel;
152
+ taskId?: string;
153
+ runId?: string;
154
+ };
149
155
  /** Per-service URL overrides. Useful for staging/dev. */
150
156
  serviceUrls?: Record<string, string>;
151
157
  /** Explicit environment used to reject cross-environment service and action origins. */
@@ -403,6 +409,7 @@ interface TopoloCatalogSearchOptions {
403
409
  declare class TopoloClient {
404
410
  private credential;
405
411
  private readonly agent;
412
+ private readonly actorContext?;
406
413
  private readonly serviceUrls?;
407
414
  private readonly environment?;
408
415
  private readonly appIds?;
@@ -534,6 +541,7 @@ declare class TopoloClient {
534
541
  actorEnvelope?: ActorEnvelope;
535
542
  }): Promise<T>;
536
543
  private executeResolvedAction;
544
+ private buildVerifiedAgentActorEnvelope;
537
545
  /**
538
546
  * Introspect the current credential. Returns the caller's resolved identity,
539
547
  * organization, and permission set. Used by CLI `whoami` and by MCP to gate
@@ -554,6 +562,15 @@ interface CredentialIntrospection {
554
562
  name: string | null;
555
563
  role: string;
556
564
  permissions: string[];
565
+ principalId?: string | null;
566
+ principalType?: 'agent_employee' | 'external_agent' | null;
567
+ accountableUserId?: string | null;
568
+ agentInstanceId?: string | null;
569
+ installationId?: string | null;
570
+ provider?: string | null;
571
+ model?: string | null;
572
+ serviceScopes?: string[];
573
+ policyRef?: string | null;
557
574
  };
558
575
  organization: {
559
576
  id: string;
package/dist/index.js CHANGED
@@ -1286,6 +1286,7 @@ var NEGATIVE_CACHE_TTL_MS = 60 * 1e3;
1286
1286
  var TopoloClient = class _TopoloClient {
1287
1287
  credential;
1288
1288
  agent;
1289
+ actorContext;
1289
1290
  serviceUrls;
1290
1291
  environment;
1291
1292
  appIds;
@@ -1316,6 +1317,11 @@ var TopoloClient = class _TopoloClient {
1316
1317
  if (!options.agent?.clientName) throw new TopoloAuthError("agent.clientName is required");
1317
1318
  this.credential = options.credential;
1318
1319
  this.agent = options.agent;
1320
+ this.actorContext = options.actorContext ? {
1321
+ channel: options.actorContext.channel,
1322
+ taskId: options.actorContext.taskId ?? `task_${generateRequestId()}`,
1323
+ runId: options.actorContext.runId ?? `run_${generateRequestId()}`
1324
+ } : void 0;
1319
1325
  this.environment = options.environment;
1320
1326
  this.serviceUrls = options.environment ? topoloServiceOrigins(options.serviceUrls, options.environment) : options.serviceUrls;
1321
1327
  this.appIds = options.appIds;
@@ -2031,8 +2037,9 @@ var TopoloClient = class _TopoloClient {
2031
2037
  );
2032
2038
  }
2033
2039
  const mapped = mapActionInput(entry, input);
2034
- if (options.actorEnvelope) {
2035
- const actorEnvelope = parseActorEnvelope(options.actorEnvelope);
2040
+ const resolvedActorEnvelope = options.actorEnvelope ?? await this.buildVerifiedAgentActorEnvelope(entry.actionId, input, options.resource);
2041
+ if (resolvedActorEnvelope) {
2042
+ const actorEnvelope = parseActorEnvelope(resolvedActorEnvelope);
2036
2043
  if (actorEnvelope.action.actionId !== entry.actionId) {
2037
2044
  throw new TopoloSdkError("actor_envelope_action_mismatch", "Actor envelope actionId does not match the executed action.");
2038
2045
  }
@@ -2053,7 +2060,7 @@ var TopoloClient = class _TopoloClient {
2053
2060
  ...mapped.query ? { query: mapped.query } : {},
2054
2061
  ...mapped.body !== void 0 ? { body: mapped.body } : {},
2055
2062
  ...options.resource ? { resource: options.resource } : {},
2056
- ...options.actorEnvelope ? { actorEnvelope: options.actorEnvelope } : {},
2063
+ ...resolvedActorEnvelope ? { actorEnvelope: resolvedActorEnvelope } : {},
2057
2064
  headers: {
2058
2065
  [TOPOLO_ACTION_ID_HEADER]: entry.actionId,
2059
2066
  [TOPOLO_ACTION_NAME_HEADER]: entry.name
@@ -2062,6 +2069,56 @@ var TopoloClient = class _TopoloClient {
2062
2069
  });
2063
2070
  return redactActionResult(result);
2064
2071
  }
2072
+ async buildVerifiedAgentActorEnvelope(actionId, input, resource) {
2073
+ if (!this.actorContext) return void 0;
2074
+ const identity = await this.introspect();
2075
+ const principalType = identity.user.principalType;
2076
+ if (principalType !== "agent_employee" && principalType !== "external_agent") return void 0;
2077
+ if (!identity.organization || !identity.user.accountableUserId || !identity.user.principalId) {
2078
+ throw new TopoloSdkError(
2079
+ "incomplete_agent_identity",
2080
+ "Verified agent credentials must resolve an organization, accountable user, and principal id."
2081
+ );
2082
+ }
2083
+ const performer = principalType === "external_agent" ? {
2084
+ principalType: "external_agent",
2085
+ principalId: identity.user.principalId,
2086
+ installationId: identity.user.installationId ?? void 0,
2087
+ provider: identity.user.provider ?? void 0,
2088
+ model: identity.user.model ?? void 0
2089
+ } : {
2090
+ principalType: "managed_agent",
2091
+ principalId: identity.user.principalId,
2092
+ agentInstanceId: identity.user.agentInstanceId ?? void 0,
2093
+ model: identity.user.model ?? void 0
2094
+ };
2095
+ if (performer.principalType === "external_agent" && (!performer.installationId || !performer.provider) || performer.principalType === "managed_agent" && !performer.agentInstanceId) {
2096
+ throw new TopoloSdkError(
2097
+ "incomplete_agent_identity",
2098
+ "Verified agent credentials are missing the performer identity required for provenance."
2099
+ );
2100
+ }
2101
+ return parseActorEnvelope({
2102
+ schemaVersion: 1,
2103
+ organizationId: identity.organization.id,
2104
+ accountableSubject: { principalType: "human", principalId: identity.user.accountableUserId },
2105
+ performer,
2106
+ delegation: {
2107
+ taskId: this.actorContext.taskId,
2108
+ runId: this.actorContext.runId,
2109
+ lineage: [{ principalType: performer.principalType, principalId: performer.principalId }]
2110
+ },
2111
+ channel: this.actorContext.channel,
2112
+ assurance: { level: "workload_identity", methods: ["client_credentials"] },
2113
+ action: {
2114
+ requestId: generateRequestId(),
2115
+ actionId,
2116
+ ...resource ? resource : {},
2117
+ inputHash: await sha256CanonicalValue(input)
2118
+ },
2119
+ issuedAt: (/* @__PURE__ */ new Date()).toISOString()
2120
+ });
2121
+ }
2065
2122
  /**
2066
2123
  * Introspect the current credential. Returns the caller's resolved identity,
2067
2124
  * organization, and permission set. Used by CLI `whoami` and by MCP to gate
@@ -2089,7 +2146,18 @@ var TopoloClient = class _TopoloClient {
2089
2146
  email: user.email,
2090
2147
  name: user.name ?? null,
2091
2148
  role: user.role ?? (kind === "api_key" ? "service" : "member"),
2092
- permissions: payload.permissions ?? user.permissions ?? []
2149
+ permissions: payload.permissions ?? user.permissions ?? [],
2150
+ ...normalizeAgentPrincipalType(user.principalType) ? {
2151
+ principalId: readOptionalString(user.principalId),
2152
+ principalType: normalizeAgentPrincipalType(user.principalType),
2153
+ accountableUserId: readOptionalString(user.accountableUserId),
2154
+ agentInstanceId: readOptionalString(user.agentInstanceId),
2155
+ installationId: readOptionalString(user.installationId),
2156
+ provider: readOptionalString(user.provider),
2157
+ model: readOptionalString(user.model),
2158
+ serviceScopes: stringArray(user.serviceScopes),
2159
+ policyRef: readOptionalString(user.policyRef)
2160
+ } : {}
2093
2161
  },
2094
2162
  organization: organization ? {
2095
2163
  id: organization.id,
@@ -2454,6 +2522,9 @@ function normalizeCredentialAuthorizationMode(value, kind) {
2454
2522
  if (value === "context_rbac" || value === "oauth_scopes" || value === "session_rbac") return value;
2455
2523
  return "unknown";
2456
2524
  }
2525
+ function normalizeAgentPrincipalType(value) {
2526
+ return value === "agent_employee" || value === "external_agent" ? value : null;
2527
+ }
2457
2528
  function describeError(body, fallback) {
2458
2529
  if (body && typeof body === "object") {
2459
2530
  const maybe = body;
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@topolo/sdk",
3
3
  "packageManager": "pnpm@10.17.1",
4
- "version": "0.16.0",
5
- "topoloPublishedVersion": "0.16.0",
4
+ "version": "0.17.1",
5
+ "topoloPublishedVersion": "0.17.1",
6
6
  "description": "Typed client SDK for the Topolo platform. Used by TopoloCli, TopoloMCP, and third-party agents.",
7
7
  "license": "UNLICENSED",
8
8
  "author": "Topolo",