agent-relay-server 0.36.1 → 0.36.2

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/docs/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Agent Relay API",
5
- "version": "0.36.1",
5
+ "version": "0.36.2",
6
6
  "description": "Real-time message bus for inter-agent communication. Agent-first: this spec is designed for machine consumption — agents can self-discover the full API surface via GET /api/spec.",
7
7
  "license": {
8
8
  "name": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay-server",
3
- "version": "0.36.1",
3
+ "version": "0.36.2",
4
4
  "description": "Lightweight HTTP message relay for inter-agent communication across machines",
5
5
  "module": "src/index.ts",
6
6
  "type": "module",
package/src/bus.ts CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  type RegisterFrame,
17
17
  } from "agent-relay-sdk/protocol";
18
18
  import { errMessage, isRecord, stringValue } from "agent-relay-sdk";
19
- import { getComponentAuth, isComponentAuthorizedFor, isAuthorized, isOriginAllowed, unauthorized } from "./security";
19
+ import { getComponentAuth, isComponentAuthorizedFor, isAuthorized, isOriginAllowed, resolveSpawnLineage, unauthorized } from "./security";
20
20
  import type { AgentCard, Command, ComponentToken, ContextState, Message, ProviderCapabilities, Task } from "./types";
21
21
 
22
22
  interface BusSocketData {
@@ -273,6 +273,10 @@ function handleRegister(ws: BusWebSocket, frame: RegisterFrame): void {
273
273
  if (payload.agentId) {
274
274
  const label = stringMeta(payload.meta, "label");
275
275
  const context = contextFromMeta(payload.meta);
276
+ // Authoritative parent lineage — spawned/managed agents register over THIS bus path, not the
277
+ // HTTP `postAgent` route, so `spawned_by` must be set here too or it stays NULL (breaking the
278
+ // parent→child shutdown gate, the `spawnedBy:` filter, and the live-children quota).
279
+ const lineage = resolveSpawnLineage(ws.data.componentAuth?.constraints);
276
280
  const agent = upsertAgent({
277
281
  id: payload.agentId,
278
282
  name: stringMeta(payload.meta, "name") ?? payload.componentId,
@@ -286,6 +290,7 @@ function handleRegister(ws: BusWebSocket, frame: RegisterFrame): void {
286
290
  instanceId: payload.instanceId,
287
291
  ...(providerCapabilities ? { providerCapabilities } : {}),
288
292
  ...(context ? { context } : {}),
293
+ ...(lineage ? { spawnedBy: lineage } : {}),
289
294
  meta: payload.meta,
290
295
  });
291
296
  epoch = agent.epoch;
@@ -11,7 +11,7 @@ import { emitAgentStatus, emitManagedAgentStateChanged, emitMessageAvailable, em
11
11
  import { getAgentProfile, getManagedAgentState, updateManagedAgentState } from "../config-store";
12
12
  import { notifyAgentReady } from "../agent-lifecycle-events";
13
13
  import { getCompactionWatch } from "../compaction-watch";
14
- import { getComponentAuth } from "../security";
14
+ import { getComponentAuth, resolveSpawnLineage } from "../security";
15
15
  import { isPathWithinBase } from "../utils";
16
16
  import { listHostDirectories } from "../agent-spawn";
17
17
  import { rankRouteCandidates, type RouteAdvisorInput } from "../context-router";
@@ -67,8 +67,7 @@ export const postAgent: Handler = async (req) => {
67
67
  // Lineage is authoritative from the registering token's signed constraints — never the
68
68
  // client-sent body (a child can't forge its own parent). Set by relay at spawn for
69
69
  // agent-initiated spawns (`spawnedBy`) and the delegating-component path (`parentAgents`).
70
- const constraints = getComponentAuth(req)?.constraints;
71
- const lineage = constraints?.spawnedBy ?? constraints?.parentAgents?.[0];
70
+ const lineage = resolveSpawnLineage(getComponentAuth(req)?.constraints);
72
71
  if (lineage) input.spawnedBy = lineage;
73
72
  const existing = getAgent(input.id);
74
73
  const agent = upsertAgent(input);
package/src/security.ts CHANGED
@@ -397,6 +397,14 @@ function hasScope(scopes: string[], requiredScope: string): boolean {
397
397
  return false;
398
398
  }
399
399
 
400
+ /** Authoritative parent lineage from a registering token's signed constraints — agent-initiated
401
+ * spawn (`spawnedBy`) or the delegating-component path (`parentAgents`). One home, used by both the
402
+ * HTTP `postAgent` route and the bus register path so `spawned_by` is set however a child registers
403
+ * (drives the parent→child shutdown gate, the `spawnedBy:` filter, and the live-children quota). */
404
+ export function resolveSpawnLineage(constraints: TokenConstraints | undefined): string | undefined {
405
+ return constraints?.spawnedBy ?? constraints?.parentAgents?.[0];
406
+ }
407
+
400
408
  function constraintsAllow(constraints: TokenConstraints | undefined, resource: AuthorizationResource | undefined): boolean {
401
409
  if (!constraints || !resource) return true;
402
410
  const hasConstraints = Object.keys(constraints).length > 0;