checkpoint state improvements

This commit is contained in:
Andrew Pareles 2025-04-09 02:45:34 -07:00
parent 8c26fd2081
commit 78671db5b8
4 changed files with 29 additions and 5 deletions

View file

@ -358,9 +358,9 @@ class ChatThreadService extends Disposable implements IChatThreadService {
else if (behavior === 'set') {
this.streamState[threadId] = state
}
else throw new Error(`setStreamState`)
}
this._onDidChangeStreamState.fire({ threadId })
}
@ -488,7 +488,6 @@ class ChatThreadService extends Disposable implements IChatThreadService {
const displayContentSoFar = this.streamState[threadId]?.displayContentSoFar ?? ''
const reasoningSoFar = this.streamState[threadId]?.reasoningSoFar ?? ''
const toolCallSoFar = this.streamState[threadId]?.toolCallSoFar
console.log('toolInProgress', toolCallSoFar)
const llmCancelToken = this.streamState[threadId]?.streamingToken
if (llmCancelToken !== undefined) { this._llmMessageService.abort(llmCancelToken) }
@ -498,6 +497,8 @@ class ChatThreadService extends Disposable implements IChatThreadService {
if (toolCallSoFar) {
this._addMessageToThread(threadId, { role: 'interrupted_streaming_tool', name: toolCallSoFar.name })
}
this._addUserCheckpoint({ threadId })
}
this._setStreamState(threadId, {}, 'set')
@ -1089,14 +1090,21 @@ We only need to do it for files that were edited since `from`, ie files between
if (!thread) return // should never happen
const llmCancelToken = this.streamState[threadId]?.streamingToken // currently streaming LLM on this thread
if (llmCancelToken === undefined && this.streamState[threadId]?.isRunning === 'LLM') {
// if about to call the other LLM, just wait for it by stopping right now
return
}
// stop it (this simply resolves the promise to free up space)
if (llmCancelToken !== undefined) this._llmMessageService.abort(llmCancelToken)
// add dummy before this message to keep checkpoint before user message idea consistent
if (thread.messages.length === 0) {
this._addUserCheckpoint({ threadId })
}
// if the current thread is already streaming, stop it (this simply resolves the promise to free up space)
const llmCancelToken = this.streamState[threadId]?.streamingToken
if (llmCancelToken !== undefined) this._llmMessageService.abort(llmCancelToken)
const { chatMode } = this._settingsService.state.globalSettings
@ -1488,6 +1496,10 @@ We only need to do it for files that were edited since `from`, ie files between
}
}
}, true)
// when change focused message idx, jump
if (messageIdx !== undefined)
this.jumpToCheckpointBeforeMessageIdx({ threadId, messageIdx, jumpToUserModified: true })
}
// set message.state

View file

@ -106,6 +106,7 @@ export const VoidInputBox2 = forwardRef<HTMLTextAreaElement, InputBox2Props>(fun
return (
<textarea
autoFocus={false}
ref={useCallback((r: HTMLTextAreaElement | null) => {
if (fnsRef)
fnsRef.current = fns

View file

@ -4,6 +4,7 @@ import { ITextModel } from '../../../../editor/common/model.js';
import { IResolvedTextEditorModel, ITextModelService } from '../../../../editor/common/services/resolverService.js';
import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js';
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
import { ITextFileService } from '../../../services/textfile/common/textfiles.js';
type VoidModelType = {
model: ITextModel | null;
@ -16,6 +17,8 @@ export interface IVoidModelService {
getModel(uri: URI): VoidModelType;
getModelFromFsPath(fsPath: string): VoidModelType;
getModelSafe(uri: URI): Promise<VoidModelType>;
saveModel(uri: URI): Promise<void>;
}
export const IVoidModelService = createDecorator<IVoidModelService>('voidVoidModelService');
@ -27,10 +30,17 @@ class VoidModelService extends Disposable implements IVoidModelService {
constructor(
@ITextModelService private readonly _textModelService: ITextModelService,
@ITextFileService private readonly _textFileService: ITextFileService,
) {
super();
}
saveModel = async (uri: URI) => {
await this._textFileService.save(uri, { // we want [our change] -> [save] so it's all treated as one change.
skipSaveParticipants: true // avoid triggering extensions etc (if they reformat the page, it will add another item to the undo stack)
})
}
initializeModel = async (uri: URI) => {
if (uri.fsPath in this._modelRefOfURI) return;
const editorModelRef = await this._textModelService.createModelReference(uri);

View file

@ -284,6 +284,7 @@ export const extractToolsWrapper = (
parser.write(newText)
// firstToolCallRef.current === state.currentToolCall is always true
onText({
...params,
fullText,