executeChatAskNative runs the buffered decision turn for native tool-use providers, offering only the enabled exception tools (ask_user, knowledge). Knowledge calls loop for a bounded number of rounds before the answer.
( ctx context.Context, tac client.ToolAwareClient, activeClient client.LLMClient, userInput, additionalContext string, tempHistory []models.Message, effectiveMaxTokens int, resolution SkillClientResolution, stopSpinner func(), askOn, kbOn, gvOn, memOn bool, )
| 99 | // providers, offering only the enabled exception tools (ask_user, knowledge). |
| 100 | // Knowledge calls loop for a bounded number of rounds before the answer. |
| 101 | func (cli *ChatCLI) executeChatAskNative( |
| 102 | ctx context.Context, |
| 103 | tac client.ToolAwareClient, |
| 104 | activeClient client.LLMClient, |
| 105 | userInput, additionalContext string, |
| 106 | tempHistory []models.Message, |
| 107 | effectiveMaxTokens int, |
| 108 | resolution SkillClientResolution, |
| 109 | stopSpinner func(), |
| 110 | askOn, kbOn, gvOn, memOn bool, |
| 111 | ) (string, error) { |
| 112 | tools := buildChatExceptionTools(askOn, kbOn, gvOn, memOn) |
| 113 | prompt := userInput + additionalContext |
| 114 | history := tempHistory |
| 115 | gvDone := false |
| 116 | |
| 117 | for round := 0; ; round++ { |
| 118 | resp, err := tac.SendPromptWithTools(ctx, prompt, history, tools, effectiveMaxTokens) |
| 119 | if err != nil && cli.refreshClientOnAuthError(err) { |
| 120 | resp, err = tac.SendPromptWithTools(ctx, prompt, history, tools, effectiveMaxTokens) |
| 121 | } |
| 122 | if err != nil { |
| 123 | cli.finishSpinner(stopSpinner) |
| 124 | return "", err |
| 125 | } |
| 126 | if resp != nil && resp.Usage != nil && cli.costTracker != nil { |
| 127 | cli.costTracker.RecordRealUsage(resolution.Provider, resolution.Model, resp.Usage) |
| 128 | } |
| 129 | |
| 130 | var calls chatExceptionCalls |
| 131 | if resp != nil { |
| 132 | for _, tc := range resp.ToolCalls { |
| 133 | calls.collect(tc.Name, tc.ArgumentsJSON(), askOn, kbOn, gvOn, memOn) |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | // Knowledge pull: execute, fold into the conversation, decide again. |
| 138 | if calls.kb != "" && round < chatKnowledgeMaxRounds { |
| 139 | result := cli.runChatKnowledge(ctx, calls.kb) |
| 140 | history, prompt = appendKnowledgeRound(history, prompt, calls.kb, result) |
| 141 | continue |
| 142 | } |
| 143 | |
| 144 | // Memory write/read: execute, fold the result in, decide again — the |
| 145 | // model may chain recall → update → verify before confirming. |
| 146 | if calls.mem != "" && round < chatMemoryMaxRounds { |
| 147 | result := cli.runChatMemory(ctx, calls.mem) |
| 148 | history, prompt = appendMemoryRound(history, prompt, calls.mem, result) |
| 149 | continue |
| 150 | } |
| 151 | |
| 152 | // Graph render: a one-shot action — render once, fold the result in, and |
| 153 | // let the next round produce the natural-language confirmation. |
| 154 | if calls.gv != "" && !gvDone { |
| 155 | result := cli.runChatGraphView(ctx, calls.gv) |
| 156 | history, prompt = appendGraphViewRound(history, prompt, calls.gv, result) |
| 157 | gvDone = true |
| 158 | continue |
no test coverage detected