agent-relay-server 0.105.2 → 0.107.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.
- package/docs/openapi.json +29 -1
- package/package.json +5 -3
- package/public/assets/{MessageBubble-CPYQQLDI.js → MessageBubble-PEdvVh_m.js} +2 -2
- package/public/assets/{MessageBubble-CPYQQLDI.js.map → MessageBubble-PEdvVh_m.js.map} +1 -1
- package/public/assets/{PlanGraphPanel-B7xZt5DI.js → PlanGraphPanel-DSts7Rtq.js} +2 -2
- package/public/assets/{PlanGraphPanel-B7xZt5DI.js.map → PlanGraphPanel-DSts7Rtq.js.map} +1 -1
- package/public/assets/{activity-UKQrQ8_0.js → activity-BcYf8YNO.js} +2 -2
- package/public/assets/{activity-UKQrQ8_0.js.map → activity-BcYf8YNO.js.map} +1 -1
- package/public/assets/{agent-profiles-Zr_5nNEJ.js → agent-profiles-CuTQtmV6.js} +2 -2
- package/public/assets/{agent-profiles-Zr_5nNEJ.js.map → agent-profiles-CuTQtmV6.js.map} +1 -1
- package/public/assets/{agents-FdrfmJsj.js → agents-CgRFJyks.js} +2 -2
- package/public/assets/{agents-FdrfmJsj.js.map → agents-CgRFJyks.js.map} +1 -1
- package/public/assets/{analytics-VximqXQ9.js → analytics-C3OTFIXo.js} +18 -18
- package/public/assets/{analytics-VximqXQ9.js.map → analytics-C3OTFIXo.js.map} +1 -1
- package/public/assets/{automation-DlEcJvgu.js → automation-CH9YGYoE.js} +2 -2
- package/public/assets/{automation-DlEcJvgu.js.map → automation-CH9YGYoE.js.map} +1 -1
- package/public/assets/{chat-D1bunuI-.js → chat-BLcm2Aht.js} +2 -2
- package/public/assets/{chat-D1bunuI-.js.map → chat-BLcm2Aht.js.map} +1 -1
- package/public/assets/{formatted-body-impl-4v9SkUD1.js → formatted-body-impl-BJTthVHg.js} +2 -2
- package/public/assets/{formatted-body-impl-4v9SkUD1.js.map → formatted-body-impl-BJTthVHg.js.map} +1 -1
- package/public/assets/{index-Vmhw442d.js → index-3ydeNO0c.js} +6 -6
- package/public/assets/index-3ydeNO0c.js.map +1 -0
- package/public/assets/{insights-CntgHcTp.js → insights-DklrIhb6.js} +2 -2
- package/public/assets/{insights-CntgHcTp.js.map → insights-DklrIhb6.js.map} +1 -1
- package/public/assets/{maintenance-Dw7frQtu.js → maintenance-FAAMGpuZ.js} +2 -2
- package/public/assets/{maintenance-Dw7frQtu.js.map → maintenance-FAAMGpuZ.js.map} +1 -1
- package/public/assets/{managed-agents-Bj--bFmZ.js → managed-agents-CVca-s3t.js} +2 -2
- package/public/assets/{managed-agents-Bj--bFmZ.js.map → managed-agents-CVca-s3t.js.map} +1 -1
- package/public/assets/{markdown-preview-impl-DGLCocU8.js → markdown-preview-impl-BPW4OQo9.js} +2 -2
- package/public/assets/{markdown-preview-impl-DGLCocU8.js.map → markdown-preview-impl-BPW4OQo9.js.map} +1 -1
- package/public/assets/{memory-yj2MIxUA.js → memory-BzuDTHC5.js} +2 -2
- package/public/assets/{memory-yj2MIxUA.js.map → memory-BzuDTHC5.js.map} +1 -1
- package/public/assets/{messages-BT5mL7iz.js → messages-_W24PNvT.js} +2 -2
- package/public/assets/{messages-BT5mL7iz.js.map → messages-_W24PNvT.js.map} +1 -1
- package/public/assets/{orchestrators-BVDAhrPk.js → orchestrators-Du6I_n8i.js} +2 -2
- package/public/assets/{orchestrators-BVDAhrPk.js.map → orchestrators-Du6I_n8i.js.map} +1 -1
- package/public/assets/{overview-DlqJIqYK.js → overview-Dyvm1qpT.js} +2 -2
- package/public/assets/{overview-DlqJIqYK.js.map → overview-Dyvm1qpT.js.map} +1 -1
- package/public/assets/{pairs-DQ4tNCo3.js → pairs-B8x1RCNd.js} +2 -2
- package/public/assets/{pairs-DQ4tNCo3.js.map → pairs-B8x1RCNd.js.map} +1 -1
- package/public/assets/{prompt-settings-DlsqOP0C.js → prompt-settings-xVXmvxB5.js} +2 -2
- package/public/assets/{prompt-settings-DlsqOP0C.js.map → prompt-settings-xVXmvxB5.js.map} +1 -1
- package/public/assets/{registry-Cw2fdWrn.js → registry-ypiICauZ.js} +2 -2
- package/public/assets/{registry-Cw2fdWrn.js.map → registry-ypiICauZ.js.map} +1 -1
- package/public/assets/{security-ucr7IT1V.js → security-BfOQ6T5r.js} +2 -2
- package/public/assets/{security-ucr7IT1V.js.map → security-BfOQ6T5r.js.map} +1 -1
- package/public/assets/{select-D8UWCtYZ.js → select-Dx8Ro-A3.js} +2 -2
- package/public/assets/{select-D8UWCtYZ.js.map → select-Dx8Ro-A3.js.map} +1 -1
- package/public/assets/settings-87clTx4N.js +6 -0
- package/public/assets/settings-87clTx4N.js.map +1 -0
- package/public/assets/{tasks-jRUvxUd5.js → tasks-1Kvp53wh.js} +2 -2
- package/public/assets/{tasks-jRUvxUd5.js.map → tasks-1Kvp53wh.js.map} +1 -1
- package/public/assets/{teams-Dn0yggD-.js → teams-DJWp4AKi.js} +2 -2
- package/public/assets/{teams-Dn0yggD-.js.map → teams-DJWp4AKi.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-fLly20IP.js → terminal-viewer-impl-DgMuRAe_.js} +2 -2
- package/public/assets/{terminal-viewer-impl-fLly20IP.js.map → terminal-viewer-impl-DgMuRAe_.js.map} +1 -1
- package/public/assets/types-DorDDvEb.js.map +1 -1
- package/public/assets/{user-avatar-BWLUHt2e.js → user-avatar-CfAUS3PZ.js} +2 -2
- package/public/assets/{user-avatar-BWLUHt2e.js.map → user-avatar-CfAUS3PZ.js.map} +1 -1
- package/public/assets/{work-queue-BAnNY0xE.js → work-queue-D-Otxd9u.js} +2 -2
- package/public/assets/{work-queue-BAnNY0xE.js.map → work-queue-D-Otxd9u.js.map} +1 -1
- package/public/index.html +1 -1
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/plugins/claude/monitors/relay-monitor.provisioned.mjs +15 -3
- package/runner/src/adapter.ts +14 -3
- package/src/branch-landed.ts +76 -1
- package/src/connectors.ts +116 -4
- package/src/db/provider-quotas.ts +6 -0
- package/src/mcp-egress-tools.ts +3 -2
- package/src/notification-router.ts +6 -1
- package/src/notification-types.ts +2 -0
- package/src/notify.ts +4 -4
- package/src/quota-band-transition.ts +6 -0
- package/src/routes/commands.ts +17 -1
- package/src/routes/index.ts +2 -1
- package/src/routes/provider-quotas.ts +13 -1
- package/src/security.ts +2 -0
- package/src/services/transient-agent-reaper.ts +16 -1
- package/src/token-db.ts +3 -3
- package/public/assets/index-Vmhw442d.js.map +0 -1
- package/public/assets/settings-Dvf_ps1B.js +0 -6
- package/public/assets/settings-Dvf_ps1B.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isRecord } from "agent-relay-sdk";
|
|
2
|
-
import { acquireProviderQuotaLease, getOrchestrator, getProviderQuotaLease, listProviderQuotas, releaseProviderQuotaLease, upsertProviderQuota } from "../db";
|
|
2
|
+
import { acquireProviderQuotaLease, getOrchestrator, getProviderQuotaLease, getProviderQuotaHistory, listProviderQuotas, releaseProviderQuotaLease, upsertProviderQuota } from "../db";
|
|
3
3
|
import { emitRelayEvent } from "../events";
|
|
4
4
|
import { quotaStateFromUnknown, providerQuotaErrorFromUnknown } from "../quota";
|
|
5
5
|
import { authContextFromRequest } from "../services/auth-context";
|
|
@@ -79,6 +79,18 @@ export const getProviderQuotaAdvisoryRoute: Handler = () => {
|
|
|
79
79
|
return json({ advisories });
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
+
// #609 — per-provider 30-day quota history (consumed by #607 analytics chart + #608 sparkline).
|
|
83
|
+
export const getProviderQuotaHistoryRoute: Handler = (req) => {
|
|
84
|
+
const url = new URL(req.url);
|
|
85
|
+
const provider = url.searchParams.get("provider");
|
|
86
|
+
if (!provider) return error("provider query parameter required");
|
|
87
|
+
const sinceMs = url.searchParams.get("sinceMs") ? Number(url.searchParams.get("sinceMs")) : undefined;
|
|
88
|
+
if (sinceMs !== undefined && (!Number.isFinite(sinceMs) || sinceMs < 0)) return error("sinceMs must be a positive timestamp");
|
|
89
|
+
const accountKey = url.searchParams.get("accountKey") ?? undefined;
|
|
90
|
+
const limit = parseQueryInt(url.searchParams.get("limit"), { min: 1, max: 10_000, clamp: true });
|
|
91
|
+
return json(getProviderQuotaHistory(provider, { sinceMs, accountKey, limit: limit ?? undefined }));
|
|
92
|
+
};
|
|
93
|
+
|
|
82
94
|
export const postProviderQuotaRoute: Handler = async (req) => {
|
|
83
95
|
const parsed = await parseBody<unknown>(req);
|
|
84
96
|
if (!parsed.ok) return error(parsed.error, parsed.status);
|
package/src/security.ts
CHANGED
|
@@ -199,6 +199,7 @@ export function requiredScopeFor(method: string, pathname: string): string | nul
|
|
|
199
199
|
if (pathname.startsWith("/api/pairs")) return method === "GET" ? "pairs:read" : "pairs:write";
|
|
200
200
|
if (pathname === "/api/provider-quota-leases/acquire" || pathname === "/api/provider-quota-leases/release") return "quota:write";
|
|
201
201
|
if (pathname === "/api/provider-quotas/advisory") return "agent:read";
|
|
202
|
+
if (pathname === "/api/provider-quotas/history") return "agent:read";
|
|
202
203
|
if (pathname === "/api/provider-quotas") return method === "GET" ? "agent:read" : "quota:write";
|
|
203
204
|
if (pathname === "/api/routing-policy") return method === "GET" ? "agent:read" : "settings:write:routing";
|
|
204
205
|
if (pathname === "/api/teams/config") return method === "GET" ? "teams:read" : "settings:write:teams";
|
|
@@ -286,6 +287,7 @@ export function requiredComponentScopeFor(method: string, pathname: string): str
|
|
|
286
287
|
if (pathname.startsWith("/api/agents")) return method === "GET" ? "agent:read" : "agent:write";
|
|
287
288
|
if (pathname === "/api/provider-quota-leases/acquire" || pathname === "/api/provider-quota-leases/release") return "quota:write";
|
|
288
289
|
if (pathname === "/api/provider-quotas/advisory") return "agent:read";
|
|
290
|
+
if (pathname === "/api/provider-quotas/history") return "agent:read";
|
|
289
291
|
if (pathname === "/api/provider-quotas") return method === "GET" ? "agent:read" : "quota:write";
|
|
290
292
|
// Per-provider quota config (#605): reads are agent:read (the orchestrator
|
|
291
293
|
// collector reads its config each tick); writes are settings:write:provider.
|
|
@@ -37,6 +37,19 @@ function defaultCommitsAhead(ws: WorkspaceRecord): number | null {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
// #800 — A transient agent is protected from reaping ONLY by one of three evidence-based states:
|
|
41
|
+
// it is not idle (still working), it is not ready (mid-startup/teardown), or it carries a REAL
|
|
42
|
+
// provider block. `isProviderBlocked` reads the agent's own `meta.providerState`, which is set
|
|
43
|
+
// exclusively from hard evidence — an HTTP 429 / StopFailure hook, the scraped CLI usage-limit
|
|
44
|
+
// modal, an approval gate, or a model-unavailable hold (see runner rate-limit.ts / control-server).
|
|
45
|
+
// It is NEVER derived from a quota-utilization number. The reaper deliberately does not read quota
|
|
46
|
+
// utilization at all, so a provider merely sitting at high 7d/5h utilization can neither cause nor
|
|
47
|
+
// prevent a reap. This keeps the false "high-util ⇒ blocked ⇒ reaped" chain (#800) impossible by
|
|
48
|
+
// construction: utilization is not an input to this decision.
|
|
49
|
+
function reapProtected(agent: ReturnType<typeof listAgents>[number]): boolean {
|
|
50
|
+
return agent.status !== "idle" || !agent.ready || isProviderBlocked(agent);
|
|
51
|
+
}
|
|
52
|
+
|
|
40
53
|
let _commitsAheadFn: (ws: WorkspaceRecord) => number | null = defaultCommitsAhead;
|
|
41
54
|
|
|
42
55
|
export function overrideCommitsAheadForTests(fn: (ws: WorkspaceRecord) => number | null): void {
|
|
@@ -109,7 +122,9 @@ export function reapTransientAgents(): Record<string, unknown> {
|
|
|
109
122
|
// A held agent (rate-limit hold #286, or any provider-blocked state) reads as
|
|
110
123
|
// idle+ready but is NOT done — reaping it would kill work that's just waiting
|
|
111
124
|
// for the limit to reset. Treat it as not-idle; the clock restarts on resume.
|
|
112
|
-
|
|
125
|
+
// #800 — `reapProtected` is the single home for that decision: it honors only
|
|
126
|
+
// evidence-based block states, never a high quota-utilization number.
|
|
127
|
+
if (reapProtected(agent)) { transientTracker.delete(agent.id); continue; }
|
|
113
128
|
const entry = transientTracker.get(agent.id) ?? { firstIdleAt: now };
|
|
114
129
|
transientTracker.set(agent.id, entry);
|
|
115
130
|
const idleForMs = now - entry.firstIdleAt;
|
package/src/token-db.ts
CHANGED
|
@@ -78,7 +78,7 @@ const BUILT_IN_PROFILES: Array<Omit<TokenProfile, "createdAt" | "updatedAt">> =
|
|
|
78
78
|
name: "Provider Agent",
|
|
79
79
|
description: "Coding-agent runtime access for messages, commands, tasks, and scoped memory reads.",
|
|
80
80
|
role: "provider",
|
|
81
|
-
scope: ["agent:read", "agent:write", "message:read", "message:send", "schedule:write", "command:read", "command:write", "task:read", "task:write", "memory:read", "artifact:read", "artifact:write", "mcp:use", "plans:read", "plans:write", "teams:read", "teams:write", "blackboard:read", "blackboard:write", "project:read", "project:write", "issue:read", "issue:write", "notifications:read", "notifications:write", "insights:write", "quota:write"],
|
|
81
|
+
scope: ["agent:read", "agent:write", "message:read", "message:send", "schedule:write", "command:read", "command:write", "task:read", "task:write", "memory:read", "artifact:read", "artifact:write", "mcp:use", "plans:read", "plans:write", "teams:read", "teams:write", "blackboard:read", "blackboard:write", "project:read", "project:write", "issue:read", "issue:write", "notifications:read", "notifications:write", "channel:egress", "insights:write", "quota:write"],
|
|
82
82
|
ttlSeconds: 24 * 60 * 60,
|
|
83
83
|
builtIn: true,
|
|
84
84
|
createdBy: "system",
|
|
@@ -88,7 +88,7 @@ const BUILT_IN_PROFILES: Array<Omit<TokenProfile, "createdAt" | "updatedAt">> =
|
|
|
88
88
|
name: "Provider Child Agent",
|
|
89
89
|
description: "Delegated child-agent runtime access, constrained to its parent and spawn request.",
|
|
90
90
|
role: "provider",
|
|
91
|
-
scope: ["agent:read", "agent:write", "message:read", "message:send", "schedule:write", "command:read", "command:write", "task:read", "task:write", "memory:read", "artifact:read", "artifact:write", "mcp:use", "teams:read", "blackboard:read", "blackboard:write", "project:read", "project:write", "issue:read", "issue:write", "notifications:read", "notifications:write", "insights:write", "quota:write"],
|
|
91
|
+
scope: ["agent:read", "agent:write", "message:read", "message:send", "schedule:write", "command:read", "command:write", "task:read", "task:write", "memory:read", "artifact:read", "artifact:write", "mcp:use", "teams:read", "blackboard:read", "blackboard:write", "project:read", "project:write", "issue:read", "issue:write", "notifications:read", "notifications:write", "channel:egress", "insights:write", "quota:write"],
|
|
92
92
|
constraints: { canDelegate: false },
|
|
93
93
|
ttlSeconds: 2 * 60 * 60,
|
|
94
94
|
builtIn: true,
|
|
@@ -99,7 +99,7 @@ const BUILT_IN_PROFILES: Array<Omit<TokenProfile, "createdAt" | "updatedAt">> =
|
|
|
99
99
|
name: "Provider Interactive Agent",
|
|
100
100
|
description: "User-launched provider runtime access constrained to its own agent and cwd for long interactive sessions.",
|
|
101
101
|
role: "provider",
|
|
102
|
-
scope: ["agent:read", "agent:write", "message:read", "message:send", "schedule:write", "command:read", "command:write", "task:read", "task:write", "memory:read", "artifact:read", "artifact:write", "mcp:use", "teams:read", "blackboard:read", "blackboard:write", "project:read", "project:write", "issue:read", "issue:write", "notifications:read", "notifications:write", "insights:write", "quota:write"],
|
|
102
|
+
scope: ["agent:read", "agent:write", "message:read", "message:send", "schedule:write", "command:read", "command:write", "task:read", "task:write", "memory:read", "artifact:read", "artifact:write", "mcp:use", "teams:read", "blackboard:read", "blackboard:write", "project:read", "project:write", "issue:read", "issue:write", "notifications:read", "notifications:write", "channel:egress", "insights:write", "quota:write"],
|
|
103
103
|
constraints: { terminalAttach: false, logsRead: false, canDelegate: false },
|
|
104
104
|
ttlSeconds: 30 * 24 * 60 * 60,
|
|
105
105
|
builtIn: true,
|