fix(server): multi step tool call (#13486)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- Bug Fixes
- Enforced a consistent step limit for AI responses across providers,
preventing excessively long generations in both text and streaming modes
for more predictable results.

- Refactor
- Centralized step limit configuration into a shared provider, ensuring
uniform behavior across providers and simplifying future maintenance.
- Standardized application of step limits in text generation and
streaming flows to align provider behavior and improve overall
reliability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2025-08-13 16:10:42 +08:00
committed by GitHub
parent 7e0de251cb
commit dd9d8adbf8
4 changed files with 4 additions and 4 deletions

View File

@@ -26,8 +26,6 @@ import {
} from '../utils'; } from '../utils';
export abstract class AnthropicProvider<T> extends CopilotProvider<T> { export abstract class AnthropicProvider<T> extends CopilotProvider<T> {
private readonly MAX_STEPS = 20;
protected abstract instance: protected abstract instance:
| AnthropicSDKProvider | AnthropicSDKProvider
| GoogleVertexAnthropicProvider; | GoogleVertexAnthropicProvider;

View File

@@ -9,6 +9,7 @@ import {
generateObject, generateObject,
generateText, generateText,
JSONParseError, JSONParseError,
stepCountIs,
streamText, streamText,
} from 'ai'; } from 'ai';
@@ -85,6 +86,7 @@ export abstract class GeminiProvider<T> extends CopilotProvider<T> {
google: this.getGeminiOptions(options, model.id), google: this.getGeminiOptions(options, model.id),
}, },
tools: await this.getTools(options, model.id), tools: await this.getTools(options, model.id),
stopWhen: stepCountIs(this.MAX_STEPS),
}); });
if (!text) throw new Error('Failed to generate text'); if (!text) throw new Error('Failed to generate text');
@@ -276,6 +278,7 @@ export abstract class GeminiProvider<T> extends CopilotProvider<T> {
google: this.getGeminiOptions(options, model.id), google: this.getGeminiOptions(options, model.id),
}, },
tools: await this.getTools(options, model.id), tools: await this.getTools(options, model.id),
stopWhen: stepCountIs(this.MAX_STEPS),
}); });
return fullStream; return fullStream;
} }

View File

@@ -296,8 +296,6 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
}, },
]; ];
private readonly MAX_STEPS = 20;
#instance!: VercelOpenAIProvider; #instance!: VercelOpenAIProvider;
override configured(): boolean { override configured(): boolean {

View File

@@ -55,6 +55,7 @@ import {
@Injectable() @Injectable()
export abstract class CopilotProvider<C = any> { export abstract class CopilotProvider<C = any> {
protected readonly logger = new Logger(this.constructor.name); protected readonly logger = new Logger(this.constructor.name);
protected readonly MAX_STEPS = 20;
protected onlineModelList: string[] = []; protected onlineModelList: string[] = [];
abstract readonly type: CopilotProviderType; abstract readonly type: CopilotProviderType;
abstract readonly models: CopilotProviderModel[]; abstract readonly models: CopilotProviderModel[];