Merge pull request #3436 from code-yeongyu/fix/bug-batch-1
fix: numeric skill names, ZWSP agent lookups, ultrawork run_in_background
This commit is contained in:
@@ -87,7 +87,7 @@ export async function loadSkillFromPathAsync(
|
|||||||
const mcpJsonMcp = await loadMcpJsonFromDirAsync(resolvedPath)
|
const mcpJsonMcp = await loadMcpJsonFromDirAsync(resolvedPath)
|
||||||
const mcpConfig = mcpJsonMcp || frontmatterMcp
|
const mcpConfig = mcpJsonMcp || frontmatterMcp
|
||||||
|
|
||||||
const baseName = data.name || defaultName
|
const baseName = String(data.name || defaultName)
|
||||||
const skillName = namePrefix ? `${namePrefix}/${baseName}` : baseName
|
const skillName = namePrefix ? `${namePrefix}/${baseName}` : baseName
|
||||||
const originalDescription = data.description || ""
|
const originalDescription = data.description || ""
|
||||||
const isOpencodeSource = scope === "opencode" || scope === "opencode-project"
|
const isOpencodeSource = scope === "opencode" || scope === "opencode-project"
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export async function loadSkillFromPath(options: {
|
|||||||
const mcpJsonMcp = await loadMcpJsonFromDir(options.resolvedPath)
|
const mcpJsonMcp = await loadMcpJsonFromDir(options.resolvedPath)
|
||||||
const mcpConfig = mcpJsonMcp || frontmatterMcp
|
const mcpConfig = mcpJsonMcp || frontmatterMcp
|
||||||
|
|
||||||
const baseName = data.name || options.defaultName
|
const baseName = String(data.name || options.defaultName)
|
||||||
const skillName = namePrefix ? `${namePrefix}/${baseName}` : baseName
|
const skillName = namePrefix ? `${namePrefix}/${baseName}` : baseName
|
||||||
const originalDescription = data.description || ""
|
const originalDescription = data.description || ""
|
||||||
const isOpencodeSource = options.scope === "opencode" || options.scope === "opencode-project"
|
const isOpencodeSource = options.scope === "opencode" || options.scope === "opencode-project"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { stripInvisibleAgentCharacters } from "../../shared/agent-display-names"
|
||||||
import type { CompactionAgentConfigCheckpoint } from "../../shared/compaction-agent-config-checkpoint"
|
import type { CompactionAgentConfigCheckpoint } from "../../shared/compaction-agent-config-checkpoint"
|
||||||
|
|
||||||
export type RecoveryPromptConfig = CompactionAgentConfigCheckpoint & {
|
export type RecoveryPromptConfig = CompactionAgentConfigCheckpoint & {
|
||||||
@@ -66,7 +67,7 @@ export function isPromptConfigRecovered(
|
|||||||
const agentMatches =
|
const agentMatches =
|
||||||
typeof actualAgent === "string" &&
|
typeof actualAgent === "string" &&
|
||||||
!isCompactionAgent(actualAgent) &&
|
!isCompactionAgent(actualAgent) &&
|
||||||
actualAgent.toLowerCase() === expectedPromptConfig.agent.toLowerCase()
|
stripInvisibleAgentCharacters(actualAgent).toLowerCase() === stripInvisibleAgentCharacters(expectedPromptConfig.agent).toLowerCase()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
agentMatches &&
|
agentMatches &&
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ TELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST.
|
|||||||
| Architecture decision needed | MUST call plan agent |
|
| Architecture decision needed | MUST call plan agent |
|
||||||
|
|
||||||
\`\`\`
|
\`\`\`
|
||||||
task(subagent_type="plan", load_skills=[], prompt="<gathered context + user request>")
|
task(subagent_type="plan", load_skills=[], run_in_background=false, prompt="<gathered context + user request>")
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
**WHY PLAN AGENT IS MANDATORY:**
|
**WHY PLAN AGENT IS MANDATORY:**
|
||||||
@@ -119,9 +119,9 @@ task(subagent_type="plan", load_skills=[], prompt="<gathered context + user requ
|
|||||||
|
|
||||||
| Scenario | Action |
|
| Scenario | Action |
|
||||||
|----------|--------|
|
|----------|--------|
|
||||||
| Plan agent asks clarifying questions | \`task(session_id="{returned_session_id}", load_skills=[], prompt="<your answer>")\` |
|
| Plan agent asks clarifying questions | \`task(session_id="{returned_session_id}", load_skills=[], run_in_background=false, prompt="<your answer>")\` |
|
||||||
| Need to refine the plan | \`task(session_id="{returned_session_id}", load_skills=[], prompt="Please adjust: <feedback>")\` |
|
| Need to refine the plan | \`task(session_id="{returned_session_id}", load_skills=[], run_in_background=false, prompt="Please adjust: <feedback>")\` |
|
||||||
| Plan needs more detail | \`task(session_id="{returned_session_id}", load_skills=[], prompt="Add more detail to Task N")\` |
|
| Plan needs more detail | \`task(session_id="{returned_session_id}", load_skills=[], run_in_background=false, prompt="Add more detail to Task N")\` |
|
||||||
|
|
||||||
**WHY SESSION_ID IS CRITICAL:**
|
**WHY SESSION_ID IS CRITICAL:**
|
||||||
- Plan agent retains FULL conversation context
|
- Plan agent retains FULL conversation context
|
||||||
@@ -131,10 +131,10 @@ task(subagent_type="plan", load_skills=[], prompt="<gathered context + user requ
|
|||||||
|
|
||||||
\`\`\`
|
\`\`\`
|
||||||
// WRONG: Starting fresh loses all context
|
// WRONG: Starting fresh loses all context
|
||||||
task(subagent_type="plan", load_skills=[], prompt="Here's more info...")
|
task(subagent_type="plan", load_skills=[], run_in_background=false, prompt="Here's more info...")
|
||||||
|
|
||||||
// CORRECT: Resume preserves everything
|
// CORRECT: Resume preserves everything
|
||||||
task(session_id="ses_abc123", load_skills=[], prompt="Here's my answer to your question: ...")
|
task(session_id="ses_abc123", load_skills=[], run_in_background=false, prompt="Here's my answer to your question: ...")
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
**FAILURE TO CALL PLAN AGENT = INCOMPLETE WORK.**
|
**FAILURE TO CALL PLAN AGENT = INCOMPLETE WORK.**
|
||||||
@@ -149,21 +149,21 @@ task(session_id="ses_abc123", load_skills=[], prompt="Here's my answer to your q
|
|||||||
|-----------|--------|-----|
|
|-----------|--------|-----|
|
||||||
| Codebase exploration | task(subagent_type="explore", load_skills=[], run_in_background=true) | Parallel, context-efficient |
|
| Codebase exploration | task(subagent_type="explore", load_skills=[], run_in_background=true) | Parallel, context-efficient |
|
||||||
| Documentation lookup | task(subagent_type="librarian", load_skills=[], run_in_background=true) | Specialized knowledge |
|
| Documentation lookup | task(subagent_type="librarian", load_skills=[], run_in_background=true) | Specialized knowledge |
|
||||||
| Planning | task(subagent_type="plan", load_skills=[]) | Parallel task graph + structured TODO list |
|
| Planning | task(subagent_type="plan", load_skills=[], run_in_background=false) | Parallel task graph + structured TODO list |
|
||||||
| Hard problem (conventional) | task(subagent_type="oracle", load_skills=[]) | Architecture, debugging, complex logic |
|
| Hard problem (conventional) | task(subagent_type="oracle", load_skills=[], run_in_background=false) | Architecture, debugging, complex logic |
|
||||||
| Hard problem (non-conventional) | task(category="artistry", load_skills=[...]) | Different approach needed |
|
| Hard problem (non-conventional) | task(category="artistry", load_skills=[...], run_in_background=true) | Different approach needed |
|
||||||
| Implementation | task(category="...", load_skills=[...]) | Domain-optimized models |
|
| Implementation | task(category="...", load_skills=[...], run_in_background=true) | Domain-optimized models |
|
||||||
|
|
||||||
**CATEGORY + SKILL DELEGATION:**
|
**CATEGORY + SKILL DELEGATION:**
|
||||||
\`\`\`
|
\`\`\`
|
||||||
// Frontend work
|
// Frontend work
|
||||||
task(category="visual-engineering", load_skills=["frontend-ui-ux"])
|
task(category="visual-engineering", load_skills=["frontend-ui-ux"], run_in_background=true)
|
||||||
|
|
||||||
// Complex logic
|
// Complex logic
|
||||||
task(category="ultrabrain", load_skills=["typescript-programmer"])
|
task(category="ultrabrain", load_skills=["typescript-programmer"], run_in_background=true)
|
||||||
|
|
||||||
// Quick fixes
|
// Quick fixes
|
||||||
task(category="quick", load_skills=["git-master"])
|
task(category="quick", load_skills=["git-master"], run_in_background=true)
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
**YOU SHOULD ONLY DO IT YOURSELF WHEN:**
|
**YOU SHOULD ONLY DO IT YOURSELF WHEN:**
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ TELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST.
|
|||||||
| Architecture decision needed | MUST call plan agent |
|
| Architecture decision needed | MUST call plan agent |
|
||||||
|
|
||||||
\`\`\`
|
\`\`\`
|
||||||
task(subagent_type="plan", load_skills=[], prompt="<gathered context + user request>")
|
task(subagent_type="plan", load_skills=[], run_in_background=false, prompt="<gathered context + user request>")
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
### SESSION CONTINUITY WITH PLAN AGENT (CRITICAL)
|
### SESSION CONTINUITY WITH PLAN AGENT (CRITICAL)
|
||||||
@@ -165,9 +165,9 @@ task(subagent_type="plan", load_skills=[], prompt="<gathered context + user requ
|
|||||||
|
|
||||||
| Scenario | Action |
|
| Scenario | Action |
|
||||||
|----------|--------|
|
|----------|--------|
|
||||||
| Plan agent asks clarifying questions | \`task(session_id="{returned_session_id}", load_skills=[], prompt="<your answer>")\` |
|
| Plan agent asks clarifying questions | \`task(session_id="{returned_session_id}", load_skills=[], run_in_background=false, prompt="<your answer>")\` |
|
||||||
| Need to refine the plan | \`task(session_id="{returned_session_id}", load_skills=[], prompt="Please adjust: <feedback>")\` |
|
| Need to refine the plan | \`task(session_id="{returned_session_id}", load_skills=[], run_in_background=false, prompt="Please adjust: <feedback>")\` |
|
||||||
| Plan needs more detail | \`task(session_id="{returned_session_id}", load_skills=[], prompt="Add more detail to Task N")\` |
|
| Plan needs more detail | \`task(session_id="{returned_session_id}", load_skills=[], run_in_background=false, prompt="Add more detail to Task N")\` |
|
||||||
|
|
||||||
**FAILURE TO CALL PLAN AGENT = INCOMPLETE WORK.**
|
**FAILURE TO CALL PLAN AGENT = INCOMPLETE WORK.**
|
||||||
|
|
||||||
@@ -183,10 +183,10 @@ task(subagent_type="plan", load_skills=[], prompt="<gathered context + user requ
|
|||||||
|-----------|--------|-----|
|
|-----------|--------|-----|
|
||||||
| Codebase exploration | task(subagent_type="explore", load_skills=[], run_in_background=true) | Parallel, context-efficient |
|
| Codebase exploration | task(subagent_type="explore", load_skills=[], run_in_background=true) | Parallel, context-efficient |
|
||||||
| Documentation lookup | task(subagent_type="librarian", load_skills=[], run_in_background=true) | Specialized knowledge |
|
| Documentation lookup | task(subagent_type="librarian", load_skills=[], run_in_background=true) | Specialized knowledge |
|
||||||
| Planning | task(subagent_type="plan", load_skills=[]) | Parallel task graph + structured TODO list |
|
| Planning | task(subagent_type="plan", load_skills=[], run_in_background=false) | Parallel task graph + structured TODO list |
|
||||||
| Hard problem (conventional) | task(subagent_type="oracle", load_skills=[]) | Architecture, debugging, complex logic |
|
| Hard problem (conventional) | task(subagent_type="oracle", load_skills=[], run_in_background=false) | Architecture, debugging, complex logic |
|
||||||
| Hard problem (non-conventional) | task(category="artistry", load_skills=[...]) | Different approach needed |
|
| Hard problem (non-conventional) | task(category="artistry", load_skills=[...], run_in_background=true) | Different approach needed |
|
||||||
| Implementation | task(category="...", load_skills=[...]) | Domain-optimized models |
|
| Implementation | task(category="...", load_skills=[...], run_in_background=true) | Domain-optimized models |
|
||||||
|
|
||||||
**YOU SHOULD ONLY DO IT YOURSELF WHEN:**
|
**YOU SHOULD ONLY DO IT YOURSELF WHEN:**
|
||||||
- Task is trivially simple (1-2 lines, obvious change)
|
- Task is trivially simple (1-2 lines, obvious change)
|
||||||
|
|||||||
@@ -71,9 +71,9 @@ Use these when they provide clear value based on the decision framework above:
|
|||||||
|----------|-------------|------------|
|
|----------|-------------|------------|
|
||||||
| explore agent | Need codebase patterns you don't have | \`task(subagent_type="explore", load_skills=[], run_in_background=true, ...)\` |
|
| explore agent | Need codebase patterns you don't have | \`task(subagent_type="explore", load_skills=[], run_in_background=true, ...)\` |
|
||||||
| librarian agent | External library docs, OSS examples | \`task(subagent_type="librarian", load_skills=[], run_in_background=true, ...)\` |
|
| librarian agent | External library docs, OSS examples | \`task(subagent_type="librarian", load_skills=[], run_in_background=true, ...)\` |
|
||||||
| oracle agent | Stuck on architecture/debugging after 2+ attempts | \`task(subagent_type="oracle", load_skills=[], ...)\` |
|
| oracle agent | Stuck on architecture/debugging after 2+ attempts | \`task(subagent_type="oracle", load_skills=[], run_in_background=false, ...)\` |
|
||||||
| plan agent | Complex multi-step with dependencies (5+ steps) | \`task(subagent_type="plan", load_skills=[], ...)\` |
|
| plan agent | Complex multi-step with dependencies (5+ steps) | \`task(subagent_type="plan", load_skills=[], run_in_background=false, ...)\` |
|
||||||
| task category | Specialized work matching a category | \`task(category="...", load_skills=[...])\` |
|
| task category | Specialized work matching a category | \`task(category="...", load_skills=[...], run_in_background=true)\` |
|
||||||
|
|
||||||
<tool_usage_rules>
|
<tool_usage_rules>
|
||||||
- Prefer tools over internal knowledge for fresh or user-specific data
|
- Prefer tools over internal knowledge for fresh or user-specific data
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ Each TODO item MUST include:
|
|||||||
|
|
||||||
| Wave | Tasks | Dispatch Command |
|
| Wave | Tasks | Dispatch Command |
|
||||||
|------|-------|------------------|
|
|------|-------|------------------|
|
||||||
| 1 | 1, 4 | \`task(category="...", load_skills=[...], run_in_background=false)\` × 2 |
|
| 1 | 1, 4 | \`task(category="...", load_skills=[...], run_in_background=true)\` × 2 |
|
||||||
| 2 | 2, 3, 5 | \`task(...)\` × 3 after Wave 1 completes |
|
| 2 | 2, 3, 5 | \`task(...)\` × 3 after Wave 1 completes |
|
||||||
| 3 | 6 | \`task(...)\` final integration |
|
| 3 | 6 | \`task(...)\` final integration |
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { stripInvisibleAgentCharacters } from "../../shared/agent-display-names"
|
||||||
import { ULTRAWORK_VERIFICATION_PROMISE } from "./constants"
|
import { ULTRAWORK_VERIFICATION_PROMISE } from "./constants"
|
||||||
|
|
||||||
export interface OracleVerificationEvidence {
|
export interface OracleVerificationEvidence {
|
||||||
@@ -54,7 +55,7 @@ export function isOracleVerified(text: string): boolean {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const isOracleAgent = evidence.agent.toLowerCase() === "oracle"
|
const isOracleAgent = stripInvisibleAgentCharacters(evidence.agent).toLowerCase() === "oracle"
|
||||||
const isVerifiedPromise = evidence.promise === ULTRAWORK_VERIFICATION_PROMISE
|
const isVerifiedPromise = evidence.promise === ULTRAWORK_VERIFICATION_PROMISE
|
||||||
|
|
||||||
return isOracleAgent && isVerifiedPromise
|
return isOracleAgent && isVerifiedPromise
|
||||||
@@ -62,7 +63,7 @@ export function isOracleVerified(text: string): boolean {
|
|||||||
|
|
||||||
export function extractOracleSessionID(text: string): string | undefined {
|
export function extractOracleSessionID(text: string): string | undefined {
|
||||||
const evidence = parseOracleVerificationEvidence(text)
|
const evidence = parseOracleVerificationEvidence(text)
|
||||||
if (!evidence || evidence.agent.toLowerCase() !== "oracle") {
|
if (!evidence || stripInvisibleAgentCharacters(evidence.agent).toLowerCase() !== "oracle") {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { consumeToolMetadata } from "../features/tool-metadata-store"
|
import { consumeToolMetadata } from "../features/tool-metadata-store"
|
||||||
import type { CreatedHooks } from "../create-hooks"
|
import type { CreatedHooks } from "../create-hooks"
|
||||||
import { log } from "../shared"
|
import { log } from "../shared"
|
||||||
|
import { stripInvisibleAgentCharacters } from "../shared/agent-display-names"
|
||||||
import type { PluginContext } from "./types"
|
import type { PluginContext } from "./types"
|
||||||
import { readState, writeState } from "../hooks/ralph-loop/storage"
|
import { readState, writeState } from "../hooks/ralph-loop/storage"
|
||||||
|
|
||||||
@@ -60,7 +61,7 @@ export function createToolExecuteAfterHandler(args: {
|
|||||||
const verificationAttemptId = prompt?.match(VERIFICATION_ATTEMPT_PATTERN)?.[1]?.trim()
|
const verificationAttemptId = prompt?.match(VERIFICATION_ATTEMPT_PATTERN)?.[1]?.trim()
|
||||||
const loopState = directory ? readState(directory) : null
|
const loopState = directory ? readState(directory) : null
|
||||||
const isVerificationContext =
|
const isVerificationContext =
|
||||||
agent === "oracle"
|
(agent ? stripInvisibleAgentCharacters(agent) : agent) === "oracle"
|
||||||
&& !!sessionId
|
&& !!sessionId
|
||||||
&& !!directory
|
&& !!directory
|
||||||
&& loopState?.active === true
|
&& loopState?.active === true
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { randomUUID } from "node:crypto"
|
|||||||
import { getMainSessionID } from "../features/claude-code-session-state"
|
import { getMainSessionID } from "../features/claude-code-session-state"
|
||||||
import { clearBoulderState } from "../features/boulder-state"
|
import { clearBoulderState } from "../features/boulder-state"
|
||||||
import { log } from "../shared"
|
import { log } from "../shared"
|
||||||
|
import { stripInvisibleAgentCharacters } from "../shared/agent-display-names"
|
||||||
import { resolveSessionAgent } from "./session-agent-resolver"
|
import { resolveSessionAgent } from "./session-agent-resolver"
|
||||||
import { parseRalphLoopArguments } from "../hooks/ralph-loop/command-arguments"
|
import { parseRalphLoopArguments } from "../hooks/ralph-loop/command-arguments"
|
||||||
import { ULTRAWORK_VERIFICATION_PROMISE } from "../hooks/ralph-loop/constants"
|
import { ULTRAWORK_VERIFICATION_PROMISE } from "../hooks/ralph-loop/constants"
|
||||||
@@ -109,7 +110,7 @@ export function createToolExecuteBeforeHandler(args: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const normalizedSubagentType =
|
const normalizedSubagentType =
|
||||||
typeof argsObject.subagent_type === "string" ? argsObject.subagent_type : undefined
|
typeof argsObject.subagent_type === "string" ? stripInvisibleAgentCharacters(argsObject.subagent_type) : undefined
|
||||||
const prompt = typeof argsObject.prompt === "string" ? argsObject.prompt : ""
|
const prompt = typeof argsObject.prompt === "string" ? argsObject.prompt : ""
|
||||||
const loopState = typeof ctx.directory === "string" ? readState(ctx.directory) : null
|
const loopState = typeof ctx.directory === "string" ? readState(ctx.directory) : null
|
||||||
const shouldInjectOracleVerification =
|
const shouldInjectOracleVerification =
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { stripInvisibleAgentCharacters } from "./agent-display-names"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Agent tool restrictions for session.prompt calls.
|
* Agent tool restrictions for session.prompt calls.
|
||||||
* OpenCode SDK's session.prompt `tools` parameter expects boolean values.
|
* OpenCode SDK's session.prompt `tools` parameter expects boolean values.
|
||||||
@@ -45,13 +47,15 @@ const AGENT_RESTRICTIONS: Record<string, Record<string, boolean>> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getAgentToolRestrictions(agentName: string): Record<string, boolean> {
|
export function getAgentToolRestrictions(agentName: string): Record<string, boolean> {
|
||||||
return AGENT_RESTRICTIONS[agentName]
|
const stripped = stripInvisibleAgentCharacters(agentName)
|
||||||
?? Object.entries(AGENT_RESTRICTIONS).find(([key]) => key.toLowerCase() === agentName.toLowerCase())?.[1]
|
return AGENT_RESTRICTIONS[stripped]
|
||||||
|
?? Object.entries(AGENT_RESTRICTIONS).find(([key]) => key.toLowerCase() === stripped.toLowerCase())?.[1]
|
||||||
?? {}
|
?? {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasAgentToolRestrictions(agentName: string): boolean {
|
export function hasAgentToolRestrictions(agentName: string): boolean {
|
||||||
const restrictions = AGENT_RESTRICTIONS[agentName]
|
const stripped = stripInvisibleAgentCharacters(agentName)
|
||||||
?? Object.entries(AGENT_RESTRICTIONS).find(([key]) => key.toLowerCase() === agentName.toLowerCase())?.[1]
|
const restrictions = AGENT_RESTRICTIONS[stripped]
|
||||||
|
?? Object.entries(AGENT_RESTRICTIONS).find(([key]) => key.toLowerCase() === stripped.toLowerCase())?.[1]
|
||||||
return restrictions !== undefined && Object.keys(restrictions).length > 0
|
return restrictions !== undefined && Object.keys(restrictions).length > 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenCodeConfig } from "../config"
|
||||||
|
import { stripInvisibleAgentCharacters } from "./agent-display-names"
|
||||||
import { AGENT_MODEL_REQUIREMENTS, CATEGORY_MODEL_REQUIREMENTS } from "./model-requirements"
|
import { AGENT_MODEL_REQUIREMENTS, CATEGORY_MODEL_REQUIREMENTS } from "./model-requirements"
|
||||||
|
|
||||||
export function resolveAgentVariant(
|
export function resolveAgentVariant(
|
||||||
@@ -9,12 +10,13 @@ export function resolveAgentVariant(
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stripped = stripInvisibleAgentCharacters(agentName)
|
||||||
const agentOverrides = config.agents as
|
const agentOverrides = config.agents as
|
||||||
| Record<string, { variant?: string; category?: string }>
|
| Record<string, { variant?: string; category?: string }>
|
||||||
| undefined
|
| undefined
|
||||||
const agentOverride = agentOverrides
|
const agentOverride = agentOverrides
|
||||||
? agentOverrides[agentName]
|
? agentOverrides[stripped]
|
||||||
?? Object.entries(agentOverrides).find(([key]) => key.toLowerCase() === agentName.toLowerCase())?.[1]
|
?? Object.entries(agentOverrides).find(([key]) => key.toLowerCase() === stripped.toLowerCase())?.[1]
|
||||||
: undefined
|
: undefined
|
||||||
if (!agentOverride) {
|
if (!agentOverride) {
|
||||||
return undefined
|
return undefined
|
||||||
@@ -37,18 +39,19 @@ export function resolveVariantForModel(
|
|||||||
agentName: string,
|
agentName: string,
|
||||||
currentModel: { providerID: string; modelID: string },
|
currentModel: { providerID: string; modelID: string },
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
|
const stripped = stripInvisibleAgentCharacters(agentName)
|
||||||
const agentOverrides = config.agents as
|
const agentOverrides = config.agents as
|
||||||
| Record<string, { variant?: string; category?: string }>
|
| Record<string, { variant?: string; category?: string }>
|
||||||
| undefined
|
| undefined
|
||||||
const agentOverride = agentOverrides
|
const agentOverride = agentOverrides
|
||||||
? agentOverrides[agentName]
|
? agentOverrides[stripped]
|
||||||
?? Object.entries(agentOverrides).find(([key]) => key.toLowerCase() === agentName.toLowerCase())?.[1]
|
?? Object.entries(agentOverrides).find(([key]) => key.toLowerCase() === stripped.toLowerCase())?.[1]
|
||||||
: undefined
|
: undefined
|
||||||
if (agentOverride?.variant) {
|
if (agentOverride?.variant) {
|
||||||
return agentOverride.variant
|
return agentOverride.variant
|
||||||
}
|
}
|
||||||
|
|
||||||
const agentRequirement = AGENT_MODEL_REQUIREMENTS[agentName]
|
const agentRequirement = AGENT_MODEL_REQUIREMENTS[stripped]
|
||||||
if (agentRequirement) {
|
if (agentRequirement) {
|
||||||
return findVariantInChain(agentRequirement.fallbackChain, currentModel)
|
return findVariantInChain(agentRequirement.fallbackChain, currentModel)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type { CategoriesConfig, AgentOverrides } from "../../config/schema"
|
|||||||
import type { DelegatedModelConfig } from "../../shared/model-resolution-types"
|
import type { DelegatedModelConfig } from "../../shared/model-resolution-types"
|
||||||
import type { FallbackEntry } from "../../shared/model-requirements"
|
import type { FallbackEntry } from "../../shared/model-requirements"
|
||||||
import { AGENT_MODEL_REQUIREMENTS } from "../../shared/model-requirements"
|
import { AGENT_MODEL_REQUIREMENTS } from "../../shared/model-requirements"
|
||||||
import { getAgentConfigKey } from "../../shared/agent-display-names"
|
import { getAgentConfigKey, stripInvisibleAgentCharacters } from "../../shared/agent-display-names"
|
||||||
import { normalizeFallbackModels } from "../../shared/model-resolver"
|
import { normalizeFallbackModels } from "../../shared/model-resolver"
|
||||||
import { buildFallbackChainFromModels } from "../../shared/fallback-chain-from-models"
|
import { buildFallbackChainFromModels } from "../../shared/fallback-chain-from-models"
|
||||||
import { log } from "../../shared"
|
import { log } from "../../shared"
|
||||||
@@ -104,20 +104,21 @@ export function createCallOmoAgent(
|
|||||||
const toolCtx = toolContext as ToolContextWithMetadata
|
const toolCtx = toolContext as ToolContextWithMetadata
|
||||||
log(`[call_omo_agent] Starting with agent: ${args.subagent_type}, background: ${args.run_in_background}`)
|
log(`[call_omo_agent] Starting with agent: ${args.subagent_type}, background: ${args.run_in_background}`)
|
||||||
|
|
||||||
// Case-insensitive agent validation - allows "Explore", "EXPLORE", "explore" etc.
|
// Strip ZWSP and case-insensitive agent validation - allows "Explore", "EXPLORE", "explore" etc.
|
||||||
|
const strippedAgentType = stripInvisibleAgentCharacters(args.subagent_type)
|
||||||
if (
|
if (
|
||||||
!ALLOWED_AGENTS.some(
|
!ALLOWED_AGENTS.some(
|
||||||
(name) => name.toLowerCase() === args.subagent_type.toLowerCase(),
|
(name) => name.toLowerCase() === strippedAgentType.toLowerCase(),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return `Error: Invalid agent type "${args.subagent_type}". Only ${ALLOWED_AGENTS.join(", ")} are allowed.`
|
return `Error: Invalid agent type "${args.subagent_type}". Only ${ALLOWED_AGENTS.join(", ")} are allowed.`
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedAgent = args.subagent_type.toLowerCase() as AllowedAgentType
|
const normalizedAgent = strippedAgentType.toLowerCase() as AllowedAgentType
|
||||||
args = { ...args, subagent_type: normalizedAgent }
|
args = { ...args, subagent_type: normalizedAgent }
|
||||||
|
|
||||||
// Check if agent is disabled
|
// Check if agent is disabled
|
||||||
if (disabledAgents.some((disabled) => disabled.toLowerCase() === normalizedAgent)) {
|
if (disabledAgents.some((disabled) => stripInvisibleAgentCharacters(disabled).toLowerCase() === normalizedAgent)) {
|
||||||
return `Error: Agent "${normalizedAgent}" is disabled via disabled_agents configuration. Remove it from disabled_agents in your ${CONFIG_BASENAME}.json to use it.`
|
return `Error: Agent "${normalizedAgent}" is disabled via disabled_agents configuration. Remove it from disabled_agents in your ${CONFIG_BASENAME}.json to use it.`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
} from "../../shared/model-suggestion-retry"
|
} from "../../shared/model-suggestion-retry"
|
||||||
import { formatDetailedError } from "./error-formatting"
|
import { formatDetailedError } from "./error-formatting"
|
||||||
import { getAgentToolRestrictions } from "../../shared/agent-tool-restrictions"
|
import { getAgentToolRestrictions } from "../../shared/agent-tool-restrictions"
|
||||||
|
import { stripInvisibleAgentCharacters } from "../../shared/agent-display-names"
|
||||||
import { applySessionPromptParams } from "../../shared/session-prompt-params-helpers"
|
import { applySessionPromptParams } from "../../shared/session-prompt-params-helpers"
|
||||||
import { setSessionTools } from "../../shared/session-tools-store"
|
import { setSessionTools } from "../../shared/session-tools-store"
|
||||||
import { createInternalAgentTextPart } from "../../shared/internal-initiator-marker"
|
import { createInternalAgentTextPart } from "../../shared/internal-initiator-marker"
|
||||||
@@ -41,7 +42,7 @@ function buildPromptGenerationParams(model: DelegatedModelConfig | undefined): R
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isOracleAgent(agentToUse: string): boolean {
|
function isOracleAgent(agentToUse: string): boolean {
|
||||||
return agentToUse.toLowerCase() === "oracle"
|
return stripInvisibleAgentCharacters(agentToUse).toLowerCase() === "oracle"
|
||||||
}
|
}
|
||||||
|
|
||||||
function isUnexpectedEofError(error: unknown): boolean {
|
function isUnexpectedEofError(error: unknown): boolean {
|
||||||
@@ -80,7 +81,7 @@ export async function sendSyncPrompt(
|
|||||||
const promptArgs = {
|
const promptArgs = {
|
||||||
path: { id: input.sessionID },
|
path: { id: input.sessionID },
|
||||||
body: {
|
body: {
|
||||||
agent: input.agentToUse.replace(/^\u200B+/, ""),
|
agent: stripInvisibleAgentCharacters(input.agentToUse),
|
||||||
system: input.systemContent,
|
system: input.systemContent,
|
||||||
tools,
|
tools,
|
||||||
parts: [createInternalAgentTextPart(effectivePrompt)],
|
parts: [createInternalAgentTextPart(effectivePrompt)],
|
||||||
|
|||||||
Reference in New Issue
Block a user