mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Distinguish implicit harness fallback pins
Signed-off-by: kenny lopez <klopez4212@gmail.com>
This commit is contained in:
@@ -98,7 +98,11 @@ with a TypeScript lookup table or an id comparison in a component.
|
||||
without changing the persisted configuration used by existing agents.
|
||||
Legacy global defaults with no saved preferred runtime are treated as
|
||||
Buzz Agent-owned for this masking boundary, so hiding Buzz Agent cannot
|
||||
leak its provider/model into another implicit fallback.
|
||||
leak its provider/model into another implicit fallback. A persisted
|
||||
per-instance harness override carries a durable explicit-vs-implicit marker:
|
||||
explicit selections continue to inherit global provider/model defaults even
|
||||
when the selected harness differs from the global preference, while
|
||||
automatic runtime-less fallback pins keep mismatched defaults masked.
|
||||
Create-mode dialogs use the implicit masked config; existing definition and
|
||||
instance edit dialogs use the raw persisted config.
|
||||
`resolvePersonaRuntime` is the shared visibility boundary for every
|
||||
|
||||
@@ -66,6 +66,8 @@ export type CreateChannelManagedAgentInput = {
|
||||
* unpinned so the persona remains authoritative.
|
||||
*/
|
||||
harnessOverride?: boolean;
|
||||
/** The pin preserves an automatic runtime-less fallback, not an explicit pick. */
|
||||
implicitHarnessFallback?: boolean;
|
||||
/** Preferred model ID from the persona. Passed to createManagedAgent. */
|
||||
model?: string;
|
||||
role?: Exclude<ChannelRole, "owner">;
|
||||
@@ -355,6 +357,7 @@ export async function provisionChannelManagedAgent(
|
||||
acpCommand: "buzz-acp",
|
||||
agentCommand: input.runtime.command,
|
||||
harnessOverride: input.harnessOverride ?? false,
|
||||
implicitHarnessFallback: input.implicitHarnessFallback ?? false,
|
||||
// Do NOT seed agentArgs from runtime.defaultArgs (see instanceInputForDefinition.ts
|
||||
// for the rationale — empty args let spawn resolve definition args live).
|
||||
agentArgs: [],
|
||||
|
||||
@@ -84,12 +84,14 @@ test("row 2: harnessOverride follows the backend-aligned formula", async () => {
|
||||
gooseRuntime,
|
||||
);
|
||||
assert.equal(match.harnessOverride, true, "picked == configured → true");
|
||||
assert.equal(match.implicitHarnessFallback, false);
|
||||
|
||||
const noPreference = await buildInstanceInputForDefinition(
|
||||
persona({ runtime: undefined }),
|
||||
gooseRuntime,
|
||||
);
|
||||
assert.equal(noPreference.harnessOverride, true, "no preference → true");
|
||||
assert.equal(noPreference.implicitHarnessFallback, true);
|
||||
|
||||
const differs = await buildInstanceInputForDefinition(
|
||||
persona({ runtime: "claude" }),
|
||||
@@ -100,6 +102,7 @@ test("row 2: harnessOverride follows the backend-aligned formula", async () => {
|
||||
false,
|
||||
"picked != configured → false (definition stays authoritative)",
|
||||
);
|
||||
assert.equal(differs.implicitHarnessFallback, false);
|
||||
});
|
||||
|
||||
test("provisioning pins a visible fallback for a runtime-less definition", () => {
|
||||
@@ -111,6 +114,7 @@ test("provisioning pins a visible fallback for a runtime-less definition", () =>
|
||||
);
|
||||
assert.equal(resolved.runtime, gooseRuntime);
|
||||
assert.equal(resolved.harnessOverride, true);
|
||||
assert.equal(resolved.implicitHarnessFallback, true);
|
||||
});
|
||||
|
||||
test("provisioning uses product ordering and leaves unavailable configured fallbacks unpinned", () => {
|
||||
@@ -121,12 +125,14 @@ test("provisioning uses product ordering and leaves unavailable configured fallb
|
||||
]);
|
||||
assert.equal(ordered.runtime, buzzAgentRuntime);
|
||||
assert.equal(ordered.harnessOverride, true);
|
||||
assert.equal(ordered.implicitHarnessFallback, true);
|
||||
|
||||
const unavailable = resolveProvisioningRuntimeForDefinition("missing", [
|
||||
gooseRuntime,
|
||||
]);
|
||||
assert.equal(unavailable.runtime, gooseRuntime);
|
||||
assert.equal(unavailable.harnessOverride, false);
|
||||
assert.equal(unavailable.implicitHarnessFallback, false);
|
||||
});
|
||||
|
||||
test("row 3: plain avatar URLs pass through; base64 data URIs upload via the injectable", async () => {
|
||||
@@ -205,6 +211,7 @@ test("no backend intent is byte-identical to the pre-intent mapping", async () =
|
||||
agentArgs: [],
|
||||
mcpCommand: "goose-mcp",
|
||||
harnessOverride: true,
|
||||
implicitHarnessFallback: false,
|
||||
model: undefined,
|
||||
provider: undefined,
|
||||
spawnAfterCreate: true,
|
||||
|
||||
@@ -120,7 +120,10 @@ export function resolveProvisioningRuntimeForDefinition(
|
||||
runtimes: readonly AcpRuntime[],
|
||||
preferredRuntimeId?: string | null,
|
||||
disabledRuntimeIds: readonly string[] = getDisabledAcpRuntimeIdsSnapshot(),
|
||||
): ResolvePersonaRuntimeResult & { harnessOverride: boolean } {
|
||||
): ResolvePersonaRuntimeResult & {
|
||||
harnessOverride: boolean;
|
||||
implicitHarnessFallback: boolean;
|
||||
} {
|
||||
const defaultRuntime = getDefaultPersonaRuntime(runtimes, preferredRuntimeId);
|
||||
const resolved = resolvePersonaRuntime(
|
||||
definitionRuntimeId,
|
||||
@@ -137,6 +140,8 @@ export function resolveProvisioningRuntimeForDefinition(
|
||||
definitionRuntimeId,
|
||||
resolved.runtime.id,
|
||||
),
|
||||
implicitHarnessFallback:
|
||||
resolved.runtime !== null && !definitionRuntimeId?.trim(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -207,6 +212,7 @@ export async function buildInstanceInputForDefinition(
|
||||
persona.runtime,
|
||||
runtime.id,
|
||||
),
|
||||
implicitHarnessFallback: !persona.runtime?.trim(),
|
||||
model: persona.model ?? undefined,
|
||||
provider: persona.provider ?? undefined,
|
||||
spawnAfterCreate: true,
|
||||
|
||||
@@ -160,6 +160,7 @@ export function AddTeamToChannelDialog({
|
||||
persona.runtime,
|
||||
personaRuntime.id,
|
||||
),
|
||||
implicitHarnessFallback: !persona.runtime?.trim(),
|
||||
model: persona.model ?? undefined,
|
||||
personaId: persona.id,
|
||||
teamId: team.id,
|
||||
|
||||
@@ -93,6 +93,7 @@ export function useApplyTemplate() {
|
||||
name: persona.displayName,
|
||||
personaId: persona.id,
|
||||
harnessOverride: resolved.harnessOverride,
|
||||
implicitHarnessFallback: resolved.implicitHarnessFallback,
|
||||
systemPrompt: persona.systemPrompt,
|
||||
avatarUrl: persona.avatarUrl ?? undefined,
|
||||
model: entry.model ?? persona.model ?? undefined,
|
||||
@@ -121,6 +122,7 @@ export function useApplyTemplate() {
|
||||
name: persona.displayName,
|
||||
personaId: persona.id,
|
||||
harnessOverride: resolved.harnessOverride,
|
||||
implicitHarnessFallback: resolved.implicitHarnessFallback,
|
||||
systemPrompt: persona.systemPrompt,
|
||||
avatarUrl: persona.avatarUrl ?? undefined,
|
||||
model: teamEntry.model ?? persona.model ?? undefined,
|
||||
|
||||
@@ -156,6 +156,7 @@ export function AddChannelBotDialog({
|
||||
name: persona.displayName,
|
||||
personaId: persona.id,
|
||||
harnessOverride: resolved.harnessOverride,
|
||||
implicitHarnessFallback: resolved.implicitHarnessFallback,
|
||||
systemPrompt: persona.systemPrompt,
|
||||
avatarUrl: persona.avatarUrl ?? undefined,
|
||||
model: persona.model ?? undefined,
|
||||
|
||||
@@ -32,7 +32,7 @@ export function useQuickBotDrop(channelId: string | null) {
|
||||
setState({ pending: true, error: null });
|
||||
|
||||
try {
|
||||
const { harnessOverride, runtime } =
|
||||
const { harnessOverride, implicitHarnessFallback, runtime } =
|
||||
resolveProvisioningRuntimeForDefinition(persona.runtime, providers);
|
||||
|
||||
if (!runtime) {
|
||||
@@ -51,6 +51,7 @@ export function useQuickBotDrop(channelId: string | null) {
|
||||
personaId: persona.id,
|
||||
model: persona.model ?? undefined,
|
||||
harnessOverride,
|
||||
implicitHarnessFallback,
|
||||
});
|
||||
|
||||
setState({ pending: false, error: null });
|
||||
|
||||
@@ -326,7 +326,7 @@ export function useMentionSendFlow({
|
||||
}
|
||||
seenPersonaIds.add(persona.id);
|
||||
|
||||
const { harnessOverride, runtime } =
|
||||
const { harnessOverride, implicitHarnessFallback, runtime } =
|
||||
resolveProvisioningRuntimeForDefinition(persona.runtime, runtimes);
|
||||
if (!runtime) {
|
||||
errors.push(`${displayName}: No agent runtime available.`);
|
||||
@@ -342,6 +342,7 @@ export function useMentionSendFlow({
|
||||
name: persona.displayName,
|
||||
personaId: persona.id,
|
||||
harnessOverride,
|
||||
implicitHarnessFallback,
|
||||
systemPrompt: persona.systemPrompt,
|
||||
avatarUrl: persona.avatarUrl ?? undefined,
|
||||
model: persona.model ?? undefined,
|
||||
|
||||
@@ -874,6 +874,7 @@ export async function createManagedAgent(input: CreateManagedAgentInput) {
|
||||
acpCommand: input.acpCommand,
|
||||
agentCommand: input.agentCommand,
|
||||
harnessOverride: input.harnessOverride ?? false,
|
||||
implicitHarnessFallback: input.implicitHarnessFallback ?? false,
|
||||
agentArgs: input.agentArgs,
|
||||
mcpCommand: input.mcpCommand,
|
||||
turnTimeoutSeconds: input.turnTimeoutSeconds,
|
||||
|
||||
@@ -456,6 +456,11 @@ export type CreateManagedAgentInput = {
|
||||
* same persona runtime id, while still ignoring missing-runtime fallbacks.
|
||||
*/
|
||||
harnessOverride?: boolean;
|
||||
/**
|
||||
* True when `harnessOverride` pins an automatically selected runtime for a
|
||||
* runtime-less persona rather than a runtime the user explicitly selected.
|
||||
*/
|
||||
implicitHarnessFallback?: boolean;
|
||||
agentArgs?: string[];
|
||||
mcpCommand?: string;
|
||||
turnTimeoutSeconds?: number;
|
||||
|
||||
Reference in New Issue
Block a user