agent-relay-server 0.69.1 → 0.70.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/src/config-store.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { cleanEnum, cleanString, cleanStringArray } from "./validation";
|
|
|
3
3
|
import { DEFAULT_CONTEXT_THRESHOLD_CONFIG, validateContextThresholdConfig } from "./context-threshold-config";
|
|
4
4
|
import { DEFAULT_SELF_RESUME_CONFIG, validateSelfResumeConfig } from "./self-resume-config";
|
|
5
5
|
import { TEAM_TEMPLATE_NAMESPACE, validateTeamTemplate } from "./team-template-config";
|
|
6
|
+
import { PROJECT_INSTRUCTION_POLICY_NAMES } from "./project-instructions";
|
|
6
7
|
import { resolveProviderSelection, type ProviderEffort } from "agent-relay-sdk/provider-catalog";
|
|
7
8
|
import { errMessage, isRecord, SPAWN_PROVIDERS, VALID_WORKSPACE_MODES } from "agent-relay-sdk"; import { effectiveProviderCatalogList } from "./provider-catalog-store";
|
|
8
9
|
import type {
|
|
@@ -54,13 +55,14 @@ const OPS_ASSISTANT_BRIEF = [
|
|
|
54
55
|
"Hold and apply session-local ops conventions the coordinator gives you. Report crisp outcomes only: command/gate, pass/fail, commit/version/host evidence, and the next blocker when one exists. Do not dump logs unless asked.",
|
|
55
56
|
"Do not make strategy, design, scope, or release-timing calls. Escalate those decisions to your spawn-parent. Report operational results to your spawn-parent by default and keep their context clean.",
|
|
56
57
|
].join("\n");
|
|
57
|
-
const BUILT_IN_AGENT_PROFILE_NAMES = new Set(["default-relay", "minimal", "isolated-research", "vanilla", "coordinator", "ops-assistant", "worker", "reviewer"]);
|
|
58
|
+
const BUILT_IN_AGENT_PROFILE_NAMES = new Set(["default-relay", "minimal", "isolated-research", "vanilla", "lean-worker", "coordinator", "ops-assistant", "worker", "reviewer"]);
|
|
58
59
|
|
|
59
60
|
const BUILT_IN_AGENT_PROFILES: AgentProfile[] = [
|
|
60
61
|
agentProfileDefaults({ name: "default-relay", description: "Relay-aware spawned agent with bundled Relay context, skills, plugins, and status integration.", base: "host" }),
|
|
61
62
|
agentProfileDefaults({ name: "minimal", description: "Repo-focused spawned agent with Relay affordances disabled and host/global extras avoided where supported.", base: "minimal" }),
|
|
62
63
|
agentProfileDefaults({ name: "isolated-research", description: "Strict profile for autonomous research runs: repo context only, no Relay prompt surface, no global extras where supported.", base: "isolated" }),
|
|
63
64
|
agentProfileDefaults({ name: "vanilla", description: "Zero host bleed (#552): isolated provider home with host plugins, skills, hooks, MCP, and the CLAUDE.md/AGENTS.md cascade (repo + global) all suppressed at launch. Relay provisions any surface explicitly per profile.", base: "vanilla" }),
|
|
65
|
+
agentProfileDefaults({ name: "lean-worker", description: "Lean worker profile (#570): vanilla host-dependency drop with only Relay context/MCP restored and Project knowledge injected from the spawn cwd.", base: "vanilla", relay: { context: true, skills: false, plugins: false, statusLine: false, mcp: true }, projectInstructions: { policy: "all" } }),
|
|
64
66
|
agentProfileDefaults({ name: "coordinator", description: "Relay-aware coordination lead for spawning worker teams, maintaining shared state, and driving review and release.", base: "host", instructions: { append: [COORDINATION_CHARTER], repoInstructions: "allow", globalInstructions: "allow" }, maxSpawnedAgents: 8 }),
|
|
65
67
|
agentProfileDefaults({ name: "ops-assistant", description: "Relay-aware ops lieutenant for a coordinator: runs tests, releases, smoke probes, gates, and host checks, then reports crisp outcomes back up.", provider: "codex", base: "host", instructions: { append: [OPS_ASSISTANT_BRIEF], repoInstructions: "allow", globalInstructions: "allow" }, permissions: { mode: "open", filesystem: "host" } }),
|
|
66
68
|
agentProfileDefaults({ name: "worker", description: "Relay-aware focused implementer with open approval posture and no delegated spawn capability.", base: "host", permissions: { mode: "open", filesystem: "host" } }),
|
|
@@ -211,6 +213,15 @@ function cleanNumber(value: unknown, field: string, opts: { min: number; max: nu
|
|
|
211
213
|
return value;
|
|
212
214
|
}
|
|
213
215
|
|
|
216
|
+
function cleanAgentProfileProjectInstructions(value: unknown): AgentProfile["projectInstructions"] {
|
|
217
|
+
if (value === undefined || value === null || value === false) return undefined;
|
|
218
|
+
if (value === true) return {};
|
|
219
|
+
if (!isRecord(value)) throw new ValidationError("projectInstructions must be a boolean or { policy } object");
|
|
220
|
+
const policy = value.policy;
|
|
221
|
+
if (policy === undefined || policy === null) return {};
|
|
222
|
+
return { policy: cleanEnum(policy, "projectInstructions.policy", PROJECT_INSTRUCTION_POLICY_NAMES) as NonNullable<AgentProfile["projectInstructions"]>["policy"] };
|
|
223
|
+
}
|
|
224
|
+
|
|
214
225
|
function agentProfileDefaults(input: Pick<AgentProfile, "name" | "base"> & Partial<AgentProfile>): AgentProfile {
|
|
215
226
|
const isolated = input.base !== "host";
|
|
216
227
|
// "vanilla" (#552) additionally suppresses the REPO instruction cascade
|
|
@@ -230,6 +241,7 @@ function agentProfileDefaults(input: Pick<AgentProfile, "name" | "base"> & Parti
|
|
|
230
241
|
repoInstructions: input.instructions?.repoInstructions ?? (vanilla ? "ignore" : "allow"),
|
|
231
242
|
globalInstructions: input.instructions?.globalInstructions ?? (isolated ? "ignore" : "allow"),
|
|
232
243
|
},
|
|
244
|
+
...(input.projectInstructions ? { projectInstructions: input.projectInstructions } : {}),
|
|
233
245
|
relay: {
|
|
234
246
|
context: input.relay?.context ?? !isolated,
|
|
235
247
|
skills: input.relay?.skills ?? !isolated,
|
|
@@ -303,6 +315,7 @@ function validateAgentProfile(key: string, value: unknown): AgentProfile {
|
|
|
303
315
|
? defaults.instructions.globalInstructions
|
|
304
316
|
: cleanEnum(instructions.globalInstructions, "instructions.globalInstructions", VALID_PROFILE_INSTRUCTION_POLICIES),
|
|
305
317
|
},
|
|
318
|
+
projectInstructions: cleanAgentProfileProjectInstructions(value.projectInstructions),
|
|
306
319
|
relay: {
|
|
307
320
|
context: relay.context === undefined ? defaults.relay.context : cleanBoolean(relay.context, "relay.context"),
|
|
308
321
|
skills: relay.skills === undefined ? defaults.relay.skills : cleanBoolean(relay.skills, "relay.skills"),
|
package/src/context-advisory.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { deriveContextThresholdFromWindowTokens, resolveProviderContextThreshold, type ProviderModelCatalogEntry, type ResolvedProviderContextThreshold } from "agent-relay-sdk/provider-catalog";
|
|
1
|
+
import { deriveContextThresholdFromWindowTokens, findProviderCatalogModel, resolveProviderContextThreshold, type ProviderModelCatalogEntry, type ResolvedProviderContextThreshold } from "agent-relay-sdk/provider-catalog";
|
|
2
2
|
import { isRecord, SPAWN_PROVIDERS } from "agent-relay-sdk";
|
|
3
3
|
import { getConfig, getNotificationsConfig } from "./config-store";
|
|
4
4
|
import { DEFAULT_CONTEXT_THRESHOLD_CONFIG, validateContextThresholdConfig } from "./context-threshold-config";
|
|
@@ -132,10 +132,11 @@ export function handleContextPressure(input: {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
function effectiveContextThreshold(agent: AgentCard): EffectiveContextThreshold {
|
|
135
|
-
const
|
|
136
|
-
const windowTokens = model?.limits?.contextWindowTokens?.value
|
|
137
|
-
?? finiteNumber(agent.providerCapabilities?.context?.windowTokens)
|
|
135
|
+
const observedWindowTokens = finiteNumber(agent.providerCapabilities?.context?.windowTokens)
|
|
138
136
|
?? finiteNumber(agent.context?.tokensMax);
|
|
137
|
+
const model = findAgentCatalogModel(agent, observedWindowTokens);
|
|
138
|
+
const windowTokens = model?.limits?.contextWindowTokens?.value
|
|
139
|
+
?? observedWindowTokens;
|
|
139
140
|
if (model?.contextThreshold) {
|
|
140
141
|
return { ...resolveProviderContextThreshold(model), source: "model" };
|
|
141
142
|
}
|
|
@@ -157,16 +158,14 @@ function explicitContextThresholdConfig(): EffectiveContextThreshold | undefined
|
|
|
157
158
|
};
|
|
158
159
|
}
|
|
159
160
|
|
|
160
|
-
function findAgentCatalogModel(agent: AgentCard): ProviderModelCatalogEntry | undefined {
|
|
161
|
+
function findAgentCatalogModel(agent: AgentCard, observedWindowTokens: number | undefined): ProviderModelCatalogEntry | undefined {
|
|
161
162
|
const runtime = agent.providerCapabilities?.model;
|
|
162
163
|
const provider = runtime?.provider;
|
|
163
164
|
if (!provider || !(SPAWN_PROVIDERS as readonly string[]).includes(provider)) return undefined;
|
|
164
165
|
const catalog = effectiveProviderCatalogList().find((entry) => entry.provider === provider);
|
|
165
166
|
if (!catalog) return undefined;
|
|
166
167
|
const ids = [runtime.alias, runtime.id, runtime.providerModel].filter((value): value is string => Boolean(value));
|
|
167
|
-
|
|
168
|
-
return catalog.models.find((model) => ids.includes(model.alias) || ids.includes(model.providerModel))
|
|
169
|
-
?? catalog.models.find((model) => lowerIds.has(model.alias.toLowerCase()) || lowerIds.has(model.providerModel.toLowerCase()));
|
|
168
|
+
return findProviderCatalogModel(catalog, ids, { observedWindowTokens });
|
|
170
169
|
}
|
|
171
170
|
|
|
172
171
|
function clearContextAdvisory(context: ContextState): ContextState {
|
|
@@ -223,9 +223,10 @@ export async function spawnAgent(input: SpawnAgentInput, ctx: AuthContext): Prom
|
|
|
223
223
|
// providers (project preamble → profile system → profile append → caller/fork context) and
|
|
224
224
|
// carries the #559 scoped-knowledge seam. Spawns without profile/project material stay
|
|
225
225
|
// byte-identical to the caller-provided systemPromptAppend.
|
|
226
|
+
const projectInstructions = input.projectInstructions ?? agentProfile?.projectInstructions;
|
|
226
227
|
const systemPromptAppend = composeSpawnInstructions({
|
|
227
228
|
...(callerProject ? { callerProject } : {}),
|
|
228
|
-
...(
|
|
229
|
+
...(projectInstructions ? { projectInstructions } : {}),
|
|
229
230
|
...(agentProfile ? { profile: agentProfile } : {}),
|
|
230
231
|
...(input.systemPromptAppend ? { callerSystemPromptAppend: input.systemPromptAppend } : {}),
|
|
231
232
|
});
|