@polderlabs/bizar 10.23.15 → 10.23.17
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/cli/commands/models.mjs +36 -1
- package/cli/provision.mjs +19 -0
- package/config/claude/agents/office-manager.md +21 -18
- package/config/claude/hooks/agent-model-guard.mjs +9 -6
- package/config/claude/hooks/worker-suggest.mjs +1 -1
- package/config/workflows/bizar-debug.js +4 -3
- package/config/workflows/bizar-implement.js +4 -3
- package/config/workflows/bizar-research.js +4 -3
- package/config/workflows/lib/dispatch.js +5 -5
- package/config/workflows/ultracode-research.js +4 -3
- package/config/workflows/ultracode-review.js +4 -3
- package/config/workflows/ultracode.js +4 -3
- package/package.json +1 -1
package/cli/commands/models.mjs
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* reject user-selected IDs.
|
|
19
19
|
*/
|
|
20
20
|
import chalk from 'chalk';
|
|
21
|
-
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
21
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
22
22
|
import { dirname, join } from 'node:path';
|
|
23
23
|
import readline from 'node:readline';
|
|
24
24
|
|
|
@@ -992,6 +992,9 @@ export function applyModelOverrides({ settingsJsonPath, pickedIds, liveIds = [],
|
|
|
992
992
|
// print-mode `[claude-code:unrecognized_model]` diagnostics for Agent SDK calls.
|
|
993
993
|
settings.modelOverrides = buildClaudeModelOverrides(synced);
|
|
994
994
|
const nativeAgentAliases = applyNativeAgentAliasTargets(settings, synced);
|
|
995
|
+
const generatedAgents = syncGeneratedModelAgents(synced, {
|
|
996
|
+
agentsDir: settingsJsonPath === undefined ? undefined : join(dirname(path), 'agents', 'bizar-models'),
|
|
997
|
+
});
|
|
995
998
|
if (requiresGatewayModelDiscovery(synced)) {
|
|
996
999
|
settings.env = {
|
|
997
1000
|
...(settings.env || {}),
|
|
@@ -1022,6 +1025,7 @@ export function applyModelOverrides({ settingsJsonPath, pickedIds, liveIds = [],
|
|
|
1022
1025
|
skippedStale: skipped,
|
|
1023
1026
|
skippedDisabled,
|
|
1024
1027
|
nativeAgentAliases,
|
|
1028
|
+
generatedAgents,
|
|
1025
1029
|
settingsPath: path,
|
|
1026
1030
|
};
|
|
1027
1031
|
}
|
|
@@ -1066,6 +1070,23 @@ export const CLAUDE_MODEL_OVERRIDE_KEYS = Object.freeze([
|
|
|
1066
1070
|
// gateway IDs below; they never select an Anthropic provider by themselves.
|
|
1067
1071
|
export const NATIVE_AGENT_ALIASES = Object.freeze(['sonnet', 'opus', 'haiku', 'fable']);
|
|
1068
1072
|
|
|
1073
|
+
const MODEL_AGENT_WORDS = Object.freeze({ 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' });
|
|
1074
|
+
|
|
1075
|
+
export function modelAgentName(modelId) {
|
|
1076
|
+
return `bizar-model-${[...String(modelId || '').toLowerCase()].map((ch) => MODEL_AGENT_WORDS[ch] || 'unknown').join('-')}`;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
export function syncGeneratedModelAgents(modelIds, opts = {}) {
|
|
1080
|
+
const agentsDir = opts.agentsDir || join(resolveClaudeConfigDir(), 'agents', 'bizar-models');
|
|
1081
|
+
const ids = [...new Set((Array.isArray(modelIds) ? modelIds : []).filter((id) => typeof id === 'string' && id.trim()).map((id) => id.trim()))];
|
|
1082
|
+
if (existsSync(agentsDir)) rmSync(agentsDir, { recursive: true, force: true });
|
|
1083
|
+
if (!ids.length) return { agentsDir, names: [] };
|
|
1084
|
+
mkdirSync(agentsDir, { recursive: true, mode: 0o700 });
|
|
1085
|
+
const names = ids.map((id) => modelAgentName(id));
|
|
1086
|
+
ids.forEach((id, index) => writeFileSync(join(agentsDir, `${names[index]}.md`), `---\nname: ${names[index]}\ndescription: Bizar configured gateway model worker.\nmodel: ${id}\n---\n\nFollow the assigned Bizar role and task. Report concise evidence to the coordinator.\n`, { mode: 0o600 }));
|
|
1087
|
+
return { agentsDir, names };
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1069
1090
|
const NATIVE_AGENT_OVERRIDE_KEYS = Object.freeze({
|
|
1070
1091
|
sonnet: 'claude-sonnet-5',
|
|
1071
1092
|
opus: 'claude-opus-5',
|
|
@@ -2304,6 +2325,7 @@ export async function run(name, args, isHelpRequest, deps = {}) {
|
|
|
2304
2325
|
|
|
2305
2326
|
const wantJson = args.includes('--json');
|
|
2306
2327
|
const wantList = args.includes('--list');
|
|
2328
|
+
const wantAgentTypes = args.includes('--agent-types');
|
|
2307
2329
|
const wantClear = args.includes('--clear');
|
|
2308
2330
|
const wantRefresh = args.includes('--refresh');
|
|
2309
2331
|
const setFlag = args.find((a) => a.startsWith('--set='));
|
|
@@ -2320,6 +2342,19 @@ export async function run(name, args, isHelpRequest, deps = {}) {
|
|
|
2320
2342
|
const routerPath = resolveRouterPath(process.cwd());
|
|
2321
2343
|
const { endpoint, authToken, source: endpointSource } = resolveEndpoint({ cwd: process.cwd() });
|
|
2322
2344
|
|
|
2345
|
+
// This is the orchestration-safe bridge from an operator-selected gateway
|
|
2346
|
+
// ID to the Claude Code definition that owns it. It is deliberately local:
|
|
2347
|
+
// no gateway discovery is needed to dispatch a model the operator selected.
|
|
2348
|
+
if (wantAgentTypes) {
|
|
2349
|
+
const router = loadRouter(routerPath);
|
|
2350
|
+
const models = configuredEnabledModels(router);
|
|
2351
|
+
const agentTypes = Object.fromEntries(models.map((id) => [id, modelAgentName(id)]));
|
|
2352
|
+
const payload = { routerPath, models, agentTypes, agentsDir: join(resolveClaudeConfigDir(), 'agents', 'bizar-models') };
|
|
2353
|
+
if (wantJson) process.stdout.write(JSON.stringify(payload, null, 2) + '\n');
|
|
2354
|
+
else for (const id of models) process.stdout.write(`${id}\t${agentTypes[id]}\n`);
|
|
2355
|
+
return true;
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2323
2358
|
// F-185: `bizar models explain <role>` — non-interactive ranking.
|
|
2324
2359
|
// Handled BEFORE the picker fetch path so it never touches the gateway.
|
|
2325
2360
|
const explainIdx = args.findIndex((a) => a === 'explain');
|
package/cli/provision.mjs
CHANGED
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
buildClaudeModelOverrides,
|
|
37
37
|
configuredEnabledModels,
|
|
38
38
|
requiresGatewayModelDiscovery,
|
|
39
|
+
syncGeneratedModelAgents,
|
|
39
40
|
} from './commands/models.mjs';
|
|
40
41
|
import { validateNativeWorkflowDirectory } from '../config/workflows/lib/native-contract.mjs';
|
|
41
42
|
|
|
@@ -502,6 +503,20 @@ export async function syncModelRouter({ dryRun = false, force = false } = {}) {
|
|
|
502
503
|
return { ok: true, message: `global model-router.json → ${dest}`, path: dest };
|
|
503
504
|
}
|
|
504
505
|
|
|
506
|
+
// Recreate the managed definition projection on every install/update. This is
|
|
507
|
+
// needed after an npm upgrade or a clean Claude directory: the router is
|
|
508
|
+
// operator-owned and preserved, while generated definitions are disposable
|
|
509
|
+
// installation artifacts derived exclusively from its selected IDs.
|
|
510
|
+
export function syncConfiguredModelAgents({ dryRun = false } = {}) {
|
|
511
|
+
const routerPath = resolveGlobalModelRouter();
|
|
512
|
+
let router = {};
|
|
513
|
+
try { if (existsSync(routerPath)) router = JSON.parse(readFileSync(routerPath, 'utf8')); } catch { return { ok: false, message: `cannot read ${routerPath}` }; }
|
|
514
|
+
const models = configuredEnabledModels(router);
|
|
515
|
+
if (dryRun) return { ok: true, message: `[dry-run] would sync ${models.length} generated model agent(s)`, models };
|
|
516
|
+
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
|
+
}
|
|
519
|
+
|
|
505
520
|
export async function syncSkillFiles({ dryRun = false, force = false } = {}) {
|
|
506
521
|
const src = join(REPO_ROOT, 'config', 'skills');
|
|
507
522
|
const dest = CLAUDE_SKILLS_DIR;
|
|
@@ -1187,6 +1202,10 @@ export async function runProvision(opts = {}) {
|
|
|
1187
1202
|
if (routerStep.ok) logOk(routerStep.message); else logErr(routerStep.message);
|
|
1188
1203
|
stepResults.push({ label: 'model-router', ...routerStep });
|
|
1189
1204
|
|
|
1205
|
+
const modelAgentsStep = syncConfiguredModelAgents({ dryRun });
|
|
1206
|
+
if (modelAgentsStep.ok) logOk(modelAgentsStep.message); else logErr(modelAgentsStep.message);
|
|
1207
|
+
stepResults.push({ label: 'model-agents', ...modelAgentsStep });
|
|
1208
|
+
|
|
1190
1209
|
section('Writing settings.json');
|
|
1191
1210
|
const settingsStep = writeClaudeSettings({ dryRun, force });
|
|
1192
1211
|
if (settingsStep.ok) logOk(settingsStep.message); else logErr(settingsStep.message);
|
|
@@ -38,16 +38,14 @@ Before every Workflow, Agent, or Agent-team call, read the global Bizar model
|
|
|
38
38
|
router and construct a small `args.routing` object whose `default`, `medium`,
|
|
39
39
|
and `high` values are explicit enabled configured gateway IDs. Include the
|
|
40
40
|
user's task in the same args object under the workflow's documented task field.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
configured model exists, stop and ask the operator to run `bizar models`; never
|
|
50
|
-
omit model selection or cycle providers.
|
|
41
|
+
Use the generated `bizar-models` user agent matching the chosen full gateway
|
|
42
|
+
ID as `subagent_type`, and omit the native Agent `model` parameter entirely.
|
|
43
|
+
That definition's frontmatter owns the full-ID selection for ordinary agents,
|
|
44
|
+
workflows, and teams. Include the raw ID in `additionalContext.bizarConfiguredModel`
|
|
45
|
+
for audit telemetry. Never use `inherit` or an unconfigured provider default.
|
|
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.
|
|
51
49
|
|
|
52
50
|
Invoke the selected workflow by `name` first. If Claude reports that the Bizar
|
|
53
51
|
name is unavailable, resolve the active Claude config directory and retry once
|
|
@@ -62,14 +60,19 @@ implementation around a broken workflow installation.
|
|
|
62
60
|
|
|
63
61
|
For every dispatch, select the cheapest sufficient enabled configured model
|
|
64
62
|
from the global Bizar router. User-selected models take precedence over tier
|
|
65
|
-
candidates; `disabledProviders` excludes both. Native aliases are
|
|
66
|
-
labels bound by `bizar models`, not Anthropic selections.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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, pass
|
|
67
|
+
its generated name as `subagent_type`, and omit `model`; the generated global
|
|
68
|
+
definition's `model:` frontmatter selects the full gateway ID. This is the
|
|
69
|
+
default for individual subagents, workflows, and agent-team teammates. For
|
|
70
|
+
teams, do not name a competing model in the spawn prompt. Use `bizar worker`
|
|
71
|
+
only when a separately launched process worktree is useful. If no enabled
|
|
72
|
+
configured candidate or generated definition exists, stop with the
|
|
73
|
+
configuration error and run `bizar models`. Never let Claude choose an
|
|
74
|
+
unconfigured default, inherit the session model, use an unmapped alias, or
|
|
75
|
+
retry by cycling models, providers, or tiers.
|
|
73
76
|
|
|
74
77
|
## Worktree Discipline and integration
|
|
75
78
|
|
|
@@ -49,6 +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 { modelAgentName } from '../../../cli/commands/models.mjs';
|
|
52
53
|
|
|
53
54
|
function deny(reason) {
|
|
54
55
|
return {
|
|
@@ -194,7 +195,7 @@ function readTransportTarget(alias, options = {}) {
|
|
|
194
195
|
|
|
195
196
|
export async function guardAgentModel(input, options = {}) {
|
|
196
197
|
if (!input || typeof input !== 'object') return {};
|
|
197
|
-
if (input.hook_event_name !== 'PreToolUse' || input.tool_name
|
|
198
|
+
if (input.hook_event_name !== 'PreToolUse' || !['Agent', 'Task'].includes(input.tool_name)) return {};
|
|
198
199
|
const toolInput = input.tool_input && typeof input.tool_input === 'object' ? input.tool_input : {};
|
|
199
200
|
const requested = typeof toolInput.model === 'string' ? toolInput.model.trim() : '';
|
|
200
201
|
const failoverBlock = readFailoverBlock(toolInput);
|
|
@@ -225,6 +226,8 @@ export async function guardAgentModel(input, options = {}) {
|
|
|
225
226
|
// Inheritance is safe only when the auditable Bizar selection equals the
|
|
226
227
|
// actual global Claude parent model and is a selected, enabled user pick.
|
|
227
228
|
if (!requested || requested === 'inherit') {
|
|
229
|
+
const generated = typeof toolInput.subagent_type === 'string' && [...userPicks].some((id) => toolInput.subagent_type === modelAgentName(id));
|
|
230
|
+
if (generated && !requested) return {};
|
|
228
231
|
const configured = configuredContext;
|
|
229
232
|
const parent = readConfiguredParentModel(options);
|
|
230
233
|
if (!configured || configured !== parent || !userPicks.has(configured)) {
|
|
@@ -245,11 +248,11 @@ export async function guardAgentModel(input, options = {}) {
|
|
|
245
248
|
return {};
|
|
246
249
|
}
|
|
247
250
|
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
if (userPicks.has(requested)
|
|
252
|
-
return {};
|
|
251
|
+
// Native Agent/Task transport accepts only Claude's four aliases, even when
|
|
252
|
+
// a gateway accepts arbitrary IDs for the main conversation. Full IDs belong
|
|
253
|
+
// in Bizar's generated subagent frontmatter, not in this enum-shaped field.
|
|
254
|
+
if (userPicks.has(requested)) {
|
|
255
|
+
return deny(`Bizar Agent dispatch blocked: native Agent model accepts aliases only. Use generated subagent_type ${modelAgentName(requested)} and omit model; re-run \`bizar models\` if it is missing.`);
|
|
253
256
|
}
|
|
254
257
|
|
|
255
258
|
// F-185 contract: when the orchestrator passes both `routingDecisionId`
|
|
@@ -60,7 +60,7 @@ 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
|
-
'-
|
|
63
|
+
'- For every Agent, workflow worker, or agent-team teammate, choose one exact ID from the enabled `bizar models` user selection, then obtain its generated definition name from `bizar models --agent-types --json`. 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
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.',
|
|
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.',
|
|
@@ -26,10 +26,11 @@ const routeModel = (risk) => {
|
|
|
26
26
|
const selected = candidate.trim()
|
|
27
27
|
return selected
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
const routeAgentType = (risk) => WORKFLOW_ROUTING.agentTypes?.[routeModel(risk)] || ''
|
|
30
|
+
if (!routeModel('medium') || !routeModel('high') || !routeAgentType('medium') || !routeAgentType('high')) {
|
|
30
31
|
return {
|
|
31
32
|
status: 'blocked',
|
|
32
|
-
reason: 'No
|
|
33
|
+
reason: 'No generated Bizar model-agent mapping was supplied for workflow routing. Run bizar models and retry; provider defaults are prohibited.',
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
let WORKFLOW_DISPATCH_SEQUENCE = 0
|
|
@@ -37,7 +38,7 @@ const dispatchAgent = (agentFn, agentName, prompt, opts = {}) => {
|
|
|
37
38
|
const sequence = ++WORKFLOW_DISPATCH_SEQUENCE
|
|
38
39
|
const prefix = `[Bizar dispatch ${sequence}: ${agentName}; role=${opts.role || 'worker'}; phase=${opts.phase || 'work'}; label=${opts.label || agentName}]`
|
|
39
40
|
const agentOptions = {
|
|
40
|
-
|
|
41
|
+
subagent_type: routeAgentType(opts.risk || 'medium'),
|
|
41
42
|
effort: opts.risk === 'high' ? 'high' : 'medium',
|
|
42
43
|
}
|
|
43
44
|
if (opts.schema) agentOptions.schema = opts.schema
|
|
@@ -25,10 +25,11 @@ const routeModel = (risk) => {
|
|
|
25
25
|
const selected = candidate.trim()
|
|
26
26
|
return selected
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
const routeAgentType = (risk) => WORKFLOW_ROUTING.agentTypes?.[routeModel(risk)] || ''
|
|
29
|
+
if (!routeModel('medium') || !routeModel('high') || !routeAgentType('medium') || !routeAgentType('high')) {
|
|
29
30
|
return {
|
|
30
31
|
status: 'blocked',
|
|
31
|
-
reason: 'No
|
|
32
|
+
reason: 'No generated Bizar model-agent mapping was supplied for workflow routing. Run bizar models and retry; provider defaults are prohibited.',
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
let WORKFLOW_DISPATCH_SEQUENCE = 0
|
|
@@ -36,7 +37,7 @@ const dispatchAgent = (agentFn, agentName, prompt, opts = {}) => {
|
|
|
36
37
|
const sequence = ++WORKFLOW_DISPATCH_SEQUENCE
|
|
37
38
|
const prefix = `[Bizar dispatch ${sequence}: ${agentName}; role=${opts.role || 'worker'}; phase=${opts.phase || 'work'}; label=${opts.label || agentName}]`
|
|
38
39
|
const agentOptions = {
|
|
39
|
-
|
|
40
|
+
subagent_type: routeAgentType(opts.risk || 'medium'),
|
|
40
41
|
effort: opts.risk === 'high' ? 'high' : 'medium',
|
|
41
42
|
}
|
|
42
43
|
if (opts.schema) agentOptions.schema = opts.schema
|
|
@@ -26,10 +26,11 @@ const routeModel = (risk) => {
|
|
|
26
26
|
const selected = candidate.trim()
|
|
27
27
|
return selected
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
const routeAgentType = (risk) => WORKFLOW_ROUTING.agentTypes?.[routeModel(risk)] || ''
|
|
30
|
+
if (!routeModel('medium') || !routeModel('high') || !routeAgentType('medium') || !routeAgentType('high')) {
|
|
30
31
|
return {
|
|
31
32
|
status: 'blocked',
|
|
32
|
-
reason: 'No
|
|
33
|
+
reason: 'No generated Bizar model-agent mapping was supplied for workflow routing. Run bizar models and retry; provider defaults are prohibited.',
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
let WORKFLOW_DISPATCH_SEQUENCE = 0
|
|
@@ -37,7 +38,7 @@ const dispatchAgent = (agentFn, agentName, prompt, opts = {}) => {
|
|
|
37
38
|
const sequence = ++WORKFLOW_DISPATCH_SEQUENCE
|
|
38
39
|
const prefix = `[Bizar dispatch ${sequence}: ${agentName}; role=${opts.role || 'worker'}; phase=${opts.phase || 'work'}; label=${opts.label || agentName}]`
|
|
39
40
|
const agentOptions = {
|
|
40
|
-
|
|
41
|
+
subagent_type: routeAgentType(opts.risk || 'medium'),
|
|
41
42
|
effort: opts.risk === 'high' ? 'high' : 'medium',
|
|
42
43
|
}
|
|
43
44
|
if (opts.schema) agentOptions.schema = opts.schema
|
|
@@ -33,6 +33,9 @@ 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
|
+
function modelAgentName(modelId) { return `bizar-model-${[...String(modelId || '').toLowerCase()].map((ch) => MODEL_AGENT_WORDS[ch] || 'unknown').join('-')}`; }
|
|
38
|
+
|
|
36
39
|
const { O_APPEND, O_CREAT, O_WRONLY } = fsConstants;
|
|
37
40
|
|
|
38
41
|
/* ────────────────────────────────────────────────────────────────────────── */
|
|
@@ -796,15 +799,12 @@ export function classifyDispatchOutcome(result, error, startMs) {
|
|
|
796
799
|
}
|
|
797
800
|
|
|
798
801
|
/**
|
|
799
|
-
* Build
|
|
800
|
-
* full model ID in an Agent invocation; use the selected gateway ID directly
|
|
801
|
-
* so every configured selection is usable by native agents and teams. The
|
|
802
|
-
* transport aliases remain a compatibility option for callers that need them.
|
|
802
|
+
* Build an Agent payload that selects a generated full-ID model definition.
|
|
803
803
|
*/
|
|
804
804
|
export function augmentPayload(opts, decision, agentName, context = {}) {
|
|
805
805
|
return {
|
|
806
806
|
...opts,
|
|
807
|
-
|
|
807
|
+
subagent_type: modelAgentName(decision.modelId),
|
|
808
808
|
additionalContext: {
|
|
809
809
|
...(opts.additionalContext && typeof opts.additionalContext === 'object' ? opts.additionalContext : {}),
|
|
810
810
|
bizarConfiguredModel: decision.modelId ?? null,
|
|
@@ -24,10 +24,11 @@ const routeModel = (risk) => {
|
|
|
24
24
|
const selected = candidate.trim()
|
|
25
25
|
return selected
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
const routeAgentType = (risk) => WORKFLOW_ROUTING.agentTypes?.[routeModel(risk)] || ''
|
|
28
|
+
if (!routeModel('medium') || !routeModel('high') || !routeAgentType('medium') || !routeAgentType('high')) {
|
|
28
29
|
return {
|
|
29
30
|
status: 'blocked',
|
|
30
|
-
reason: 'No
|
|
31
|
+
reason: 'No generated Bizar model-agent mapping was supplied for workflow routing. Run bizar models and retry; provider defaults are prohibited.',
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
let WORKFLOW_DISPATCH_SEQUENCE = 0
|
|
@@ -35,7 +36,7 @@ const dispatchAgent = (agentFn, agentName, prompt, opts = {}) => {
|
|
|
35
36
|
const sequence = ++WORKFLOW_DISPATCH_SEQUENCE
|
|
36
37
|
const prefix = `[Bizar dispatch ${sequence}: ${agentName}; role=${opts.role || 'worker'}; phase=${opts.phase || 'work'}; label=${opts.label || agentName}]`
|
|
37
38
|
const agentOptions = {
|
|
38
|
-
|
|
39
|
+
subagent_type: routeAgentType(opts.risk || 'medium'),
|
|
39
40
|
effort: opts.risk === 'high' ? 'high' : 'medium',
|
|
40
41
|
}
|
|
41
42
|
if (opts.schema) agentOptions.schema = opts.schema
|
|
@@ -23,10 +23,11 @@ const routeModel = (risk) => {
|
|
|
23
23
|
const selected = candidate.trim()
|
|
24
24
|
return selected
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
const routeAgentType = (risk) => WORKFLOW_ROUTING.agentTypes?.[routeModel(risk)] || ''
|
|
27
|
+
if (!routeModel('medium') || !routeModel('high') || !routeAgentType('medium') || !routeAgentType('high')) {
|
|
27
28
|
return {
|
|
28
29
|
status: 'blocked',
|
|
29
|
-
reason: 'No
|
|
30
|
+
reason: 'No generated Bizar model-agent mapping was supplied for workflow routing. Run bizar models and retry; provider defaults are prohibited.',
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
let WORKFLOW_DISPATCH_SEQUENCE = 0
|
|
@@ -34,7 +35,7 @@ const dispatchAgent = (agentFn, agentName, prompt, opts = {}) => {
|
|
|
34
35
|
const sequence = ++WORKFLOW_DISPATCH_SEQUENCE
|
|
35
36
|
const prefix = `[Bizar dispatch ${sequence}: ${agentName}; role=${opts.role || 'worker'}; phase=${opts.phase || 'work'}; label=${opts.label || agentName}]`
|
|
36
37
|
const agentOptions = {
|
|
37
|
-
|
|
38
|
+
subagent_type: routeAgentType(opts.risk || 'medium'),
|
|
38
39
|
effort: opts.risk === 'high' ? 'high' : 'medium',
|
|
39
40
|
}
|
|
40
41
|
if (opts.schema) agentOptions.schema = opts.schema
|
|
@@ -25,10 +25,11 @@ const routeModel = (risk) => {
|
|
|
25
25
|
const selected = candidate.trim()
|
|
26
26
|
return selected
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
const routeAgentType = (risk) => WORKFLOW_ROUTING.agentTypes?.[routeModel(risk)] || ''
|
|
29
|
+
if (!routeModel('medium') || !routeModel('high') || !routeAgentType('medium') || !routeAgentType('high')) {
|
|
29
30
|
return {
|
|
30
31
|
status: 'blocked',
|
|
31
|
-
reason: 'No
|
|
32
|
+
reason: 'No generated Bizar model-agent mapping was supplied for workflow routing. Run bizar models and retry; provider defaults are prohibited.',
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
let WORKFLOW_DISPATCH_SEQUENCE = 0
|
|
@@ -36,7 +37,7 @@ const dispatchAgent = (agentFn, agentName, prompt, opts = {}) => {
|
|
|
36
37
|
const sequence = ++WORKFLOW_DISPATCH_SEQUENCE
|
|
37
38
|
const prefix = `[Bizar dispatch ${sequence}: ${agentName}; role=${opts.role || 'worker'}; phase=${opts.phase || 'work'}; label=${opts.label || agentName}]`
|
|
38
39
|
const agentOptions = {
|
|
39
|
-
|
|
40
|
+
subagent_type: routeAgentType(opts.risk || 'medium'),
|
|
40
41
|
effort: opts.risk === 'high' ? 'high' : 'medium',
|
|
41
42
|
}
|
|
42
43
|
if (opts.schema) agentOptions.schema = opts.schema
|
package/package.json
CHANGED