@polderlabs/bizar 10.23.19 → 10.23.21

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.
@@ -995,6 +995,9 @@ export function applyModelOverrides({ settingsJsonPath, pickedIds, liveIds = [],
995
995
  const generatedAgents = syncGeneratedModelAgents(synced, {
996
996
  agentsDir: settingsJsonPath === undefined ? undefined : join(dirname(path), 'agents', 'bizar-models'),
997
997
  });
998
+ const stableRoleAgents = syncStableRoleModelAgents(synced, {
999
+ agentsDir: settingsJsonPath === undefined ? undefined : join(dirname(path), 'agents'),
1000
+ });
998
1001
  if (requiresGatewayModelDiscovery(synced)) {
999
1002
  settings.env = {
1000
1003
  ...(settings.env || {}),
@@ -1026,6 +1029,7 @@ export function applyModelOverrides({ settingsJsonPath, pickedIds, liveIds = [],
1026
1029
  skippedDisabled,
1027
1030
  nativeAgentAliases,
1028
1031
  generatedAgents,
1032
+ stableRoleAgents,
1029
1033
  settingsPath: path,
1030
1034
  };
1031
1035
  }
@@ -1102,6 +1106,38 @@ export function syncGeneratedModelAgents(modelIds, opts = {}) {
1102
1106
  return { agentsDir, names };
1103
1107
  }
1104
1108
 
1109
+ /**
1110
+ * Bind the ordinary, recognizable Bizar role definitions to the default
1111
+ * operator-selected model. Claude Code watches definition edits, so future
1112
+ * `subagent_type: greg` calls use the chosen full ID without a restart or an
1113
+ * alias-only native `model` parameter. Generated per-model definitions remain
1114
+ * available for explicitly requested advanced routing.
1115
+ */
1116
+ export function syncStableRoleModelAgents(modelIds, opts = {}) {
1117
+ const agentsDir = opts.agentsDir || join(resolveClaudeConfigDir(), 'agents');
1118
+ const defaultModel = (Array.isArray(modelIds) ? modelIds : []).find((id) => typeof id === 'string' && id.trim())?.trim() || null;
1119
+ const names = [];
1120
+ for (const role of BIZAR_AGENT_ROLES) {
1121
+ const path = join(agentsDir, `${role}.md`);
1122
+ if (!existsSync(path)) continue;
1123
+ const source = readFileSync(path, 'utf8');
1124
+ if (!source.startsWith('---\n')) continue;
1125
+ const end = source.indexOf('\n---', 4);
1126
+ if (end < 0) continue;
1127
+ const frontmatter = source.slice(4, end);
1128
+ const body = source.slice(end + 4);
1129
+ const nextFrontmatter = defaultModel
1130
+ ? (/^model:\s*.*$/m.test(frontmatter)
1131
+ ? frontmatter.replace(/^model:\s*.*$/m, `model: ${defaultModel}`)
1132
+ : `${frontmatter}\nmodel: ${defaultModel}`)
1133
+ : frontmatter.replace(/^model:\s*.*\n?/m, '');
1134
+ const next = `---\n${nextFrontmatter}\n---${body}`;
1135
+ if (next !== source) writeFileSync(path, next, { mode: 0o600 });
1136
+ names.push(role);
1137
+ }
1138
+ return { agentsDir, names, defaultModel };
1139
+ }
1140
+
1105
1141
  const NATIVE_AGENT_OVERRIDE_KEYS = Object.freeze({
1106
1142
  sonnet: 'claude-sonnet-5',
1107
1143
  opus: 'claude-opus-5',
@@ -2364,9 +2400,20 @@ export async function run(name, args, isHelpRequest, deps = {}) {
2364
2400
  const router = loadRouter(routerPath);
2365
2401
  const models = configuredEnabledModels(router);
2366
2402
  const agentTypes = Object.fromEntries(models.map((id) => [id, Object.fromEntries(BIZAR_AGENT_ROLES.map((role) => [role, modelAgentName(id, role)]))]));
2367
- const payload = { routerPath, models, agentTypes, agentsDir: join(resolveClaudeConfigDir(), 'agents', 'bizar-models') };
2403
+ const stableRoleTypes = Object.fromEntries(BIZAR_AGENT_ROLES.map((role) => [role, role]));
2404
+ const payload = {
2405
+ routerPath,
2406
+ models,
2407
+ defaultModel: models[0] || null,
2408
+ stableRoleTypes,
2409
+ agentTypes,
2410
+ agentsDir: join(resolveClaudeConfigDir(), 'agents', 'bizar-models'),
2411
+ };
2368
2412
  if (wantJson) process.stdout.write(JSON.stringify(payload, null, 2) + '\n');
2369
- else for (const id of models) process.stdout.write(`${id}\t${JSON.stringify(agentTypes[id])}\n`);
2413
+ else {
2414
+ process.stdout.write(`default\t${JSON.stringify(stableRoleTypes)}\n`);
2415
+ for (const id of models) process.stdout.write(`${id}\t${JSON.stringify(agentTypes[id])}\n`);
2416
+ }
2370
2417
  return true;
2371
2418
  }
2372
2419
 
package/cli/provision.mjs CHANGED
@@ -37,6 +37,7 @@ import {
37
37
  configuredEnabledModels,
38
38
  requiresGatewayModelDiscovery,
39
39
  syncGeneratedModelAgents,
40
+ syncStableRoleModelAgents,
40
41
  } from './commands/models.mjs';
41
42
  import { validateNativeWorkflowDirectory } from '../config/workflows/lib/native-contract.mjs';
42
43
 
@@ -514,7 +515,8 @@ export function syncConfiguredModelAgents({ dryRun = false } = {}) {
514
515
  const models = configuredEnabledModels(router);
515
516
  if (dryRun) return { ok: true, message: `[dry-run] would sync ${models.length} generated model agent(s)`, models };
516
517
  const generated = syncGeneratedModelAgents(models, { agentsDir: join(resolveClaudeDir(), 'agents', 'bizar-models') });
517
- return { ok: true, message: `${generated.names.length} generated model agent(s) synced`, ...generated };
518
+ const stable = syncStableRoleModelAgents(models, { agentsDir: join(resolveClaudeDir(), 'agents') });
519
+ return { ok: true, message: `${stable.names.length} stable role model(s) and ${generated.names.length} generated model agent(s) synced`, ...generated, stableRoleAgents: stable };
518
520
  }
519
521
 
520
522
  export async function syncSkillFiles({ dryRun = false, force = false } = {}) {
@@ -368,10 +368,7 @@ Background (async, returns immediately):
368
368
 
369
369
  ### Coordinating multiple background agents
370
370
 
371
- When fanning out several research or exploration tasks, issue multiple `Agent` calls in the **same message** with `run_in_background: true`. Each runs in parallel. Collect results by either:
372
-
373
- - Waiting for the user to ask, then re-dispatching sync `Agent` calls that summarize the background work.
374
- - Reading the background agent's final summary when it completes.
371
+ When fanning out several research or exploration tasks, issue multiple `Agent` calls in the **same message** with `run_in_background: true`. Each runs in parallel. Collect the original final summary/result when the task completes. Do not re-dispatch a completed background agent to summarize its work: that creates a new, context-poor task and its acknowledgement is not a replacement for the original deliverable.
375
372
 
376
373
  ---
377
374
 
@@ -44,8 +44,8 @@ That definition's frontmatter owns the full-ID selection for ordinary agents,
44
44
  workflows, and teams. Include the raw ID in `additionalContext.bizarConfiguredModel`
45
45
  for audit telemetry. Never use `inherit` or an unconfigured provider default.
46
46
  `sonnet`, `opus`, `haiku`, and `fable` are compatibility aliases only. If no
47
- generated configured definition exists, stop and ask the operator to run
48
- `bizar models`; never omit the generated agent type or cycle providers.
47
+ stable Bizar role definition exists, stop and ask the operator to run
48
+ `bizar models`; never omit the stable role type or cycle providers.
49
49
 
50
50
  Invoke the selected workflow by `name` first. If Claude reports that the Bizar
51
51
  name is unavailable, resolve the active Claude config directory and retry once
@@ -59,21 +59,20 @@ implementation around a broken workflow installation.
59
59
  ## Models
60
60
 
61
61
  For every dispatch, select the cheapest sufficient enabled configured model
62
- from the global Bizar router. User-selected models take precedence over tier
63
- candidates; `disabledProviders` excludes both. Native aliases are compatibility
64
- transport labels bound by `bizar models`, not Anthropic selections. Native
65
- Agent/Task calls accept only those aliases, so do not pass a full gateway ID in
66
- `model`. Run `bizar models --agent-types --json`, look up the selected ID and
67
- Bizar role, pass its role-specific generated name (for example `greg-*` or
68
- `todd-*`) as `subagent_type`, and omit `model`; the generated global
62
+ from the global Bizar router. The default selected model is written into each
63
+ stable global Bizar role definition by `bizar models`; `disabledProviders`
64
+ excludes invalid selections. Native aliases are compatibility transport labels
65
+ bound by `bizar models`, not Anthropic selections. Pass the stable role name
66
+ (for example `greg` or `todd`) as `subagent_type` and omit native `model`; the
69
67
  definition's `model:` frontmatter selects the full gateway ID. This is the
70
- default for individual subagents, workflows, and agent-team teammates. For
71
- teams, do not name a competing model in the spawn prompt. Use `bizar worker`
72
- only when a separately launched process worktree is useful. If no enabled
73
- configured candidate or generated definition exists, stop with the
68
+ default for individual subagents, workflows, and agent-team teammates. Use
69
+ `bizar models --agent-types --json` only for an explicit advanced per-model
70
+ choice. For teams, do not name a competing model in the spawn prompt. Use
71
+ `bizar worker` only when a separately launched process worktree is useful. If
72
+ no enabled configured candidate or stable definition exists, stop with the
74
73
  configuration error and run `bizar models`. Never let Claude choose an
75
- unconfigured default, inherit the session model, use an unmapped alias, or
76
- retry by cycling models, providers, or tiers.
74
+ unconfigured default, use an unmapped alias, or retry by cycling models,
75
+ providers, or tiers.
77
76
 
78
77
  ## Worktree Discipline and integration
79
78
 
@@ -94,8 +93,10 @@ Worktree branches use `wt/<agent_type>-<short-task-id>`.
94
93
  - Inspect an idle task after its second idle notification. Stop and reassign a
95
94
  task that has no progress/evidence; do not model-cycle it.
96
95
  - A `TaskCompleted`, `SubagentStop`, or `<task-notification>` is terminal. Read
97
- its `<result>`, mark the worker done/failed, merge queued work, and continue
98
- the active objective. Never route a completion notification as a new prompt.
96
+ its original `<result>` once, mark the worker done/failed, merge queued work,
97
+ and continue the active objective. Never route a completion notification as
98
+ a new prompt, send it back to the worker, or replace its deliverable with a
99
+ later acknowledgement/status reply.
99
100
 
100
101
  ## Learning and completion
101
102
 
@@ -49,7 +49,7 @@ import { pathToFileURL } from 'node:url';
49
49
 
50
50
  import { loadModelRouter } from '../../../config/agents/model-assignment.mjs';
51
51
  import { resolveClaudeConfigDir } from '../../../cli/config-paths.mjs';
52
- import { isGeneratedModelAgentName } from '../../../cli/commands/models.mjs';
52
+ import { BIZAR_AGENT_ROLES, isGeneratedModelAgentName } from '../../../cli/commands/models.mjs';
53
53
 
54
54
  function deny(reason) {
55
55
  return {
@@ -223,11 +223,14 @@ export async function guardAgentModel(input, options = {}) {
223
223
  : '';
224
224
 
225
225
  // The native Agent tool rejects arbitrary gateway IDs in its `model` enum.
226
- // Inheritance is safe only when the auditable Bizar selection equals the
227
- // actual global Claude parent model and is a selected, enabled user pick.
226
+ // Stable Bizar definitions own their selected full ID in frontmatter, so an
227
+ // omitted native model is correct and must not be coupled to the parent
228
+ // session model. Generated per-model definitions remain valid too.
228
229
  if (!requested || requested === 'inherit') {
229
230
  const generated = isGeneratedModelAgentName(toolInput.subagent_type, [...userPicks]);
231
+ const stable = BIZAR_AGENT_ROLES.includes(String(toolInput.subagent_type || '').trim());
230
232
  if (generated && !requested) return {};
233
+ if (stable && !requested && userPicks.size > 0) return {};
231
234
  const configured = configuredContext;
232
235
  const parent = readConfiguredParentModel(options);
233
236
  if (!configured || configured !== parent || !userPicks.has(configured)) {
@@ -252,7 +255,7 @@ export async function guardAgentModel(input, options = {}) {
252
255
  // a gateway accepts arbitrary IDs for the main conversation. Full IDs belong
253
256
  // in Bizar's generated subagent frontmatter, not in this enum-shaped field.
254
257
  if (userPicks.has(requested)) {
255
- return deny('Bizar Agent dispatch blocked: native Agent model accepts aliases only. Use the role-specific generated subagent_type from `bizar models --agent-types --json` and omit model; re-run `bizar models` if it is missing.');
258
+ return deny('Bizar Agent dispatch blocked: native Agent model accepts aliases only. Use the stable Bizar role as subagent_type (for example `greg` or `todd`) and omit model; run `bizar models` if the role definition is missing.');
256
259
  }
257
260
 
258
261
  // F-185 contract: when the orchestrator passes both `routingDecisionId`
@@ -188,7 +188,7 @@ function startupBriefing(cwd, featureBrief, recentCommits, projectLine, progress
188
188
  if (progressLast) lines.push(`- Progress: ${progressLast}.`);
189
189
  lines.push('- You are @mike. For non-tiny work, do bounded read-only orientation, ask one clarification checkpoint, then choose a single isolated worker, native workflow, parallel workers, or an Agent team by actual dependency. Use worktrees for editors and explicit Bizar models for every Agent.');
190
190
  lines.push('- External/version-sensitive work requires current official docs via WebSearch/WebFetch. Use relevant installed skills; apply i-have-adhd to user output. WIP=1.');
191
- lines.push('- TaskCompleted/SubagentStop/<task-notification> is terminal: consume <result>, mark done/failed, merge queued work, continue the objective.');
191
+ lines.push('- TaskCompleted/SubagentStop/<task-notification> is terminal: consume its original <result> once, mark done/failed, merge queued work, and continue the objective. Never turn a terminal notification into a worker follow-up or replace that result with a later status reply.');
192
192
  // Default-first-stop hint when nothing is active yet.
193
193
  if (featureBrief && featureBrief.active.length === 0) {
194
194
  lines.push(
@@ -56,7 +56,11 @@ export function handleTeamLifecycle(input, options = {}) {
56
56
  task.updatedAt = now;
57
57
  if (event === 'TaskCompleted' || event === 'SubagentStop') {
58
58
  task.state = /fail|error/i.test(record.status) ? 'failed' : 'completed';
59
- context = `Agent task ${taskId} is terminal (${task.state}). Consume its result, reconcile/merge its worktree, and continue the active objective.`;
59
+ // Claude Code already delivers the terminal result to the parent. Do
60
+ // not add another instruction here: lifecycle hook output can be
61
+ // surfaced in an agent context and turn a completed task into a bogus
62
+ // follow-up conversation ("Ready", "No action needed", etc.).
63
+ // This hook owns durable liveness telemetry only.
60
64
  } else if (event === 'TeammateIdle') {
61
65
  task.idleCount = Number(task.idleCount || 0) + 1;
62
66
  if (task.idleCount >= 2) context = `Agent task ${taskId} has been idle ${task.idleCount} times. Inspect its evidence now; stop and reassign if it made no progress. Do not model-cycle.`;
@@ -60,8 +60,8 @@ const ROUTE_POLICY = [
60
60
  'Adaptive Bizar routing policy:',
61
61
  '- If this is the primary session, you ARE @mike. First do only bounded read-only orientation. Then ask one concise clarification question describing the inferred outcome, the material choice/risk, and your proposed coordination mode. Wait for the answer before edits, branches, tests, or editor dispatch. If the user explicitly waives questions, continue autonomously.',
62
62
  '- After clarification, choose the lightest coordination mode: a direct tiny edit, one isolated Agent for a bounded change, a native Bizar Workflow for repeatable phased work, parallel Agents for disjoint scopes, or an Agent team only when 3+ sustained roles need cross-talk. Do not force a workflow or team when it adds no value.',
63
- '- For every Agent, workflow worker, or agent-team teammate, choose one exact ID from the enabled `bizar models` user selection, then obtain its role-specific generated definition name from `bizar models --agent-types --json` (for example greg or todd). Pass that name as `subagent_type` and OMIT the native `model` field. The definition frontmatter owns the exact gateway ID. Never put a raw gateway ID or a Claude family alias in the native model field; aliases are compatibility-only. For teams, do not name a competing model in the spawn prompt. If the map or definition is missing, run `bizar models`; do not retry by cycling providers or tiers. Every editing worker uses call-level `isolation: "worktree"`. For genuinely disjoint writable scopes, dispatch concurrently; otherwise use one owner.',
64
- '- Consume terminal agent results, merge queued worktrees with bizar worktree-merge, and run integration checks in the primary session. A subagent may not recursively dispatch itself.',
63
+ '- For every normal Agent, workflow worker, or agent-team teammate, pass its stable Bizar role name (`greg`, `todd`, `linda`, and so on) as `subagent_type` and OMIT the native `model` field. `bizar models` keeps that global role definition frontmatter bound to the default enabled operator-selected gateway ID. Never put a raw gateway ID or a Claude family alias in the native model field; aliases are compatibility-only. `bizar models --agent-types --json` is advanced explicit per-model routing only. For teams, do not name a competing model in the spawn prompt. If the stable role definition is missing, run `bizar models`; do not retry by cycling providers or tiers. Every editing worker uses call-level `isolation: "worktree"`. For genuinely disjoint writable scopes, dispatch concurrently; otherwise use one owner.',
64
+ '- Consume each terminal agent result exactly once from its original `<result>`/final summary, merge queued worktrees with bizar worktree-merge, and run integration checks in the primary session. Never send a terminal notification, idle ping, or completed task back to that agent as a follow-up and never re-dispatch a completed background agent merely to summarize its result. A subagent may not recursively dispatch itself.',
65
65
  '- Do NOT execute any tool you do not have. If a tool you need is missing from your tools list, dispatch to a subagent that has it — do not pretend you have it.',
66
66
  '- If you are already running as a Bizar custom agent, follow your assigned role and do not recursively dispatch yourself.',
67
67
  ].join('\n');
@@ -83,7 +83,7 @@ process.stdin.on('end', async () => {
83
83
  process.stdout.write(JSON.stringify({
84
84
  hookSpecificOutput: {
85
85
  hookEventName: 'UserPromptSubmit',
86
- additionalContext: 'Bizar terminal task update: consume the structured status and <result> now. Mark the agent terminal, merge any queued worktree, continue the active objective, and do not route this notification as a new request.',
86
+ additionalContext: 'Bizar terminal task update: consume this original structured <result> exactly once. Mark the agent terminal and merge any queued worktree. Do not send this notification back to the agent, do not request a follow-up acknowledgement, and do not replace its result with a later idle/status reply.',
87
87
  },
88
88
  }) + '\n');
89
89
  return;
@@ -26,7 +26,7 @@ const routeModel = (risk) => {
26
26
  const selected = candidate.trim()
27
27
  return selected
28
28
  }
29
- const routeAgentType = (risk, role = 'todd') => WORKFLOW_ROUTING.agentTypes?.[routeModel(risk)]?.[({ 'research-analyst': 'greg', planner: 'paul', implementer: 'todd', 'qa-reviewer': 'linda', reviewer: 'linda' }[role] || role)] || ''
29
+ const routeAgentType = (_risk, role = 'todd') => ({ 'research-analyst': 'greg', planner: 'paul', architect: 'paul', implementer: 'todd', 'qa-reviewer': 'linda', reviewer: 'linda', adversarial: 'linda', security: 'linda', qa: 'linda' }[role] || role)
30
30
  if (!routeModel('medium') || !routeModel('high') || !routeAgentType('medium') || !routeAgentType('high')) {
31
31
  return {
32
32
  status: 'blocked',
@@ -25,7 +25,7 @@ const routeModel = (risk) => {
25
25
  const selected = candidate.trim()
26
26
  return selected
27
27
  }
28
- const routeAgentType = (risk, role = 'todd') => WORKFLOW_ROUTING.agentTypes?.[routeModel(risk)]?.[({ 'research-analyst': 'greg', planner: 'paul', implementer: 'todd', 'qa-reviewer': 'linda', reviewer: 'linda' }[role] || role)] || ''
28
+ const routeAgentType = (_risk, role = 'todd') => ({ 'research-analyst': 'greg', planner: 'paul', architect: 'paul', implementer: 'todd', 'qa-reviewer': 'linda', reviewer: 'linda', adversarial: 'linda', security: 'linda', qa: 'linda' }[role] || role)
29
29
  if (!routeModel('medium') || !routeModel('high') || !routeAgentType('medium') || !routeAgentType('high')) {
30
30
  return {
31
31
  status: 'blocked',
@@ -26,7 +26,7 @@ const routeModel = (risk) => {
26
26
  const selected = candidate.trim()
27
27
  return selected
28
28
  }
29
- const routeAgentType = (risk, role = 'todd') => WORKFLOW_ROUTING.agentTypes?.[routeModel(risk)]?.[({ 'research-analyst': 'greg', planner: 'paul', implementer: 'todd', 'qa-reviewer': 'linda', reviewer: 'linda' }[role] || role)] || ''
29
+ const routeAgentType = (_risk, role = 'todd') => ({ 'research-analyst': 'greg', planner: 'paul', architect: 'paul', implementer: 'todd', 'qa-reviewer': 'linda', reviewer: 'linda', adversarial: 'linda', security: 'linda', qa: 'linda' }[role] || role)
30
30
  if (!routeModel('medium') || !routeModel('high') || !routeAgentType('medium') || !routeAgentType('high')) {
31
31
  return {
32
32
  status: 'blocked',
@@ -33,15 +33,14 @@ import { existsSync, readFileSync, appendFileSync, mkdirSync, writeFileSync, ren
33
33
  import { homedir } from 'node:os';
34
34
  import { dirname, isAbsolute, join, resolve } from 'node:path';
35
35
 
36
- const MODEL_AGENT_WORDS = { a:'alpha', b:'bravo', c:'charlie', d:'delta', e:'echo', f:'foxtrot', g:'golf', h:'hotel', i:'india', j:'juliet', k:'kilo', l:'lima', m:'mike', n:'november', o:'oscar', p:'papa', q:'quebec', r:'romeo', s:'sierra', t:'tango', u:'uniform', v:'victor', w:'whiskey', x:'xray', y:'yankee', z:'zulu', 0:'zero', 1:'one', 2:'two', 3:'three', 4:'four', 5:'five', 6:'six', 7:'seven', 8:'eight', 9:'nine', '/':'slash', '.':'dot', '-':'dash', '_':'under' };
37
36
  const ROLE_TO_BIZAR_AGENT = Object.freeze({
38
- 'research-analyst': 'greg', planner: 'paul', implementer: 'todd',
39
- 'qa-reviewer': 'linda', reviewer: 'linda', 'debug-specialist': 'carl',
37
+ 'research-analyst': 'greg', planner: 'paul', architect: 'paul', implementer: 'todd',
38
+ 'qa-reviewer': 'linda', reviewer: 'linda', adversarial: 'linda', security: 'linda', qa: 'linda', 'debug-specialist': 'carl',
40
39
  'principal-engineer': 'karen', 'ui-designer': 'ria', 'it-lead': 'steve',
41
40
  'knowledge-manager': 'oscar', 'support-tech': 'kevin', 'exec-assistant': 'pam',
42
41
  'office-coordinator': 'brenda', 'office-greeter': 'janet', 'brand-designer': 'brad',
43
42
  });
44
- function modelAgentName(modelId, role = 'todd') { return `${ROLE_TO_BIZAR_AGENT[role] || (Object.values(ROLE_TO_BIZAR_AGENT).includes(role) ? role : 'todd')}-bizar-${[...String(modelId || '').toLowerCase()].map((ch) => MODEL_AGENT_WORDS[ch] || 'unknown').join('-')}`; }
43
+ function stableAgentName(role = 'todd') { return ROLE_TO_BIZAR_AGENT[role] || (Object.values(ROLE_TO_BIZAR_AGENT).includes(role) ? role : 'todd'); }
45
44
 
46
45
  const { O_APPEND, O_CREAT, O_WRONLY } = fsConstants;
47
46
 
@@ -806,12 +805,14 @@ export function classifyDispatchOutcome(result, error, startMs) {
806
805
  }
807
806
 
808
807
  /**
809
- * Build an Agent payload that selects a generated full-ID model definition.
808
+ * Build an Agent payload that selects a stable Bizar role definition. Its
809
+ * frontmatter is refreshed by `bizar models` with the default selected full
810
+ * gateway ID, avoiding the alias-only native `model` transport.
810
811
  */
811
812
  export function augmentPayload(opts, decision, agentName, context = {}) {
812
813
  return {
813
814
  ...opts,
814
- subagent_type: modelAgentName(decision.modelId, opts.role),
815
+ subagent_type: stableAgentName(opts.role),
815
816
  additionalContext: {
816
817
  ...(opts.additionalContext && typeof opts.additionalContext === 'object' ? opts.additionalContext : {}),
817
818
  bizarConfiguredModel: decision.modelId ?? null,
@@ -24,7 +24,7 @@ const routeModel = (risk) => {
24
24
  const selected = candidate.trim()
25
25
  return selected
26
26
  }
27
- const routeAgentType = (risk, role = 'todd') => WORKFLOW_ROUTING.agentTypes?.[routeModel(risk)]?.[({ 'research-analyst': 'greg', planner: 'paul', implementer: 'todd', 'qa-reviewer': 'linda', reviewer: 'linda' }[role] || role)] || ''
27
+ const routeAgentType = (_risk, role = 'todd') => ({ 'research-analyst': 'greg', planner: 'paul', architect: 'paul', implementer: 'todd', 'qa-reviewer': 'linda', reviewer: 'linda', adversarial: 'linda', security: 'linda', qa: 'linda' }[role] || role)
28
28
  if (!routeModel('medium') || !routeModel('high') || !routeAgentType('medium') || !routeAgentType('high')) {
29
29
  return {
30
30
  status: 'blocked',
@@ -23,7 +23,7 @@ const routeModel = (risk) => {
23
23
  const selected = candidate.trim()
24
24
  return selected
25
25
  }
26
- const routeAgentType = (risk, role = 'todd') => WORKFLOW_ROUTING.agentTypes?.[routeModel(risk)]?.[({ 'research-analyst': 'greg', planner: 'paul', implementer: 'todd', 'qa-reviewer': 'linda', reviewer: 'linda' }[role] || role)] || ''
26
+ const routeAgentType = (_risk, role = 'todd') => ({ 'research-analyst': 'greg', planner: 'paul', architect: 'paul', implementer: 'todd', 'qa-reviewer': 'linda', reviewer: 'linda', adversarial: 'linda', security: 'linda', qa: 'linda' }[role] || role)
27
27
  if (!routeModel('medium') || !routeModel('high') || !routeAgentType('medium') || !routeAgentType('high')) {
28
28
  return {
29
29
  status: 'blocked',
@@ -25,7 +25,7 @@ const routeModel = (risk) => {
25
25
  const selected = candidate.trim()
26
26
  return selected
27
27
  }
28
- const routeAgentType = (risk, role = 'todd') => WORKFLOW_ROUTING.agentTypes?.[routeModel(risk)]?.[({ 'research-analyst': 'greg', planner: 'paul', implementer: 'todd', 'qa-reviewer': 'linda', reviewer: 'linda' }[role] || role)] || ''
28
+ const routeAgentType = (_risk, role = 'todd') => ({ 'research-analyst': 'greg', planner: 'paul', architect: 'paul', implementer: 'todd', 'qa-reviewer': 'linda', reviewer: 'linda', adversarial: 'linda', security: 'linda', qa: 'linda' }[role] || role)
29
29
  if (!routeModel('medium') || !routeModel('high') || !routeAgentType('medium') || !routeAgentType('high')) {
30
30
  return {
31
31
  status: 'blocked',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polderlabs/bizar",
3
- "version": "10.23.19",
3
+ "version": "10.23.21",
4
4
  "description": "Autonomous, human-in-the-loop multi-agent harness for Claude Code with guarded workflows, typed SDK primitives, and MCP tools.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * SDK version constant. Keep synchronized with the workspace package versions.
3
3
  */
4
- export declare const SDK_VERSION: "10.23.13";
4
+ export declare const SDK_VERSION: "10.23.21";
5
5
  //# sourceMappingURL=version.d.ts.map
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * SDK version constant. Keep synchronized with the workspace package versions.
3
3
  */
4
- export const SDK_VERSION = "10.23.13";
4
+ export const SDK_VERSION = "10.23.21";
5
5
  //# sourceMappingURL=version.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polderlabs/bizar-sdk",
3
- "version": "10.23.13",
3
+ "version": "10.23.21",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",