Disallow unsafe type assertions (#18688)

This commit is contained in:
Christian Gunderman
2026-02-10 00:10:15 +00:00
committed by GitHub
parent bce1caefd0
commit fd65416a2f
188 changed files with 592 additions and 47 deletions

View File

@@ -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[],
);

View File

@@ -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);
}

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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;

View File

@@ -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,
);
}