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 +1 -1
- package/package.json +1 -1
- package/src/bus.ts +6 -1
- package/src/routes/agents-spawn.ts +2 -3
- package/src/security.ts +8 -0
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.
|
|
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
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
|
|
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;
|