mirror of
https://github.com/vxcontrol/pentagi.git
synced 2026-07-21 16:25:27 -04:00
fix(provider): optimize ToolCallIDTemplate generation while product starting
- Modified prompt templates to enforce completion requirements for function calls.
This commit is contained in:
@@ -20,6 +20,8 @@ var configFS embed.FS
|
||||
|
||||
const AnthropicAgentModel = "claude-sonnet-4-20250514"
|
||||
|
||||
const AnthropicToolCallIDTemplate = "toolu_{r:24:b}"
|
||||
|
||||
func BuildProviderConfig(configData []byte) (*pconfig.ProviderConfig, error) {
|
||||
defaultOptions := []llms.CallOption{
|
||||
llms.WithModel(AnthropicAgentModel),
|
||||
@@ -177,5 +179,5 @@ func (p *anthropicProvider) GetUsage(info map[string]any) pconfig.CallUsage {
|
||||
}
|
||||
|
||||
func (p *anthropicProvider) GetToolCallIDTemplate(ctx context.Context, prompter templates.Prompter) (string, error) {
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter)
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter, AnthropicToolCallIDTemplate)
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ var configFS embed.FS
|
||||
|
||||
const BedrockAgentModel = bedrock.ModelAnthropicClaudeSonnet4
|
||||
|
||||
const BedrockToolCallIDTemplate = "tooluse_{r:22:x}"
|
||||
|
||||
func BuildProviderConfig(configData []byte) (*pconfig.ProviderConfig, error) {
|
||||
defaultOptions := []llms.CallOption{
|
||||
llms.WithModel(BedrockAgentModel),
|
||||
@@ -248,7 +250,7 @@ func (p *bedrockProvider) GetUsage(info map[string]any) pconfig.CallUsage {
|
||||
}
|
||||
|
||||
func (p *bedrockProvider) GetToolCallIDTemplate(ctx context.Context, prompter templates.Prompter) (string, error) {
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter)
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter, BedrockToolCallIDTemplate)
|
||||
}
|
||||
|
||||
func extractToolsFromOptions(options []llms.CallOption) []llms.Tool {
|
||||
|
||||
@@ -183,5 +183,5 @@ func (p *customProvider) GetUsage(info map[string]any) pconfig.CallUsage {
|
||||
}
|
||||
|
||||
func (p *customProvider) GetToolCallIDTemplate(ctx context.Context, prompter templates.Prompter) (string, error) {
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter)
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter, "")
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ var configFS embed.FS
|
||||
|
||||
const DeepSeekAgentModel = "deepseek-chat"
|
||||
|
||||
const DeepSeekToolCallIDTemplate = "call_{r:2:d}_{r:24:b}"
|
||||
|
||||
func BuildProviderConfig(configData []byte) (*pconfig.ProviderConfig, error) {
|
||||
defaultOptions := []llms.CallOption{
|
||||
llms.WithModel(DeepSeekAgentModel),
|
||||
@@ -175,5 +177,5 @@ func (p *deepseekProvider) GetUsage(info map[string]any) pconfig.CallUsage {
|
||||
}
|
||||
|
||||
func (p *deepseekProvider) GetToolCallIDTemplate(ctx context.Context, prompter templates.Prompter) (string, error) {
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter)
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter, DeepSeekToolCallIDTemplate)
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ const GeminiAgentModel = "gemini-2.5-flash"
|
||||
|
||||
const defaultGeminiHost = "generativelanguage.googleapis.com"
|
||||
|
||||
const GeminiToolCallIDTemplate = "{r:8:x}"
|
||||
|
||||
func BuildProviderConfig(configData []byte) (*pconfig.ProviderConfig, error) {
|
||||
defaultOptions := []llms.CallOption{
|
||||
llms.WithModel(GeminiAgentModel),
|
||||
@@ -186,5 +188,5 @@ func (p *geminiProvider) GetUsage(info map[string]any) pconfig.CallUsage {
|
||||
}
|
||||
|
||||
func (p *geminiProvider) GetToolCallIDTemplate(ctx context.Context, prompter templates.Prompter) (string, error) {
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter)
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter, GeminiToolCallIDTemplate)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ var configFS embed.FS
|
||||
|
||||
const GLMAgentModel = "glm-4.7-flashx"
|
||||
|
||||
const GLMToolCallIDTemplate = "call_-{r:19:d}"
|
||||
|
||||
func BuildProviderConfig(configData []byte) (*pconfig.ProviderConfig, error) {
|
||||
defaultOptions := []llms.CallOption{
|
||||
llms.WithModel(GLMAgentModel),
|
||||
@@ -173,5 +175,5 @@ func (p *glmProvider) GetUsage(info map[string]any) pconfig.CallUsage {
|
||||
}
|
||||
|
||||
func (p *glmProvider) GetToolCallIDTemplate(ctx context.Context, prompter templates.Prompter) (string, error) {
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter)
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter, GLMToolCallIDTemplate)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
simple:
|
||||
model: "kimi-k2-turbo-preview"
|
||||
temperature: 0.6
|
||||
temperature: 0.3
|
||||
n: 1
|
||||
max_tokens: 8192
|
||||
extra_body:
|
||||
tool_choice: "auto"
|
||||
price:
|
||||
input: 1.15
|
||||
output: 8.0
|
||||
|
||||
simple_json:
|
||||
model: "kimi-k2-turbo-preview"
|
||||
temperature: 0.6
|
||||
temperature: 0.3
|
||||
n: 1
|
||||
max_tokens: 4096
|
||||
json: true
|
||||
@@ -22,6 +24,8 @@ primary_agent:
|
||||
temperature: 1.0
|
||||
n: 1
|
||||
max_tokens: 16384
|
||||
extra_body:
|
||||
tool_choice: "auto"
|
||||
price:
|
||||
input: 0.6
|
||||
output: 3.0
|
||||
@@ -31,6 +35,8 @@ assistant:
|
||||
temperature: 1.0
|
||||
n: 1
|
||||
max_tokens: 16384
|
||||
extra_body:
|
||||
tool_choice: "auto"
|
||||
price:
|
||||
input: 0.6
|
||||
output: 3.0
|
||||
@@ -40,6 +46,8 @@ generator:
|
||||
temperature: 1.0
|
||||
n: 1
|
||||
max_tokens: 32768
|
||||
extra_body:
|
||||
tool_choice: "auto"
|
||||
price:
|
||||
input: 0.6
|
||||
output: 3.0
|
||||
@@ -49,6 +57,8 @@ refiner:
|
||||
temperature: 1.0
|
||||
n: 1
|
||||
max_tokens: 20480
|
||||
extra_body:
|
||||
tool_choice: "auto"
|
||||
price:
|
||||
input: 0.6
|
||||
output: 3.0
|
||||
@@ -67,6 +77,8 @@ reflector:
|
||||
temperature: 0.7
|
||||
n: 1
|
||||
max_tokens: 4096
|
||||
extra_body:
|
||||
tool_choice: "auto"
|
||||
price:
|
||||
input: 0.6
|
||||
output: 2.5
|
||||
@@ -76,6 +88,8 @@ searcher:
|
||||
temperature: 0.7
|
||||
n: 1
|
||||
max_tokens: 4096
|
||||
extra_body:
|
||||
tool_choice: "auto"
|
||||
price:
|
||||
input: 0.6
|
||||
output: 2.5
|
||||
@@ -85,6 +99,8 @@ enricher:
|
||||
temperature: 0.7
|
||||
n: 1
|
||||
max_tokens: 4096
|
||||
extra_body:
|
||||
tool_choice: "auto"
|
||||
price:
|
||||
input: 0.6
|
||||
output: 2.5
|
||||
@@ -94,6 +110,8 @@ coder:
|
||||
temperature: 1.0
|
||||
n: 1
|
||||
max_tokens: 20480
|
||||
extra_body:
|
||||
tool_choice: "auto"
|
||||
price:
|
||||
input: 0.6
|
||||
output: 3.0
|
||||
@@ -103,6 +121,8 @@ installer:
|
||||
temperature: 0.7
|
||||
n: 1
|
||||
max_tokens: 16384
|
||||
extra_body:
|
||||
tool_choice: "auto"
|
||||
price:
|
||||
input: 1.15
|
||||
output: 8.0
|
||||
@@ -112,6 +132,8 @@ pentester:
|
||||
temperature: 0.8
|
||||
n: 1
|
||||
max_tokens: 16384
|
||||
extra_body:
|
||||
tool_choice: "auto"
|
||||
price:
|
||||
input: 1.15
|
||||
output: 8.0
|
||||
|
||||
@@ -21,6 +21,8 @@ var configFS embed.FS
|
||||
|
||||
const KimiAgentModel = "kimi-k2-turbo-preview"
|
||||
|
||||
const KimiToolCallIDTemplate = "{f}:{r:1:d}"
|
||||
|
||||
func BuildProviderConfig(configData []byte) (*pconfig.ProviderConfig, error) {
|
||||
defaultOptions := []llms.CallOption{
|
||||
llms.WithModel(KimiAgentModel),
|
||||
@@ -175,5 +177,5 @@ func (p *kimiProvider) GetUsage(info map[string]any) pconfig.CallUsage {
|
||||
}
|
||||
|
||||
func (p *kimiProvider) GetToolCallIDTemplate(ctx context.Context, prompter templates.Prompter) (string, error) {
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter)
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter, KimiToolCallIDTemplate)
|
||||
}
|
||||
|
||||
@@ -295,5 +295,5 @@ func (p *ollamaProvider) GetUsage(info map[string]any) pconfig.CallUsage {
|
||||
}
|
||||
|
||||
func (p *ollamaProvider) GetToolCallIDTemplate(ctx context.Context, prompter templates.Prompter) (string, error) {
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter)
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter, "")
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ var configFS embed.FS
|
||||
|
||||
const OpenAIAgentModel = "o4-mini"
|
||||
|
||||
const OpenAIToolCallIDTemplate = "call_{r:24:b}"
|
||||
|
||||
func BuildProviderConfig(configData []byte) (*pconfig.ProviderConfig, error) {
|
||||
defaultOptions := []llms.CallOption{
|
||||
llms.WithModel(OpenAIAgentModel),
|
||||
@@ -169,5 +171,5 @@ func (p *openaiProvider) GetUsage(info map[string]any) pconfig.CallUsage {
|
||||
}
|
||||
|
||||
func (p *openaiProvider) GetToolCallIDTemplate(ctx context.Context, prompter templates.Prompter) (string, error) {
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter)
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter, OpenAIToolCallIDTemplate)
|
||||
}
|
||||
|
||||
@@ -46,6 +46,44 @@ func storeInCache(provider Provider, template string) {
|
||||
cacheTemplates.Store(provider.Type(), template)
|
||||
}
|
||||
|
||||
// testTemplate validates a template by collecting a single sample from the LLM
|
||||
// and checking if it matches the provided template pattern.
|
||||
// Returns true if the template is valid, false otherwise (including any errors).
|
||||
// This function makes a real LLM call to collect samples for validation.
|
||||
func testTemplate(
|
||||
ctx context.Context,
|
||||
provider Provider,
|
||||
opt pconfig.ProviderOptionsType,
|
||||
prompter templates.Prompter,
|
||||
template string,
|
||||
) bool {
|
||||
// If no template provided, skip validation
|
||||
if template == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// Collect one sample to validate the template
|
||||
samples, err := runToolCallIDCollector(ctx, provider, opt, prompter)
|
||||
if err != nil {
|
||||
// Any error means validation failed
|
||||
return false
|
||||
}
|
||||
|
||||
// If no samples collected, validation failed
|
||||
if len(samples) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Validate the template against collected samples
|
||||
if err := templates.ValidatePattern(template, samples); err != nil {
|
||||
// Template doesn't match
|
||||
return false
|
||||
}
|
||||
|
||||
// Template validated successfully
|
||||
return true
|
||||
}
|
||||
|
||||
// DetermineToolCallIDTemplate analyzes tool call ID format by collecting samples
|
||||
// and using AI to detect the pattern, with fallback to heuristic analysis
|
||||
func DetermineToolCallIDTemplate(
|
||||
@@ -53,6 +91,7 @@ func DetermineToolCallIDTemplate(
|
||||
provider Provider,
|
||||
opt pconfig.ProviderOptionsType,
|
||||
prompter templates.Prompter,
|
||||
defaultTemplate string,
|
||||
) (string, error) {
|
||||
ctx, observation := obs.Observer.NewObservation(ctx)
|
||||
agent := observation.Agent(
|
||||
@@ -84,6 +123,12 @@ func DetermineToolCallIDTemplate(
|
||||
return wrapEndAgentSpan(template, "found in cache", nil)
|
||||
}
|
||||
|
||||
// Step 0.5: Test default template if provided (makes one LLM call for validation)
|
||||
if defaultTemplate != "" && testTemplate(ctx, provider, opt, prompter, defaultTemplate) {
|
||||
storeInCache(provider, defaultTemplate)
|
||||
return wrapEndAgentSpan(defaultTemplate, "validated default template", nil)
|
||||
}
|
||||
|
||||
// Step 1: Collect 5 sample tool call IDs in parallel
|
||||
samples, err := collectToolCallIDSamples(ctx, provider, opt, prompter)
|
||||
if err != nil {
|
||||
@@ -244,9 +289,15 @@ func runToolCallIDCollector(
|
||||
// Call LLM with tool
|
||||
messages := []llms.MessageContent{
|
||||
{
|
||||
Role: llms.ChatMessageTypeHuman,
|
||||
Role: llms.ChatMessageTypeSystem,
|
||||
Parts: []llms.ContentPart{llms.TextContent{Text: prompt}},
|
||||
},
|
||||
{
|
||||
Role: llms.ChatMessageTypeHuman,
|
||||
Parts: []llms.ContentPart{llms.TextContent{
|
||||
Text: fmt.Sprintf("Call the %s function", testFunctionName),
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
response, err := provider.CallWithTools(ctx, opt, messages, []llms.Tool{testTool}, nil)
|
||||
@@ -332,9 +383,15 @@ func detectPatternWithAI(
|
||||
// Call LLM with tool
|
||||
messages := []llms.MessageContent{
|
||||
{
|
||||
Role: llms.ChatMessageTypeHuman,
|
||||
Role: llms.ChatMessageTypeSystem,
|
||||
Parts: []llms.ContentPart{llms.TextContent{Text: prompt}},
|
||||
},
|
||||
{
|
||||
Role: llms.ChatMessageTypeHuman,
|
||||
Parts: []llms.ContentPart{llms.TextContent{
|
||||
Text: fmt.Sprintf("Submit the detected pattern template for the function %s", patternFunctionName),
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
response, err := provider.CallWithTools(ctx, opt, messages, []llms.Tool{patternTool}, nil)
|
||||
|
||||
@@ -21,6 +21,8 @@ var configFS embed.FS
|
||||
|
||||
const QwenAgentModel = "qwen-plus"
|
||||
|
||||
const QwenToolCallIDTemplate = "call_{r:24:h}"
|
||||
|
||||
func BuildProviderConfig(configData []byte) (*pconfig.ProviderConfig, error) {
|
||||
defaultOptions := []llms.CallOption{
|
||||
llms.WithModel(QwenAgentModel),
|
||||
@@ -174,5 +176,5 @@ func (p *qwenProvider) GetUsage(info map[string]any) pconfig.CallUsage {
|
||||
}
|
||||
|
||||
func (p *qwenProvider) GetToolCallIDTemplate(ctx context.Context, prompter templates.Prompter) (string, error) {
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter)
|
||||
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter, QwenToolCallIDTemplate)
|
||||
}
|
||||
|
||||
@@ -14,9 +14,14 @@ DO NOT:
|
||||
- Describe what you will do instead of doing it
|
||||
- Explain your reasoning before calling the function
|
||||
- Ask questions or request clarification
|
||||
- End your turn without making function calls
|
||||
- Provide a text response as a substitute for function calls
|
||||
|
||||
REQUIRED ACTION: Call {{.FunctionName}} function exactly three times in parallel with value=42.
|
||||
|
||||
COMPLETION REQUIREMENT: Your work is NOT complete until you have successfully invoked the {{.FunctionName}} function exactly three times.
|
||||
DO NOT terminate, finish, or end your response without making these function calls.
|
||||
|
||||
Any response that does not include exactly three function calls will be treated as a CRITICAL ERROR.
|
||||
</mandatory_protocol>
|
||||
|
||||
|
||||
@@ -14,9 +14,14 @@ DO NOT:
|
||||
- Describe your analysis in plain text
|
||||
- Explain your reasoning before calling the function
|
||||
- Ask questions or request clarification
|
||||
- End your turn without making a function call
|
||||
- Provide a text response as a substitute for a function call
|
||||
|
||||
REQUIRED ACTION: Call {{.FunctionName}} function immediately with the detected pattern template.
|
||||
|
||||
COMPLETION REQUIREMENT: Your work is NOT complete until you have successfully invoked the {{.FunctionName}} function.
|
||||
DO NOT terminate, finish, or end your response without making this function call.
|
||||
|
||||
Any response that does not include a function call will be treated as a CRITICAL ERROR and will force a retry.
|
||||
</mandatory_protocol>
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ const ASSISTANT_LOG_TYPENAME = 'AssistantLog';
|
||||
const MAX_RETRY_DELAY_MS = 30_000;
|
||||
const STREAMING_CACHE_MAX_ENTRIES = 500;
|
||||
const STREAMING_CACHE_TTL_MS = 1000 * 60 * 5;
|
||||
const STREAMING_THROTTLE_MS = 100;
|
||||
const STREAMING_THROTTLE_MS = 50;
|
||||
|
||||
// --- Types ---
|
||||
|
||||
@@ -35,8 +35,17 @@ type SubscriptionAction = 'add' | 'create' | 'delete' | 'update';
|
||||
|
||||
const EMPTY_LOG_ENTRY: StreamingLogEntry = { message: null, result: null, thinking: null };
|
||||
|
||||
const concatStrings = (existing: null | string | undefined, incoming: null | string | undefined): null | string =>
|
||||
existing && incoming ? `${existing}${incoming}` : (existing ?? incoming ?? null);
|
||||
const concatStrings = (existing: null | string | undefined, incoming: null | string | undefined): null | string => {
|
||||
if (existing === null || existing === undefined) {
|
||||
return incoming ?? null;
|
||||
}
|
||||
|
||||
if (incoming === null || incoming === undefined) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
return `${existing}${incoming}`;
|
||||
};
|
||||
|
||||
const resolveSubscriptionAction = (name: string): SubscriptionAction => {
|
||||
if (name.endsWith('Deleted')) {
|
||||
|
||||
Reference in New Issue
Block a user