fix(task): append plan delegation prompt requirements
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -2,6 +2,7 @@ import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types"
|
|||||||
import type { ExecutorContext, ParentContext } from "./executor-types"
|
import type { ExecutorContext, ParentContext } from "./executor-types"
|
||||||
import type { FallbackEntry } from "../../shared/model-requirements"
|
import type { FallbackEntry } from "../../shared/model-requirements"
|
||||||
import { getTimingConfig } from "./timing"
|
import { getTimingConfig } from "./timing"
|
||||||
|
import { buildTaskPrompt } from "./prompt-builder"
|
||||||
import { storeToolMetadata } from "../../features/tool-metadata-store"
|
import { storeToolMetadata } from "../../features/tool-metadata-store"
|
||||||
import { formatDetailedError } from "./error-formatting"
|
import { formatDetailedError } from "./error-formatting"
|
||||||
import { getSessionTools } from "../../shared/session-tools-store"
|
import { getSessionTools } from "../../shared/session-tools-store"
|
||||||
@@ -20,9 +21,10 @@ export async function executeBackgroundTask(
|
|||||||
const { manager } = executorCtx
|
const { manager } = executorCtx
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const effectivePrompt = buildTaskPrompt(args.prompt, agentToUse)
|
||||||
const task = await manager.launch({
|
const task = await manager.launch({
|
||||||
description: args.description,
|
description: args.description,
|
||||||
prompt: args.prompt,
|
prompt: effectivePrompt,
|
||||||
agent: agentToUse,
|
agent: agentToUse,
|
||||||
parentSessionID: parentContext.sessionID,
|
parentSessionID: parentContext.sessionID,
|
||||||
parentMessageID: parentContext.messageID,
|
parentMessageID: parentContext.messageID,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export { createDelegateTask, resolveCategoryConfig, buildSystemContent } from "./tools"
|
export { createDelegateTask, resolveCategoryConfig, buildSystemContent, buildTaskPrompt } from "./tools"
|
||||||
export type { DelegateTaskToolOptions, SyncSessionCreatedEvent, BuildSystemContentInput } from "./tools"
|
export type { DelegateTaskToolOptions, SyncSessionCreatedEvent, BuildSystemContentInput } from "./tools"
|
||||||
export type * from "./types"
|
export type * from "./types"
|
||||||
export * from "./constants"
|
export * from "./constants"
|
||||||
|
|||||||
@@ -3,6 +3,14 @@ import { buildPlanAgentSystemPrepend, isPlanAgent } from "./constants"
|
|||||||
import { buildSystemContentWithTokenLimit } from "./token-limiter"
|
import { buildSystemContentWithTokenLimit } from "./token-limiter"
|
||||||
|
|
||||||
const FREE_OR_LOCAL_PROMPT_TOKEN_LIMIT = 24000
|
const FREE_OR_LOCAL_PROMPT_TOKEN_LIMIT = 24000
|
||||||
|
const PLAN_AGENT_PROMPT_APPEND = `
|
||||||
|
|
||||||
|
Additional requirements for this planning request:
|
||||||
|
- Answer in English.
|
||||||
|
- Write the plan in English.
|
||||||
|
- Plan well for ultrawork execution.
|
||||||
|
- Use TDD-oriented planning.
|
||||||
|
- Include a clear atomic commit strategy.`
|
||||||
|
|
||||||
function usesFreeOrLocalModel(model: { providerID: string; modelID: string; variant?: string } | undefined): boolean {
|
function usesFreeOrLocalModel(model: { providerID: string; modelID: string; variant?: string } | undefined): boolean {
|
||||||
if (!model) {
|
if (!model) {
|
||||||
@@ -52,3 +60,11 @@ export function buildSystemContent(input: BuildSystemContentInput): string | und
|
|||||||
effectiveMaxPromptTokens
|
effectiveMaxPromptTokens
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildTaskPrompt(prompt: string, agentName: string | undefined): string {
|
||||||
|
if (!isPlanAgent(agentName)) {
|
||||||
|
return prompt
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${prompt}${PLAN_AGENT_PROMPT_APPEND}`
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { formatDuration } from "./time-formatter"
|
|||||||
import { syncContinuationDeps, type SyncContinuationDeps } from "./sync-continuation-deps"
|
import { syncContinuationDeps, type SyncContinuationDeps } from "./sync-continuation-deps"
|
||||||
import { setSessionTools } from "../../shared/session-tools-store"
|
import { setSessionTools } from "../../shared/session-tools-store"
|
||||||
import { normalizeSDKResponse } from "../../shared"
|
import { normalizeSDKResponse } from "../../shared"
|
||||||
|
import { buildTaskPrompt } from "./prompt-builder"
|
||||||
|
|
||||||
export async function executeSyncContinuation(
|
export async function executeSyncContinuation(
|
||||||
args: DelegateTaskArgs,
|
args: DelegateTaskArgs,
|
||||||
@@ -82,6 +83,7 @@ export async function executeSyncContinuation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const allowTask = isPlanFamily(resumeAgent)
|
const allowTask = isPlanFamily(resumeAgent)
|
||||||
|
const effectivePrompt = buildTaskPrompt(args.prompt, resumeAgent)
|
||||||
const tools = {
|
const tools = {
|
||||||
...(resumeAgent ? getAgentToolRestrictions(resumeAgent) : {}),
|
...(resumeAgent ? getAgentToolRestrictions(resumeAgent) : {}),
|
||||||
task: allowTask,
|
task: allowTask,
|
||||||
@@ -97,7 +99,7 @@ export async function executeSyncContinuation(
|
|||||||
...(resumeModel !== undefined ? { model: resumeModel } : {}),
|
...(resumeModel !== undefined ? { model: resumeModel } : {}),
|
||||||
...(resumeVariant !== undefined ? { variant: resumeVariant } : {}),
|
...(resumeVariant !== undefined ? { variant: resumeVariant } : {}),
|
||||||
tools,
|
tools,
|
||||||
parts: [{ type: "text", text: args.prompt }],
|
parts: [{ type: "text", text: effectivePrompt }],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} catch (promptError) {
|
} catch (promptError) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { DelegateTaskArgs, OpencodeClient } from "./types"
|
import type { DelegateTaskArgs, OpencodeClient } from "./types"
|
||||||
import { isPlanFamily } from "./constants"
|
import { isPlanFamily } from "./constants"
|
||||||
|
import { buildTaskPrompt } from "./prompt-builder"
|
||||||
import {
|
import {
|
||||||
promptSyncWithModelSuggestionRetry,
|
promptSyncWithModelSuggestionRetry,
|
||||||
promptWithModelSuggestionRetry,
|
promptWithModelSuggestionRetry,
|
||||||
@@ -43,6 +44,7 @@ export async function sendSyncPrompt(
|
|||||||
deps: SendSyncPromptDeps = sendSyncPromptDeps
|
deps: SendSyncPromptDeps = sendSyncPromptDeps
|
||||||
): Promise<string | null> {
|
): Promise<string | null> {
|
||||||
const allowTask = isPlanFamily(input.agentToUse)
|
const allowTask = isPlanFamily(input.agentToUse)
|
||||||
|
const effectivePrompt = buildTaskPrompt(input.args.prompt, input.agentToUse)
|
||||||
const tools = {
|
const tools = {
|
||||||
task: allowTask,
|
task: allowTask,
|
||||||
call_omo_agent: true,
|
call_omo_agent: true,
|
||||||
@@ -57,7 +59,7 @@ export async function sendSyncPrompt(
|
|||||||
agent: input.agentToUse,
|
agent: input.agentToUse,
|
||||||
system: input.systemContent,
|
system: input.systemContent,
|
||||||
tools,
|
tools,
|
||||||
parts: [createInternalAgentTextPart(input.args.prompt)],
|
parts: [createInternalAgentTextPart(effectivePrompt)],
|
||||||
...(input.categoryModel
|
...(input.categoryModel
|
||||||
? { model: { providerID: input.categoryModel.providerID, modelID: input.categoryModel.modelID } }
|
? { model: { providerID: input.categoryModel.providerID, modelID: input.categoryModel.modelID } }
|
||||||
: {}),
|
: {}),
|
||||||
|
|||||||
@@ -2896,6 +2896,37 @@ describe("sisyphus-task", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("buildTaskPrompt", () => {
|
||||||
|
test("appends English ULW TDD and commit guidance for plan agent", () => {
|
||||||
|
// given
|
||||||
|
const { buildTaskPrompt } = require("./tools")
|
||||||
|
const prompt = "Create a work plan for this feature"
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = buildTaskPrompt(prompt, "plan")
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result).toContain(prompt)
|
||||||
|
expect(result).toContain("Answer in English.")
|
||||||
|
expect(result).toContain("Write the plan in English.")
|
||||||
|
expect(result).toContain("Plan well for ultrawork execution.")
|
||||||
|
expect(result).toContain("Use TDD-oriented planning.")
|
||||||
|
expect(result).toContain("Include a clear atomic commit strategy.")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("does not append plan guidance for non-plan agents", () => {
|
||||||
|
// given
|
||||||
|
const { buildTaskPrompt } = require("./tools")
|
||||||
|
const prompt = "Investigate this module"
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = buildTaskPrompt(prompt, "explore")
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result).toBe(prompt)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("modelInfo detection via resolveCategoryConfig", () => {
|
describe("modelInfo detection via resolveCategoryConfig", () => {
|
||||||
test("catalog model is used for category with catalog entry", () => {
|
test("catalog model is used for category with catalog entry", () => {
|
||||||
// given - ultrabrain has catalog entry
|
// given - ultrabrain has catalog entry
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import {
|
|||||||
|
|
||||||
export { resolveCategoryConfig } from "./categories"
|
export { resolveCategoryConfig } from "./categories"
|
||||||
export type { SyncSessionCreatedEvent, DelegateTaskToolOptions, BuildSystemContentInput } from "./types"
|
export type { SyncSessionCreatedEvent, DelegateTaskToolOptions, BuildSystemContentInput } from "./types"
|
||||||
export { buildSystemContent } from "./prompt-builder"
|
export { buildSystemContent, buildTaskPrompt } from "./prompt-builder"
|
||||||
|
|
||||||
export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefinition {
|
export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefinition {
|
||||||
const { userCategories } = options
|
const { userCategories } = options
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types"
|
import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types"
|
||||||
import type { ExecutorContext, ParentContext, SessionMessage } from "./executor-types"
|
import type { ExecutorContext, ParentContext, SessionMessage } from "./executor-types"
|
||||||
import { DEFAULT_SYNC_POLL_TIMEOUT_MS, getTimingConfig } from "./timing"
|
import { DEFAULT_SYNC_POLL_TIMEOUT_MS, getTimingConfig } from "./timing"
|
||||||
|
import { buildTaskPrompt } from "./prompt-builder"
|
||||||
import { storeToolMetadata } from "../../features/tool-metadata-store"
|
import { storeToolMetadata } from "../../features/tool-metadata-store"
|
||||||
import { formatDuration } from "./time-formatter"
|
import { formatDuration } from "./time-formatter"
|
||||||
import { formatDetailedError } from "./error-formatting"
|
import { formatDetailedError } from "./error-formatting"
|
||||||
@@ -20,9 +21,10 @@ export async function executeUnstableAgentTask(
|
|||||||
const { manager, client, syncPollTimeoutMs } = executorCtx
|
const { manager, client, syncPollTimeoutMs } = executorCtx
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const effectivePrompt = buildTaskPrompt(args.prompt, agentToUse)
|
||||||
const task = await manager.launch({
|
const task = await manager.launch({
|
||||||
description: args.description,
|
description: args.description,
|
||||||
prompt: args.prompt,
|
prompt: effectivePrompt,
|
||||||
agent: agentToUse,
|
agent: agentToUse,
|
||||||
parentSessionID: parentContext.sessionID,
|
parentSessionID: parentContext.sessionID,
|
||||||
parentMessageID: parentContext.messageID,
|
parentMessageID: parentContext.messageID,
|
||||||
|
|||||||
Reference in New Issue
Block a user