fix(hooks): switch session.prompt to promptAsync in all hooks
This commit is contained in:
parent
5f21ddf473
commit
46e02b9457
@ -484,7 +484,7 @@ export function createAtlasHook(
|
||||
: undefined
|
||||
}
|
||||
|
||||
await ctx.client.session.prompt({
|
||||
await ctx.client.session.promptAsync({
|
||||
path: { id: sessionID },
|
||||
body: {
|
||||
agent: agent ?? "atlas",
|
||||
|
||||
@ -364,7 +364,7 @@ export function createRalphLoopHook(
|
||||
: undefined
|
||||
}
|
||||
|
||||
await ctx.client.session.prompt({
|
||||
await ctx.client.session.promptAsync({
|
||||
path: { id: sessionID },
|
||||
body: {
|
||||
...(agent !== undefined ? { agent } : {}),
|
||||
|
||||
@ -75,7 +75,7 @@ function extractResumeConfig(userMessage: MessageData | undefined, sessionID: st
|
||||
|
||||
async function resumeSession(client: Client, config: ResumeConfig): Promise<boolean> {
|
||||
try {
|
||||
await client.session.prompt({
|
||||
await client.session.promptAsync({
|
||||
path: { id: config.sessionID },
|
||||
body: {
|
||||
parts: [{ type: "text", text: RECOVERY_RESUME_TEXT }],
|
||||
@ -185,7 +185,7 @@ async function recoverToolResultMissing(
|
||||
}))
|
||||
|
||||
try {
|
||||
await client.session.prompt({
|
||||
await client.session.promptAsync({
|
||||
path: { id: sessionID },
|
||||
// @ts-expect-error - SDK types may not include tool_result parts
|
||||
body: { parts: toolResultParts },
|
||||
|
||||
@ -245,7 +245,7 @@ ${todoList}`
|
||||
try {
|
||||
log(`[${HOOK_NAME}] Injecting continuation`, { sessionID, agent: agentName, model, incompleteCount: freshIncompleteCount })
|
||||
|
||||
await ctx.client.session.prompt({
|
||||
await ctx.client.session.promptAsync({
|
||||
path: { id: sessionID },
|
||||
body: {
|
||||
agent: agentName,
|
||||
|
||||
@ -25,6 +25,15 @@ type BabysitterContext = {
|
||||
}
|
||||
query?: { directory?: string }
|
||||
}) => Promise<unknown>
|
||||
promptAsync: (args: {
|
||||
path: { id: string }
|
||||
body: {
|
||||
parts: Array<{ type: "text"; text: string }>
|
||||
agent?: string
|
||||
model?: { providerID: string; modelID: string }
|
||||
}
|
||||
query?: { directory?: string }
|
||||
}) => Promise<unknown>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -218,7 +227,7 @@ export function createUnstableAgentBabysitterHook(ctx: BabysitterContext, option
|
||||
const { agent, model } = await resolveMainSessionTarget(ctx, mainSessionID)
|
||||
|
||||
try {
|
||||
await ctx.client.session.prompt({
|
||||
await ctx.client.session.promptAsync({
|
||||
path: { id: mainSessionID },
|
||||
body: {
|
||||
...(agent ? { agent } : {}),
|
||||
|
||||
@ -212,9 +212,9 @@ describe("parseModelSuggestion", () => {
|
||||
|
||||
describe("promptWithModelSuggestionRetry", () => {
|
||||
it("should succeed on first try without retry", async () => {
|
||||
// given a client where prompt succeeds
|
||||
// given a client where promptAsync succeeds
|
||||
const promptMock = mock(() => Promise.resolve())
|
||||
const client = { session: { prompt: promptMock } }
|
||||
const client = { session: { promptAsync: promptMock } }
|
||||
|
||||
// when calling promptWithModelSuggestionRetry
|
||||
await promptWithModelSuggestionRetry(client as any, {
|
||||
@ -225,21 +225,158 @@ describe("promptWithModelSuggestionRetry", () => {
|
||||
},
|
||||
})
|
||||
|
||||
// then should call prompt exactly once
|
||||
// then should call promptAsync exactly once
|
||||
expect(promptMock).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("should retry with suggestion on model-not-found error", async () => {
|
||||
// given a client that fails first with model-not-found, then succeeds
|
||||
const promptMock = mock()
|
||||
.mockRejectedValueOnce({
|
||||
name: "ProviderModelNotFoundError",
|
||||
data: {
|
||||
providerID: "anthropic",
|
||||
modelID: "claude-sonet-4",
|
||||
suggestions: ["claude-sonnet-4"],
|
||||
it("should throw error from promptAsync directly on model-not-found error", async () => {
|
||||
// given a client that fails with model-not-found error
|
||||
const promptMock = mock().mockRejectedValueOnce({
|
||||
name: "ProviderModelNotFoundError",
|
||||
data: {
|
||||
providerID: "anthropic",
|
||||
modelID: "claude-sonet-4",
|
||||
suggestions: ["claude-sonnet-4"],
|
||||
},
|
||||
})
|
||||
const client = { session: { promptAsync: promptMock } }
|
||||
|
||||
// when calling promptWithModelSuggestionRetry
|
||||
// then should throw the error without retrying
|
||||
await expect(
|
||||
promptWithModelSuggestionRetry(client as any, {
|
||||
path: { id: "session-1" },
|
||||
body: {
|
||||
agent: "explore",
|
||||
parts: [{ type: "text", text: "hello" }],
|
||||
model: { providerID: "anthropic", modelID: "claude-sonet-4" },
|
||||
},
|
||||
})
|
||||
).rejects.toThrow()
|
||||
|
||||
// and should call promptAsync only once
|
||||
expect(promptMock).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("should throw original error when no suggestion available", async () => {
|
||||
// given a client that fails with a non-model-not-found error
|
||||
const originalError = new Error("Connection refused")
|
||||
const promptMock = mock().mockRejectedValueOnce(originalError)
|
||||
const client = { session: { promptAsync: promptMock } }
|
||||
|
||||
// when calling promptWithModelSuggestionRetry
|
||||
// then should throw the original error
|
||||
await expect(
|
||||
promptWithModelSuggestionRetry(client as any, {
|
||||
path: { id: "session-1" },
|
||||
body: {
|
||||
parts: [{ type: "text", text: "hello" }],
|
||||
model: { providerID: "anthropic", modelID: "claude-sonnet-4" },
|
||||
},
|
||||
})
|
||||
).rejects.toThrow("Connection refused")
|
||||
|
||||
expect(promptMock).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("should throw error from promptAsync directly", async () => {
|
||||
// given a client that fails with an error
|
||||
const error = new Error("Still not found")
|
||||
const promptMock = mock().mockRejectedValueOnce(error)
|
||||
const client = { session: { promptAsync: promptMock } }
|
||||
|
||||
// when calling promptWithModelSuggestionRetry
|
||||
// then should throw the error
|
||||
await expect(
|
||||
promptWithModelSuggestionRetry(client as any, {
|
||||
path: { id: "session-1" },
|
||||
body: {
|
||||
parts: [{ type: "text", text: "hello" }],
|
||||
model: { providerID: "anthropic", modelID: "claude-sonnet-4" },
|
||||
},
|
||||
})
|
||||
).rejects.toThrow("Still not found")
|
||||
|
||||
// and should call promptAsync only once
|
||||
expect(promptMock).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("should pass all body fields through to promptAsync", async () => {
|
||||
// given a client where promptAsync succeeds
|
||||
const promptMock = mock().mockResolvedValueOnce(undefined)
|
||||
const client = { session: { promptAsync: promptMock } }
|
||||
|
||||
// when calling with additional body fields
|
||||
await promptWithModelSuggestionRetry(client as any, {
|
||||
path: { id: "session-1" },
|
||||
body: {
|
||||
agent: "explore",
|
||||
system: "You are a helpful agent",
|
||||
tools: { task: false },
|
||||
parts: [{ type: "text", text: "hello" }],
|
||||
model: { providerID: "anthropic", modelID: "claude-sonnet-4" },
|
||||
variant: "max",
|
||||
},
|
||||
})
|
||||
|
||||
// then call should pass all fields through unchanged
|
||||
const call = promptMock.mock.calls[0][0]
|
||||
expect(call.body.agent).toBe("explore")
|
||||
expect(call.body.system).toBe("You are a helpful agent")
|
||||
expect(call.body.tools).toEqual({ task: false })
|
||||
expect(call.body.variant).toBe("max")
|
||||
expect(call.body.model).toEqual({
|
||||
providerID: "anthropic",
|
||||
modelID: "claude-sonnet-4",
|
||||
})
|
||||
})
|
||||
|
||||
it("should throw string error message from promptAsync", async () => {
|
||||
// given a client that fails with a string error
|
||||
const promptMock = mock().mockRejectedValueOnce(
|
||||
new Error("Model not found: anthropic/claude-sonet-4. Did you mean: claude-sonnet-4?")
|
||||
)
|
||||
const client = { session: { promptAsync: promptMock } }
|
||||
|
||||
// when calling promptWithModelSuggestionRetry
|
||||
// then should throw the error
|
||||
await expect(
|
||||
promptWithModelSuggestionRetry(client as any, {
|
||||
path: { id: "session-1" },
|
||||
body: {
|
||||
parts: [{ type: "text", text: "hello" }],
|
||||
model: { providerID: "anthropic", modelID: "claude-sonnet-4" },
|
||||
},
|
||||
})
|
||||
).rejects.toThrow()
|
||||
|
||||
// and should call promptAsync only once
|
||||
expect(promptMock).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("should throw error when no model in original request", async () => {
|
||||
// given a client that fails with an error
|
||||
const modelNotFoundError = new Error(
|
||||
"Model not found: anthropic/claude-sonet-4. Did you mean: claude-sonnet-4?"
|
||||
)
|
||||
const promptMock = mock().mockRejectedValueOnce(modelNotFoundError)
|
||||
const client = { session: { promptAsync: promptMock } }
|
||||
|
||||
// when calling without model in body
|
||||
// then should throw the error
|
||||
await expect(
|
||||
promptWithModelSuggestionRetry(client as any, {
|
||||
path: { id: "session-1" },
|
||||
body: {
|
||||
parts: [{ type: "text", text: "hello" }],
|
||||
},
|
||||
})
|
||||
).rejects.toThrow()
|
||||
|
||||
// and should call promptAsync only once
|
||||
expect(promptMock).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
.mockResolvedValueOnce(undefined)
|
||||
const client = { session: { prompt: promptMock } }
|
||||
|
||||
|
||||
@ -219,18 +219,18 @@ Original error: ${createResult.error}`
|
||||
log(`[call_omo_agent] Sending prompt to session ${sessionID}`)
|
||||
log(`[call_omo_agent] Prompt text:`, args.prompt.substring(0, 100))
|
||||
|
||||
try {
|
||||
await ctx.client.session.prompt({
|
||||
path: { id: sessionID },
|
||||
body: {
|
||||
agent: args.subagent_type,
|
||||
tools: {
|
||||
...getAgentToolRestrictions(args.subagent_type),
|
||||
task: false,
|
||||
},
|
||||
parts: [{ type: "text", text: args.prompt }],
|
||||
},
|
||||
})
|
||||
try {
|
||||
await ctx.client.session.promptAsync({
|
||||
path: { id: sessionID },
|
||||
body: {
|
||||
agent: args.subagent_type,
|
||||
tools: {
|
||||
...getAgentToolRestrictions(args.subagent_type),
|
||||
task: false,
|
||||
},
|
||||
parts: [{ type: "text", text: args.prompt }],
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
log(`[call_omo_agent] Prompt error:`, errorMessage)
|
||||
|
||||
@ -211,20 +211,20 @@ export async function executeSyncContinuation(
|
||||
: undefined
|
||||
}
|
||||
|
||||
await client.session.prompt({
|
||||
path: { id: args.session_id! },
|
||||
body: {
|
||||
...(resumeAgent !== undefined ? { agent: resumeAgent } : {}),
|
||||
...(resumeModel !== undefined ? { model: resumeModel } : {}),
|
||||
tools: {
|
||||
...(resumeAgent ? getAgentToolRestrictions(resumeAgent) : {}),
|
||||
task: false,
|
||||
call_omo_agent: true,
|
||||
question: false,
|
||||
},
|
||||
parts: [{ type: "text", text: args.prompt }],
|
||||
},
|
||||
})
|
||||
await client.session.promptAsync({
|
||||
path: { id: args.session_id! },
|
||||
body: {
|
||||
...(resumeAgent !== undefined ? { agent: resumeAgent } : {}),
|
||||
...(resumeModel !== undefined ? { model: resumeModel } : {}),
|
||||
tools: {
|
||||
...(resumeAgent ? getAgentToolRestrictions(resumeAgent) : {}),
|
||||
task: false,
|
||||
call_omo_agent: true,
|
||||
question: false,
|
||||
},
|
||||
parts: [{ type: "text", text: args.prompt }],
|
||||
},
|
||||
})
|
||||
} catch (promptError) {
|
||||
if (toastManager) {
|
||||
toastManager.removeTask(taskId)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user