fix(background-agent): route session prompts by directory
This commit is contained in:
@@ -7,6 +7,38 @@ import { BackgroundManager } from "./manager"
|
|||||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||||
|
|
||||||
describe("BackgroundManager session permission", () => {
|
describe("BackgroundManager session permission", () => {
|
||||||
|
test("passes parent directory route when prompting the child session", async () => {
|
||||||
|
// given
|
||||||
|
const promptCalls: Array<Record<string, unknown>> = []
|
||||||
|
const client = {
|
||||||
|
session: {
|
||||||
|
get: async () => ({ data: { directory: "/parent" } }),
|
||||||
|
create: async () => ({ data: { id: "ses_child" } }),
|
||||||
|
promptAsync: async (input: Record<string, unknown>) => {
|
||||||
|
promptCalls.push(input)
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
abort: async () => ({}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const manager = new BackgroundManager({ pluginContext: unsafeTestValue<PluginInput>({ client, directory: tmpdir() }) })
|
||||||
|
|
||||||
|
// when
|
||||||
|
await manager.launch({
|
||||||
|
description: "Test task",
|
||||||
|
prompt: "Do something",
|
||||||
|
agent: "explore",
|
||||||
|
parentSessionId: "ses_parent",
|
||||||
|
parentMessageId: "msg_parent",
|
||||||
|
})
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 50))
|
||||||
|
manager.shutdown()
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(promptCalls).toHaveLength(1)
|
||||||
|
expect(promptCalls[0]?.query).toEqual({ directory: "/parent" })
|
||||||
|
})
|
||||||
|
|
||||||
test("passes query directory when loading the parent session", async () => {
|
test("passes query directory when loading the parent session", async () => {
|
||||||
// given
|
// given
|
||||||
const getCalls: Array<Record<string, unknown>> = []
|
const getCalls: Array<Record<string, unknown>> = []
|
||||||
|
|||||||
@@ -14,9 +14,11 @@ import {
|
|||||||
getAgentToolRestrictions,
|
getAgentToolRestrictions,
|
||||||
normalizePromptTools,
|
normalizePromptTools,
|
||||||
normalizeSDKResponse,
|
normalizeSDKResponse,
|
||||||
promptWithModelSuggestionRetry,
|
|
||||||
resolveInheritedPromptTools,
|
resolveInheritedPromptTools,
|
||||||
createInternalAgentTextPart,
|
createInternalAgentTextPart,
|
||||||
|
messagesInDirectory,
|
||||||
|
promptAsyncInDirectory,
|
||||||
|
promptWithRetryInDirectory,
|
||||||
} from "../../shared"
|
} from "../../shared"
|
||||||
import { resolveMessageEventSessionID, resolveSessionEventID } from "../../shared/event-session-id"
|
import { resolveMessageEventSessionID, resolveSessionEventID } from "../../shared/event-session-id"
|
||||||
import { applySessionPromptParams } from "../../shared/session-prompt-params-helpers"
|
import { applySessionPromptParams } from "../../shared/session-prompt-params-helpers"
|
||||||
@@ -89,7 +91,6 @@ import {
|
|||||||
resolveSubagentSpawnContext,
|
resolveSubagentSpawnContext,
|
||||||
type SubagentSpawnContext,
|
type SubagentSpawnContext,
|
||||||
} from "./subagent-spawn-limits"
|
} from "./subagent-spawn-limits"
|
||||||
|
|
||||||
type OpencodeClient = PluginInput["client"]
|
type OpencodeClient = PluginInput["client"]
|
||||||
|
|
||||||
type ParentWakePromptContext = {
|
type ParentWakePromptContext = {
|
||||||
@@ -781,10 +782,10 @@ The fallback retry session is now created and can be inspected directly.
|
|||||||
parts: [createInternalAgentTextPart(input.prompt)],
|
parts: [createInternalAgentTextPart(input.prompt)],
|
||||||
}
|
}
|
||||||
|
|
||||||
promptWithModelSuggestionRetry(this.client, {
|
promptWithRetryInDirectory(this.client, {
|
||||||
path: { id: sessionID },
|
path: { id: sessionID },
|
||||||
body: promptBody,
|
body: promptBody,
|
||||||
}).catch(async (error) => {
|
}, parentDirectory).catch(async (error) => {
|
||||||
// Retry with fallback agent if the original agent was unregistered (e.g., after a model switch)
|
// Retry with fallback agent if the original agent was unregistered (e.g., after a model switch)
|
||||||
if (isAgentNotFoundError(error) && input.agent !== FALLBACK_AGENT) {
|
if (isAgentNotFoundError(error) && input.agent !== FALLBACK_AGENT) {
|
||||||
log("[background-agent] Agent not found, retrying with fallback agent", {
|
log("[background-agent] Agent not found, retrying with fallback agent", {
|
||||||
@@ -797,10 +798,10 @@ The fallback retry session is now created and can be inspected directly.
|
|||||||
includeTeamToolDenylist: input.teamRunId === undefined,
|
includeTeamToolDenylist: input.teamRunId === undefined,
|
||||||
})
|
})
|
||||||
setSessionTools(sessionID, fallbackBody.tools as Record<string, boolean>)
|
setSessionTools(sessionID, fallbackBody.tools as Record<string, boolean>)
|
||||||
await promptWithModelSuggestionRetry(this.client, {
|
await promptWithRetryInDirectory(this.client, {
|
||||||
path: { id: sessionID },
|
path: { id: sessionID },
|
||||||
body: fallbackBody,
|
body: fallbackBody,
|
||||||
})
|
}, parentDirectory)
|
||||||
task.agent = FALLBACK_AGENT
|
task.agent = FALLBACK_AGENT
|
||||||
return
|
return
|
||||||
} catch (retryError) {
|
} catch (retryError) {
|
||||||
@@ -1145,7 +1146,7 @@ The fallback retry session is now created and can be inspected directly.
|
|||||||
applySessionPromptParams(existingTask.sessionId!, existingTask.model)
|
applySessionPromptParams(existingTask.sessionId!, existingTask.model)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.client.session.promptAsync({
|
promptAsyncInDirectory(this.client, {
|
||||||
path: { id: existingTask.sessionId },
|
path: { id: existingTask.sessionId },
|
||||||
body: {
|
body: {
|
||||||
agent: existingTask.agent,
|
agent: existingTask.agent,
|
||||||
@@ -1165,7 +1166,7 @@ The fallback retry session is now created and can be inspected directly.
|
|||||||
})(),
|
})(),
|
||||||
parts: [createInternalAgentTextPart(input.prompt)],
|
parts: [createInternalAgentTextPart(input.prompt)],
|
||||||
},
|
},
|
||||||
}).catch(async (error) => {
|
}, this.directory).catch(async (error) => {
|
||||||
log("[background-agent] resume prompt error:", error)
|
log("[background-agent] resume prompt error:", error)
|
||||||
const errorInfo = {
|
const errorInfo = {
|
||||||
name: extractErrorName(error),
|
name: extractErrorName(error),
|
||||||
@@ -1741,9 +1742,9 @@ The task was re-queued on a fallback model after a retryable failure.
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await this.client.session.messages({
|
const response = await messagesInDirectory(this.client, {
|
||||||
path: { id: sessionID },
|
path: { id: sessionID },
|
||||||
})
|
}, this.directory)
|
||||||
|
|
||||||
const messages = normalizeSDKResponse(response, [] as Array<{ info?: { role?: string } }>, { preferResponseOnMissingData: true })
|
const messages = normalizeSDKResponse(response, [] as Array<{ info?: { role?: string } }>, { preferResponseOnMissingData: true })
|
||||||
|
|
||||||
@@ -2152,7 +2153,9 @@ The task was re-queued on a fallback model after a retryable failure.
|
|||||||
|
|
||||||
if (this.enableParentSessionNotifications) {
|
if (this.enableParentSessionNotifications) {
|
||||||
try {
|
try {
|
||||||
const messagesResp = await this.client.session.messages({ path: { id: task.parentSessionId } })
|
const messagesResp = await messagesInDirectory(this.client, {
|
||||||
|
path: { id: task.parentSessionId },
|
||||||
|
}, this.directory)
|
||||||
const messages = normalizeSDKResponse(messagesResp, [] as Array<{
|
const messages = normalizeSDKResponse(messagesResp, [] as Array<{
|
||||||
info?: {
|
info?: {
|
||||||
agent?: string
|
agent?: string
|
||||||
@@ -2214,14 +2217,14 @@ The task was re-queued on a fallback model after a retryable failure.
|
|||||||
...(resolvedTools ? { tools: resolvedTools } : {}),
|
...(resolvedTools ? { tools: resolvedTools } : {}),
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await this.client.session.promptAsync({
|
await promptAsyncInDirectory(this.client, {
|
||||||
path: { id: task.parentSessionId },
|
path: { id: task.parentSessionId },
|
||||||
body: {
|
body: {
|
||||||
noReply: !shouldReply,
|
noReply: !shouldReply,
|
||||||
...parentPromptContext,
|
...parentPromptContext,
|
||||||
parts: [createInternalAgentTextPart(notification)],
|
parts: [createInternalAgentTextPart(notification)],
|
||||||
},
|
},
|
||||||
})
|
}, this.directory)
|
||||||
log("[background-agent] Sent notification to parent session:", {
|
log("[background-agent] Sent notification to parent session:", {
|
||||||
taskId: task.id,
|
taskId: task.id,
|
||||||
allComplete,
|
allComplete,
|
||||||
|
|||||||
@@ -535,6 +535,58 @@ describe("background-agent spawner fallback model promotion", () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("passes parent directory route when prompting the child session", async () => {
|
||||||
|
// given
|
||||||
|
const promptCalls: Array<Record<string, unknown>> = []
|
||||||
|
|
||||||
|
const client = {
|
||||||
|
session: {
|
||||||
|
get: async () => ({ data: { directory: "/parent/dir" } }),
|
||||||
|
create: async () => ({ data: { id: "ses_child_query" } }),
|
||||||
|
promptAsync: async (input: Record<string, unknown>) => {
|
||||||
|
promptCalls.push(input)
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const task = createTask({
|
||||||
|
description: "Test task",
|
||||||
|
prompt: "Do work",
|
||||||
|
agent: "sisyphus-junior",
|
||||||
|
parentSessionId: "ses_parent",
|
||||||
|
parentMessageId: "msg_parent",
|
||||||
|
})
|
||||||
|
|
||||||
|
const item = {
|
||||||
|
task,
|
||||||
|
input: {
|
||||||
|
description: task.description,
|
||||||
|
prompt: task.prompt,
|
||||||
|
agent: task.agent,
|
||||||
|
parentSessionId: task.parentSessionId,
|
||||||
|
parentMessageId: task.parentMessageId,
|
||||||
|
parentModel: task.parentModel,
|
||||||
|
parentAgent: task.parentAgent,
|
||||||
|
model: task.model,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
await startTask(item as never, {
|
||||||
|
client: client as never,
|
||||||
|
directory: "/fallback",
|
||||||
|
concurrencyManager: { release: () => {} } as never,
|
||||||
|
tmuxEnabled: false,
|
||||||
|
onTaskError: () => {},
|
||||||
|
})
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 0))
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(promptCalls).toHaveLength(1)
|
||||||
|
expect(promptCalls[0]?.query).toEqual({ directory: "/parent/dir" })
|
||||||
|
})
|
||||||
|
|
||||||
test("strips leading zwsp from prompt body agent before promptAsync", async () => {
|
test("strips leading zwsp from prompt body agent before promptAsync", async () => {
|
||||||
//#given
|
//#given
|
||||||
const promptCalls: Array<{ body?: { agent?: string } }> = []
|
const promptCalls: Array<{ body?: { agent?: string } }> = []
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { BackgroundTask, LaunchInput, ResumeInput } from "./types"
|
import type { BackgroundTask, LaunchInput, ResumeInput } from "./types"
|
||||||
import type { OpencodeClient, OnSubagentSessionCreated, QueueItem } from "./constants"
|
import type { OpencodeClient, OnSubagentSessionCreated, QueueItem } from "./constants"
|
||||||
import { log, getAgentToolRestrictions, promptWithModelSuggestionRetry, createInternalAgentTextPart } from "../../shared"
|
import { log, getAgentToolRestrictions, createInternalAgentTextPart, promptWithRetryInDirectory } from "../../shared"
|
||||||
import { applySessionPromptParams } from "../../shared/session-prompt-params-helpers"
|
import { applySessionPromptParams } from "../../shared/session-prompt-params-helpers"
|
||||||
import { subagentSessions } from "../claude-code-session-state"
|
import { subagentSessions } from "../claude-code-session-state"
|
||||||
import { getTaskToastManager } from "../task-toast-manager"
|
import { getTaskToastManager } from "../task-toast-manager"
|
||||||
@@ -171,10 +171,10 @@ export async function startTask(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Must fire BEFORE tmux callback: attach client needs session activity to render TUI.
|
// Must fire BEFORE tmux callback: attach client needs session activity to render TUI.
|
||||||
const promptChain = promptWithModelSuggestionRetry(client, {
|
const promptChain = promptWithRetryInDirectory(client, {
|
||||||
path: { id: sessionID },
|
path: { id: sessionID },
|
||||||
body: promptBody,
|
body: promptBody,
|
||||||
}).catch(async (error) => {
|
}, parentDirectory).catch(async (error) => {
|
||||||
if (isAgentNotFoundError(error) && input.agent !== FALLBACK_AGENT) {
|
if (isAgentNotFoundError(error) && input.agent !== FALLBACK_AGENT) {
|
||||||
log("[background-agent] Agent not found, retrying with fallback agent", {
|
log("[background-agent] Agent not found, retrying with fallback agent", {
|
||||||
original: input.agent,
|
original: input.agent,
|
||||||
@@ -182,12 +182,12 @@ export async function startTask(
|
|||||||
taskId: task.id,
|
taskId: task.id,
|
||||||
})
|
})
|
||||||
try {
|
try {
|
||||||
await promptWithModelSuggestionRetry(client, {
|
await promptWithRetryInDirectory(client, {
|
||||||
path: { id: sessionID },
|
path: { id: sessionID },
|
||||||
body: buildFallbackBody(promptBody, FALLBACK_AGENT, {
|
body: buildFallbackBody(promptBody, FALLBACK_AGENT, {
|
||||||
includeTeamToolDenylist: input.teamRunId === undefined,
|
includeTeamToolDenylist: input.teamRunId === undefined,
|
||||||
}),
|
}),
|
||||||
})
|
}, parentDirectory)
|
||||||
task.agent = FALLBACK_AGENT
|
task.agent = FALLBACK_AGENT
|
||||||
return
|
return
|
||||||
} catch (retryError) {
|
} catch (retryError) {
|
||||||
@@ -227,18 +227,19 @@ export async function startTask(
|
|||||||
export async function resumeTask(
|
export async function resumeTask(
|
||||||
task: BackgroundTask,
|
task: BackgroundTask,
|
||||||
input: ResumeInput,
|
input: ResumeInput,
|
||||||
ctx: Pick<SpawnerContext, "client" | "concurrencyManager" | "onTaskError">
|
ctx: Pick<SpawnerContext, "client" | "concurrencyManager" | "directory" | "onTaskError">
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { client, concurrencyManager, onTaskError } = ctx
|
const { client, concurrencyManager, directory, onTaskError } = ctx
|
||||||
|
|
||||||
if (!task.sessionId) {
|
if (!task.sessionId) {
|
||||||
throw new Error(`Task has no sessionID: ${task.id}`)
|
throw new Error(`Task has no sessionID: ${task.id}`)
|
||||||
}
|
}
|
||||||
|
const sessionID = task.sessionId
|
||||||
|
|
||||||
if (task.status === "running") {
|
if (task.status === "running") {
|
||||||
log("[background-agent] Resume skipped - task already running:", {
|
log("[background-agent] Resume skipped - task already running:", {
|
||||||
taskId: task.id,
|
taskId: task.id,
|
||||||
sessionID: task.sessionId,
|
sessionID,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -262,7 +263,7 @@ export async function resumeTask(
|
|||||||
lastUpdate: new Date(),
|
lastUpdate: new Date(),
|
||||||
}
|
}
|
||||||
|
|
||||||
subagentSessions.add(task.sessionId)
|
subagentSessions.add(sessionID)
|
||||||
|
|
||||||
const toastManager = getTaskToastManager()
|
const toastManager = getTaskToastManager()
|
||||||
if (toastManager) {
|
if (toastManager) {
|
||||||
@@ -274,10 +275,10 @@ export async function resumeTask(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
log("[background-agent] Resuming task:", { taskId: task.id, sessionID: task.sessionId })
|
log("[background-agent] Resuming task:", { taskId: task.id, sessionID })
|
||||||
|
|
||||||
log("[background-agent] Resuming task - calling prompt (fire-and-forget) with:", {
|
log("[background-agent] Resuming task - calling prompt (fire-and-forget) with:", {
|
||||||
sessionID: task.sessionId,
|
sessionID,
|
||||||
agent: task.agent,
|
agent: task.agent,
|
||||||
model: task.model,
|
model: task.model,
|
||||||
promptLength: input.prompt.length,
|
promptLength: input.prompt.length,
|
||||||
@@ -291,7 +292,7 @@ export async function resumeTask(
|
|||||||
: undefined
|
: undefined
|
||||||
const resumeVariant = task.model?.variant
|
const resumeVariant = task.model?.variant
|
||||||
|
|
||||||
applySessionPromptParams(task.sessionId, task.model)
|
applySessionPromptParams(sessionID, task.model)
|
||||||
|
|
||||||
const resumeBody = {
|
const resumeBody = {
|
||||||
agent: task.agent,
|
agent: task.agent,
|
||||||
@@ -308,10 +309,10 @@ export async function resumeTask(
|
|||||||
parts: [createInternalAgentTextPart(input.prompt)],
|
parts: [createInternalAgentTextPart(input.prompt)],
|
||||||
}
|
}
|
||||||
|
|
||||||
client.session.promptAsync({
|
promptWithRetryInDirectory(client, {
|
||||||
path: { id: task.sessionId },
|
path: { id: sessionID },
|
||||||
body: resumeBody,
|
body: resumeBody,
|
||||||
}).catch(async (error) => {
|
}, directory).catch(async (error) => {
|
||||||
if (isAgentNotFoundError(error) && task.agent !== FALLBACK_AGENT) {
|
if (isAgentNotFoundError(error) && task.agent !== FALLBACK_AGENT) {
|
||||||
log("[background-agent] Resume agent not found, retrying with fallback agent", {
|
log("[background-agent] Resume agent not found, retrying with fallback agent", {
|
||||||
original: task.agent,
|
original: task.agent,
|
||||||
@@ -319,12 +320,12 @@ export async function resumeTask(
|
|||||||
taskId: task.id,
|
taskId: task.id,
|
||||||
})
|
})
|
||||||
try {
|
try {
|
||||||
await promptWithModelSuggestionRetry(client, {
|
await promptWithRetryInDirectory(client, {
|
||||||
path: { id: task.sessionId! },
|
path: { id: sessionID },
|
||||||
body: buildFallbackBody(resumeBody, FALLBACK_AGENT, {
|
body: buildFallbackBody(resumeBody, FALLBACK_AGENT, {
|
||||||
includeTeamToolDenylist: task.teamRunId === undefined,
|
includeTeamToolDenylist: task.teamRunId === undefined,
|
||||||
}),
|
}),
|
||||||
})
|
}, directory)
|
||||||
task.agent = FALLBACK_AGENT
|
task.agent = FALLBACK_AGENT
|
||||||
return
|
return
|
||||||
} catch (retryError) {
|
} catch (retryError) {
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ type PromptAsyncCall = {
|
|||||||
noReply?: boolean
|
noReply?: boolean
|
||||||
parts?: unknown[]
|
parts?: unknown[]
|
||||||
}
|
}
|
||||||
|
query?: {
|
||||||
|
directory: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type FakeTimers = {
|
type FakeTimers = {
|
||||||
@@ -274,6 +277,24 @@ describe("BackgroundManager.notifyParentSession cleanup scheduling", () => {
|
|||||||
expect(notificationPayload).toContain(OMO_INTERNAL_INITIATOR_MARKER)
|
expect(notificationPayload).toContain(OMO_INTERNAL_INITIATOR_MARKER)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("#when all-complete notification wakes parent #then prompt stays in the same OpenCode directory instance", async () => {
|
||||||
|
// given
|
||||||
|
const { manager, promptAsyncCalls } = createManager(true)
|
||||||
|
managerUnderTest = manager
|
||||||
|
const directory = Reflect.get(manager, "directory") as string
|
||||||
|
const task = createTask({ id: "task-a", parentSessionId: "parent-1", description: "task A", status: "completed", completedAt: new Date("2026-03-11T00:01:00.000Z") })
|
||||||
|
getTasks(manager).set(task.id, task)
|
||||||
|
getPendingByParent(manager).set(task.parentSessionId, new Set([task.id]))
|
||||||
|
|
||||||
|
// when
|
||||||
|
await notifyParentSessionForTest(manager, task)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(promptAsyncCalls).toHaveLength(1)
|
||||||
|
expect(promptAsyncCalls[0]?.body.noReply).toBe(false)
|
||||||
|
expect(promptAsyncCalls[0]?.query).toEqual({ directory })
|
||||||
|
})
|
||||||
|
|
||||||
test("#when busy parent later becomes idle #then completion notification is not replayed as a second parent prompt", async () => {
|
test("#when busy parent later becomes idle #then completion notification is not replayed as a second parent prompt", async () => {
|
||||||
// given
|
// given
|
||||||
const sessionStatuses: Record<string, { type: string }> = {
|
const sessionStatuses: Record<string, { type: string }> = {
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ export * from "./project-discovery-dirs"
|
|||||||
export * from "./normalize-sdk-response"
|
export * from "./normalize-sdk-response"
|
||||||
export * from "./record-type-guard"
|
export * from "./record-type-guard"
|
||||||
export * from "./session-directory-resolver"
|
export * from "./session-directory-resolver"
|
||||||
|
export * from "./session-route"
|
||||||
export * from "./prompt-tools"
|
export * from "./prompt-tools"
|
||||||
export * from "./compaction-marker"
|
export * from "./compaction-marker"
|
||||||
export * from "./internal-initiator-marker"
|
export * from "./internal-initiator-marker"
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import type { PluginInput } from "@opencode-ai/plugin"
|
||||||
|
import {
|
||||||
|
promptSyncWithModelSuggestionRetry,
|
||||||
|
promptWithModelSuggestionRetry,
|
||||||
|
} from "./model-suggestion-retry"
|
||||||
|
|
||||||
|
type OpencodeClient = PluginInput["client"]
|
||||||
|
|
||||||
|
type PromptAsyncArgs = Parameters<OpencodeClient["session"]["promptAsync"]>[0]
|
||||||
|
type SessionMessagesArgs = Parameters<OpencodeClient["session"]["messages"]>[0]
|
||||||
|
type PromptRetryClient = Parameters<typeof promptWithModelSuggestionRetry>[0]
|
||||||
|
type PromptRetryArgs = Parameters<typeof promptWithModelSuggestionRetry>[1]
|
||||||
|
type PromptSyncRetryClient = Parameters<typeof promptSyncWithModelSuggestionRetry>[0]
|
||||||
|
type PromptSyncRetryArgs = Parameters<typeof promptSyncWithModelSuggestionRetry>[1]
|
||||||
|
|
||||||
|
export function routeSessionPrompt(args: PromptAsyncArgs, directory: string): PromptAsyncArgs {
|
||||||
|
return {
|
||||||
|
...args,
|
||||||
|
query: { directory },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function routePromptRetry(args: PromptRetryArgs, directory: string): PromptRetryArgs {
|
||||||
|
return {
|
||||||
|
...args,
|
||||||
|
query: { directory },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function routePromptSyncRetry(
|
||||||
|
args: PromptSyncRetryArgs,
|
||||||
|
directory: string,
|
||||||
|
): PromptSyncRetryArgs {
|
||||||
|
return {
|
||||||
|
...args,
|
||||||
|
query: { directory },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function routeSessionMessages(
|
||||||
|
args: SessionMessagesArgs,
|
||||||
|
directory: string,
|
||||||
|
): SessionMessagesArgs {
|
||||||
|
return {
|
||||||
|
...args,
|
||||||
|
query: { directory },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function promptAsyncInDirectory(
|
||||||
|
client: OpencodeClient,
|
||||||
|
args: PromptAsyncArgs,
|
||||||
|
directory: string,
|
||||||
|
): Promise<unknown> {
|
||||||
|
return client.session.promptAsync(routeSessionPrompt(args, directory))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function promptWithRetryInDirectory(
|
||||||
|
client: PromptRetryClient,
|
||||||
|
args: PromptRetryArgs,
|
||||||
|
directory: string,
|
||||||
|
): Promise<void> {
|
||||||
|
return promptWithModelSuggestionRetry(client, routePromptRetry(args, directory))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function promptSyncWithRetryInDirectory(
|
||||||
|
client: PromptSyncRetryClient,
|
||||||
|
args: PromptSyncRetryArgs,
|
||||||
|
directory: string,
|
||||||
|
): Promise<void> {
|
||||||
|
return promptSyncWithModelSuggestionRetry(client, routePromptSyncRetry(args, directory))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function messagesInDirectory(
|
||||||
|
client: OpencodeClient,
|
||||||
|
args: SessionMessagesArgs,
|
||||||
|
directory: string,
|
||||||
|
): Promise<unknown> {
|
||||||
|
return client.session.messages(routeSessionMessages(args, directory))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user