feat: create draft framework for cli & sdk

This commit is contained in:
mingholy.lmh
2025-11-23 19:36:31 +08:00
parent 6729980b47
commit e1ffaec499
58 changed files with 8982 additions and 668 deletions

View File

@@ -939,9 +939,25 @@ export abstract class BaseJsonOutputAdapter {
this.emitMessageImpl(message);
}
/**
* Checks if responseParts contain any functionResponse with an error.
* This handles cancelled responses and other error cases where the error
* is embedded in responseParts rather than the top-level error field.
* @param responseParts - Array of Part objects
* @returns Error message if found, undefined otherwise
*/
private checkResponsePartsForError(
responseParts: Part[] | undefined,
): string | undefined {
// Use the shared helper function defined at file level
return checkResponsePartsForError(responseParts);
}
/**
* Emits a tool result message.
* Collects execution denied tool calls for inclusion in result messages.
* Handles both explicit errors (response.error) and errors embedded in
* responseParts (e.g., cancelled responses).
* @param request - Tool call request info
* @param response - Tool call response info
* @param parentToolUseId - Parent tool use ID (null for main agent)
@@ -951,6 +967,14 @@ export abstract class BaseJsonOutputAdapter {
response: ToolCallResponseInfo,
parentToolUseId: string | null = null,
): void {
// Check for errors in responseParts (e.g., cancelled responses)
const responsePartsError = this.checkResponsePartsForError(
response.responseParts,
);
// Determine if this is an error response
const hasError = Boolean(response.error) || Boolean(responsePartsError);
// Track permission denials (execution denied errors)
if (
response.error &&
@@ -967,7 +991,7 @@ export abstract class BaseJsonOutputAdapter {
const block: ToolResultBlock = {
type: 'tool_result',
tool_use_id: request.callId,
is_error: Boolean(response.error),
is_error: hasError,
};
const content = toolResultContent(response);
if (content !== undefined) {
@@ -1173,11 +1197,41 @@ export function partsToString(parts: Part[]): string {
.join('');
}
/**
* Checks if responseParts contain any functionResponse with an error.
* Helper function for extracting error messages from responseParts.
* @param responseParts - Array of Part objects
* @returns Error message if found, undefined otherwise
*/
function checkResponsePartsForError(
responseParts: Part[] | undefined,
): string | undefined {
if (!responseParts || responseParts.length === 0) {
return undefined;
}
for (const part of responseParts) {
if (
'functionResponse' in part &&
part.functionResponse?.response &&
typeof part.functionResponse.response === 'object' &&
'error' in part.functionResponse.response &&
part.functionResponse.response['error']
) {
const error = part.functionResponse.response['error'];
return typeof error === 'string' ? error : String(error);
}
}
return undefined;
}
/**
* Extracts content from tool response.
* Uses functionResponsePartsToString to properly handle functionResponse parts,
* which correctly extracts output content from functionResponse objects rather
* than simply concatenating text or JSON.stringify.
* Also handles errors embedded in responseParts (e.g., cancelled responses).
*
* @param response - Tool call response
* @returns String content or undefined
@@ -1188,6 +1242,11 @@ export function toolResultContent(
if (response.error) {
return response.error.message;
}
// Check for errors in responseParts (e.g., cancelled responses)
const responsePartsError = checkResponsePartsForError(response.responseParts);
if (responsePartsError) {
return responsePartsError;
}
if (
typeof response.resultDisplay === 'string' &&
response.resultDisplay.trim().length > 0