oh-my-claudecode-opencode 0.6.11 → 0.7.0
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/bin/omco-setup.js +10 -0
- package/bin/omco-setup.ts +10 -0
- package/dist/categories/constants.d.ts +49 -0
- package/dist/categories/index.d.ts +16 -0
- package/dist/categories/resolver.d.ts +15 -0
- package/dist/categories/types.d.ts +20 -0
- package/dist/config/index.d.ts +41 -0
- package/dist/index.js +547 -133
- package/dist/tools/call-omco-agent.d.ts +2 -1
- package/dist/tools/model-resolution-service.d.ts +15 -0
- package/package.json +1 -1
package/bin/omco-setup.js
CHANGED
|
@@ -87,6 +87,16 @@ async function main() {
|
|
|
87
87
|
};
|
|
88
88
|
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + `
|
|
89
89
|
`);
|
|
90
|
+
try {
|
|
91
|
+
const written = JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
92
|
+
if (written.model_mapping?.tierDefaults) {
|
|
93
|
+
console.log(`
|
|
94
|
+
✅ Config verification passed.`);
|
|
95
|
+
}
|
|
96
|
+
} catch {
|
|
97
|
+
console.error(`
|
|
98
|
+
⚠️ Warning: Could not verify written config.`);
|
|
99
|
+
}
|
|
90
100
|
console.log(`
|
|
91
101
|
✅ Configured tier mapping for ${provider}:
|
|
92
102
|
`);
|
package/bin/omco-setup.ts
CHANGED
|
@@ -105,6 +105,16 @@ async function main() {
|
|
|
105
105
|
// Write config
|
|
106
106
|
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
|
|
107
107
|
|
|
108
|
+
// Verify config can be read back
|
|
109
|
+
try {
|
|
110
|
+
const written = JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
111
|
+
if (written.model_mapping?.tierDefaults) {
|
|
112
|
+
console.log(`\n✅ Config verification passed.`);
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
console.error(`\n⚠️ Warning: Could not verify written config.`);
|
|
116
|
+
}
|
|
117
|
+
|
|
108
118
|
console.log(`\n✅ Configured tier mapping for ${provider}:\n`);
|
|
109
119
|
console.log(` haiku → ${tiers.haiku}`);
|
|
110
120
|
console.log(` sonnet → ${tiers.sonnet}`);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { CategoryConfig } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Prompt append for visual-engineering category.
|
|
4
|
+
* Encourages bold design choices and distinctive aesthetics.
|
|
5
|
+
*/
|
|
6
|
+
export declare const VISUAL_CATEGORY_PROMPT_APPEND = "<Category_Context>\nYou are working on VISUAL/UI tasks.\n\nDesign-first mindset:\n- Bold aesthetic choices over safe defaults\n- Unexpected layouts, asymmetry, grid-breaking elements\n- Distinctive typography (avoid: Arial, Inter, Roboto, Space Grotesk)\n- Cohesive color palettes with sharp accents\n- High-impact animations with staggered reveals\n- Atmosphere: gradient meshes, noise textures, layered transparencies\n\nAVOID: Generic fonts, purple gradients on white, predictable layouts, cookie-cutter patterns.\n</Category_Context>";
|
|
7
|
+
/**
|
|
8
|
+
* Prompt append for ultrabrain category.
|
|
9
|
+
* Encourages strategic thinking and architectural clarity.
|
|
10
|
+
*/
|
|
11
|
+
export declare const ULTRABRAIN_CATEGORY_PROMPT_APPEND = "<Category_Context>\nYou are working on COMPLEX ARCHITECTURE / DEEP REASONING tasks.\n\nStrategic advisor mindset:\n- Bias toward simplicity: least complex solution that fulfills requirements\n- Leverage existing code/patterns over new components\n- Prioritize developer experience and maintainability\n- One clear recommendation with effort estimate (Quick/Short/Medium/Large)\n- Signal when advanced approach warranted\n\nResponse format:\n- Bottom line (2-3 sentences)\n- Action plan (numbered steps)\n- Risks and mitigations (if relevant)\n</Category_Context>";
|
|
12
|
+
/**
|
|
13
|
+
* Prompt append for artistry category.
|
|
14
|
+
* Encourages radical creativity and unconventional approaches.
|
|
15
|
+
*/
|
|
16
|
+
export declare const ARTISTRY_CATEGORY_PROMPT_APPEND = "<Category_Context>\nYou are working on HIGHLY CREATIVE / ARTISTIC tasks.\n\nArtistic genius mindset:\n- Push far beyond conventional boundaries\n- Explore radical, unconventional directions\n- Surprise and delight: unexpected twists, novel combinations\n- Rich detail and vivid expression\n- Break patterns deliberately when it serves the creative vision\n\nApproach:\n- Generate diverse, bold options first\n- Embrace ambiguity and wild experimentation\n- Balance novelty with coherence\n- This is for tasks requiring exceptional creativity\n</Category_Context>";
|
|
17
|
+
/**
|
|
18
|
+
* Prompt append for quick category.
|
|
19
|
+
* Optimized for fast, focused execution with less capable models.
|
|
20
|
+
*/
|
|
21
|
+
export declare const QUICK_CATEGORY_PROMPT_APPEND = "<Category_Context>\nYou are working on SMALL / QUICK tasks.\n\nEfficient execution mindset:\n- Fast, focused, minimal overhead\n- Get to the point immediately\n- No over-engineering\n- Simple solutions for simple problems\n\nApproach:\n- Minimal viable implementation\n- Skip unnecessary abstractions\n- Direct and concise\n</Category_Context>\n\n<Caller_Warning>\nTHIS CATEGORY USES A LESS CAPABLE MODEL (haiku tier).\n\nThe model executing this task has LIMITED reasoning capacity. Your prompt MUST be:\n\n**EXHAUSTIVELY EXPLICIT** - Leave NOTHING to interpretation:\n1. MUST DO: List every required action as atomic, numbered steps\n2. MUST NOT DO: Explicitly forbid likely mistakes and deviations\n3. EXPECTED OUTPUT: Describe exact success criteria with concrete examples\n\n**WHY THIS MATTERS:**\n- Less capable models WILL deviate without explicit guardrails\n- Vague instructions \u2192 unpredictable results\n- Implicit expectations \u2192 missed requirements\n\n**PROMPT STRUCTURE (MANDATORY):**\n```\nTASK: [One-sentence goal]\n\nMUST DO:\n1. [Specific action with exact details]\n2. [Another specific action]\n...\n\nMUST NOT DO:\n- [Forbidden action + why]\n- [Another forbidden action]\n...\n\nEXPECTED OUTPUT:\n- [Exact deliverable description]\n- [Success criteria / verification method]\n```\n\nIf your prompt lacks this structure, REWRITE IT before delegating.\n</Caller_Warning>";
|
|
22
|
+
/**
|
|
23
|
+
* Prompt append for unspecified-low category.
|
|
24
|
+
* For moderate-effort tasks that don't fit specific categories.
|
|
25
|
+
*/
|
|
26
|
+
export declare const UNSPECIFIED_LOW_CATEGORY_PROMPT_APPEND = "<Category_Context>\nYou are working on tasks that don't fit specific categories but require moderate effort.\n\n<Selection_Gate>\nBEFORE selecting this category, VERIFY ALL conditions:\n1. Task does NOT fit: quick (trivial), visual-engineering (UI), ultrabrain (deep logic), artistry (creative), writing (docs)\n2. Task requires more than trivial effort but is NOT system-wide\n3. Scope is contained within a few files/modules\n\nIf task fits ANY other category, DO NOT select unspecified-low.\nThis is NOT a default choice - it's for genuinely unclassifiable moderate-effort work.\n</Selection_Gate>\n</Category_Context>\n\n<Caller_Warning>\nTHIS CATEGORY USES A MID-TIER MODEL (sonnet tier).\n\n**PROVIDE CLEAR STRUCTURE:**\n1. MUST DO: Enumerate required actions explicitly\n2. MUST NOT DO: State forbidden actions to prevent scope creep\n3. EXPECTED OUTPUT: Define concrete success criteria\n</Caller_Warning>";
|
|
27
|
+
/**
|
|
28
|
+
* Prompt append for unspecified-high category.
|
|
29
|
+
* For high-effort tasks that don't fit specific categories.
|
|
30
|
+
*/
|
|
31
|
+
export declare const UNSPECIFIED_HIGH_CATEGORY_PROMPT_APPEND = "<Category_Context>\nYou are working on tasks that don't fit specific categories but require substantial effort.\n\n<Selection_Gate>\nBEFORE selecting this category, VERIFY ALL conditions:\n1. Task does NOT fit: quick (trivial), visual-engineering (UI), ultrabrain (deep logic), artistry (creative), writing (docs)\n2. Task requires substantial effort across multiple systems/modules\n3. Changes have broad impact or require careful coordination\n4. NOT just \"complex\" - must be genuinely unclassifiable AND high-effort\n\nIf task fits ANY other category, DO NOT select unspecified-high.\nIf task is unclassifiable but moderate-effort, use unspecified-low instead.\n</Selection_Gate>\n</Category_Context>";
|
|
32
|
+
/**
|
|
33
|
+
* Prompt append for writing category.
|
|
34
|
+
* Optimized for documentation and prose tasks.
|
|
35
|
+
*/
|
|
36
|
+
export declare const WRITING_CATEGORY_PROMPT_APPEND = "<Category_Context>\nYou are working on WRITING / PROSE tasks.\n\nWordsmith mindset:\n- Clear, flowing prose\n- Appropriate tone and voice\n- Engaging and readable\n- Proper structure and organization\n\nApproach:\n- Understand the audience\n- Draft with care\n- Polish for clarity and impact\n- Documentation, READMEs, articles, technical writing\n</Category_Context>";
|
|
37
|
+
/**
|
|
38
|
+
* Default category configurations.
|
|
39
|
+
* Uses abstract tier names (haiku/sonnet/opus) that will be resolved to actual provider/model by the model resolution service.
|
|
40
|
+
*/
|
|
41
|
+
export declare const DEFAULT_CATEGORIES: Record<string, CategoryConfig>;
|
|
42
|
+
/**
|
|
43
|
+
* Map of category names to their prompt appends.
|
|
44
|
+
*/
|
|
45
|
+
export declare const CATEGORY_PROMPT_APPENDS: Record<string, string>;
|
|
46
|
+
/**
|
|
47
|
+
* Map of category names to their human-readable descriptions.
|
|
48
|
+
*/
|
|
49
|
+
export declare const CATEGORY_DESCRIPTIONS: Record<string, string>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Categories module for OMCO.
|
|
3
|
+
*
|
|
4
|
+
* Categories provide semantic task classification that automatically maps to:
|
|
5
|
+
* - Model tier (haiku/sonnet/opus)
|
|
6
|
+
* - Temperature settings
|
|
7
|
+
* - Thinking budget (via variant)
|
|
8
|
+
* - Specialized prompt context
|
|
9
|
+
*
|
|
10
|
+
* This allows calling code to delegate tasks by semantic meaning rather than
|
|
11
|
+
* worrying about technical model selection details.
|
|
12
|
+
*/
|
|
13
|
+
export type { CategoryConfig, CategoriesConfig } from "./types";
|
|
14
|
+
export { DEFAULT_CATEGORIES, CATEGORY_PROMPT_APPENDS, CATEGORY_DESCRIPTIONS, VISUAL_CATEGORY_PROMPT_APPEND, ULTRABRAIN_CATEGORY_PROMPT_APPEND, ARTISTRY_CATEGORY_PROMPT_APPEND, QUICK_CATEGORY_PROMPT_APPEND, UNSPECIFIED_LOW_CATEGORY_PROMPT_APPEND, UNSPECIFIED_HIGH_CATEGORY_PROMPT_APPEND, WRITING_CATEGORY_PROMPT_APPEND } from "./constants";
|
|
15
|
+
export type { ResolvedCategory } from "./resolver";
|
|
16
|
+
export { resolveCategoryConfig, getAvailableCategories } from "./resolver";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CategoryConfig, CategoriesConfig } from "./types";
|
|
2
|
+
export interface ResolvedCategory {
|
|
3
|
+
config: CategoryConfig;
|
|
4
|
+
promptAppend: string;
|
|
5
|
+
tier: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Resolve a category name to its configuration.
|
|
9
|
+
* Priority: user override > default category
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveCategoryConfig(categoryName: string, userCategories?: CategoriesConfig): ResolvedCategory | null;
|
|
12
|
+
/**
|
|
13
|
+
* Get list of all available category names.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getAvailableCategories(userCategories?: CategoriesConfig): string[];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for a delegation category.
|
|
3
|
+
* Categories determine which model tier and behavior profile to use for delegated tasks.
|
|
4
|
+
*/
|
|
5
|
+
export interface CategoryConfig {
|
|
6
|
+
/** Abstract model tier name (haiku/sonnet/opus) - resolved by model resolution service */
|
|
7
|
+
model?: string;
|
|
8
|
+
/** Model variant for extended thinking budget */
|
|
9
|
+
variant?: "low" | "medium" | "high" | "max" | "xhigh";
|
|
10
|
+
/** Human-readable description of what this category is for */
|
|
11
|
+
description?: string;
|
|
12
|
+
/** Additional prompt context appended when using this category */
|
|
13
|
+
prompt_append?: string;
|
|
14
|
+
/** Flag indicating this agent configuration is experimental/unstable */
|
|
15
|
+
is_unstable_agent?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Map of category names to their configurations.
|
|
19
|
+
*/
|
|
20
|
+
export type CategoriesConfig = Record<string, CategoryConfig>;
|
package/dist/config/index.d.ts
CHANGED
|
@@ -96,6 +96,32 @@ declare const AutopilotConfigSchema: z.ZodObject<{
|
|
|
96
96
|
off: "off";
|
|
97
97
|
}>>;
|
|
98
98
|
}, z.core.$strip>;
|
|
99
|
+
export declare const CategoryConfigSchema: z.ZodObject<{
|
|
100
|
+
model: z.ZodOptional<z.ZodString>;
|
|
101
|
+
variant: z.ZodOptional<z.ZodEnum<{
|
|
102
|
+
low: "low";
|
|
103
|
+
medium: "medium";
|
|
104
|
+
high: "high";
|
|
105
|
+
max: "max";
|
|
106
|
+
xhigh: "xhigh";
|
|
107
|
+
}>>;
|
|
108
|
+
description: z.ZodOptional<z.ZodString>;
|
|
109
|
+
prompt_append: z.ZodOptional<z.ZodString>;
|
|
110
|
+
is_unstable_agent: z.ZodOptional<z.ZodBoolean>;
|
|
111
|
+
}, z.core.$strip>;
|
|
112
|
+
export declare const CategoriesConfigSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
113
|
+
model: z.ZodOptional<z.ZodString>;
|
|
114
|
+
variant: z.ZodOptional<z.ZodEnum<{
|
|
115
|
+
low: "low";
|
|
116
|
+
medium: "medium";
|
|
117
|
+
high: "high";
|
|
118
|
+
max: "max";
|
|
119
|
+
xhigh: "xhigh";
|
|
120
|
+
}>>;
|
|
121
|
+
description: z.ZodOptional<z.ZodString>;
|
|
122
|
+
prompt_append: z.ZodOptional<z.ZodString>;
|
|
123
|
+
is_unstable_agent: z.ZodOptional<z.ZodBoolean>;
|
|
124
|
+
}, z.core.$strip>>;
|
|
99
125
|
declare const UltraQAConfigSchema: z.ZodObject<{
|
|
100
126
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
101
127
|
maxIterations: z.ZodOptional<z.ZodNumber>;
|
|
@@ -274,6 +300,19 @@ declare const OmoOmcsConfigSchema: z.ZodObject<{
|
|
|
274
300
|
toastDuration: z.ZodOptional<z.ZodNumber>;
|
|
275
301
|
trackMetrics: z.ZodOptional<z.ZodBoolean>;
|
|
276
302
|
}, z.core.$strip>>;
|
|
303
|
+
categories: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
304
|
+
model: z.ZodOptional<z.ZodString>;
|
|
305
|
+
variant: z.ZodOptional<z.ZodEnum<{
|
|
306
|
+
low: "low";
|
|
307
|
+
medium: "medium";
|
|
308
|
+
high: "high";
|
|
309
|
+
max: "max";
|
|
310
|
+
xhigh: "xhigh";
|
|
311
|
+
}>>;
|
|
312
|
+
description: z.ZodOptional<z.ZodString>;
|
|
313
|
+
prompt_append: z.ZodOptional<z.ZodString>;
|
|
314
|
+
is_unstable_agent: z.ZodOptional<z.ZodBoolean>;
|
|
315
|
+
}, z.core.$strip>>>;
|
|
277
316
|
omco_agent: z.ZodOptional<z.ZodObject<{
|
|
278
317
|
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
279
318
|
planner_enabled: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -296,6 +335,8 @@ export type McpServersConfig = z.infer<typeof McpServersConfigSchema>;
|
|
|
296
335
|
export type PermissionsConfig = z.infer<typeof PermissionsConfigSchema>;
|
|
297
336
|
export type MagicKeywordsConfig = z.infer<typeof MagicKeywordsConfigSchema>;
|
|
298
337
|
export type RoutingConfig = z.infer<typeof RoutingConfigSchema>;
|
|
338
|
+
export type CategoryConfig = z.infer<typeof CategoryConfigSchema>;
|
|
339
|
+
export type CategoriesConfig = z.infer<typeof CategoriesConfigSchema>;
|
|
299
340
|
export type HookName = "todo-continuation-enforcer" | "keyword-detector" | "ralph-loop" | "session-recovery" | "agent-usage-reminder" | "context-window-monitor" | "comment-checker" | "tool-output-truncator" | "system-prompt-injector" | "persistent-mode" | "remember-tag-processor" | "autopilot" | "ultraqa-loop" | "context-recovery" | "edit-error-recovery" | "omc-orchestrator";
|
|
300
341
|
export type AgentName = "omc" | "architect" | "researcher" | "explore" | "frontendEngineer" | "documentWriter" | "multimodalLooker" | "critic" | "analyst" | "planner" | "oracle" | "librarian" | "frontend-ui-ux-engineer" | "document-writer" | "multimodal-looker";
|
|
301
342
|
export declare function loadConfig(directory: string): OmoOmcsConfig;
|
package/dist/index.js
CHANGED
|
@@ -20592,6 +20592,14 @@ var AutopilotConfigSchema = exports_external.object({
|
|
|
20592
20592
|
maxPhaseRetries: exports_external.number().min(1).max(10).optional(),
|
|
20593
20593
|
delegationEnforcement: exports_external.enum(["strict", "warn", "off"]).optional()
|
|
20594
20594
|
});
|
|
20595
|
+
var CategoryConfigSchema = exports_external.object({
|
|
20596
|
+
model: exports_external.string().optional(),
|
|
20597
|
+
variant: exports_external.enum(["low", "medium", "high", "max", "xhigh"]).optional(),
|
|
20598
|
+
description: exports_external.string().optional(),
|
|
20599
|
+
prompt_append: exports_external.string().optional(),
|
|
20600
|
+
is_unstable_agent: exports_external.boolean().optional()
|
|
20601
|
+
});
|
|
20602
|
+
var CategoriesConfigSchema = exports_external.record(exports_external.string(), CategoryConfigSchema);
|
|
20595
20603
|
var UltraQAConfigSchema = exports_external.object({
|
|
20596
20604
|
enabled: exports_external.boolean().optional(),
|
|
20597
20605
|
maxIterations: exports_external.number().min(1).max(100).optional(),
|
|
@@ -20644,6 +20652,7 @@ var OmoOmcsConfigSchema = exports_external.object({
|
|
|
20644
20652
|
context_recovery: ContextRecoveryConfigSchema.optional(),
|
|
20645
20653
|
edit_error_recovery: EditErrorRecoveryConfigSchema.optional(),
|
|
20646
20654
|
tui_status: TuiStatusConfigSchema.optional(),
|
|
20655
|
+
categories: CategoriesConfigSchema.optional(),
|
|
20647
20656
|
omco_agent: exports_external.object({
|
|
20648
20657
|
disabled: exports_external.boolean().optional(),
|
|
20649
20658
|
planner_enabled: exports_external.boolean().optional(),
|
|
@@ -20674,16 +20683,16 @@ function loadConfig(directory) {
|
|
|
20674
20683
|
}
|
|
20675
20684
|
return {
|
|
20676
20685
|
agents: {
|
|
20677
|
-
omc: {
|
|
20678
|
-
architect: {
|
|
20679
|
-
researcher: {
|
|
20680
|
-
explore: {
|
|
20681
|
-
frontendEngineer: {
|
|
20682
|
-
documentWriter: {
|
|
20683
|
-
multimodalLooker: {
|
|
20684
|
-
critic: {
|
|
20685
|
-
analyst: {
|
|
20686
|
-
planner: {
|
|
20686
|
+
omc: { tier: "opus", enabled: true },
|
|
20687
|
+
architect: { tier: "opus", enabled: true },
|
|
20688
|
+
researcher: { tier: "sonnet", enabled: true },
|
|
20689
|
+
explore: { tier: "haiku", enabled: true },
|
|
20690
|
+
frontendEngineer: { tier: "sonnet", enabled: true },
|
|
20691
|
+
documentWriter: { tier: "haiku", enabled: true },
|
|
20692
|
+
multimodalLooker: { tier: "sonnet", enabled: true },
|
|
20693
|
+
critic: { tier: "opus", enabled: true },
|
|
20694
|
+
analyst: { tier: "opus", enabled: true },
|
|
20695
|
+
planner: { tier: "opus", enabled: true }
|
|
20687
20696
|
},
|
|
20688
20697
|
features: {
|
|
20689
20698
|
parallelExecution: true,
|
|
@@ -20714,11 +20723,6 @@ function loadConfig(directory) {
|
|
|
20714
20723
|
defaultTier: "MEDIUM",
|
|
20715
20724
|
escalationEnabled: true,
|
|
20716
20725
|
maxEscalations: 2,
|
|
20717
|
-
tierModels: {
|
|
20718
|
-
LOW: "github-copilot/claude-haiku-4",
|
|
20719
|
-
MEDIUM: "github-copilot/claude-sonnet-4",
|
|
20720
|
-
HIGH: "github-copilot/claude-opus-4"
|
|
20721
|
-
},
|
|
20722
20726
|
agentOverrides: {
|
|
20723
20727
|
architect: { tier: "HIGH", reason: "Advisory agent requires deep reasoning" },
|
|
20724
20728
|
planner: { tier: "HIGH", reason: "Strategic planning requires deep reasoning" },
|
|
@@ -20770,7 +20774,8 @@ function loadConfig(directory) {
|
|
|
20770
20774
|
},
|
|
20771
20775
|
omco_agent: {
|
|
20772
20776
|
disabled: false
|
|
20773
|
-
}
|
|
20777
|
+
},
|
|
20778
|
+
categories: {}
|
|
20774
20779
|
};
|
|
20775
20780
|
}
|
|
20776
20781
|
|
|
@@ -21873,6 +21878,29 @@ function createBackgroundManager(ctx, config2, modelService) {
|
|
|
21873
21878
|
}
|
|
21874
21879
|
return count;
|
|
21875
21880
|
};
|
|
21881
|
+
const detectConfiguredProvider = async () => {
|
|
21882
|
+
try {
|
|
21883
|
+
const providersResp = await ctx.client.provider.list({
|
|
21884
|
+
query: { directory: ctx.directory }
|
|
21885
|
+
});
|
|
21886
|
+
const providers = providersResp.data;
|
|
21887
|
+
for (const provider of providers || []) {
|
|
21888
|
+
if (provider.models && provider.models.length > 0) {
|
|
21889
|
+
const modelConfig = {
|
|
21890
|
+
providerID: provider.id,
|
|
21891
|
+
modelID: provider.models[0].id
|
|
21892
|
+
};
|
|
21893
|
+
log(`Detected configured provider as fallback`, { providerID: modelConfig.providerID, modelID: modelConfig.modelID });
|
|
21894
|
+
return modelConfig;
|
|
21895
|
+
}
|
|
21896
|
+
}
|
|
21897
|
+
log(`No configured providers found`);
|
|
21898
|
+
return;
|
|
21899
|
+
} catch (err) {
|
|
21900
|
+
log(`Failed to detect configured provider`, { error: String(err) });
|
|
21901
|
+
return;
|
|
21902
|
+
}
|
|
21903
|
+
};
|
|
21876
21904
|
const getParentSessionModel = async (parentSessionID) => {
|
|
21877
21905
|
if (modelCache.has(parentSessionID)) {
|
|
21878
21906
|
return modelCache.get(parentSessionID);
|
|
@@ -21894,11 +21922,17 @@ function createBackgroundManager(ctx, config2, modelService) {
|
|
|
21894
21922
|
return model;
|
|
21895
21923
|
}
|
|
21896
21924
|
log(`Parent session has no assistant messages with model info`, { parentSessionID });
|
|
21897
|
-
return;
|
|
21898
21925
|
} catch (err) {
|
|
21899
21926
|
log(`Failed to get parent session model`, { parentSessionID, error: String(err) });
|
|
21900
|
-
return;
|
|
21901
21927
|
}
|
|
21928
|
+
try {
|
|
21929
|
+
const configuredModel = await detectConfiguredProvider();
|
|
21930
|
+
if (configuredModel) {
|
|
21931
|
+
modelCache.set(parentSessionID, configuredModel);
|
|
21932
|
+
return configuredModel;
|
|
21933
|
+
}
|
|
21934
|
+
} catch {}
|
|
21935
|
+
return;
|
|
21902
21936
|
};
|
|
21903
21937
|
const createTask = async (parentSessionID, description, prompt, agent, model) => {
|
|
21904
21938
|
const runningCount = getRunningCount();
|
|
@@ -21906,109 +21940,127 @@ function createBackgroundManager(ctx, config2, modelService) {
|
|
|
21906
21940
|
throw new Error(`Max concurrent tasks (${defaultConcurrency}) reached. Wait for some to complete.`);
|
|
21907
21941
|
}
|
|
21908
21942
|
const taskId = generateTaskId();
|
|
21909
|
-
|
|
21910
|
-
|
|
21911
|
-
|
|
21912
|
-
|
|
21913
|
-
|
|
21914
|
-
|
|
21915
|
-
|
|
21916
|
-
|
|
21917
|
-
|
|
21918
|
-
|
|
21919
|
-
const resolvedModel = modelService ? modelService.resolveModelForAgent(agent, parentModel) : parentModel;
|
|
21920
|
-
if (resolvedModel && resolvedModel !== parentModel) {
|
|
21921
|
-
log(`[background-manager] Using tier-mapped model for ${agent}`, {
|
|
21922
|
-
providerID: resolvedModel.providerID,
|
|
21923
|
-
modelID: resolvedModel.modelID
|
|
21924
|
-
});
|
|
21925
|
-
}
|
|
21926
|
-
(async () => {
|
|
21927
|
-
try {
|
|
21928
|
-
const sessionResp = await ctx.client.session.create({
|
|
21929
|
-
body: {
|
|
21930
|
-
parentID: parentSessionID,
|
|
21931
|
-
title: `${agent}: ${description}`
|
|
21932
|
-
},
|
|
21933
|
-
query: { directory: ctx.directory }
|
|
21943
|
+
try {
|
|
21944
|
+
const parentModel = model || await getParentSessionModel(parentSessionID);
|
|
21945
|
+
const resolvedModel = modelService ? modelService.resolveModelForAgent(agent, parentModel) : parentModel;
|
|
21946
|
+
if (!resolvedModel) {
|
|
21947
|
+
throw new Error(`[OMCO] No model available for agent "${agent}". ` + `Configure tier mapping with 'npx omco-setup'.`);
|
|
21948
|
+
}
|
|
21949
|
+
if (resolvedModel !== parentModel) {
|
|
21950
|
+
log(`[background-manager] Using tier-mapped model for ${agent}`, {
|
|
21951
|
+
providerID: resolvedModel.providerID,
|
|
21952
|
+
modelID: resolvedModel.modelID
|
|
21934
21953
|
});
|
|
21935
|
-
|
|
21936
|
-
|
|
21937
|
-
|
|
21938
|
-
|
|
21939
|
-
|
|
21940
|
-
|
|
21941
|
-
|
|
21942
|
-
|
|
21954
|
+
}
|
|
21955
|
+
const task = {
|
|
21956
|
+
id: taskId,
|
|
21957
|
+
status: "running",
|
|
21958
|
+
description,
|
|
21959
|
+
parentSessionID,
|
|
21960
|
+
startedAt: Date.now()
|
|
21961
|
+
};
|
|
21962
|
+
tasks.set(taskId, task);
|
|
21963
|
+
log(`Background task created`, { taskId, description, agent });
|
|
21964
|
+
(async () => {
|
|
21965
|
+
try {
|
|
21966
|
+
const sessionResp = await ctx.client.session.create({
|
|
21967
|
+
body: {
|
|
21968
|
+
parentID: parentSessionID,
|
|
21969
|
+
title: `${agent}: ${description}`
|
|
21970
|
+
},
|
|
21971
|
+
query: { directory: ctx.directory }
|
|
21972
|
+
});
|
|
21973
|
+
const sessionID = sessionResp.data?.id ?? sessionResp.id;
|
|
21974
|
+
if (!sessionID)
|
|
21975
|
+
throw new Error("Failed to create session");
|
|
21976
|
+
task.sessionID = sessionID;
|
|
21977
|
+
const canonicalName = isAlias(agent) ? getCanonicalName(agent) : agent;
|
|
21978
|
+
const agentDef = getAgent(canonicalName);
|
|
21979
|
+
const systemPrompt = agentDef?.systemPrompt || "";
|
|
21980
|
+
const fullPrompt = systemPrompt ? `${systemPrompt}
|
|
21943
21981
|
|
|
21944
21982
|
${prompt}` : prompt;
|
|
21945
|
-
|
|
21946
|
-
|
|
21947
|
-
|
|
21948
|
-
|
|
21949
|
-
|
|
21950
|
-
|
|
21951
|
-
|
|
21952
|
-
|
|
21953
|
-
|
|
21954
|
-
|
|
21955
|
-
|
|
21956
|
-
|
|
21957
|
-
|
|
21958
|
-
|
|
21959
|
-
|
|
21960
|
-
|
|
21961
|
-
|
|
21962
|
-
|
|
21963
|
-
|
|
21964
|
-
|
|
21965
|
-
|
|
21966
|
-
|
|
21967
|
-
|
|
21968
|
-
|
|
21969
|
-
|
|
21970
|
-
|
|
21971
|
-
|
|
21972
|
-
|
|
21973
|
-
|
|
21974
|
-
|
|
21975
|
-
|
|
21976
|
-
|
|
21977
|
-
|
|
21978
|
-
|
|
21979
|
-
|
|
21983
|
+
const promptBody = {
|
|
21984
|
+
parts: [{ type: "text", text: fullPrompt }]
|
|
21985
|
+
};
|
|
21986
|
+
if (resolvedModel) {
|
|
21987
|
+
promptBody.model = resolvedModel;
|
|
21988
|
+
log(`Using model for subagent`, { taskId, ...resolvedModel });
|
|
21989
|
+
}
|
|
21990
|
+
let promptResp = await ctx.client.session.prompt({
|
|
21991
|
+
path: { id: sessionID },
|
|
21992
|
+
body: promptBody,
|
|
21993
|
+
query: { directory: ctx.directory }
|
|
21994
|
+
});
|
|
21995
|
+
let promptData = promptResp.data;
|
|
21996
|
+
if (promptResp.error) {
|
|
21997
|
+
throw new Error(`Prompt failed: ${JSON.stringify(promptResp.error)}`);
|
|
21998
|
+
}
|
|
21999
|
+
if (promptData?.info?.error) {
|
|
22000
|
+
const err = promptData.info.error;
|
|
22001
|
+
const isModelError = err.name === "ProviderModelNotFoundError" || err.name === "ProviderNotFoundError" || err.name?.includes("Model") || err.name?.includes("Provider");
|
|
22002
|
+
if (isModelError && parentModel && resolvedModel !== parentModel) {
|
|
22003
|
+
log(`[background-manager] Model error with tier-mapped model, retrying with parent session model`, {
|
|
22004
|
+
taskId,
|
|
22005
|
+
error: err.name,
|
|
22006
|
+
failedModel: resolvedModel,
|
|
22007
|
+
fallbackModel: parentModel
|
|
22008
|
+
});
|
|
22009
|
+
promptBody.model = parentModel;
|
|
22010
|
+
promptResp = await ctx.client.session.prompt({
|
|
22011
|
+
path: { id: sessionID },
|
|
22012
|
+
body: promptBody,
|
|
22013
|
+
query: { directory: ctx.directory }
|
|
22014
|
+
});
|
|
22015
|
+
promptData = promptResp.data;
|
|
22016
|
+
if (promptResp.error) {
|
|
22017
|
+
throw new Error(`Prompt failed after retry: ${JSON.stringify(promptResp.error)}`);
|
|
22018
|
+
}
|
|
21980
22019
|
}
|
|
21981
22020
|
}
|
|
21982
|
-
|
|
21983
|
-
|
|
21984
|
-
|
|
21985
|
-
|
|
21986
|
-
throw new Error(`[${err.name}] ${errMsg}`);
|
|
21987
|
-
}
|
|
21988
|
-
const result = promptData?.parts?.filter((p) => p.type === "text" && p.text).map((p) => p.text).join(`
|
|
21989
|
-
`) || "";
|
|
21990
|
-
task.result = result;
|
|
21991
|
-
task.status = "completed";
|
|
21992
|
-
task.completedAt = Date.now();
|
|
21993
|
-
log(`Background task completed`, { taskId, duration: task.completedAt - task.startedAt });
|
|
21994
|
-
ctx.client.tui.showToast({
|
|
21995
|
-
body: {
|
|
21996
|
-
title: "Background Task Completed",
|
|
21997
|
-
message: `${description.substring(0, 40)}...`,
|
|
21998
|
-
variant: "success",
|
|
21999
|
-
duration: 3000
|
|
22021
|
+
if (promptData?.info?.error) {
|
|
22022
|
+
const err = promptData.info.error;
|
|
22023
|
+
const errMsg = err.data?.message || err.name || "Unknown error";
|
|
22024
|
+
throw new Error(`[${err.name}] ${errMsg}`);
|
|
22000
22025
|
}
|
|
22001
|
-
|
|
22002
|
-
|
|
22003
|
-
|
|
22004
|
-
|
|
22005
|
-
|
|
22006
|
-
|
|
22007
|
-
|
|
22008
|
-
|
|
22009
|
-
|
|
22010
|
-
|
|
22011
|
-
|
|
22026
|
+
const result = promptData?.parts?.filter((p) => p.type === "text" && p.text).map((p) => p.text).join(`
|
|
22027
|
+
`) || "";
|
|
22028
|
+
task.result = result;
|
|
22029
|
+
task.status = "completed";
|
|
22030
|
+
task.completedAt = Date.now();
|
|
22031
|
+
log(`Background task completed`, { taskId, duration: task.completedAt - task.startedAt });
|
|
22032
|
+
ctx.client.tui.showToast({
|
|
22033
|
+
body: {
|
|
22034
|
+
title: "Background Task Completed",
|
|
22035
|
+
message: `${description.substring(0, 40)}...`,
|
|
22036
|
+
variant: "success",
|
|
22037
|
+
duration: 3000
|
|
22038
|
+
}
|
|
22039
|
+
}).catch((err) => {
|
|
22040
|
+
log(`Toast notification failed`, { taskId, error: String(err) });
|
|
22041
|
+
});
|
|
22042
|
+
} catch (err) {
|
|
22043
|
+
task.status = "failed";
|
|
22044
|
+
task.error = String(err);
|
|
22045
|
+
task.completedAt = Date.now();
|
|
22046
|
+
log(`Background task failed`, { taskId, error: task.error });
|
|
22047
|
+
}
|
|
22048
|
+
})();
|
|
22049
|
+
return task;
|
|
22050
|
+
} catch (err) {
|
|
22051
|
+
const failedTask = {
|
|
22052
|
+
id: taskId,
|
|
22053
|
+
status: "failed",
|
|
22054
|
+
description,
|
|
22055
|
+
parentSessionID,
|
|
22056
|
+
error: String(err),
|
|
22057
|
+
startedAt: Date.now(),
|
|
22058
|
+
completedAt: Date.now()
|
|
22059
|
+
};
|
|
22060
|
+
tasks.set(taskId, failedTask);
|
|
22061
|
+
log(`Background task failed during creation`, { taskId, error: String(err) });
|
|
22062
|
+
return failedTask;
|
|
22063
|
+
}
|
|
22012
22064
|
};
|
|
22013
22065
|
const getTask = (taskId) => {
|
|
22014
22066
|
return tasks.get(taskId);
|
|
@@ -34475,14 +34527,243 @@ Use \`background_output\` to get results. Prompts MUST be in English.`,
|
|
|
34475
34527
|
};
|
|
34476
34528
|
}
|
|
34477
34529
|
|
|
34530
|
+
// src/categories/constants.ts
|
|
34531
|
+
var VISUAL_CATEGORY_PROMPT_APPEND = `<Category_Context>
|
|
34532
|
+
You are working on VISUAL/UI tasks.
|
|
34533
|
+
|
|
34534
|
+
Design-first mindset:
|
|
34535
|
+
- Bold aesthetic choices over safe defaults
|
|
34536
|
+
- Unexpected layouts, asymmetry, grid-breaking elements
|
|
34537
|
+
- Distinctive typography (avoid: Arial, Inter, Roboto, Space Grotesk)
|
|
34538
|
+
- Cohesive color palettes with sharp accents
|
|
34539
|
+
- High-impact animations with staggered reveals
|
|
34540
|
+
- Atmosphere: gradient meshes, noise textures, layered transparencies
|
|
34541
|
+
|
|
34542
|
+
AVOID: Generic fonts, purple gradients on white, predictable layouts, cookie-cutter patterns.
|
|
34543
|
+
</Category_Context>`;
|
|
34544
|
+
var ULTRABRAIN_CATEGORY_PROMPT_APPEND = `<Category_Context>
|
|
34545
|
+
You are working on COMPLEX ARCHITECTURE / DEEP REASONING tasks.
|
|
34546
|
+
|
|
34547
|
+
Strategic advisor mindset:
|
|
34548
|
+
- Bias toward simplicity: least complex solution that fulfills requirements
|
|
34549
|
+
- Leverage existing code/patterns over new components
|
|
34550
|
+
- Prioritize developer experience and maintainability
|
|
34551
|
+
- One clear recommendation with effort estimate (Quick/Short/Medium/Large)
|
|
34552
|
+
- Signal when advanced approach warranted
|
|
34553
|
+
|
|
34554
|
+
Response format:
|
|
34555
|
+
- Bottom line (2-3 sentences)
|
|
34556
|
+
- Action plan (numbered steps)
|
|
34557
|
+
- Risks and mitigations (if relevant)
|
|
34558
|
+
</Category_Context>`;
|
|
34559
|
+
var ARTISTRY_CATEGORY_PROMPT_APPEND = `<Category_Context>
|
|
34560
|
+
You are working on HIGHLY CREATIVE / ARTISTIC tasks.
|
|
34561
|
+
|
|
34562
|
+
Artistic genius mindset:
|
|
34563
|
+
- Push far beyond conventional boundaries
|
|
34564
|
+
- Explore radical, unconventional directions
|
|
34565
|
+
- Surprise and delight: unexpected twists, novel combinations
|
|
34566
|
+
- Rich detail and vivid expression
|
|
34567
|
+
- Break patterns deliberately when it serves the creative vision
|
|
34568
|
+
|
|
34569
|
+
Approach:
|
|
34570
|
+
- Generate diverse, bold options first
|
|
34571
|
+
- Embrace ambiguity and wild experimentation
|
|
34572
|
+
- Balance novelty with coherence
|
|
34573
|
+
- This is for tasks requiring exceptional creativity
|
|
34574
|
+
</Category_Context>`;
|
|
34575
|
+
var QUICK_CATEGORY_PROMPT_APPEND = `<Category_Context>
|
|
34576
|
+
You are working on SMALL / QUICK tasks.
|
|
34577
|
+
|
|
34578
|
+
Efficient execution mindset:
|
|
34579
|
+
- Fast, focused, minimal overhead
|
|
34580
|
+
- Get to the point immediately
|
|
34581
|
+
- No over-engineering
|
|
34582
|
+
- Simple solutions for simple problems
|
|
34583
|
+
|
|
34584
|
+
Approach:
|
|
34585
|
+
- Minimal viable implementation
|
|
34586
|
+
- Skip unnecessary abstractions
|
|
34587
|
+
- Direct and concise
|
|
34588
|
+
</Category_Context>
|
|
34589
|
+
|
|
34590
|
+
<Caller_Warning>
|
|
34591
|
+
THIS CATEGORY USES A LESS CAPABLE MODEL (haiku tier).
|
|
34592
|
+
|
|
34593
|
+
The model executing this task has LIMITED reasoning capacity. Your prompt MUST be:
|
|
34594
|
+
|
|
34595
|
+
**EXHAUSTIVELY EXPLICIT** - Leave NOTHING to interpretation:
|
|
34596
|
+
1. MUST DO: List every required action as atomic, numbered steps
|
|
34597
|
+
2. MUST NOT DO: Explicitly forbid likely mistakes and deviations
|
|
34598
|
+
3. EXPECTED OUTPUT: Describe exact success criteria with concrete examples
|
|
34599
|
+
|
|
34600
|
+
**WHY THIS MATTERS:**
|
|
34601
|
+
- Less capable models WILL deviate without explicit guardrails
|
|
34602
|
+
- Vague instructions \u2192 unpredictable results
|
|
34603
|
+
- Implicit expectations \u2192 missed requirements
|
|
34604
|
+
|
|
34605
|
+
**PROMPT STRUCTURE (MANDATORY):**
|
|
34606
|
+
\`\`\`
|
|
34607
|
+
TASK: [One-sentence goal]
|
|
34608
|
+
|
|
34609
|
+
MUST DO:
|
|
34610
|
+
1. [Specific action with exact details]
|
|
34611
|
+
2. [Another specific action]
|
|
34612
|
+
...
|
|
34613
|
+
|
|
34614
|
+
MUST NOT DO:
|
|
34615
|
+
- [Forbidden action + why]
|
|
34616
|
+
- [Another forbidden action]
|
|
34617
|
+
...
|
|
34618
|
+
|
|
34619
|
+
EXPECTED OUTPUT:
|
|
34620
|
+
- [Exact deliverable description]
|
|
34621
|
+
- [Success criteria / verification method]
|
|
34622
|
+
\`\`\`
|
|
34623
|
+
|
|
34624
|
+
If your prompt lacks this structure, REWRITE IT before delegating.
|
|
34625
|
+
</Caller_Warning>`;
|
|
34626
|
+
var UNSPECIFIED_LOW_CATEGORY_PROMPT_APPEND = `<Category_Context>
|
|
34627
|
+
You are working on tasks that don't fit specific categories but require moderate effort.
|
|
34628
|
+
|
|
34629
|
+
<Selection_Gate>
|
|
34630
|
+
BEFORE selecting this category, VERIFY ALL conditions:
|
|
34631
|
+
1. Task does NOT fit: quick (trivial), visual-engineering (UI), ultrabrain (deep logic), artistry (creative), writing (docs)
|
|
34632
|
+
2. Task requires more than trivial effort but is NOT system-wide
|
|
34633
|
+
3. Scope is contained within a few files/modules
|
|
34634
|
+
|
|
34635
|
+
If task fits ANY other category, DO NOT select unspecified-low.
|
|
34636
|
+
This is NOT a default choice - it's for genuinely unclassifiable moderate-effort work.
|
|
34637
|
+
</Selection_Gate>
|
|
34638
|
+
</Category_Context>
|
|
34639
|
+
|
|
34640
|
+
<Caller_Warning>
|
|
34641
|
+
THIS CATEGORY USES A MID-TIER MODEL (sonnet tier).
|
|
34642
|
+
|
|
34643
|
+
**PROVIDE CLEAR STRUCTURE:**
|
|
34644
|
+
1. MUST DO: Enumerate required actions explicitly
|
|
34645
|
+
2. MUST NOT DO: State forbidden actions to prevent scope creep
|
|
34646
|
+
3. EXPECTED OUTPUT: Define concrete success criteria
|
|
34647
|
+
</Caller_Warning>`;
|
|
34648
|
+
var UNSPECIFIED_HIGH_CATEGORY_PROMPT_APPEND = `<Category_Context>
|
|
34649
|
+
You are working on tasks that don't fit specific categories but require substantial effort.
|
|
34650
|
+
|
|
34651
|
+
<Selection_Gate>
|
|
34652
|
+
BEFORE selecting this category, VERIFY ALL conditions:
|
|
34653
|
+
1. Task does NOT fit: quick (trivial), visual-engineering (UI), ultrabrain (deep logic), artistry (creative), writing (docs)
|
|
34654
|
+
2. Task requires substantial effort across multiple systems/modules
|
|
34655
|
+
3. Changes have broad impact or require careful coordination
|
|
34656
|
+
4. NOT just "complex" - must be genuinely unclassifiable AND high-effort
|
|
34657
|
+
|
|
34658
|
+
If task fits ANY other category, DO NOT select unspecified-high.
|
|
34659
|
+
If task is unclassifiable but moderate-effort, use unspecified-low instead.
|
|
34660
|
+
</Selection_Gate>
|
|
34661
|
+
</Category_Context>`;
|
|
34662
|
+
var WRITING_CATEGORY_PROMPT_APPEND = `<Category_Context>
|
|
34663
|
+
You are working on WRITING / PROSE tasks.
|
|
34664
|
+
|
|
34665
|
+
Wordsmith mindset:
|
|
34666
|
+
- Clear, flowing prose
|
|
34667
|
+
- Appropriate tone and voice
|
|
34668
|
+
- Engaging and readable
|
|
34669
|
+
- Proper structure and organization
|
|
34670
|
+
|
|
34671
|
+
Approach:
|
|
34672
|
+
- Understand the audience
|
|
34673
|
+
- Draft with care
|
|
34674
|
+
- Polish for clarity and impact
|
|
34675
|
+
- Documentation, READMEs, articles, technical writing
|
|
34676
|
+
</Category_Context>`;
|
|
34677
|
+
var DEFAULT_CATEGORIES = {
|
|
34678
|
+
"visual-engineering": {
|
|
34679
|
+
model: "opus",
|
|
34680
|
+
description: "Frontend, UI/UX, design, styling, animation"
|
|
34681
|
+
},
|
|
34682
|
+
ultrabrain: {
|
|
34683
|
+
model: "opus",
|
|
34684
|
+
variant: "high",
|
|
34685
|
+
description: "Deep logical reasoning, complex architecture decisions requiring extensive analysis"
|
|
34686
|
+
},
|
|
34687
|
+
artistry: {
|
|
34688
|
+
model: "opus",
|
|
34689
|
+
variant: "max",
|
|
34690
|
+
description: "Highly creative/artistic tasks, novel ideas"
|
|
34691
|
+
},
|
|
34692
|
+
quick: {
|
|
34693
|
+
model: "haiku",
|
|
34694
|
+
description: "Trivial tasks - single file changes, typo fixes, simple modifications"
|
|
34695
|
+
},
|
|
34696
|
+
"unspecified-low": {
|
|
34697
|
+
model: "sonnet",
|
|
34698
|
+
description: "Tasks that don't fit other categories, moderate effort required"
|
|
34699
|
+
},
|
|
34700
|
+
"unspecified-high": {
|
|
34701
|
+
model: "opus",
|
|
34702
|
+
variant: "max",
|
|
34703
|
+
description: "Tasks that don't fit other categories, high effort required"
|
|
34704
|
+
},
|
|
34705
|
+
writing: {
|
|
34706
|
+
model: "sonnet",
|
|
34707
|
+
description: "Documentation, prose, technical writing"
|
|
34708
|
+
}
|
|
34709
|
+
};
|
|
34710
|
+
var CATEGORY_PROMPT_APPENDS = {
|
|
34711
|
+
"visual-engineering": VISUAL_CATEGORY_PROMPT_APPEND,
|
|
34712
|
+
ultrabrain: ULTRABRAIN_CATEGORY_PROMPT_APPEND,
|
|
34713
|
+
artistry: ARTISTRY_CATEGORY_PROMPT_APPEND,
|
|
34714
|
+
quick: QUICK_CATEGORY_PROMPT_APPEND,
|
|
34715
|
+
"unspecified-low": UNSPECIFIED_LOW_CATEGORY_PROMPT_APPEND,
|
|
34716
|
+
"unspecified-high": UNSPECIFIED_HIGH_CATEGORY_PROMPT_APPEND,
|
|
34717
|
+
writing: WRITING_CATEGORY_PROMPT_APPEND
|
|
34718
|
+
};
|
|
34719
|
+
var CATEGORY_DESCRIPTIONS = {
|
|
34720
|
+
"visual-engineering": "Frontend, UI/UX, design, styling, animation",
|
|
34721
|
+
ultrabrain: "Deep logical reasoning, complex architecture decisions requiring extensive analysis",
|
|
34722
|
+
artistry: "Highly creative/artistic tasks, novel ideas",
|
|
34723
|
+
quick: "Trivial tasks - single file changes, typo fixes, simple modifications",
|
|
34724
|
+
"unspecified-low": "Tasks that don't fit other categories, moderate effort required",
|
|
34725
|
+
"unspecified-high": "Tasks that don't fit other categories, high effort required",
|
|
34726
|
+
writing: "Documentation, prose, technical writing"
|
|
34727
|
+
};
|
|
34728
|
+
// src/categories/resolver.ts
|
|
34729
|
+
function resolveCategoryConfig(categoryName, userCategories) {
|
|
34730
|
+
const defaultConfig = DEFAULT_CATEGORIES[categoryName];
|
|
34731
|
+
const userConfig = userCategories?.[categoryName];
|
|
34732
|
+
const defaultPromptAppend = CATEGORY_PROMPT_APPENDS[categoryName] ?? "";
|
|
34733
|
+
if (!defaultConfig && !userConfig) {
|
|
34734
|
+
return null;
|
|
34735
|
+
}
|
|
34736
|
+
const config3 = {
|
|
34737
|
+
...defaultConfig,
|
|
34738
|
+
...userConfig
|
|
34739
|
+
};
|
|
34740
|
+
const tier = config3.model ?? "sonnet";
|
|
34741
|
+
let promptAppend = defaultPromptAppend;
|
|
34742
|
+
if (userConfig?.prompt_append) {
|
|
34743
|
+
promptAppend = defaultPromptAppend ? defaultPromptAppend + `
|
|
34744
|
+
|
|
34745
|
+
` + userConfig.prompt_append : userConfig.prompt_append;
|
|
34746
|
+
}
|
|
34747
|
+
return { config: config3, promptAppend, tier };
|
|
34748
|
+
}
|
|
34749
|
+
function getAvailableCategories(userCategories) {
|
|
34750
|
+
const allCategories = { ...DEFAULT_CATEGORIES, ...userCategories };
|
|
34751
|
+
return Object.keys(allCategories);
|
|
34752
|
+
}
|
|
34478
34753
|
// src/tools/call-omco-agent.ts
|
|
34479
|
-
function createCallOmcoAgent(ctx, manager, modelService) {
|
|
34754
|
+
function createCallOmcoAgent(ctx, manager, modelService, userCategories) {
|
|
34480
34755
|
const agentNames = listAgentNames();
|
|
34481
34756
|
const agentList = agentNames.map((name) => {
|
|
34482
34757
|
const agent = getAgent(name);
|
|
34483
34758
|
const aliasNote = isAlias(name) ? ` (alias for ${getCanonicalName(name)})` : "";
|
|
34484
34759
|
return `- ${name}${aliasNote}: ${agent?.description || "Agent"}`;
|
|
34485
34760
|
}).join(`
|
|
34761
|
+
`);
|
|
34762
|
+
const categoryNames = getAvailableCategories(userCategories);
|
|
34763
|
+
const categoryList = categoryNames.map((name) => {
|
|
34764
|
+
const desc = CATEGORY_DESCRIPTIONS[name] || userCategories?.[name]?.description || "Category";
|
|
34765
|
+
return `- ${name}: ${desc}`;
|
|
34766
|
+
}).join(`
|
|
34486
34767
|
`);
|
|
34487
34768
|
return tool({
|
|
34488
34769
|
description: `Spawn specialized agent for delegation. run_in_background REQUIRED (true=async with task_id, false=sync).
|
|
@@ -34490,38 +34771,119 @@ function createCallOmcoAgent(ctx, manager, modelService) {
|
|
|
34490
34771
|
Available agents:
|
|
34491
34772
|
${agentList}
|
|
34492
34773
|
|
|
34774
|
+
Available categories:
|
|
34775
|
+
${categoryList}
|
|
34776
|
+
|
|
34493
34777
|
Prompts MUST be in English. Use \`background_output\` for async results.`,
|
|
34494
34778
|
args: {
|
|
34495
34779
|
description: tool.schema.string().describe("Short description of task"),
|
|
34496
34780
|
prompt: tool.schema.string().describe("Task prompt"),
|
|
34497
|
-
subagent_type: tool.schema.string().describe(`Agent type to spawn. Available: ${agentNames.join(", ")}`),
|
|
34781
|
+
subagent_type: tool.schema.string().optional().describe(`Agent type to spawn. Available: ${agentNames.join(", ")}`),
|
|
34782
|
+
category: tool.schema.string().optional().describe(`Category for delegation (e.g., 'quick', 'visual-engineering', 'ultrabrain'). Mutually exclusive with subagent_type.`),
|
|
34498
34783
|
run_in_background: tool.schema.boolean().describe("Run async (true) or sync (false)"),
|
|
34499
34784
|
session_id: tool.schema.string().optional().describe("Existing session to continue")
|
|
34500
34785
|
},
|
|
34501
34786
|
async execute(args, context) {
|
|
34502
|
-
const { description, prompt, subagent_type, run_in_background } = args;
|
|
34503
|
-
|
|
34504
|
-
|
|
34787
|
+
const { description, prompt, subagent_type, category, run_in_background } = args;
|
|
34788
|
+
if (subagent_type && category) {
|
|
34789
|
+
return JSON.stringify({
|
|
34790
|
+
status: "failed",
|
|
34791
|
+
error: "subagent_type and category are mutually exclusive. Provide only one."
|
|
34792
|
+
});
|
|
34793
|
+
}
|
|
34794
|
+
if (!subagent_type && !category) {
|
|
34505
34795
|
return JSON.stringify({
|
|
34506
34796
|
status: "failed",
|
|
34507
|
-
error:
|
|
34797
|
+
error: "Either subagent_type or category must be provided."
|
|
34508
34798
|
});
|
|
34509
34799
|
}
|
|
34510
|
-
|
|
34800
|
+
let enhancedPrompt;
|
|
34801
|
+
let tierForResolution;
|
|
34802
|
+
let agentTypeForLogging;
|
|
34803
|
+
if (category) {
|
|
34804
|
+
const resolved = resolveCategoryConfig(category, userCategories);
|
|
34805
|
+
if (!resolved) {
|
|
34806
|
+
return JSON.stringify({
|
|
34807
|
+
status: "failed",
|
|
34808
|
+
error: `Unknown category: ${category}. Available: ${getAvailableCategories(userCategories).join(", ")}`
|
|
34809
|
+
});
|
|
34810
|
+
}
|
|
34811
|
+
enhancedPrompt = resolved.promptAppend ? `${resolved.promptAppend}
|
|
34812
|
+
|
|
34813
|
+
---
|
|
34814
|
+
|
|
34815
|
+
${prompt}` : prompt;
|
|
34816
|
+
tierForResolution = resolved.tier;
|
|
34817
|
+
agentTypeForLogging = `category:${category}`;
|
|
34818
|
+
log(`[call-omco-agent] Using category delegation`, { category, tier: tierForResolution });
|
|
34819
|
+
} else {
|
|
34820
|
+
const agent = getAgent(subagent_type);
|
|
34821
|
+
if (!agent) {
|
|
34822
|
+
return JSON.stringify({
|
|
34823
|
+
status: "failed",
|
|
34824
|
+
error: `Unknown agent type: ${subagent_type}. Available: ${listAgentNames().join(", ")}`
|
|
34825
|
+
});
|
|
34826
|
+
}
|
|
34827
|
+
enhancedPrompt = `${agent.systemPrompt}
|
|
34511
34828
|
|
|
34512
34829
|
---
|
|
34513
34830
|
|
|
34514
34831
|
${prompt}`;
|
|
34832
|
+
agentTypeForLogging = subagent_type;
|
|
34833
|
+
}
|
|
34515
34834
|
const parentModel = await manager.getParentSessionModel(context.sessionID);
|
|
34516
|
-
|
|
34517
|
-
if (
|
|
34518
|
-
|
|
34519
|
-
|
|
34520
|
-
|
|
34521
|
-
|
|
34835
|
+
let resolvedModel = parentModel;
|
|
34836
|
+
if (modelService) {
|
|
34837
|
+
try {
|
|
34838
|
+
if (category && tierForResolution) {
|
|
34839
|
+
const categoryModel = modelService.resolveModelForCategory(tierForResolution, parentModel);
|
|
34840
|
+
if (categoryModel) {
|
|
34841
|
+
resolvedModel = categoryModel;
|
|
34842
|
+
if (resolvedModel && resolvedModel !== parentModel) {
|
|
34843
|
+
log(`[call-omco-agent] Using tier-mapped model for category ${category}`, {
|
|
34844
|
+
tier: tierForResolution,
|
|
34845
|
+
providerID: resolvedModel.providerID,
|
|
34846
|
+
modelID: resolvedModel.modelID
|
|
34847
|
+
});
|
|
34848
|
+
}
|
|
34849
|
+
} else if (!parentModel) {
|
|
34850
|
+
const errorMsg = `[OMCO] Cannot resolve model for category "${category}" (tier: ${tierForResolution}).
|
|
34851
|
+
|
|
34852
|
+
` + `No tier mapping configured. Run one of:
|
|
34853
|
+
` + ` 1. npx omco-setup (interactive setup)
|
|
34854
|
+
` + ` 2. Add tierDefaults to ~/.config/opencode/omco.json:
|
|
34855
|
+
` + ` {
|
|
34856
|
+
` + ` "model_mapping": {
|
|
34857
|
+
` + ` "tierDefaults": {
|
|
34858
|
+
` + ` "haiku": "openai/gpt-4o-mini",
|
|
34859
|
+
` + ` "sonnet": "openai/gpt-4o",
|
|
34860
|
+
` + ` "opus": "openai/o1"
|
|
34861
|
+
` + ` }
|
|
34862
|
+
` + ` }
|
|
34863
|
+
` + ` }`;
|
|
34864
|
+
return JSON.stringify({
|
|
34865
|
+
status: "failed",
|
|
34866
|
+
error: errorMsg
|
|
34867
|
+
});
|
|
34868
|
+
}
|
|
34869
|
+
} else if (subagent_type) {
|
|
34870
|
+
resolvedModel = modelService.resolveModelForAgentOrThrow(subagent_type, parentModel);
|
|
34871
|
+
if (resolvedModel && resolvedModel !== parentModel) {
|
|
34872
|
+
log(`[call-omco-agent] Using tier-mapped model for ${subagent_type}`, {
|
|
34873
|
+
providerID: resolvedModel.providerID,
|
|
34874
|
+
modelID: resolvedModel.modelID
|
|
34875
|
+
});
|
|
34876
|
+
}
|
|
34877
|
+
}
|
|
34878
|
+
} catch (err) {
|
|
34879
|
+
return JSON.stringify({
|
|
34880
|
+
status: "failed",
|
|
34881
|
+
error: err instanceof Error ? err.message : String(err)
|
|
34882
|
+
});
|
|
34883
|
+
}
|
|
34522
34884
|
}
|
|
34523
34885
|
if (run_in_background) {
|
|
34524
|
-
const task = await manager.createTask(context.sessionID, description, enhancedPrompt,
|
|
34886
|
+
const task = await manager.createTask(context.sessionID, description, enhancedPrompt, agentTypeForLogging, resolvedModel);
|
|
34525
34887
|
return JSON.stringify({
|
|
34526
34888
|
task_id: task.id,
|
|
34527
34889
|
session_id: task.sessionID,
|
|
@@ -34533,7 +34895,7 @@ ${prompt}`;
|
|
|
34533
34895
|
const sessionResp = await ctx.client.session.create({
|
|
34534
34896
|
body: {
|
|
34535
34897
|
parentID: context.sessionID,
|
|
34536
|
-
title: `${
|
|
34898
|
+
title: `${agentTypeForLogging}: ${description}`
|
|
34537
34899
|
},
|
|
34538
34900
|
query: { directory: ctx.directory }
|
|
34539
34901
|
});
|
|
@@ -34545,7 +34907,7 @@ ${prompt}`;
|
|
|
34545
34907
|
};
|
|
34546
34908
|
if (resolvedModel) {
|
|
34547
34909
|
promptBody.model = resolvedModel;
|
|
34548
|
-
log(`Using resolved model for sync agent call`, {
|
|
34910
|
+
log(`Using resolved model for sync agent call`, { agentType: agentTypeForLogging, ...resolvedModel });
|
|
34549
34911
|
}
|
|
34550
34912
|
let promptResp = await ctx.client.session.prompt({
|
|
34551
34913
|
path: { id: sessionID },
|
|
@@ -34735,12 +35097,64 @@ function createModelResolutionService(modelMappingConfig, agentOverrides) {
|
|
|
34735
35097
|
}
|
|
34736
35098
|
return fallbackModel;
|
|
34737
35099
|
};
|
|
35100
|
+
const resolveModelForAgentOrThrow = (agentName, fallbackModel) => {
|
|
35101
|
+
const result = resolveModelForAgent(agentName, fallbackModel);
|
|
35102
|
+
if (result)
|
|
35103
|
+
return result;
|
|
35104
|
+
const tierDefaults2 = resolver.getTierDefaults();
|
|
35105
|
+
const hasConfiguredTiers2 = Object.values(tierDefaults2).some((m) => m.includes("/"));
|
|
35106
|
+
let errorMessage = `[OMCO] Cannot resolve model for agent "${agentName}".`;
|
|
35107
|
+
if (!hasConfiguredTiers2) {
|
|
35108
|
+
errorMessage += `
|
|
35109
|
+
|
|
35110
|
+
No tier mapping configured. Run one of:
|
|
35111
|
+
` + ` 1. npx omco-setup (interactive setup)
|
|
35112
|
+
` + ` 2. Add tierDefaults to ~/.config/opencode/omco.json:
|
|
35113
|
+
` + ` {
|
|
35114
|
+
` + ` "model_mapping": {
|
|
35115
|
+
` + ` "tierDefaults": {
|
|
35116
|
+
` + ` "haiku": "openai/gpt-4o-mini",
|
|
35117
|
+
` + ` "sonnet": "openai/gpt-4o",
|
|
35118
|
+
` + ` "opus": "openai/o1"
|
|
35119
|
+
` + ` }
|
|
35120
|
+
` + ` }
|
|
35121
|
+
` + ` }`;
|
|
35122
|
+
} else {
|
|
35123
|
+
errorMessage += `
|
|
35124
|
+
|
|
35125
|
+
Tier mapping is configured but no fallback model available.
|
|
35126
|
+
` + `This usually means the parent session hasn't started yet.
|
|
35127
|
+
` + `Try sending a message first to establish the session model.`;
|
|
35128
|
+
}
|
|
35129
|
+
throw new Error(errorMessage);
|
|
35130
|
+
};
|
|
34738
35131
|
const isTierMappingConfigured = () => {
|
|
34739
35132
|
return hasConfiguredTiers;
|
|
34740
35133
|
};
|
|
35134
|
+
const resolveModelForCategory = (categoryTier, fallbackModel) => {
|
|
35135
|
+
const tierDefaults2 = resolver.getTierDefaults();
|
|
35136
|
+
const mappedModel = tierDefaults2[categoryTier];
|
|
35137
|
+
if (mappedModel) {
|
|
35138
|
+
const modelConfig = parseModelString(mappedModel);
|
|
35139
|
+
if (modelConfig) {
|
|
35140
|
+
if (debugLogging) {
|
|
35141
|
+
log(`[model-resolution] Resolved category tier "${categoryTier}": ${mappedModel}`);
|
|
35142
|
+
}
|
|
35143
|
+
return modelConfig;
|
|
35144
|
+
}
|
|
35145
|
+
}
|
|
35146
|
+
if (debugLogging) {
|
|
35147
|
+
log(`[model-resolution] No mapping for category tier "${categoryTier}", using fallback`, {
|
|
35148
|
+
fallback: fallbackModel ? `${fallbackModel.providerID}/${fallbackModel.modelID}` : "none"
|
|
35149
|
+
});
|
|
35150
|
+
}
|
|
35151
|
+
return fallbackModel;
|
|
35152
|
+
};
|
|
34741
35153
|
return {
|
|
34742
35154
|
resolveModelForAgent,
|
|
34743
|
-
|
|
35155
|
+
resolveModelForAgentOrThrow,
|
|
35156
|
+
isTierMappingConfigured,
|
|
35157
|
+
resolveModelForCategory
|
|
34744
35158
|
};
|
|
34745
35159
|
}
|
|
34746
35160
|
|
|
@@ -38635,7 +39049,7 @@ var OmoOmcsPlugin = async (ctx) => {
|
|
|
38635
39049
|
}
|
|
38636
39050
|
const backgroundManager = createBackgroundManager(ctx, pluginConfig.background_task, modelService);
|
|
38637
39051
|
const backgroundTools = createBackgroundTools(backgroundManager, ctx.client);
|
|
38638
|
-
const callOmcoAgent = createCallOmcoAgent(ctx, backgroundManager, modelService);
|
|
39052
|
+
const callOmcoAgent = createCallOmcoAgent(ctx, backgroundManager, modelService, pluginConfig.categories);
|
|
38639
39053
|
const systemPromptInjector = createSystemPromptInjector(ctx);
|
|
38640
39054
|
const skillInjector = createSkillInjector(ctx);
|
|
38641
39055
|
const ralphLoop = createRalphLoopHook(ctx, {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type PluginInput, type ToolDefinition } from "@opencode-ai/plugin";
|
|
2
2
|
import type { BackgroundManager } from "./background-manager";
|
|
3
3
|
import type { ModelResolutionService } from "./model-resolution-service";
|
|
4
|
-
|
|
4
|
+
import type { CategoriesConfig } from "../categories/types";
|
|
5
|
+
export declare function createCallOmcoAgent(ctx: PluginInput, manager: BackgroundManager, modelService?: ModelResolutionService, userCategories?: CategoriesConfig): ToolDefinition;
|
|
@@ -27,10 +27,25 @@ export interface ModelResolutionService {
|
|
|
27
27
|
* @returns Resolved ModelConfig or undefined if should use fallback
|
|
28
28
|
*/
|
|
29
29
|
resolveModelForAgent(agentName: string, fallbackModel?: ModelConfig): ModelConfig | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Resolve model for an agent, always returning a result or throwing
|
|
32
|
+
* @param agentName - Name of the agent (canonical or alias)
|
|
33
|
+
* @param fallbackModel - Parent session model to use if resolution fails
|
|
34
|
+
* @returns Resolved ModelConfig (never undefined)
|
|
35
|
+
* @throws Error with actionable message if model cannot be resolved
|
|
36
|
+
*/
|
|
37
|
+
resolveModelForAgentOrThrow(agentName: string, fallbackModel?: ModelConfig): ModelConfig;
|
|
30
38
|
/**
|
|
31
39
|
* Check if tier mapping is configured (tierDefaults has provider/model format)
|
|
32
40
|
*/
|
|
33
41
|
isTierMappingConfigured(): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Resolve model for a category-based tier (abstract tier name)
|
|
44
|
+
* @param categoryTier - Abstract tier name (haiku, sonnet, opus)
|
|
45
|
+
* @param fallbackModel - Parent session model to use if resolution fails
|
|
46
|
+
* @returns Resolved ModelConfig or undefined if no mapping found
|
|
47
|
+
*/
|
|
48
|
+
resolveModelForCategory(categoryTier: string, fallbackModel?: ModelConfig): ModelConfig | undefined;
|
|
34
49
|
}
|
|
35
50
|
/**
|
|
36
51
|
* Create a ModelResolutionService instance
|