fix extractGrammar and lots of misc improvements

This commit is contained in:
Andrew Pareles 2025-04-11 03:13:11 -07:00
parent fa9a3db86f
commit 2dcdd78316
7 changed files with 50 additions and 36 deletions

View file

@ -661,7 +661,6 @@ class ChatThreadService extends Disposable implements IChatThreadService {
// above just defines helpers, below starts the actual function
const { chatMode } = this._settingsService.state.globalSettings // should not change as we loop even if user changes it, so it goes here
console.log('a', chatMode)
// clear any previous error
this._setStreamState(threadId, { error: undefined }, 'set')
@ -670,13 +669,11 @@ class ChatThreadService extends Disposable implements IChatThreadService {
let isRunningWhenEnd: IsRunningType = undefined
let aborted = false
console.log('b')
// before enter loop, call tool
if (callThisToolFirst) {
const { interrupted } = await this._runToolCall(threadId, callThisToolFirst.name, { preapproved: true, validatedParams: callThisToolFirst.params })
if (interrupted) return
}
console.log('c')
// tool use loop
while (shouldSendAnotherMessage) {
@ -688,17 +685,14 @@ class ChatThreadService extends Disposable implements IChatThreadService {
let resMessageIsDonePromise: (toolCall?: RawToolCallObj | undefined) => void // resolves when user approves this tool use (or if tool doesn't require approval)
const messageIsDonePromise = new Promise<RawToolCallObj | undefined>((res, rej) => { resMessageIsDonePromise = res })
console.log('d')
// send llm message
this._setStreamState(threadId, { isRunning: 'LLM' }, 'merge')
const systemMessage = await this._generateSystemMessage(chatMode)
console.log('e0')
const llmMessages = await this._generateLLMMessages(threadId)
const messages: LLMChatMessage[] = [
{ role: 'system', content: systemMessage },
...llmMessages
]
console.log('e')
const llmCancelToken = this._llmMessageService.sendLLMMessage({
messagesType: 'chatMessages',
@ -740,20 +734,14 @@ class ChatThreadService extends Disposable implements IChatThreadService {
break
}
this._setStreamState(threadId, { streamingToken: llmCancelToken }, 'merge') // new stream token for the new message
console.log('waiting...')
const toolCall = await messageIsDonePromise // wait for message to complete
console.log('done!')
if (aborted) { return }
console.log('H')
this._setStreamState(threadId, { streamingToken: undefined }, 'merge') // streaming message is done
console.log('I')
// call tool if there is one
const tool: RawToolCallObj | undefined = toolCall
if (tool) {
console.log('J')
const { awaitingUserApproval, interrupted } = await this._runToolCall(threadId, tool.name, { preapproved: false, unvalidatedToolParams: tool.rawParams })
console.log('K')
// stop if interrupted. we don't have to do this for llmMessage because we have a stream token for it and onAbort gets called, but we don't have the equivalent for tools.
// just detect tool interruption which is the same as chat interruption right now
@ -768,17 +756,14 @@ class ChatThreadService extends Disposable implements IChatThreadService {
}
} // end while
console.log('L')
// if awaiting user approval, keep isRunning true, else end isRunning
this._setStreamState(threadId, { isRunning: isRunningWhenEnd }, 'merge')
console.log('M')
// add checkpoint before the next user message
if (!isRunningWhenEnd)
this._addUserCheckpoint({ threadId })
console.log('N')
// capture number of messages sent
this._metricsService.capture('Agent Loop Done', { nMessagesSent, chatMode })
@ -969,7 +954,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
const [_, toIdx] = c
if (toIdx === fromIdx) return
console.log(`going from ${fromIdx} to ${toIdx}`)
// console.log(`going from ${fromIdx} to ${toIdx}`)
// update the user's checkpoint
this._addUserModificationsToCurrCheckpoint({ threadId })
@ -1064,6 +1049,7 @@ We only need to do it for files that were edited since `from`, ie files between
severity: error ? Severity.Warning : Severity.Info,
message: error ? `Error: ${error} ` : `A new Chat result is ready.`,
source: messageContent,
sticky: true,
actions: {
primary: [{
id: 'void.goToChat',

View file

@ -638,6 +638,16 @@ export const FeaturesTab = () => {
/>
<span className='text-void-fg-3 text-xs pointer-events-none'>{voidSettingsState.globalSettings.autoApprove ? 'Auto-approve' : 'Auto-approve'}</span>
</div>
{/* Tool Lint Errors Switch */}
<div className='flex items-center gap-x-2 my-2'>
<VoidSwitch
size='xs'
value={voidSettingsState.globalSettings.includeToolLintErrors}
onChange={(newVal) => voidSettingsService.setGlobalSetting('includeToolLintErrors', newVal)}
/>
<span className='text-void-fg-3 text-xs pointer-events-none'>{voidSettingsState.globalSettings.includeToolLintErrors ? 'Include after-edit lint errors' : `Don't include lint errors`}</span>
</div>
</div>
</div>

View file

@ -18,6 +18,7 @@ import { IMarkerService } from '../../../../platform/markers/common/markers.js'
import { timeout } from '../../../../base/common/async.js'
import { RawToolParamsObj } from '../common/sendLLMMessageTypes.js'
import { ToolName } from '../common/prompt/prompts.js'
import { IVoidSettingsService } from '../common/voidSettingsService.js'
// tool use for AI
@ -151,6 +152,7 @@ export class ToolsService implements IToolsService {
@IVoidCommandBarService private readonly commandBarService: IVoidCommandBarService,
@IDirectoryStrService private readonly directoryStrService: IDirectoryStrService,
@IMarkerService private readonly markerService: IMarkerService,
@IVoidSettingsService private readonly voidSettingsService: IVoidSettingsService,
) {
const queryBuilder = instantiationService.createInstance(QueryBuilder);
@ -412,10 +414,13 @@ export class ToolsService implements IToolsService {
return `URI ${params.uri.fsPath} successfully deleted.`
},
edit_file: (params, result) => {
const lintErrsString = (
this.voidSettingsService.state.globalSettings.includeToolLintErrors ?
(result.lintErrors ? ` Lint errors found after change:\n${lintErrorsStr(result.lintErrors)}.\nIf this is related to a change made while calling this tool, you might want to fix the error.`
: ` No lint errors found.`)
: '')
const additionalStr = result.lintErrors ? `Lint errors found after change:\n${lintErrorsStr(result.lintErrors)}.\nIf this is related to a change made while calling this tool, you might want to fix the error.` : `No lint errors found.`
return `Change successfully made to ${params.uri.fsPath}.${additionalStr}`
return `Change successfully made to ${params.uri.fsPath}.${lintErrsString}`
},
run_terminal_command: (params, result) => {
const {

View file

@ -16,6 +16,10 @@ export const tripleTick = ['```', '```']
export const MAX_DIRSTR_CHARS_TOTAL_BEGINNING = 20_000
export const MAX_DIRSTR_CHARS_TOTAL_TOOL = 20_000
export const MAX_DIRSTR_RESULTS_TOTAL_BEGINNING = 100
export const MAX_DIRSTR_RESULTS_TOTAL_TOOL = 100
export const MAX_PREFIX_SUFFIX_CHARS = 20_000
@ -300,8 +304,8 @@ ${directoryStr}
}
if (mode === 'gather') {
details.push(`Your primary use of tools should be to gather information to help the user understand the codebase and answer their query.`)
details.push(`You should extensively read files, types, content, etc and gather relevant context.`)
details.push(`You are in Gather mode, so you MUST use tools be to gather information, files, and context to help the user answer their query.`)
details.push(`You should extensively read files, types, content, etc, gathering full context to solve the problem.`)
}

View file

@ -211,7 +211,15 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
}
async readAndInitializeState() {
const readS = await this._readState();
let readS: VoidSettingsState
try {
readS = await this._readState();
// 1.0.3 addition, remove when enough users have had this code run
if (readS.globalSettings.includeToolLintErrors === undefined) readS.globalSettings.includeToolLintErrors = true
}
catch (e) {
readS = defaultState()
}
// the stored data structure might be outdated, so we need to update it here
const finalState = readS

View file

@ -356,6 +356,7 @@ export type GlobalSettings = {
chatMode: ChatMode;
autoApprove: boolean;
showInlineSuggestions: boolean;
includeToolLintErrors: boolean;
}
export const defaultGlobalSettings: GlobalSettings = {
@ -367,6 +368,7 @@ export const defaultGlobalSettings: GlobalSettings = {
chatMode: 'agent',
autoApprove: false,
showInlineSuggestions: true,
includeToolLintErrors: true,
}
export type GlobalSettingName = keyof GlobalSettings

View file

@ -166,6 +166,15 @@ const parseXMLPrefixToToolCall = (toolName: ToolName, str: string, toolOfToolNam
let isDone = false
const getAnswer = (): RawToolCallObj => {
// trim off all whitespace at and before first \n and after last \n for each param
for (const p in paramsObj) {
const paramName = p as ToolParamName
const orig = paramsObj[paramName]
if (orig === undefined) continue
paramsObj[paramName] = trimBeforeAndAfterNewLines(orig)
}
// return tool call
const ans: RawToolCallObj = {
name: toolName,
rawParams: paramsObj,
@ -260,7 +269,6 @@ export const extractToolsWrapper = (
let trueFullText = ''
let latestToolCall: RawToolCallObj | undefined = undefined
let foundOpenTag: { idx: number, toolName: ToolName } | null = null
let openToolTagBuffer = '' // the characters we've seen so far that come after a < with no space afterwards, not yet added to fullText
@ -270,7 +278,7 @@ export const extractToolsWrapper = (
prevFullTextLen = params.fullText.length
trueFullText = params.fullText
console.log('NEWTEXT', JSON.stringify(newText))
// console.log('NEWTEXT', JSON.stringify(newText))
if (foundOpenTag === null) {
@ -278,7 +286,7 @@ export const extractToolsWrapper = (
// ensure the code below doesn't run if only half a tag has been written
const isPartial = findPartiallyWrittenToolTagAtEnd(newFullText, toolOpenTags)
if (isPartial) {
console.log('--- partial!!!')
// console.log('--- partial!!!')
openToolTagBuffer += newText
}
// if no tooltag is partially written at the end, attempt to get the index
@ -292,7 +300,7 @@ export const extractToolsWrapper = (
if (i !== null) {
const [idx, toolTag] = i
const toolName = toolTag.substring(1, toolTag.length - 1) as ToolName
console.log('found ', toolName)
// console.log('found ', toolName)
foundOpenTag = { idx, toolName }
// do not count anything at or after i in fullText
@ -329,15 +337,6 @@ export const extractToolsWrapper = (
fullText = fullText.trimEnd()
const toolCall = latestToolCall
if (toolCall) {
// trim off all whitespace at and before first \n and after last \n for each param
for (const p in toolCall.rawParams) {
const paramName = p as ToolParamName
const orig = toolCall.rawParams[paramName]
if (orig === undefined) continue
toolCall.rawParams[paramName] = trimBeforeAndAfterNewLines(orig)
}
}
// console.log('final message!!!', trueFullText)
// console.log('----- returning ----\n', fullText)
@ -351,7 +350,7 @@ export const extractToolsWrapper = (
// trim all whitespace up until the first newline, and all whitespace after the last newline
// trim all whitespace up until the first newline, and all whitespace up until the last newline
const trimBeforeAndAfterNewLines = (s: string) => {
if (!s) return s;