mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-07-09 01:27:41 -07:00
Disallow unsafe type assertions (#18688)
This commit is contained in:
committed by
GitHub
parent
bce1caefd0
commit
fd65416a2f
@@ -185,6 +185,7 @@ export async function parseAgentMarkdown(
|
||||
} catch (error) {
|
||||
throw new AgentLoadError(
|
||||
filePath,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
`YAML frontmatter parsing failed: ${(error as Error).message}`,
|
||||
);
|
||||
}
|
||||
@@ -328,12 +329,14 @@ export async function loadAgentsFromDirectory(
|
||||
dirEntries = await fs.readdir(dir, { withFileTypes: true });
|
||||
} catch (error) {
|
||||
// If directory doesn't exist, just return empty
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
||||
return result;
|
||||
}
|
||||
result.errors.push(
|
||||
new AgentLoadError(
|
||||
dir,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
`Could not list directory: ${(error as Error).message}`,
|
||||
),
|
||||
);
|
||||
@@ -364,6 +367,7 @@ export async function loadAgentsFromDirectory(
|
||||
result.errors.push(
|
||||
new AgentLoadError(
|
||||
filePath,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
`Unexpected error: ${(error as Error).message}`,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -822,6 +822,7 @@ export class LocalAgentExecutor<TOutput extends z.ZodTypeAny> {
|
||||
for (const [index, functionCall] of functionCalls.entries()) {
|
||||
const callId = functionCall.id ?? `${promptId}-${index}`;
|
||||
const args = functionCall.args ?? {};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const toolName = functionCall.name as string;
|
||||
|
||||
this.emitActivity('TOOL_CALL_START', {
|
||||
@@ -1107,6 +1108,7 @@ export class LocalAgentExecutor<TOutput extends z.ZodTypeAny> {
|
||||
...schema
|
||||
} = jsonSchema;
|
||||
completeTool.parameters!.properties![outputConfig.outputName] =
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
schema as Schema;
|
||||
completeTool.parameters!.required!.push(outputConfig.outputName);
|
||||
} else {
|
||||
|
||||
@@ -26,5 +26,6 @@ export function createAvailabilityServiceMock(
|
||||
selectFirstAvailable: vi.fn().mockReturnValue(selection),
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return service as unknown as ModelAvailabilityService;
|
||||
}
|
||||
|
||||
@@ -208,6 +208,7 @@ function toContent(content: ContentUnion): Content {
|
||||
// it's a Part
|
||||
return {
|
||||
role: 'user',
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
parts: [toPart(content as Part)],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ export async function getExperiments(
|
||||
'Invalid format for experiments file: `flags` and `experimentIds` must be arrays if present.',
|
||||
);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return parseExperiments(response as ListExperimentsResponse);
|
||||
} catch (e) {
|
||||
debugLogger.debug('Failed to read experiments from GEMINI_EXP', e);
|
||||
|
||||
@@ -125,6 +125,7 @@ export class OAuthCredentialStorage {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const credentials = JSON.parse(credsJson) as Credentials;
|
||||
|
||||
// Save to new storage
|
||||
|
||||
@@ -115,6 +115,7 @@ async function initOauthClient(
|
||||
|
||||
if (
|
||||
credentials &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(credentials as { type?: string }).type ===
|
||||
'external_account_authorized_user'
|
||||
) {
|
||||
@@ -602,6 +603,7 @@ export function getAvailablePort(): Promise<number> {
|
||||
}
|
||||
const server = net.createServer();
|
||||
server.listen(0, () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const address = server.address()! as net.AddressInfo;
|
||||
port = address.port;
|
||||
});
|
||||
|
||||
@@ -301,6 +301,7 @@ export class CodeAssistServer implements ContentGenerator {
|
||||
body: JSON.stringify(req),
|
||||
signal,
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return res.data as T;
|
||||
}
|
||||
|
||||
@@ -318,6 +319,7 @@ export class CodeAssistServer implements ContentGenerator {
|
||||
responseType: 'json',
|
||||
signal,
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return res.data as T;
|
||||
}
|
||||
|
||||
@@ -351,6 +353,7 @@ export class CodeAssistServer implements ContentGenerator {
|
||||
|
||||
return (async function* (): AsyncGenerator<T> {
|
||||
const rl = readline.createInterface({
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
input: res.data as NodeJS.ReadableStream,
|
||||
crlfDelay: Infinity, // Recognizes '\r\n' and '\n' as line breaks
|
||||
});
|
||||
@@ -363,6 +366,7 @@ export class CodeAssistServer implements ContentGenerator {
|
||||
if (bufferedLines.length === 0) {
|
||||
continue; // no data to yield
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
yield JSON.parse(bufferedLines.join('\n')) as T;
|
||||
bufferedLines = []; // Reset the buffer after yielding
|
||||
}
|
||||
@@ -390,11 +394,13 @@ export class CodeAssistServer implements ContentGenerator {
|
||||
|
||||
function isVpcScAffectedUser(error: unknown): boolean {
|
||||
if (error && typeof error === 'object' && 'response' in error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const gaxiosError = error as {
|
||||
response?: {
|
||||
data?: unknown;
|
||||
};
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const response = gaxiosError.response?.data as
|
||||
| GoogleRpcResponse
|
||||
| undefined;
|
||||
|
||||
@@ -42,6 +42,7 @@ export async function* performRestore<
|
||||
content: 'Restored project to the state before the tool call.',
|
||||
};
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const error = e as Error;
|
||||
if (error.message.includes('unable to read tree')) {
|
||||
yield {
|
||||
|
||||
@@ -146,7 +146,7 @@ export class MessageBus extends EventEmitter {
|
||||
this.subscribe<TResponse>(responseType, responseHandler);
|
||||
|
||||
// Publish the request with correlation ID
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises, @typescript-eslint/no-unsafe-type-assertion
|
||||
this.publish({ ...request, correlationId } as TRequest);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ export async function executeToolWithHooks(
|
||||
setPidCallback?: (pid: number) => void,
|
||||
config?: Config,
|
||||
): Promise<ToolResult> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const toolInput = (invocation.params || {}) as Record<string, unknown>;
|
||||
let inputWasModified = false;
|
||||
let modifiedKeys: string[] = [];
|
||||
|
||||
@@ -224,6 +224,7 @@ export class CoreToolScheduler {
|
||||
tool: toolInstance,
|
||||
invocation,
|
||||
status: 'success',
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
response: auxiliaryData as ToolCallResponseInfo,
|
||||
durationMs,
|
||||
outcome,
|
||||
@@ -237,6 +238,7 @@ export class CoreToolScheduler {
|
||||
request: currentCall.request,
|
||||
status: 'error',
|
||||
tool: toolInstance,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
response: auxiliaryData as ToolCallResponseInfo,
|
||||
durationMs,
|
||||
outcome,
|
||||
@@ -247,6 +249,7 @@ export class CoreToolScheduler {
|
||||
request: currentCall.request,
|
||||
tool: toolInstance,
|
||||
status: 'awaiting_approval',
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
confirmationDetails: auxiliaryData as ToolCallConfirmationDetails,
|
||||
startTime: existingStartTime,
|
||||
outcome,
|
||||
@@ -347,6 +350,7 @@ export class CoreToolScheduler {
|
||||
|
||||
const invocationOrError = this.buildInvocation(
|
||||
call.tool,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
args as Record<string, unknown>,
|
||||
);
|
||||
if (invocationOrError instanceof Error) {
|
||||
@@ -356,6 +360,7 @@ export class CoreToolScheduler {
|
||||
ToolErrorType.INVALID_TOOL_PARAMS,
|
||||
);
|
||||
return {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
request: { ...call.request, args: args as Record<string, unknown> },
|
||||
status: 'error',
|
||||
tool: call.tool,
|
||||
@@ -365,6 +370,7 @@ export class CoreToolScheduler {
|
||||
|
||||
return {
|
||||
...call,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
request: { ...call.request, args: args as Record<string, unknown> },
|
||||
invocation: invocationOrError,
|
||||
};
|
||||
@@ -749,6 +755,7 @@ export class CoreToolScheduler {
|
||||
this.cancelAll(signal);
|
||||
return; // `cancelAll` calls `checkAndNotifyCompletion`, so we can exit here.
|
||||
} else if (outcome === ToolConfirmationOutcome.ModifyWithEditor) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const waitingToolCall = toolCall as WaitingToolCall;
|
||||
|
||||
const editorType = this.getPreferredEditor();
|
||||
@@ -756,6 +763,7 @@ export class CoreToolScheduler {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
this.setStatusInternal(callId, 'awaiting_approval', signal, {
|
||||
...waitingToolCall.confirmationDetails,
|
||||
isModifying: true,
|
||||
@@ -770,12 +778,14 @@ export class CoreToolScheduler {
|
||||
// Restore status (isModifying: false) and update diff if result exists
|
||||
if (result) {
|
||||
this.setArgsInternal(callId, result.updatedParams);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
this.setStatusInternal(callId, 'awaiting_approval', signal, {
|
||||
...waitingToolCall.confirmationDetails,
|
||||
fileDiff: result.updatedDiff,
|
||||
isModifying: false,
|
||||
} as ToolCallConfirmationDetails);
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
this.setStatusInternal(callId, 'awaiting_approval', signal, {
|
||||
...waitingToolCall.confirmationDetails,
|
||||
isModifying: false,
|
||||
@@ -786,13 +796,16 @@ export class CoreToolScheduler {
|
||||
// re-confirmation.
|
||||
if (payload && 'newContent' in payload && toolCall) {
|
||||
const result = await this.toolModifier.applyInlineModify(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
toolCall as WaitingToolCall,
|
||||
payload,
|
||||
signal,
|
||||
);
|
||||
if (result) {
|
||||
this.setArgsInternal(callId, result.updatedParams);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
this.setStatusInternal(callId, 'awaiting_approval', signal, {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
...(toolCall as WaitingToolCall).confirmationDetails,
|
||||
fileDiff: result.updatedDiff,
|
||||
} as ToolCallConfirmationDetails);
|
||||
|
||||
@@ -51,6 +51,7 @@ export class FakeContentGenerator implements ContentGenerator {
|
||||
const responses = fileContent
|
||||
.split('\n')
|
||||
.filter((line) => line.trim() !== '')
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
.map((line) => JSON.parse(line) as FakeResponse);
|
||||
return new FakeContentGenerator(responses);
|
||||
}
|
||||
@@ -71,6 +72,7 @@ export class FakeContentGenerator implements ContentGenerator {
|
||||
`Unexpected response type, next response was for ${response.method} but expected ${method}`,
|
||||
);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return response.response as R;
|
||||
}
|
||||
|
||||
|
||||
@@ -560,6 +560,7 @@ export class GeminiChat {
|
||||
beforeModelResult.modifiedContents &&
|
||||
Array.isArray(beforeModelResult.modifiedContents)
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
contentsToUse = beforeModelResult.modifiedContents as Content[];
|
||||
}
|
||||
|
||||
@@ -577,6 +578,7 @@ export class GeminiChat {
|
||||
toolSelectionResult.tools &&
|
||||
Array.isArray(toolSelectionResult.tools)
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
config.tools = toolSelectionResult.tools as Tool[];
|
||||
}
|
||||
}
|
||||
@@ -820,6 +822,7 @@ export class GeminiChat {
|
||||
(candidate) => candidate.finishReason,
|
||||
);
|
||||
if (candidateWithReason) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
finishReason = candidateWithReason.finishReason as FinishReason;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ export class Logger {
|
||||
await this._backupCorruptedLogFile('malformed_array');
|
||||
return [];
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return parsedLogs.filter(
|
||||
(entry) =>
|
||||
typeof entry.sessionId === 'string' &&
|
||||
@@ -105,6 +106,7 @@ export class Logger {
|
||||
typeof entry.message === 'string',
|
||||
) as LogEntry[];
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const nodeError = error as NodeJS.ErrnoException;
|
||||
if (nodeError.code === 'ENOENT') {
|
||||
return [];
|
||||
@@ -298,6 +300,7 @@ export class Logger {
|
||||
await fs.access(newPath);
|
||||
return newPath; // Found it, use the new path.
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const nodeError = error as NodeJS.ErrnoException;
|
||||
if (nodeError.code !== 'ENOENT') {
|
||||
throw error; // A real error occurred, rethrow it.
|
||||
@@ -311,6 +314,7 @@ export class Logger {
|
||||
await fs.access(oldPath);
|
||||
return oldPath; // Found it, use the old path.
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const nodeError = error as NodeJS.ErrnoException;
|
||||
if (nodeError.code !== 'ENOENT') {
|
||||
throw error; // A real error occurred, rethrow it.
|
||||
@@ -352,6 +356,7 @@ export class Logger {
|
||||
|
||||
// Handle legacy format (just an array of Content)
|
||||
if (Array.isArray(parsedContent)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return { history: parsedContent as Content[] };
|
||||
}
|
||||
|
||||
@@ -360,6 +365,7 @@ export class Logger {
|
||||
parsedContent !== null &&
|
||||
'history' in parsedContent
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return parsedContent as Checkpoint;
|
||||
}
|
||||
|
||||
@@ -368,6 +374,7 @@ export class Logger {
|
||||
);
|
||||
return { history: [] };
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const nodeError = error as NodeJS.ErrnoException;
|
||||
if (nodeError.code === 'ENOENT') {
|
||||
// This is okay, it just means the checkpoint doesn't exist in either format.
|
||||
@@ -397,6 +404,7 @@ export class Logger {
|
||||
await fs.unlink(newPath);
|
||||
deletedSomething = true;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const nodeError = error as NodeJS.ErrnoException;
|
||||
if (nodeError.code !== 'ENOENT') {
|
||||
debugLogger.error(
|
||||
@@ -415,6 +423,7 @@ export class Logger {
|
||||
await fs.unlink(oldPath);
|
||||
deletedSomething = true;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const nodeError = error as NodeJS.ErrnoException;
|
||||
if (nodeError.code !== 'ENOENT') {
|
||||
debugLogger.error(
|
||||
@@ -444,6 +453,7 @@ export class Logger {
|
||||
await fs.access(filePath);
|
||||
return true;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const nodeError = error as NodeJS.ErrnoException;
|
||||
if (nodeError.code === 'ENOENT') {
|
||||
return false; // It truly doesn't exist in either format.
|
||||
|
||||
@@ -177,7 +177,8 @@ export class LoggingContentGenerator implements ContentGenerator {
|
||||
this.config.getContentGeneratorConfig()?.authType,
|
||||
errorType,
|
||||
isStructuredError(error)
|
||||
? (error as StructuredError).status
|
||||
? // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(error as StructuredError).status
|
||||
: undefined,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -48,6 +48,7 @@ export class RecordingContentGenerator implements ContentGenerator {
|
||||
);
|
||||
const recordedResponse: FakeResponse = {
|
||||
method: 'generateContent',
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
response: {
|
||||
candidates: response.candidates,
|
||||
usageMetadata: response.usageMetadata,
|
||||
@@ -73,6 +74,7 @@ export class RecordingContentGenerator implements ContentGenerator {
|
||||
|
||||
async function* stream(filePath: string) {
|
||||
for await (const response of realResponses) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(recordedResponse.response as GenerateContentResponse[]).push({
|
||||
candidates: response.candidates,
|
||||
usageMetadata: response.usageMetadata,
|
||||
|
||||
@@ -384,7 +384,8 @@ export class Turn {
|
||||
error !== null &&
|
||||
'status' in error &&
|
||||
typeof (error as { status: unknown }).status === 'number'
|
||||
? (error as { status: number }).status
|
||||
? // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(error as { status: number }).status
|
||||
: undefined;
|
||||
const structuredError: StructuredError = {
|
||||
message: getErrorMessage(error),
|
||||
|
||||
@@ -102,6 +102,7 @@ export class HookAggregator {
|
||||
|
||||
case HookEventName.BeforeToolSelection:
|
||||
return this.mergeToolSelectionOutputs(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
outputs as BeforeToolSelectionOutput[],
|
||||
);
|
||||
|
||||
|
||||
@@ -226,6 +226,7 @@ please review the project settings (.gemini/settings.json) and remove them.`;
|
||||
this.validateHookConfig(hookConfig, eventName, source)
|
||||
) {
|
||||
// Check if this hook is in the disabled list
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const hookName = this.getHookName({
|
||||
config: hookConfig,
|
||||
} as HookRegistryEntry);
|
||||
@@ -282,6 +283,7 @@ please review the project settings (.gemini/settings.json) and remove them.`;
|
||||
*/
|
||||
private isValidEventName(eventName: string): eventName is HookEventName {
|
||||
const validEventNames = Object.values(HookEventName);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return validEventNames.includes(eventName as HookEventName);
|
||||
}
|
||||
|
||||
|
||||
@@ -174,6 +174,7 @@ export class HookRunner {
|
||||
typeof additionalContext === 'string' &&
|
||||
'prompt' in modifiedInput
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(modifiedInput as BeforeAgentInput).prompt +=
|
||||
'\n\n' + additionalContext;
|
||||
}
|
||||
@@ -183,16 +184,19 @@ export class HookRunner {
|
||||
case HookEventName.BeforeModel:
|
||||
if ('llm_request' in hookOutput.hookSpecificOutput) {
|
||||
// For BeforeModel, we update the LLM request
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const hookBeforeModelOutput = hookOutput as BeforeModelOutput;
|
||||
if (
|
||||
hookBeforeModelOutput.hookSpecificOutput?.llm_request &&
|
||||
'llm_request' in modifiedInput
|
||||
) {
|
||||
// Merge the partial request with the existing request
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const currentRequest = (modifiedInput as BeforeModelInput)
|
||||
.llm_request;
|
||||
const partialRequest =
|
||||
hookBeforeModelOutput.hookSpecificOutput.llm_request;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(modifiedInput as BeforeModelInput).llm_request = {
|
||||
...currentRequest,
|
||||
...partialRequest,
|
||||
@@ -203,11 +207,14 @@ export class HookRunner {
|
||||
|
||||
case HookEventName.BeforeTool:
|
||||
if ('tool_input' in hookOutput.hookSpecificOutput) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const newToolInput = hookOutput.hookSpecificOutput[
|
||||
'tool_input'
|
||||
] as Record<string, unknown>;
|
||||
if (newToolInput && 'tool_input' in modifiedInput) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(modifiedInput as BeforeToolInput).tool_input = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
...(modifiedInput as BeforeToolInput).tool_input,
|
||||
...newToolInput,
|
||||
};
|
||||
@@ -355,6 +362,7 @@ export class HookRunner {
|
||||
parsed = JSON.parse(parsed);
|
||||
}
|
||||
if (parsed) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
output = parsed as HookOutput;
|
||||
}
|
||||
} catch {
|
||||
|
||||
@@ -262,6 +262,7 @@ export class HookSystem {
|
||||
|
||||
const blockingError = hookOutput?.getBlockingError();
|
||||
if (blockingError?.blocked) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const beforeModelOutput = hookOutput as BeforeModelHookOutput;
|
||||
const syntheticResponse = beforeModelOutput.getSyntheticResponse();
|
||||
return {
|
||||
@@ -273,6 +274,7 @@ export class HookSystem {
|
||||
}
|
||||
|
||||
if (hookOutput) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const beforeModelOutput = hookOutput as BeforeModelHookOutput;
|
||||
const modifiedRequest =
|
||||
beforeModelOutput.applyLLMRequestModifications(llmRequest);
|
||||
@@ -319,6 +321,7 @@ export class HookSystem {
|
||||
}
|
||||
|
||||
if (hookOutput) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const afterModelOutput = hookOutput as AfterModelHookOutput;
|
||||
const modifiedResponse = afterModelOutput.getModifiedResponse();
|
||||
if (modifiedResponse) {
|
||||
|
||||
@@ -282,6 +282,7 @@ export class HookTranslatorGenAIv1 extends HookTranslator {
|
||||
parts: textParts,
|
||||
},
|
||||
finishReason:
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
candidate.finishReason as LLMResponse['candidates'][0]['finishReason'],
|
||||
index: candidate.index,
|
||||
safetyRatings: candidate.safetyRatings?.map((rating) => ({
|
||||
@@ -306,6 +307,7 @@ export class HookTranslatorGenAIv1 extends HookTranslator {
|
||||
*/
|
||||
fromHookLLMResponse(hookResponse: LLMResponse): GenerateContentResponse {
|
||||
// Build response object with proper structure
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const response: GenerateContentResponse = {
|
||||
text: hookResponse.text,
|
||||
candidates: hookResponse.candidates.map((candidate) => ({
|
||||
@@ -315,6 +317,7 @@ export class HookTranslatorGenAIv1 extends HookTranslator {
|
||||
text: part,
|
||||
})),
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
finishReason: candidate.finishReason as FinishReason,
|
||||
index: candidate.index,
|
||||
safetyRatings: candidate.safetyRatings,
|
||||
@@ -330,6 +333,7 @@ export class HookTranslatorGenAIv1 extends HookTranslator {
|
||||
*/
|
||||
toHookToolConfig(sdkToolConfig: ToolConfig): HookToolConfig {
|
||||
return {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
mode: sdkToolConfig.functionCallingConfig?.mode as HookToolConfig['mode'],
|
||||
allowedFunctionNames:
|
||||
sdkToolConfig.functionCallingConfig?.allowedFunctionNames,
|
||||
@@ -342,7 +346,8 @@ export class HookTranslatorGenAIv1 extends HookTranslator {
|
||||
fromHookToolConfig(hookToolConfig: HookToolConfig): ToolConfig {
|
||||
const functionCallingConfig: FunctionCallingConfig | undefined =
|
||||
hookToolConfig.mode || hookToolConfig.allowedFunctionNames
|
||||
? ({
|
||||
? // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
({
|
||||
mode: hookToolConfig.mode,
|
||||
allowedFunctionNames: hookToolConfig.allowedFunctionNames,
|
||||
} as FunctionCallingConfig)
|
||||
|
||||
@@ -71,6 +71,7 @@ export class TrustedHooksManager {
|
||||
const untrusted: string[] = [];
|
||||
|
||||
for (const eventName of Object.keys(hooks)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const definitions = hooks[eventName as HookEventName];
|
||||
if (!Array.isArray(definitions)) continue;
|
||||
|
||||
@@ -99,6 +100,7 @@ export class TrustedHooksManager {
|
||||
const currentTrusted = new Set(this.trustedHooks[projectPath] || []);
|
||||
|
||||
for (const eventName of Object.keys(hooks)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const definitions = hooks[eventName as HookEventName];
|
||||
if (!Array.isArray(definitions)) continue;
|
||||
|
||||
|
||||
@@ -270,6 +270,7 @@ export class BeforeToolHookOutput extends DefaultHookOutput {
|
||||
input !== null &&
|
||||
!Array.isArray(input)
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return input as Record<string, unknown>;
|
||||
}
|
||||
}
|
||||
@@ -286,6 +287,7 @@ export class BeforeModelHookOutput extends DefaultHookOutput {
|
||||
*/
|
||||
getSyntheticResponse(): GenerateContentResponse | undefined {
|
||||
if (this.hookSpecificOutput && 'llm_response' in this.hookSpecificOutput) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const hookResponse = this.hookSpecificOutput[
|
||||
'llm_response'
|
||||
] as LLMResponse;
|
||||
@@ -304,12 +306,14 @@ export class BeforeModelHookOutput extends DefaultHookOutput {
|
||||
target: GenerateContentParameters,
|
||||
): GenerateContentParameters {
|
||||
if (this.hookSpecificOutput && 'llm_request' in this.hookSpecificOutput) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const hookRequest = this.hookSpecificOutput[
|
||||
'llm_request'
|
||||
] as Partial<LLMRequest>;
|
||||
if (hookRequest) {
|
||||
// Convert hook format to SDK format
|
||||
const sdkRequest = defaultHookTranslator.fromHookLLMRequest(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
hookRequest as LLMRequest,
|
||||
target,
|
||||
);
|
||||
@@ -335,6 +339,7 @@ export class BeforeToolSelectionHookOutput extends DefaultHookOutput {
|
||||
tools?: ToolListUnion;
|
||||
}): { toolConfig?: GenAIToolConfig; tools?: ToolListUnion } {
|
||||
if (this.hookSpecificOutput && 'toolConfig' in this.hookSpecificOutput) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const hookToolConfig = this.hookSpecificOutput[
|
||||
'toolConfig'
|
||||
] as HookToolConfig;
|
||||
@@ -362,12 +367,14 @@ export class AfterModelHookOutput extends DefaultHookOutput {
|
||||
*/
|
||||
getModifiedResponse(): GenerateContentResponse | undefined {
|
||||
if (this.hookSpecificOutput && 'llm_response' in this.hookSpecificOutput) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const hookResponse = this.hookSpecificOutput[
|
||||
'llm_response'
|
||||
] as Partial<LLMResponse>;
|
||||
if (hookResponse?.candidates?.[0]?.content?.parts?.length) {
|
||||
// Convert hook format to SDK format
|
||||
return defaultHookTranslator.fromHookLLMResponse(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
hookResponse as LLMResponse,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -213,8 +213,10 @@ export async function createProxyAwareFetch(ideServerHost: string) {
|
||||
...init,
|
||||
dispatcher: agent,
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const options = fetchOptions as unknown as import('undici').RequestInit;
|
||||
const response = await fetchFn(url, options);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return new Response(response.body as ReadableStream<unknown> | null, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
|
||||
@@ -143,6 +143,7 @@ export class MCPOAuthProvider {
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return (await response.json()) as OAuthClientRegistrationResponse;
|
||||
}
|
||||
|
||||
@@ -377,6 +378,7 @@ export class MCPOAuthProvider {
|
||||
}
|
||||
|
||||
server.listen(listenPort, () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const address = server.address() as net.AddressInfo;
|
||||
serverPort = address.port;
|
||||
debugLogger.log(
|
||||
@@ -580,6 +582,7 @@ export class MCPOAuthProvider {
|
||||
|
||||
// Try to parse as JSON first, fall back to form-urlencoded
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return JSON.parse(responseText) as OAuthTokenResponse;
|
||||
} catch {
|
||||
// Parse form-urlencoded response
|
||||
@@ -702,6 +705,7 @@ export class MCPOAuthProvider {
|
||||
|
||||
// Try to parse as JSON first, fall back to form-urlencoded
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return JSON.parse(responseText) as OAuthTokenResponse;
|
||||
} catch {
|
||||
// Parse form-urlencoded response
|
||||
|
||||
@@ -61,6 +61,7 @@ export class MCPOAuthTokenStorage implements TokenStorage {
|
||||
try {
|
||||
const tokenFile = this.getTokenFilePath();
|
||||
const data = await fs.readFile(tokenFile, 'utf-8');
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const tokens = JSON.parse(data) as OAuthCredentials[];
|
||||
|
||||
for (const credential of tokens) {
|
||||
@@ -68,6 +69,7 @@ export class MCPOAuthTokenStorage implements TokenStorage {
|
||||
}
|
||||
} catch (error) {
|
||||
// File doesn't exist or is invalid, return empty map
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
coreEvents.emitFeedback(
|
||||
'error',
|
||||
@@ -222,6 +224,7 @@ export class MCPOAuthTokenStorage implements TokenStorage {
|
||||
const tokenFile = this.getTokenFilePath();
|
||||
await fs.unlink(tokenFile);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
coreEvents.emitFeedback(
|
||||
'error',
|
||||
|
||||
@@ -101,6 +101,7 @@ export class OAuthUtils {
|
||||
if (!response.ok) {
|
||||
return null;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return (await response.json()) as OAuthProtectedResourceMetadata;
|
||||
} catch (error) {
|
||||
debugLogger.debug(
|
||||
@@ -124,6 +125,7 @@ export class OAuthUtils {
|
||||
if (!response.ok) {
|
||||
return null;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return (await response.json()) as OAuthAuthorizationServerMetadata;
|
||||
} catch (error) {
|
||||
debugLogger.debug(
|
||||
|
||||
@@ -114,6 +114,7 @@ export class ServiceAccountImpersonationProvider implements McpAuthProvider {
|
||||
coreEvents.emitFeedback(
|
||||
'error',
|
||||
'Failed to obtain authentication token.',
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
e as Error,
|
||||
);
|
||||
return undefined;
|
||||
|
||||
@@ -72,9 +72,11 @@ export class FileTokenStorage extends BaseTokenStorage {
|
||||
try {
|
||||
const data = await fs.readFile(this.tokenFilePath, 'utf-8');
|
||||
const decrypted = this.decrypt(data);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const tokens = JSON.parse(decrypted) as Record<string, OAuthCredentials>;
|
||||
return new Map(Object.entries(tokens));
|
||||
} catch (error: unknown) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const err = error as NodeJS.ErrnoException & { message?: string };
|
||||
if (err.code === 'ENOENT') {
|
||||
return new Map();
|
||||
@@ -144,6 +146,7 @@ export class FileTokenStorage extends BaseTokenStorage {
|
||||
try {
|
||||
await fs.unlink(this.tokenFilePath);
|
||||
} catch (error: unknown) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const err = error as NodeJS.ErrnoException;
|
||||
if (err.code !== 'ENOENT') {
|
||||
throw error;
|
||||
@@ -176,6 +179,7 @@ export class FileTokenStorage extends BaseTokenStorage {
|
||||
try {
|
||||
await fs.unlink(this.tokenFilePath);
|
||||
} catch (error: unknown) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const err = error as NodeJS.ErrnoException;
|
||||
if (err.code !== 'ENOENT') {
|
||||
throw error;
|
||||
|
||||
@@ -70,6 +70,7 @@ export class KeychainTokenStorage
|
||||
return null;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const credentials = JSON.parse(data) as OAuthCredentials;
|
||||
|
||||
if (this.isTokenExpired(credentials)) {
|
||||
@@ -179,6 +180,7 @@ export class KeychainTokenStorage
|
||||
|
||||
for (const cred of credentials) {
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const data = JSON.parse(cred.password) as OAuthCredentials;
|
||||
if (!this.isTokenExpired(data)) {
|
||||
result.set(cred.account, data);
|
||||
@@ -223,6 +225,7 @@ export class KeychainTokenStorage
|
||||
try {
|
||||
await this.deleteCredentials(server);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
errors.push(error as Error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,6 +382,7 @@ export function createPolicyUpdater(
|
||||
const fileContent = await fs.readFile(policyFile, 'utf-8');
|
||||
existingData = toml.parse(fileContent) as { rule?: TomlRule[] };
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
debugLogger.warn(
|
||||
`Failed to parse ${policyFile}, overwriting with new policy.`,
|
||||
@@ -424,6 +425,7 @@ export function createPolicyUpdater(
|
||||
|
||||
// Serialize back to TOML
|
||||
// @iarna/toml stringify might not produce beautiful output but it handles escaping correctly
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const newContent = toml.stringify(existingData as toml.JsonMap);
|
||||
|
||||
// Atomic write: write to tmp then rename
|
||||
|
||||
@@ -312,6 +312,7 @@ export class PolicyEngine {
|
||||
|
||||
if (toolName && SHELL_TOOL_NAMES.includes(toolName)) {
|
||||
isShellCommand = true;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const args = toolCall.args as { command?: string; dir_path?: string };
|
||||
command = args?.command;
|
||||
shellDirPath = args?.dir_path;
|
||||
|
||||
@@ -111,6 +111,7 @@ export function stableStringify(obj: unknown): string {
|
||||
const pairs: string[] = [];
|
||||
|
||||
for (const key of sortedKeys) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const value = (currentObj as Record<string, unknown>)[key];
|
||||
// Skip undefined and function values in objects (per JSON spec)
|
||||
if (value !== undefined && typeof value !== 'function') {
|
||||
|
||||
@@ -234,6 +234,7 @@ export async function loadPoliciesFromToml(
|
||||
.filter((entry) => entry.isFile() && entry.name.endsWith('.toml'))
|
||||
.map((entry) => entry.name);
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const error = e as NodeJS.ErrnoException;
|
||||
if (error.code === 'ENOENT') {
|
||||
// Directory doesn't exist, skip it (not an error)
|
||||
@@ -262,6 +263,7 @@ export async function loadPoliciesFromToml(
|
||||
try {
|
||||
parsed = toml.parse(fileContent);
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const error = e as Error;
|
||||
errors.push({
|
||||
filePath,
|
||||
@@ -356,6 +358,7 @@ export async function loadPoliciesFromToml(
|
||||
try {
|
||||
policyRule.argsPattern = new RegExp(argsPattern);
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const error = e as Error;
|
||||
errors.push({
|
||||
filePath,
|
||||
@@ -411,6 +414,7 @@ export async function loadPoliciesFromToml(
|
||||
const safetyCheckerRule: SafetyCheckerRule = {
|
||||
toolName: effectiveToolName,
|
||||
priority: checker.priority,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
checker: checker.checker as SafetyCheckerConfig,
|
||||
modes: checker.modes,
|
||||
};
|
||||
@@ -419,6 +423,7 @@ export async function loadPoliciesFromToml(
|
||||
try {
|
||||
safetyCheckerRule.argsPattern = new RegExp(argsPattern);
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const error = e as Error;
|
||||
errors.push({
|
||||
filePath,
|
||||
@@ -440,6 +445,7 @@ export async function loadPoliciesFromToml(
|
||||
|
||||
checkers.push(...parsedCheckers);
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const error = e as NodeJS.ErrnoException;
|
||||
// Catch-all for unexpected errors
|
||||
if (error.code !== 'ENOENT') {
|
||||
|
||||
@@ -35,8 +35,10 @@ export function getHookSource(input: Record<string, unknown>): HookSource {
|
||||
const source = input['hook_source'];
|
||||
if (
|
||||
typeof source === 'string' &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
VALID_HOOK_SOURCES.includes(source as HookSource)
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return source as HookSource;
|
||||
}
|
||||
return 'project';
|
||||
|
||||
@@ -183,11 +183,11 @@ export class PromptProvider {
|
||||
})),
|
||||
} as snippets.SystemPromptOptions;
|
||||
|
||||
basePrompt = (
|
||||
activeSnippets.getCoreSystemPrompt as (
|
||||
options: snippets.SystemPromptOptions,
|
||||
) => string
|
||||
)(options);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const getCoreSystemPrompt = activeSnippets.getCoreSystemPrompt as (
|
||||
options: snippets.SystemPromptOptions,
|
||||
) => string;
|
||||
basePrompt = getCoreSystemPrompt(options);
|
||||
}
|
||||
|
||||
// --- Finalization (Shell) ---
|
||||
|
||||
@@ -49,6 +49,7 @@ export class CompositeStrategy implements TerminalStrategy {
|
||||
0,
|
||||
-1,
|
||||
) as RoutingStrategy[];
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const terminalStrategy = this.strategies[
|
||||
this.strategies.length - 1
|
||||
] as TerminalStrategy;
|
||||
|
||||
@@ -23,6 +23,7 @@ export interface InProcessChecker {
|
||||
export class AllowedPathChecker implements InProcessChecker {
|
||||
async check(input: SafetyCheckInput): Promise<SafetyCheckResult> {
|
||||
const { toolCall, context } = input;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const config = input.config as AllowedPathConfig | undefined;
|
||||
|
||||
// Build list of allowed directories
|
||||
|
||||
@@ -23,6 +23,7 @@ export class ContextBuilder {
|
||||
return {
|
||||
environment: {
|
||||
cwd: process.cwd(),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
workspaces: this.config
|
||||
.getWorkspaceContext()
|
||||
.getDirectories() as string[],
|
||||
@@ -44,11 +45,12 @@ export class ContextBuilder {
|
||||
|
||||
for (const key of requiredKeys) {
|
||||
if (key in fullContext) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-type-assertion
|
||||
(minimalContext as any)[key] = fullContext[key];
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return minimalContext as SafetyCheckInput['context'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ export async function awaitConfirmation(
|
||||
MessageBusType.TOOL_CONFIRMATION_RESPONSE,
|
||||
{ signal },
|
||||
)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const response = msg as ToolConfirmationResponse;
|
||||
if (response.correlationId === correlationId) {
|
||||
return {
|
||||
@@ -84,6 +85,7 @@ export async function awaitConfirmation(
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
if (signal.aborted || (error as Error).name === 'AbortError') {
|
||||
throw new Error('Operation cancelled');
|
||||
}
|
||||
@@ -232,6 +234,7 @@ async function handleExternalModification(
|
||||
}
|
||||
|
||||
const result = await modifier.handleModifyWithEditor(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
state.firstActiveCall as WaitingToolCall,
|
||||
editor,
|
||||
signal,
|
||||
@@ -258,6 +261,7 @@ async function handleInlineModification(
|
||||
): Promise<void> {
|
||||
const { state, modifier } = deps;
|
||||
const result = await modifier.applyInlineModify(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
state.firstActiveCall as WaitingToolCall,
|
||||
payload,
|
||||
signal,
|
||||
|
||||
@@ -476,6 +476,7 @@ export class Scheduler {
|
||||
if (signal.aborted) throw new Error('Operation cancelled');
|
||||
this.state.updateStatus(callId, 'executing');
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const activeCall = this.state.firstActiveCall as ExecutingToolCall;
|
||||
|
||||
const result = await runWithToolCallContext(
|
||||
|
||||
@@ -370,6 +370,7 @@ export class SchedulerStateManager {
|
||||
confirmationDetails = data.confirmationDetails;
|
||||
} else {
|
||||
// TODO: Remove legacy callback shape once event-driven migration is complete
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
confirmationDetails = data as ToolCallConfirmationDetails;
|
||||
}
|
||||
|
||||
@@ -489,6 +490,7 @@ export class SchedulerStateManager {
|
||||
|
||||
private toExecuting(call: ToolCall, data?: unknown): ExecutingToolCall {
|
||||
this.validateHasToolAndInvocation(call, 'executing');
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const execData = data as Partial<ExecutingToolCall> | undefined;
|
||||
const liveOutput =
|
||||
execData?.liveOutput ??
|
||||
|
||||
@@ -48,6 +48,7 @@ export class ToolModificationHandler {
|
||||
typeof toolCall.request.args
|
||||
>(
|
||||
toolCall.request.args,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
modifyContext as ModifyContext<typeof toolCall.request.args>,
|
||||
editorType,
|
||||
signal,
|
||||
@@ -76,6 +77,7 @@ export class ToolModificationHandler {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const modifyContext = toolCall.tool.getModifyContext(
|
||||
signal,
|
||||
) as ModifyContext<typeof toolCall.request.args>;
|
||||
|
||||
@@ -191,6 +191,7 @@ export class ChatRecordingService {
|
||||
if (
|
||||
error instanceof Error &&
|
||||
'code' in error &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(error as NodeJS.ErrnoException).code === 'ENOSPC'
|
||||
) {
|
||||
this.conversationFile = null;
|
||||
@@ -420,6 +421,7 @@ export class ChatRecordingService {
|
||||
this.cachedLastConvData = fs.readFileSync(this.conversationFile!, 'utf8');
|
||||
return JSON.parse(this.cachedLastConvData);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
debugLogger.error('Error reading conversation file.', error);
|
||||
throw error;
|
||||
@@ -460,6 +462,7 @@ export class ChatRecordingService {
|
||||
if (
|
||||
error instanceof Error &&
|
||||
'code' in error &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(error as NodeJS.ErrnoException).code === 'ENOSPC'
|
||||
) {
|
||||
this.conversationFile = null;
|
||||
|
||||
@@ -449,6 +449,7 @@ export class LoopDetectionService {
|
||||
return false;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const flashConfidence = flashResult[
|
||||
'unproductive_state_confidence'
|
||||
] as number;
|
||||
@@ -490,7 +491,8 @@ export class LoopDetectionService {
|
||||
);
|
||||
|
||||
const mainModelConfidence = mainModelResult
|
||||
? (mainModelResult['unproductive_state_confidence'] as number)
|
||||
? // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(mainModelResult['unproductive_state_confidence'] as number)
|
||||
: 0;
|
||||
|
||||
logLlmLoopCheck(
|
||||
|
||||
@@ -245,6 +245,7 @@ export class ModelConfigService {
|
||||
let matchedLevel = 0; // Default to Global
|
||||
const isMatch = matchEntries.every(([key, value]) => {
|
||||
if (key === 'model') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const level = modelToLevel.get(value as string);
|
||||
if (level === undefined) return false;
|
||||
matchedLevel = level;
|
||||
@@ -253,6 +254,7 @@ export class ModelConfigService {
|
||||
if (key === 'overrideScope' && value === 'core') {
|
||||
return context.overrideScope === 'core' || !context.overrideScope;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return context[key as keyof ModelConfigKey] === value;
|
||||
});
|
||||
|
||||
@@ -291,6 +293,7 @@ export class ModelConfigService {
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return {
|
||||
model: resolved.model,
|
||||
generateContentConfig: resolved.generateContentConfig,
|
||||
@@ -321,7 +324,9 @@ export class ModelConfigService {
|
||||
config2: GenerateContentConfig | undefined,
|
||||
): GenerateContentConfig {
|
||||
return ModelConfigService.genericDeepMerge(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
config1 as Record<string, unknown> | undefined,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
config2 as Record<string, unknown> | undefined,
|
||||
) as GenerateContentConfig;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export const makeResolvedModelConfig = (
|
||||
model: string,
|
||||
overrides: Partial<ResolvedModelConfig['generateContentConfig']> = {},
|
||||
): ResolvedModelConfig =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
({
|
||||
model,
|
||||
generateContentConfig: {
|
||||
|
||||
@@ -510,6 +510,7 @@ export class ShellExecutionService {
|
||||
|
||||
return { pid: child.pid, result };
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const error = e as Error;
|
||||
return {
|
||||
pid: undefined,
|
||||
@@ -778,6 +779,7 @@ export class ShellExecutionService {
|
||||
this.activePtys.delete(ptyProcess.pid);
|
||||
// Attempt to destroy the PTY to ensure FD is closed
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(ptyProcess as IPty & { destroy?: () => void }).destroy?.();
|
||||
} catch {
|
||||
// Ignore errors during cleanup
|
||||
@@ -860,6 +862,7 @@ export class ShellExecutionService {
|
||||
|
||||
return { pid: ptyProcess.pid, result };
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const error = e as Error;
|
||||
if (error.message.includes('posix_spawnp failed')) {
|
||||
onOutputEvent({
|
||||
@@ -1105,6 +1108,7 @@ export class ShellExecutionService {
|
||||
} catch (e) {
|
||||
// Ignore errors if the pty has already exited, which can happen
|
||||
// due to a race condition between the exit event and this call.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const err = e as { code?: string; message?: string };
|
||||
const isEsrch = err.code === 'ESRCH';
|
||||
const isWindowsPtyError = err.message?.includes(
|
||||
|
||||
@@ -189,6 +189,7 @@ export class ToolOutputMaskingService {
|
||||
await fsPromises.writeFile(filePath, content, 'utf-8');
|
||||
|
||||
const originalResponse =
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(part.functionResponse.response as Record<string, unknown>) || {};
|
||||
|
||||
const totalLines = content.split('\n').length;
|
||||
@@ -268,6 +269,7 @@ export class ToolOutputMaskingService {
|
||||
|
||||
private getToolOutputContent(part: Part): string | null {
|
||||
if (!part.functionResponse) return null;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const response = part.functionResponse.response as Record<string, unknown>;
|
||||
if (!response) return null;
|
||||
|
||||
@@ -286,6 +288,7 @@ export class ToolOutputMaskingService {
|
||||
}
|
||||
|
||||
private formatShellPreview(response: Record<string, unknown>): string {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const content = (response['output'] || response['stdout'] || '') as string;
|
||||
if (typeof content !== 'string') {
|
||||
return typeof content === 'object'
|
||||
|
||||
@@ -42,6 +42,7 @@ function parseFrontmatter(
|
||||
try {
|
||||
const parsed = yaml.load(content);
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const { name, description } = parsed as Record<string, unknown>;
|
||||
if (typeof name === 'string' && typeof description === 'string') {
|
||||
return { name, description };
|
||||
|
||||
@@ -174,6 +174,7 @@ export class ActivityMonitor {
|
||||
eventTypes: Record<ActivityType, number>;
|
||||
timeRange: { start: number; end: number } | null;
|
||||
} {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const eventTypes = {} as Record<ActivityType, number>;
|
||||
let start = Number.MAX_SAFE_INTEGER;
|
||||
let end = 0;
|
||||
|
||||
@@ -450,6 +450,7 @@ export class ClearcutLogger {
|
||||
if (this.config?.getDebugMode()) {
|
||||
debugLogger.log('Flushing log events to Clearcut.');
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const eventsToSend = this.events.toArray() as LogEventEntry[][];
|
||||
this.events.clear();
|
||||
|
||||
@@ -493,6 +494,7 @@ export class ClearcutLogger {
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
if (this.config?.getDebugMode()) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
debugLogger.warn('Error flushing log events:', e as Error);
|
||||
}
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ export class GcpLogExporter implements LogRecordExporter {
|
||||
} catch (error) {
|
||||
resultCallback({
|
||||
code: ExportResultCode.FAILED,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
error: error as Error,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import type { Config } from '../config/config.js';
|
||||
describe('Circular Reference Integration Test', () => {
|
||||
it('should handle HttpsProxyAgent-like circular references in clearcut logging', () => {
|
||||
// Create a mock config with proxy
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const mockConfig = {
|
||||
getTelemetryEnabled: () => true,
|
||||
getUsageStatisticsEnabled: () => true,
|
||||
@@ -56,7 +57,7 @@ describe('Circular Reference Integration Test', () => {
|
||||
const logger = ClearcutLogger.getInstance(mockConfig);
|
||||
|
||||
expect(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-type-assertion
|
||||
logger?.enqueueLogEvent(problematicEvent as any);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
@@ -22,6 +22,7 @@ import { MockTool } from '../test-utils/mock-tool.js';
|
||||
describe('Circular Reference Handling', () => {
|
||||
it('should handle circular references in tool function arguments', () => {
|
||||
// Create a mock config
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const mockConfig = {
|
||||
getTelemetryEnabled: () => true,
|
||||
getUsageStatisticsEnabled: () => true,
|
||||
@@ -78,6 +79,7 @@ describe('Circular Reference Handling', () => {
|
||||
});
|
||||
|
||||
it('should handle normal objects without circular references', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const mockConfig = {
|
||||
getTelemetryEnabled: () => true,
|
||||
getUsageStatisticsEnabled: () => true,
|
||||
|
||||
@@ -111,6 +111,7 @@ export function logUserPrompt(config: Config, event: UserPromptEvent): void {
|
||||
}
|
||||
|
||||
export function logToolCall(config: Config, event: ToolCallEvent): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const uiEvent = {
|
||||
...event,
|
||||
'event.name': EVENT_TOOL_CALL,
|
||||
@@ -242,6 +243,7 @@ export function logRipgrepFallback(
|
||||
}
|
||||
|
||||
export function logApiError(config: Config, event: ApiErrorEvent): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const uiEvent = {
|
||||
...event,
|
||||
'event.name': EVENT_API_ERROR,
|
||||
@@ -273,6 +275,7 @@ export function logApiError(config: Config, event: ApiErrorEvent): void {
|
||||
}
|
||||
|
||||
export function logApiResponse(config: Config, event: ApiResponseEvent): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const uiEvent = {
|
||||
...event,
|
||||
'event.name': EVENT_API_RESPONSE,
|
||||
@@ -372,6 +375,7 @@ export function logSlashCommand(
|
||||
}
|
||||
|
||||
export function logRewind(config: Config, event: RewindEvent): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const uiEvent = {
|
||||
...event,
|
||||
'event.name': EVENT_REWIND,
|
||||
|
||||
@@ -77,6 +77,7 @@ const COUNTER_DEFINITIONS = {
|
||||
description: 'Counts tool calls, tagged by function name and success.',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Counter) => (toolCallCounter = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
function_name: string;
|
||||
success: boolean;
|
||||
@@ -88,6 +89,7 @@ const COUNTER_DEFINITIONS = {
|
||||
description: 'Counts API requests, tagged by model and status.',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Counter) => (apiRequestCounter = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
model: string;
|
||||
status_code?: number | string;
|
||||
@@ -98,6 +100,7 @@ const COUNTER_DEFINITIONS = {
|
||||
description: 'Counts the total number of tokens used.',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Counter) => (tokenUsageCounter = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
model: string;
|
||||
type: 'input' | 'output' | 'thought' | 'cache' | 'tool';
|
||||
@@ -113,6 +116,7 @@ const COUNTER_DEFINITIONS = {
|
||||
description: 'Counts file operations (create, read, update).',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Counter) => (fileOperationCounter = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
operation: FileOperation;
|
||||
lines?: number;
|
||||
@@ -125,6 +129,7 @@ const COUNTER_DEFINITIONS = {
|
||||
description: 'Number of lines changed (from file diffs).',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Counter) => (linesChangedCounter = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
function_name?: string;
|
||||
type: 'added' | 'removed';
|
||||
@@ -152,6 +157,7 @@ const COUNTER_DEFINITIONS = {
|
||||
description: 'Counts model routing failures.',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Counter) => (modelRoutingFailureCounter = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
'routing.decision_source': string;
|
||||
'routing.error_message': string;
|
||||
@@ -161,6 +167,7 @@ const COUNTER_DEFINITIONS = {
|
||||
description: 'Counts model slash command calls.',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Counter) => (modelSlashCommandCallCounter = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
'slash_command.model.model_name': string;
|
||||
},
|
||||
@@ -169,6 +176,7 @@ const COUNTER_DEFINITIONS = {
|
||||
description: 'Counts chat compression events.',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Counter) => (chatCompressionCounter = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
tokens_before: number;
|
||||
tokens_after: number;
|
||||
@@ -178,6 +186,7 @@ const COUNTER_DEFINITIONS = {
|
||||
description: 'Counts agent runs, tagged by name and termination reason.',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Counter) => (agentRunCounter = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
agent_name: string;
|
||||
terminate_reason: string;
|
||||
@@ -187,6 +196,7 @@ const COUNTER_DEFINITIONS = {
|
||||
description: 'Counts agent recovery attempts.',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Counter) => (agentRecoveryAttemptCounter = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
agent_name: string;
|
||||
reason: string;
|
||||
@@ -210,6 +220,7 @@ const COUNTER_DEFINITIONS = {
|
||||
description: 'Counts plan executions (switching from Plan Mode).',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Counter) => (planExecutionCounter = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
approval_mode: string;
|
||||
},
|
||||
@@ -218,6 +229,7 @@ const COUNTER_DEFINITIONS = {
|
||||
description: 'Counts hook calls, tagged by hook event name and success.',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Counter) => (hookCallCounter = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
hook_event_name: string;
|
||||
hook_name: string;
|
||||
@@ -232,6 +244,7 @@ const HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'ms',
|
||||
valueType: ValueType.INT,
|
||||
assign: (h: Histogram) => (toolCallLatencyHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
function_name: string;
|
||||
},
|
||||
@@ -241,6 +254,7 @@ const HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'ms',
|
||||
valueType: ValueType.INT,
|
||||
assign: (h: Histogram) => (apiRequestLatencyHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
model: string;
|
||||
},
|
||||
@@ -250,6 +264,7 @@ const HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'ms',
|
||||
valueType: ValueType.INT,
|
||||
assign: (h: Histogram) => (modelRoutingLatencyHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
'routing.decision_model': string;
|
||||
'routing.decision_source': string;
|
||||
@@ -260,6 +275,7 @@ const HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'ms',
|
||||
valueType: ValueType.INT,
|
||||
assign: (h: Histogram) => (agentDurationHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
agent_name: string;
|
||||
},
|
||||
@@ -276,6 +292,7 @@ const HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'turns',
|
||||
valueType: ValueType.INT,
|
||||
assign: (h: Histogram) => (agentTurnsHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
agent_name: string;
|
||||
},
|
||||
@@ -285,6 +302,7 @@ const HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'ms',
|
||||
valueType: ValueType.INT,
|
||||
assign: (h: Histogram) => (agentRecoveryAttemptDurationHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
agent_name: string;
|
||||
},
|
||||
@@ -294,6 +312,7 @@ const HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'token',
|
||||
valueType: ValueType.INT,
|
||||
assign: (h: Histogram) => (genAiClientTokenUsageHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
'gen_ai.operation.name': string;
|
||||
'gen_ai.provider.name': string;
|
||||
@@ -309,6 +328,7 @@ const HISTOGRAM_DEFINITIONS = {
|
||||
unit: 's',
|
||||
valueType: ValueType.DOUBLE,
|
||||
assign: (h: Histogram) => (genAiClientOperationDurationHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
'gen_ai.operation.name': string;
|
||||
'gen_ai.provider.name': string;
|
||||
@@ -324,6 +344,7 @@ const HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'ms',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Histogram) => (hookCallLatencyHistogram = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
hook_event_name: string;
|
||||
hook_name: string;
|
||||
@@ -337,6 +358,7 @@ const PERFORMANCE_COUNTER_DEFINITIONS = {
|
||||
description: 'Performance regression detection events.',
|
||||
valueType: ValueType.INT,
|
||||
assign: (c: Counter) => (regressionDetectionCounter = c),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
metric: string;
|
||||
severity: 'low' | 'medium' | 'high';
|
||||
@@ -353,6 +375,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'ms',
|
||||
valueType: ValueType.DOUBLE,
|
||||
assign: (h: Histogram) => (startupTimeHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
phase: string;
|
||||
details?: Record<string, string | number | boolean>;
|
||||
@@ -363,6 +386,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'bytes',
|
||||
valueType: ValueType.INT,
|
||||
assign: (h: Histogram) => (memoryUsageGauge = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
memory_type: MemoryMetricType;
|
||||
component?: string;
|
||||
@@ -389,6 +413,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'ms',
|
||||
valueType: ValueType.INT,
|
||||
assign: (h: Histogram) => (toolExecutionBreakdownHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
function_name: string;
|
||||
phase: ToolExecutionPhase;
|
||||
@@ -400,6 +425,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'ratio',
|
||||
valueType: ValueType.DOUBLE,
|
||||
assign: (h: Histogram) => (tokenEfficiencyHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
model: string;
|
||||
metric: string;
|
||||
@@ -411,6 +437,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'ms',
|
||||
valueType: ValueType.INT,
|
||||
assign: (h: Histogram) => (apiRequestBreakdownHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
model: string;
|
||||
phase: ApiRequestPhase;
|
||||
@@ -421,6 +448,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'score',
|
||||
valueType: ValueType.DOUBLE,
|
||||
assign: (h: Histogram) => (performanceScoreGauge = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
category: string;
|
||||
baseline?: number;
|
||||
@@ -432,6 +460,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'percent',
|
||||
valueType: ValueType.DOUBLE,
|
||||
assign: (h: Histogram) => (regressionPercentageChangeHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
metric: string;
|
||||
severity: 'low' | 'medium' | 'high';
|
||||
@@ -445,6 +474,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
|
||||
unit: 'percent',
|
||||
valueType: ValueType.DOUBLE,
|
||||
assign: (h: Histogram) => (baselineComparisonHistogram = h),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
attributes: {} as {
|
||||
metric: string;
|
||||
category: string;
|
||||
|
||||
@@ -65,8 +65,10 @@ function getStringReferences(parts: AnyPart[]): StringReference[] {
|
||||
} else if (part instanceof GenericPart) {
|
||||
if (part.type === 'executableCode' && typeof part['code'] === 'string') {
|
||||
refs.push({
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
get: () => part['code'] as string,
|
||||
set: (val: string) => (part['code'] = val),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
len: () => (part['code'] as string).length,
|
||||
});
|
||||
} else if (
|
||||
@@ -74,8 +76,10 @@ function getStringReferences(parts: AnyPart[]): StringReference[] {
|
||||
typeof part['output'] === 'string'
|
||||
) {
|
||||
refs.push({
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
get: () => part['output'] as string,
|
||||
set: (val: string) => (part['output'] = val),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
len: () => (part['output'] as string).length,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -316,6 +316,7 @@ export class ToolCallEvent implements BaseTelemetryEvent {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
this.function_name = function_name as string;
|
||||
this.function_args = function_args!;
|
||||
this.duration_ms = duration_ms!;
|
||||
|
||||
@@ -62,6 +62,7 @@ export class MockMessageBus {
|
||||
if (!this.subscriptions.has(type)) {
|
||||
this.subscriptions.set(type, new Set());
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
this.subscriptions.get(type)!.add(listener as (message: Message) => void);
|
||||
},
|
||||
);
|
||||
@@ -73,6 +74,7 @@ export class MockMessageBus {
|
||||
<T extends Message>(type: T['type'], listener: (message: T) => void) => {
|
||||
const listeners = this.subscriptions.get(type);
|
||||
if (listeners) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
listeners.delete(listener as (message: Message) => void);
|
||||
}
|
||||
},
|
||||
@@ -101,6 +103,7 @@ export class MockMessageBus {
|
||||
* Create a mock MessageBus for testing
|
||||
*/
|
||||
export function createMockMessageBus(): MessageBus {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return new MockMessageBus() as unknown as MessageBus;
|
||||
}
|
||||
|
||||
@@ -110,5 +113,6 @@ export function createMockMessageBus(): MessageBus {
|
||||
export function getMockMessageBusInstance(
|
||||
messageBus: MessageBus,
|
||||
): MockMessageBus {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return messageBus as unknown as MockMessageBus;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ export function createMockWorkspaceContext(
|
||||
): WorkspaceContext {
|
||||
const allDirs = [rootDir, ...additionalDirs];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const mockWorkspaceContext = {
|
||||
addDirectory: vi.fn(),
|
||||
getDirectories: vi.fn().mockReturnValue(allDirs),
|
||||
|
||||
@@ -175,6 +175,7 @@ export class ActivateSkillTool extends BaseDeclarativeTool<
|
||||
} else {
|
||||
schema = z.object({
|
||||
name: z
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
.enum(skillNames as [string, ...string[]])
|
||||
.describe('The name of the skill to activate.'),
|
||||
});
|
||||
|
||||
@@ -875,6 +875,7 @@ class LenientJsonSchemaValidator implements jsonSchemaValidator {
|
||||
);
|
||||
return (input: unknown) => ({
|
||||
valid: true as const,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
data: input as T,
|
||||
errorMessage: undefined,
|
||||
});
|
||||
@@ -889,6 +890,7 @@ export function populateMcpServerCommand(
|
||||
): Record<string, MCPServerConfig> {
|
||||
if (mcpServerCommand) {
|
||||
const cmd = mcpServerCommand;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const args = parse(cmd, process.env) as string[];
|
||||
if (args.some((arg) => typeof arg !== 'string')) {
|
||||
throw new Error('failed to parse mcpServerCommand: ' + cmd);
|
||||
@@ -1068,6 +1070,7 @@ export async function discoverTools(
|
||||
'error',
|
||||
`Error discovering tool: '${
|
||||
toolDef.name
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
}' from MCP server '${mcpServerName}': ${(error as Error).message}`,
|
||||
error,
|
||||
);
|
||||
@@ -1121,6 +1124,7 @@ class McpCallableTool implements CallableTool {
|
||||
const result = await this.client.callTool(
|
||||
{
|
||||
name: call.name!,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
arguments: call.args as Record<string, unknown>,
|
||||
},
|
||||
undefined,
|
||||
@@ -1550,6 +1554,7 @@ export async function connectToMcpServer(
|
||||
return { client: mcpClient, transport };
|
||||
} catch (error) {
|
||||
await transport.close();
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
firstAttemptError = error as Error;
|
||||
throw error;
|
||||
}
|
||||
@@ -1589,6 +1594,7 @@ export async function connectToMcpServer(
|
||||
);
|
||||
return { client: mcpClient, transport: sseTransport };
|
||||
} catch (sseFallbackError) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
sseError = sseFallbackError as Error;
|
||||
|
||||
// If SSE also returned 401, handle OAuth below
|
||||
@@ -1929,6 +1935,7 @@ export async function createTransport(
|
||||
let transport: Transport = new StdioClientTransport({
|
||||
command: mcpServerConfig.command,
|
||||
args: mcpServerConfig.args || [],
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
env: sanitizeEnvironment(
|
||||
{
|
||||
...process.env,
|
||||
@@ -1965,7 +1972,7 @@ export async function createTransport(
|
||||
|
||||
const underlyingTransport =
|
||||
transport instanceof XcodeMcpBridgeFixTransport
|
||||
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
? // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-type-assertion
|
||||
(transport as any).transport
|
||||
: transport;
|
||||
|
||||
|
||||
@@ -373,6 +373,7 @@ function transformResourceLinkBlock(block: McpResourceLinkBlock): Part {
|
||||
*/
|
||||
function transformMcpContentToParts(sdkResponse: Part[]): Part[] {
|
||||
const funcResponse = sdkResponse?.[0]?.functionResponse;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const mcpContent = funcResponse?.response?.['content'] as McpContentBlock[];
|
||||
const toolName = funcResponse?.name || 'unknown tool';
|
||||
|
||||
@@ -410,6 +411,7 @@ function transformMcpContentToParts(sdkResponse: Part[]): Part[] {
|
||||
* @returns A formatted string representing the tool's output.
|
||||
*/
|
||||
function getStringifiedResultForDisplay(rawResponse: Part[]): string {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const mcpContent = rawResponse?.[0]?.functionResponse?.response?.[
|
||||
'content'
|
||||
] as McpContentBlock[];
|
||||
|
||||
@@ -94,6 +94,7 @@ async function readMemoryFileContent(): Promise<string> {
|
||||
try {
|
||||
return await fs.readFile(getGlobalMemoryFilePath(), 'utf-8');
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const error = err as Error & { code?: string };
|
||||
if (!(error instanceof Error) || error.code !== 'ENOENT') throw err;
|
||||
return '';
|
||||
|
||||
@@ -265,7 +265,9 @@ export class ToolRegistry {
|
||||
}
|
||||
|
||||
if (priorityA === 2) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const serverA = (toolA as DiscoveredMCPTool).serverName;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const serverB = (toolB as DiscoveredMCPTool).serverName;
|
||||
return serverA.localeCompare(serverB);
|
||||
}
|
||||
@@ -319,6 +321,7 @@ export class ToolRegistry {
|
||||
'Tool discovery command is empty or contains only whitespace.',
|
||||
);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const proc = spawn(cmdParts[0] as string, cmdParts.slice(1) as string[]);
|
||||
let stdout = '';
|
||||
const stdoutDecoder = new StringDecoder('utf8');
|
||||
@@ -398,6 +401,7 @@ export class ToolRegistry {
|
||||
} else if (Array.isArray(tool['functionDeclarations'])) {
|
||||
functions.push(...tool['functionDeclarations']);
|
||||
} else if (tool['name']) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
functions.push(tool as FunctionDeclaration);
|
||||
}
|
||||
}
|
||||
@@ -420,6 +424,7 @@ export class ToolRegistry {
|
||||
func.name,
|
||||
DISCOVERED_TOOL_PREFIX + func.name,
|
||||
func.description ?? '',
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
parameters as Record<string, unknown>,
|
||||
this.messageBus,
|
||||
),
|
||||
@@ -552,6 +557,7 @@ export class ToolRegistry {
|
||||
getToolsByServer(serverName: string): AnyDeclarativeTool[] {
|
||||
const serverTools: AnyDeclarativeTool[] = [];
|
||||
for (const tool of this.getActiveTools()) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
if ((tool as DiscoveredMCPTool)?.serverName === serverName) {
|
||||
serverTools.push(tool);
|
||||
}
|
||||
|
||||
@@ -195,6 +195,7 @@ export abstract class BaseToolInvocation<
|
||||
correlationId,
|
||||
toolCall: {
|
||||
name: this._toolName,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
args: this.params as Record<string, unknown>,
|
||||
},
|
||||
serverName: this._serverName,
|
||||
@@ -536,6 +537,7 @@ export function isTool(obj: unknown): obj is AnyDeclarativeTool {
|
||||
obj !== null &&
|
||||
'name' in obj &&
|
||||
'build' in obj &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
typeof (obj as AnyDeclarativeTool).build === 'function'
|
||||
);
|
||||
}
|
||||
@@ -590,8 +592,10 @@ export function hasCycleInSchema(schema: object): boolean {
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
current = (current as Record<string, unknown>)[segment];
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return current as object;
|
||||
}
|
||||
|
||||
@@ -639,6 +643,7 @@ export function hasCycleInSchema(schema: object): boolean {
|
||||
if (Object.prototype.hasOwnProperty.call(node, key)) {
|
||||
if (
|
||||
traverse(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(node as Record<string, unknown>)[key],
|
||||
visitedRefs,
|
||||
pathRefs,
|
||||
|
||||
@@ -194,6 +194,7 @@ ${textContent}
|
||||
returnDisplay: `Content for ${url} processed using fallback fetch.`,
|
||||
};
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const error = e as Error;
|
||||
const errorMessage = `Error during fallback fetch for ${url}: ${error.message}`;
|
||||
return {
|
||||
@@ -291,6 +292,7 @@ ${textContent}
|
||||
const sources = groundingMetadata?.groundingChunks as
|
||||
| GroundingChunkItem[]
|
||||
| undefined;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const groundingSupports = groundingMetadata?.groundingSupports as
|
||||
| GroundingSupportItem[]
|
||||
| undefined;
|
||||
|
||||
@@ -91,6 +91,7 @@ class WebSearchToolInvocation extends BaseToolInvocation<
|
||||
const sources = groundingMetadata?.groundingChunks as
|
||||
| GroundingChunkItem[]
|
||||
| undefined;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const groundingSupports = groundingMetadata?.groundingSupports as
|
||||
| GroundingSupportItem[]
|
||||
| undefined;
|
||||
|
||||
@@ -75,7 +75,7 @@ export class XcodeMcpBridgeFixTransport
|
||||
// We can cast because we verified 'result' is in response,
|
||||
// but TS might still be picky if the type is a strict union.
|
||||
// Let's treat it safely.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-type-assertion
|
||||
const result = response.result as any;
|
||||
|
||||
// Check if we have content but missing structuredContent
|
||||
|
||||
@@ -80,6 +80,7 @@ export async function bfsFileSearch(
|
||||
return { currentDir, entries };
|
||||
} catch (error) {
|
||||
// Warn user that a directory could not be read, as this affects search results.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const message = (error as Error)?.message ?? 'Unknown error';
|
||||
debugLogger.warn(
|
||||
`[WARN] Skipping unreadable directory: ${currentDir} (${message})`,
|
||||
@@ -153,6 +154,7 @@ export function bfsFileSearchSync(
|
||||
foundFiles,
|
||||
);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const message = (error as Error)?.message ?? 'Unknown error';
|
||||
debugLogger.warn(
|
||||
`[WARN] Skipping unreadable directory: ${currentDir} (${message})`,
|
||||
|
||||
@@ -49,6 +49,7 @@ export function generateCheckpointFileName(
|
||||
toolCall: ToolCallRequestInfo,
|
||||
): string | null {
|
||||
const toolArgs = toolCall.args;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const toolFilePath = toolArgs['file_path'] as string;
|
||||
|
||||
if (!toolFilePath) {
|
||||
@@ -167,6 +168,7 @@ export function getCheckpointInfoList(
|
||||
|
||||
for (const [file, content] of checkpointFiles) {
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const toolCallData = JSON.parse(content) as ToolCallData;
|
||||
if (toolCallData.messageId) {
|
||||
checkpointInfoList.push({
|
||||
|
||||
@@ -208,9 +208,12 @@ export async function resolveEditorAsync(
|
||||
|
||||
coreEvents.emit(CoreEvent.RequestEditorSelection);
|
||||
|
||||
return once(coreEvents, CoreEvent.EditorSelected, { signal })
|
||||
.then(([payload]) => (payload as EditorSelectedPayload).editor)
|
||||
.catch(() => undefined);
|
||||
return (
|
||||
once(coreEvents, CoreEvent.EditorSelected, { signal })
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
.then(([payload]) => (payload as EditorSelectedPayload).editor)
|
||||
.catch(() => undefined)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -98,6 +98,7 @@ interface ResponseData {
|
||||
|
||||
export function toFriendlyError(error: unknown): unknown {
|
||||
if (error && typeof error === 'object' && 'response' in error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const gaxiosError = error as GaxiosError;
|
||||
const data = parseResponseData(gaxiosError);
|
||||
if (data && data.error && data.error.message && data.error.code) {
|
||||
@@ -122,11 +123,13 @@ function parseResponseData(error: GaxiosError): ResponseData | undefined {
|
||||
// Inexplicably, Gaxios sometimes doesn't JSONify the response data.
|
||||
if (typeof error.response?.data === 'string') {
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return JSON.parse(error.response?.data) as ResponseData;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return error.response?.data as ResponseData | undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -199,14 +199,14 @@ export class CoreEventEmitter extends EventEmitter<CoreEvents> {
|
||||
if (this._eventBacklog.length >= CoreEventEmitter.MAX_BACKLOG_SIZE) {
|
||||
this._eventBacklog.shift();
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
this._eventBacklog.push({ event, args } as EventBacklogItem);
|
||||
} else {
|
||||
(
|
||||
this.emit as <K extends keyof CoreEvents>(
|
||||
event: K,
|
||||
...args: CoreEvents[K]
|
||||
) => boolean
|
||||
)(event, ...args);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(this.emit as (event: K, ...args: CoreEvents[K]) => boolean)(
|
||||
event,
|
||||
...args,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,12 +319,11 @@ export class CoreEventEmitter extends EventEmitter<CoreEvents> {
|
||||
const backlog = [...this._eventBacklog];
|
||||
this._eventBacklog.length = 0; // Clear in-place
|
||||
for (const item of backlog) {
|
||||
(
|
||||
this.emit as <K extends keyof CoreEvents>(
|
||||
event: K,
|
||||
...args: CoreEvents[K]
|
||||
) => boolean
|
||||
)(item.event, ...item.args);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(this.emit as (event: keyof CoreEvents, ...args: unknown[]) => boolean)(
|
||||
item.event,
|
||||
...item.args,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ export function convertToFunctionResponse(
|
||||
if (inlineDataParts.length > 0) {
|
||||
if (isMultimodalFRSupported) {
|
||||
// Nest inlineData if supported by the model
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(part.functionResponse as unknown as { parts: Part[] }).parts =
|
||||
inlineDataParts;
|
||||
} else {
|
||||
@@ -151,6 +152,7 @@ export function getFunctionCalls(
|
||||
}
|
||||
const functionCallParts = parts
|
||||
.filter((part) => !!part.functionCall)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
.map((part) => part.functionCall as FunctionCall);
|
||||
return functionCallParts.length > 0 ? functionCallParts : undefined;
|
||||
}
|
||||
@@ -163,6 +165,7 @@ export function getFunctionCallsFromParts(
|
||||
}
|
||||
const functionCallParts = parts
|
||||
.filter((part) => !!part.functionCall)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
.map((part) => part.functionCall as FunctionCall);
|
||||
return functionCallParts.length > 0 ? functionCallParts : undefined;
|
||||
}
|
||||
|
||||
@@ -195,6 +195,7 @@ export function parseGoogleApiError(error: unknown): GoogleApiError | null {
|
||||
if (Array.isArray(errorDetails)) {
|
||||
for (const detail of errorDetails) {
|
||||
if (detail && typeof detail === 'object') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const detailObj = detail as Record<string, unknown>;
|
||||
const typeKey = Object.keys(detailObj).find(
|
||||
(key) => key.trim() === '@type',
|
||||
@@ -205,6 +206,7 @@ export function parseGoogleApiError(error: unknown): GoogleApiError | null {
|
||||
delete detailObj[typeKey];
|
||||
}
|
||||
// We can just cast it; the consumer will have to switch on @type
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
details.push(detailObj as unknown as GoogleApiErrorDetail);
|
||||
}
|
||||
}
|
||||
@@ -253,6 +255,7 @@ function fromGaxiosError(errorObj: object): ErrorShape | undefined {
|
||||
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if ('error' in data) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
outerError = (data as { error: ErrorShape }).error;
|
||||
}
|
||||
}
|
||||
@@ -309,6 +312,7 @@ function fromApiError(errorObj: object): ErrorShape | undefined {
|
||||
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if ('error' in data) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
outerError = (data as { error: ErrorShape }).error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,10 @@ export function getErrorStatus(error: unknown): number | undefined {
|
||||
typeof (error as { response?: unknown }).response === 'object' &&
|
||||
(error as { response?: unknown }).response !== null
|
||||
) {
|
||||
const response = (
|
||||
error as { response: { status?: unknown; headers?: unknown } }
|
||||
).response;
|
||||
const response =
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(error as { response: { status?: unknown; headers?: unknown } })
|
||||
.response;
|
||||
if ('status' in response && typeof response.status === 'number') {
|
||||
return response.status;
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ async function generateJsonWithTimeout<T>(
|
||||
timeoutSignal,
|
||||
]),
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return result as T;
|
||||
} catch (err) {
|
||||
debugLogger.debug(
|
||||
|
||||
@@ -54,6 +54,7 @@ async function findProjectRoot(startDir: string): Promise<string | null> {
|
||||
typeof error === 'object' &&
|
||||
error !== null &&
|
||||
'code' in error &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(error as { code: string }).code === 'ENOENT';
|
||||
|
||||
// Only log unexpected errors in non-test environments
|
||||
@@ -63,6 +64,7 @@ async function findProjectRoot(startDir: string): Promise<string | null> {
|
||||
|
||||
if (!isENOENT && !isTestEnv) {
|
||||
if (typeof error === 'object' && error !== null && 'code' in error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const fsError = error as { code: string; message: string };
|
||||
logger.warn(
|
||||
`Error checking for .git directory at ${gitPath}: ${fsError.message}`,
|
||||
@@ -311,6 +313,7 @@ export function concatenateInstructions(
|
||||
return instructionContents
|
||||
.filter((item) => typeof item.content === 'string')
|
||||
.map((item) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const trimmedContent = (item.content as string).trim();
|
||||
if (trimmedContent.length === 0) {
|
||||
return null;
|
||||
@@ -359,6 +362,7 @@ export async function loadGlobalMemory(
|
||||
.filter((item) => item.content !== null)
|
||||
.map((item) => ({
|
||||
path: item.filePath,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
content: item.content as string,
|
||||
})),
|
||||
};
|
||||
@@ -456,6 +460,7 @@ export async function loadEnvironmentMemory(
|
||||
.filter((item) => item.content !== null)
|
||||
.map((item) => ({
|
||||
path: item.filePath,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
content: item.content as string,
|
||||
})),
|
||||
};
|
||||
@@ -640,6 +645,7 @@ export async function loadJitSubdirectoryMemory(
|
||||
.filter((item) => item.content !== null)
|
||||
.map((item) => ({
|
||||
path: item.filePath,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
content: item.content as string,
|
||||
})),
|
||||
};
|
||||
|
||||
@@ -109,6 +109,7 @@ export async function checkNextSpeaker(
|
||||
];
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const parsedResponse = (await baseLlmClient.generateJson({
|
||||
modelConfigKey: { model: 'next-speaker-checker' },
|
||||
contents,
|
||||
|
||||
@@ -30,6 +30,7 @@ export function partToString(
|
||||
}
|
||||
|
||||
// Cast to Part, assuming it might contain project-specific fields
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const part = value as Part & {
|
||||
videoMetadata?: unknown;
|
||||
thought?: string;
|
||||
|
||||
@@ -20,7 +20,9 @@ export function isApiError(error: unknown): error is ApiError {
|
||||
typeof error === 'object' &&
|
||||
error !== null &&
|
||||
'error' in error &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
typeof (error as ApiError).error === 'object' &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
'message' in (error as ApiError).error
|
||||
);
|
||||
}
|
||||
@@ -30,6 +32,7 @@ export function isStructuredError(error: unknown): error is StructuredError {
|
||||
typeof error === 'object' &&
|
||||
error !== null &&
|
||||
'message' in error &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
typeof (error as StructuredError).message === 'string'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ function getNetworkErrorCode(error: unknown): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
if ('code' in obj && typeof (obj as { code: unknown }).code === 'string') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return (obj as { code: string }).code;
|
||||
}
|
||||
return undefined;
|
||||
@@ -196,6 +197,7 @@ export async function retryWithBackoff<T>(
|
||||
|
||||
if (
|
||||
shouldRetryOnContent &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
shouldRetryOnContent(result as GenerateContentResponse)
|
||||
) {
|
||||
const jitter = currentDelay * 0.3 * (Math.random() * 2 - 1);
|
||||
@@ -327,6 +329,7 @@ export async function retryWithBackoff<T>(
|
||||
// Generic retry logic for other errors
|
||||
if (
|
||||
attempt >= maxAttempts ||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
!shouldRetryOnError(error as Error, retryFetchErrors)
|
||||
) {
|
||||
throw error;
|
||||
|
||||
@@ -56,6 +56,7 @@ function removeEmptyObjects(data: any): object {
|
||||
export function safeJsonStringifyBooleanValuesOnly(obj: any): string {
|
||||
let configSeen = false;
|
||||
return JSON.stringify(removeEmptyObjects(obj), (key, value) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
if ((value as Config) !== null && !configSeen) {
|
||||
configSeen = true;
|
||||
return value;
|
||||
|
||||
@@ -12,9 +12,9 @@ import * as addFormats from 'ajv-formats';
|
||||
import { debugLogger } from './debugLogger.js';
|
||||
|
||||
// Ajv's ESM/CJS interop: use 'any' for compatibility as recommended by Ajv docs
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-type-assertion
|
||||
const AjvClass = (AjvPkg as any).default || AjvPkg;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-type-assertion
|
||||
const Ajv2020Class = (Ajv2020Pkg as any).default || Ajv2020Pkg;
|
||||
|
||||
const ajvOptions = {
|
||||
@@ -34,7 +34,7 @@ const ajvDefault: Ajv = new AjvClass(ajvOptions);
|
||||
// Draft-2020-12 validator for MCP servers using rmcp
|
||||
const ajv2020: Ajv = new Ajv2020Class(ajvOptions);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-type-assertion
|
||||
const addFormatsFunc = (addFormats as any).default || addFormats;
|
||||
addFormatsFunc(ajvDefault);
|
||||
addFormatsFunc(ajv2020);
|
||||
@@ -90,6 +90,7 @@ export class SchemaValidator {
|
||||
// This matches LenientJsonSchemaValidator behavior in mcp-client.ts.
|
||||
debugLogger.warn(
|
||||
`Failed to compile schema (${
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(schema as Record<string, unknown>)?.['$schema'] ?? '<no $schema>'
|
||||
}): ${error instanceof Error ? error.message : String(error)}. ` +
|
||||
'Skipping parameter validation.',
|
||||
@@ -121,6 +122,7 @@ export class SchemaValidator {
|
||||
// Skip validation rather than blocking tool usage.
|
||||
debugLogger.warn(
|
||||
`Failed to validate schema (${
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
(schema as Record<string, unknown>)?.['$schema'] ?? '<no $schema>'
|
||||
}): ${error instanceof Error ? error.message : String(error)}. ` +
|
||||
'Skipping schema validation.',
|
||||
|
||||
@@ -66,6 +66,7 @@ export async function isDirectorySecure(
|
||||
} catch (error) {
|
||||
return {
|
||||
secure: false,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
reason: `A security check for the system policy directory '${dirPath}' failed and could not be completed. Please file a bug report. Original error: ${(error as Error).message}`,
|
||||
};
|
||||
}
|
||||
@@ -93,11 +94,13 @@ export async function isDirectorySecure(
|
||||
|
||||
return { secure: true };
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
||||
return { secure: true };
|
||||
}
|
||||
return {
|
||||
secure: false,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
reason: `Failed to access directory: ${(error as Error).message}`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -237,6 +237,7 @@ function parseCommandTree(
|
||||
progressCallback: () => {
|
||||
if (performance.now() > deadline) {
|
||||
timedOut = true;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return true as unknown as void; // Returning true cancels parsing, but type says void
|
||||
}
|
||||
},
|
||||
|
||||
@@ -52,6 +52,26 @@ export function disableSimulationAfterFallback(): void {
|
||||
fallbackOccurred = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a simulated 429 error response
|
||||
*/
|
||||
export function createSimulated429Error(): Error {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const error = new Error('Rate limit exceeded (simulated)') as Error & {
|
||||
status: number;
|
||||
};
|
||||
error.status = 429;
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset simulation state when switching auth methods
|
||||
*/
|
||||
export function resetSimulationState(): void {
|
||||
fallbackOccurred = false;
|
||||
resetRequestCounter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable 429 simulation programmatically (for tests)
|
||||
*/
|
||||
|
||||
@@ -88,6 +88,7 @@ function estimateFunctionResponseTokens(part: Part, depth: number): number {
|
||||
}
|
||||
|
||||
// Gemini 3: Handle nested multimodal parts recursively.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const nestedParts = (fr as unknown as { parts?: Part[] }).parts;
|
||||
if (nestedParts && nestedParts.length > 0) {
|
||||
totalTokens += estimateTokenCountSync(nestedParts, depth + 1);
|
||||
|
||||
@@ -104,6 +104,7 @@ export function doesToolInvocationMatch(
|
||||
// This invocation has no command - nothing to check.
|
||||
continue;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
command = String((invocation.params as { command: string }).command);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ export class UserAccountManager {
|
||||
debugLogger.log('Invalid accounts file schema, starting fresh.');
|
||||
return defaultState;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const { active, old } = parsed as Partial<UserAccounts>;
|
||||
const isValid =
|
||||
(active === undefined || active === null || typeof active === 'string') &&
|
||||
|
||||
Reference in New Issue
Block a user