swarm ui: a soft context limit field in an agent's inference settings
A whole percent from 5 to 100 of the model's context window, sent as soft_context_percent next to max_subagents. The inference row shows it, the edit dialog and the create form take it, and an archetype can carry it.
This commit is contained in:
parent
b19b730a3a
commit
e9af6cf2c7
3 changed files with 109 additions and 7 deletions
|
|
@ -26,6 +26,11 @@ import { FormStack } from "../../ui/form-stack/FormStack.js";
|
|||
import "../../ui/badge-row/BadgeRow.css";
|
||||
import "./AgentInference.css";
|
||||
import { MAX_SUBAGENTS, maxSubagentsValue } from "./max-subagents.js";
|
||||
import {
|
||||
MAX_SOFT_CONTEXT_PERCENT,
|
||||
MIN_SOFT_CONTEXT_PERCENT,
|
||||
softContextValue,
|
||||
} from "./soft-context.js";
|
||||
|
||||
type Source = "swarm" | "agent_nix" | "local_file" | "default";
|
||||
|
||||
|
|
@ -35,6 +40,7 @@ interface Settings {
|
|||
effort?: string;
|
||||
subagent_models?: string[];
|
||||
max_subagents?: number;
|
||||
soft_context_percent?: number;
|
||||
}
|
||||
|
||||
// Mirrors `EffectiveInference`.
|
||||
|
|
@ -81,13 +87,14 @@ function inferenceUrl(agent: string): string {
|
|||
return `/api/agents/${encodeURIComponent(agent)}/inference`;
|
||||
}
|
||||
|
||||
// The four inference boxes as typed. Shared by the editor here and the
|
||||
// The inference boxes as typed. Shared by the editor here and the
|
||||
// create-agent form, which send what `draftBody` makes of them.
|
||||
export interface InferenceDraft {
|
||||
model: string;
|
||||
effort: string;
|
||||
subagents: string;
|
||||
maxSubagents: string;
|
||||
softContext: string;
|
||||
}
|
||||
|
||||
export const EMPTY_INFERENCE_DRAFT: InferenceDraft = {
|
||||
|
|
@ -95,6 +102,7 @@ export const EMPTY_INFERENCE_DRAFT: InferenceDraft = {
|
|||
effort: "",
|
||||
subagents: "",
|
||||
maxSubagents: "",
|
||||
softContext: "",
|
||||
};
|
||||
|
||||
// Why the draft would be refused, or null when it is fine to send.
|
||||
|
|
@ -106,6 +114,9 @@ export function draftProblem(d: InferenceDraft): string | null {
|
|||
.find((p) => p !== null) ??
|
||||
(maxSubagentsValue(d.maxSubagents) === null
|
||||
? `max subagents is a whole number from 0 (no subagents) to ${MAX_SUBAGENTS}, or empty for no cap`
|
||||
: null) ??
|
||||
(softContextValue(d.softContext) === null
|
||||
? `soft context limit is a whole percent from ${MIN_SOFT_CONTEXT_PERCENT} to ${MAX_SOFT_CONTEXT_PERCENT}, or empty for the agent's own`
|
||||
: null)
|
||||
);
|
||||
}
|
||||
|
|
@ -115,7 +126,8 @@ export function draftIsEmpty(d: InferenceDraft): boolean {
|
|||
d.model.trim() === "" &&
|
||||
d.effort === "" &&
|
||||
parseModels(d.subagents).length === 0 &&
|
||||
d.maxSubagents.trim() === ""
|
||||
d.maxSubagents.trim() === "" &&
|
||||
d.softContext.trim() === ""
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -128,6 +140,8 @@ export function draftBody(d: InferenceDraft): Settings {
|
|||
if (models.length > 0) body.subagent_models = models;
|
||||
const max = maxSubagentsValue(d.maxSubagents);
|
||||
if (typeof max === "number") body.max_subagents = max;
|
||||
const soft = softContextValue(d.softContext);
|
||||
if (typeof soft === "number") body.soft_context_percent = soft;
|
||||
return body;
|
||||
}
|
||||
|
||||
|
|
@ -174,6 +188,14 @@ export function InferenceFields({
|
|||
pattern="[0-9]*"
|
||||
onInput={(maxSubagents) => onChange({ ...draft, maxSubagents })}
|
||||
/>
|
||||
<TextField
|
||||
id={`${idPrefix}-soft-context`}
|
||||
label="soft context limit (%)"
|
||||
value={draft.softContext}
|
||||
placeholder="empty for the agent's own"
|
||||
pattern="[0-9]*"
|
||||
onInput={(softContext) => onChange({ ...draft, softContext })}
|
||||
/>
|
||||
{problem ? <Hint tone="error">{problem}</Hint> : null}
|
||||
</>
|
||||
);
|
||||
|
|
@ -278,11 +300,22 @@ export function AgentInference({ agent }: { agent: string }) {
|
|||
}
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<Badge
|
||||
label="soft context limit"
|
||||
value={
|
||||
configured?.soft_context_percent === undefined
|
||||
? "its own"
|
||||
: `${configured.soft_context_percent}%`
|
||||
}
|
||||
title="the agent compacts at the end of a turn once its context passes this share of the window; a turn can run past it"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<Badge
|
||||
variant="quiet"
|
||||
value="edit"
|
||||
title={`set the swarm's model, effort, subagent models and subagent cap for ${agent}`}
|
||||
title={`set the swarm's model, effort, subagent models, subagent cap and soft context limit for ${agent}`}
|
||||
onClick={() => setEditing(true)}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -325,6 +358,7 @@ function InferenceForm({
|
|||
effort: configured?.effort ?? "",
|
||||
subagents: (configured?.subagent_models ?? []).join(", "),
|
||||
maxSubagents: configured?.max_subagents?.toString() ?? "",
|
||||
softContext: configured?.soft_context_percent?.toString() ?? "",
|
||||
});
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [problem, setProblem] = useState<ProblemDetails | null>(null);
|
||||
|
|
|
|||
22
frontend/packages/swarm-ui/src/agent/detail/soft-context.ts
Normal file
22
frontend/packages/swarm-ui/src/agent/detail/soft-context.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// The create form's and the inference dialog's `soft_context_percent` field,
|
||||
// kept out of the component so `npm test` can run it.
|
||||
|
||||
/** The lowest `soft_context_percent` the swarm accepts. */
|
||||
export const MIN_SOFT_CONTEXT_PERCENT = 5;
|
||||
/** The highest: the whole context window. */
|
||||
export const MAX_SOFT_CONTEXT_PERCENT = 100;
|
||||
|
||||
/**
|
||||
* `soft_context_percent` as typed: `undefined` for empty (the agent's own
|
||||
* default), the number for a whole number from [`MIN_SOFT_CONTEXT_PERCENT`]
|
||||
* to [`MAX_SOFT_CONTEXT_PERCENT`], else `null`.
|
||||
*/
|
||||
export function softContextValue(text: string): number | null | undefined {
|
||||
const t = text.trim();
|
||||
if (t === "") return undefined;
|
||||
if (!/^\d+$/.test(t)) return null;
|
||||
const n = Number(t);
|
||||
return n >= MIN_SOFT_CONTEXT_PERCENT && n <= MAX_SOFT_CONTEXT_PERCENT
|
||||
? n
|
||||
: null;
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ export interface Archetype {
|
|||
effort?: string;
|
||||
subagent_models?: string[];
|
||||
max_subagents?: number;
|
||||
soft_context_percent?: number;
|
||||
};
|
||||
prompt?: string;
|
||||
/** The archetype's icon as SVG text. */
|
||||
|
|
@ -69,6 +70,10 @@ export function prefill(
|
|||
inference.max_subagents === undefined
|
||||
? ""
|
||||
: String(inference.max_subagents),
|
||||
softContext:
|
||||
inference.soft_context_percent === undefined
|
||||
? ""
|
||||
: String(inference.soft_context_percent),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue