Skip to content

Commit 5cd1448

Browse files
committed
revert ctrl-c to cancel
1 parent 9e7a311 commit 5cd1448

File tree

5 files changed

+85
-111
lines changed

5 files changed

+85
-111
lines changed

cli/src/hooks/use-keyboard-handlers.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ export const useKeyboardHandlers = ({
4949
if (abortControllerRef.current) {
5050
abortControllerRef.current.abort()
5151
}
52-
53-
return
5452
}
5553

5654
if (isCtrlC) {

cli/src/hooks/use-send-message.ts

Lines changed: 53 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -616,46 +616,6 @@ export const useSendMessage = ({
616616

617617
const abortController = new AbortController()
618618
abortControllerRef.current = abortController
619-
abortController.signal.addEventListener('abort', () => {
620-
setIsStreaming(false)
621-
setCanProcessQueue(true)
622-
updateChainInProgress(false)
623-
setIsWaitingForResponse(false)
624-
timerController.stop('aborted')
625-
626-
applyMessageUpdate((prev) =>
627-
prev.map((msg) => {
628-
if (msg.id !== aiMessageId) {
629-
return msg
630-
}
631-
632-
const blocks: ContentBlock[] = msg.blocks ? [...msg.blocks] : []
633-
const lastBlock = blocks[blocks.length - 1]
634-
635-
if (lastBlock && lastBlock.type === 'text') {
636-
const interruptedBlock: ContentBlock = {
637-
type: 'text',
638-
content: `${lastBlock.content}\n\n[response interrupted]`,
639-
}
640-
return {
641-
...msg,
642-
blocks: [...blocks.slice(0, -1), interruptedBlock],
643-
isComplete: true,
644-
}
645-
}
646-
647-
const interruptionNotice: ContentBlock = {
648-
type: 'text',
649-
content: '[response interrupted]',
650-
}
651-
return {
652-
...msg,
653-
blocks: [...blocks, interruptionNotice],
654-
isComplete: true,
655-
}
656-
}),
657-
)
658-
})
659619

660620
try {
661621
// Load local agent definitions from .agents directory
@@ -1346,11 +1306,6 @@ export const useSendMessage = ({
13461306
},
13471307
})
13481308

1349-
if (!result.success) {
1350-
logger.warn({ error: result.error }, 'Agent run failed')
1351-
return
1352-
}
1353-
13541309
setIsStreaming(false)
13551310
setCanProcessQueue(true)
13561311
updateChainInProgress(false)
@@ -1387,6 +1342,8 @@ export const useSendMessage = ({
13871342

13881343
previousRunStateRef.current = result
13891344
} catch (error) {
1345+
const isAborted = error instanceof Error && error.name === 'AbortError'
1346+
13901347
logger.error(
13911348
{ error: getErrorObject(error) },
13921349
'SDK client.run() failed',
@@ -1395,26 +1352,61 @@ export const useSendMessage = ({
13951352
setCanProcessQueue(true)
13961353
updateChainInProgress(false)
13971354
setIsWaitingForResponse(false)
1398-
timerController.stop('error')
1355+
timerController.stop(isAborted ? 'aborted' : 'error')
13991356

1400-
const errorMessage =
1401-
error instanceof Error ? error.message : 'Unknown error occurred'
1402-
applyMessageUpdate((prev) =>
1403-
prev.map((msg) =>
1404-
msg.id === aiMessageId
1405-
? {
1357+
if (isAborted) {
1358+
applyMessageUpdate((prev) =>
1359+
prev.map((msg) => {
1360+
if (msg.id !== aiMessageId) {
1361+
return msg
1362+
}
1363+
1364+
const blocks: ContentBlock[] = msg.blocks ? [...msg.blocks] : []
1365+
const lastBlock = blocks[blocks.length - 1]
1366+
1367+
if (lastBlock && lastBlock.type === 'text') {
1368+
const interruptedBlock: ContentBlock = {
1369+
type: 'text',
1370+
content: `${lastBlock.content}\n\n[response interrupted]`,
1371+
}
1372+
return {
14061373
...msg,
1407-
content: msg.content + `\n\n**Error:** ${errorMessage}`,
1374+
blocks: [...blocks.slice(0, -1), interruptedBlock],
1375+
isComplete: true,
14081376
}
1409-
: msg,
1410-
),
1411-
)
1377+
}
14121378

1413-
applyMessageUpdate((prev) =>
1414-
prev.map((msg) =>
1415-
msg.id === aiMessageId ? { ...msg, isComplete: true } : msg,
1416-
),
1417-
)
1379+
const interruptionNotice: ContentBlock = {
1380+
type: 'text',
1381+
content: '[response interrupted]',
1382+
}
1383+
return {
1384+
...msg,
1385+
blocks: [...blocks, interruptionNotice],
1386+
isComplete: true,
1387+
}
1388+
}),
1389+
)
1390+
} else {
1391+
const errorMessage =
1392+
error instanceof Error ? error.message : 'Unknown error occurred'
1393+
applyMessageUpdate((prev) =>
1394+
prev.map((msg) =>
1395+
msg.id === aiMessageId
1396+
? {
1397+
...msg,
1398+
content: msg.content + `\n\n**Error:** ${errorMessage}`,
1399+
}
1400+
: msg,
1401+
),
1402+
)
1403+
1404+
applyMessageUpdate((prev) =>
1405+
prev.map((msg) =>
1406+
msg.id === aiMessageId ? { ...msg, isComplete: true } : msg,
1407+
),
1408+
)
1409+
}
14181410
}
14191411
},
14201412
[

sdk/src/client.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { WEBSITE_URL } from './constants'
1+
import { BACKEND_URL, WEBSITE_URL } from './constants'
22
import { run } from './run'
33
import { API_KEY_ENV_VAR } from '../../common/src/old-constants'
44

55
import type { RunOptions, CodebuffClientOptions } from './run'
66
import type { RunState } from './run-state'
7-
import type { ErrorOr } from '@codebuff/common/util/error'
87

98
export class CodebuffClient {
109
public options: CodebuffClientOptions & {
@@ -49,13 +48,11 @@ export class CodebuffClient {
4948
* @param maxAgentSteps - (Optional) Maximum number of steps the agent can take before stopping. Use this as a safety measure in case your agent starts going off the rails. A reasonable number is around 20.
5049
* @param env - (Optional) Environment variables to pass to terminal commands executed by the agent. These will be merged with process.env, with the custom values taking precedence. Can also be provided in individual run() calls to override.
5150
*
52-
* @returns A Promise that resolves to one of:
53-
* - { "success": true, value: runState } (a RunState JSON object which you can pass to a subsequent run() call to continue the run. Use result.output to get the agent's output.)
54-
* - { "success": false, error: error } (a JSON object containing `name`, `message`, and `stack` properties)
51+
* @returns A Promise that resolves to a RunState JSON object which you can pass to a subsequent run() call to continue the run. Use result.output to get the agent's output.
5552
*/
5653
public async run(
5754
options: RunOptions & CodebuffClientOptions,
58-
): Promise<ErrorOr<RunState>> {
55+
): Promise<RunState> {
5956
return run({ ...this.options, ...options })
6057
}
6158

sdk/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ export type * from '../../common/src/types/json'
22
export type * from '../../common/src/types/messages/codebuff-message'
33
export type * from '../../common/src/types/messages/data-content'
44
export type * from '../../common/src/types/print-mode'
5-
export type * from '../../common/src/util/error'
65
export type * from './run'
76
// Agent type exports
87
export type { AgentDefinition } from '../../common/src/templates/initial-agents-dir/types/agent-definition'

sdk/src/run.ts

Lines changed: 29 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { toOptionalFile } from '@codebuff/common/old-constants'
77
import { toolNames } from '@codebuff/common/tools/constants'
88
import { clientToolCallSchema } from '@codebuff/common/tools/list'
99
import { AgentOutputSchema } from '@codebuff/common/types/session-state'
10-
import { failure, success } from '@codebuff/common/util/error'
1110
import { cloneDeep } from 'lodash'
1211

1312
import { getAgentRuntimeImpl } from './impl/agent-runtime'
@@ -45,7 +44,6 @@ import type {
4544
import type { PrintModeEvent } from '@codebuff/common/types/print-mode'
4645
import type { SessionState } from '@codebuff/common/types/session-state'
4746
import type { Source } from '@codebuff/common/types/source'
48-
import type { ErrorOr, Failure } from '@codebuff/common/util/error'
4947

5048
export type CodebuffClientOptions = {
5149
apiKey?: string
@@ -100,13 +98,12 @@ export type RunOptions = {
10098
signal?: AbortSignal
10199
}
102100

103-
function checkAborted(signal?: AbortSignal): Failure | null {
104-
if (!signal?.aborted) {
105-
return null
101+
function checkAborted(signal?: AbortSignal) {
102+
if (signal?.aborted) {
103+
const error = new Error('Run cancelled by user')
104+
error.name = 'AbortError'
105+
throw error
106106
}
107-
const error = new Error('Run cancelled by user')
108-
error.name = 'AbortError'
109-
return failure(error)
110107
}
111108

112109
type RunReturnType = Awaited<ReturnType<typeof run>>
@@ -140,11 +137,8 @@ export async function run({
140137
CodebuffClientOptions & {
141138
apiKey: string
142139
fingerprintId: string
143-
}): Promise<ErrorOr<RunState>> {
144-
const aborted = checkAborted(signal)
145-
if (aborted) {
146-
return aborted
147-
}
140+
}): Promise<RunState> {
141+
checkAborted(signal)
148142

149143
const fs = await (typeof fsSource === 'function' ? fsSource() : fsSource)
150144

@@ -174,11 +168,7 @@ export async function run({
174168
const onResponseChunk = async (
175169
action: ServerAction<'response-chunk'>,
176170
): Promise<void> => {
177-
const aborted = checkAborted(signal)
178-
if (aborted) {
179-
resolve(aborted)
180-
return
181-
}
171+
checkAborted(signal)
182172
const { chunk } = action
183173
if (typeof chunk !== 'string') {
184174
if (chunk.type === 'reasoning') {
@@ -215,11 +205,7 @@ export async function run({
215205
const onSubagentResponseChunk = async (
216206
action: ServerAction<'subagent-response-chunk'>,
217207
) => {
218-
const aborted = checkAborted(signal)
219-
if (aborted) {
220-
resolve(aborted)
221-
return
222-
}
208+
checkAborted(signal)
223209
const { agentId, agentType, chunk } = action
224210

225211
if (handleStreamChunk) {
@@ -395,10 +381,7 @@ export async function run({
395381
const promptId = Math.random().toString(36).substring(2, 15)
396382

397383
// Send input
398-
const isAborted = checkAborted(signal)
399-
if (isAborted) {
400-
return isAborted
401-
}
384+
checkAborted(signal)
402385

403386
const userInfo = await getUserInfoFromApiKey({
404387
...agentRuntimeImpl,
@@ -587,15 +570,13 @@ async function handlePromptResponse({
587570
}) {
588571
if (action.type === 'prompt-error') {
589572
onError({ message: action.message })
590-
resolve(
591-
failure({
592-
sessionState: initialSessionState,
593-
output: {
594-
type: 'error',
595-
message: action.message,
596-
},
597-
}),
598-
)
573+
resolve({
574+
sessionState: initialSessionState,
575+
output: {
576+
type: 'error',
577+
message: action.message,
578+
},
579+
})
599580
} else if (action.type === 'prompt-response') {
600581
// Stop enforcing session state schema! It's a black box we will pass back to the server.
601582
// Only check the output schema.
@@ -607,7 +588,10 @@ async function handlePromptResponse({
607588
'If this issues persists, please contact support@codebuff.com',
608589
].join('\n')
609590
onError({ message })
610-
resolve(failure(new Error(message)))
591+
resolve({
592+
sessionState: initialSessionState,
593+
output: { type: 'error', message },
594+
})
611595
return
612596
}
613597
const { sessionState, output } = action
@@ -619,14 +603,18 @@ async function handlePromptResponse({
619603
message: 'No output from agent',
620604
},
621605
}
622-
resolve(success(state))
606+
resolve(state)
623607
} else {
624608
action satisfies never
625609
onError({
626610
message: 'Internal error: prompt response type not handled',
627611
})
628-
resolve(
629-
failure(new Error('Internal error: prompt response type not handled')),
630-
)
612+
resolve({
613+
sessionState: initialSessionState,
614+
output: {
615+
type: 'error',
616+
message: 'Internal error: prompt response type not handled',
617+
},
618+
})
631619
}
632620
}

0 commit comments

Comments
 (0)