This commit is contained in:
Andrew Pareles 2024-11-14 00:53:06 -08:00
parent 1fe12d2bfd
commit 13f6fd5c66
11 changed files with 206 additions and 122 deletions

51
package-lock.json generated
View file

@ -152,6 +152,7 @@
"path-browserify": "^1.0.1",
"postcss": "^8.4.33",
"postcss-nesting": "^12.0.2",
"posthog-js": "^1.184.2",
"pump": "^1.0.1",
"rcedit": "^1.1.0",
"react": "^18.3.1",
@ -6503,6 +6504,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/core-js": {
"version": "3.39.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz",
"integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@ -8397,6 +8410,13 @@
}
}
},
"node_modules/fflate": {
"version": "0.4.8",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
"integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==",
"dev": true,
"license": "MIT"
},
"node_modules/figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
@ -17455,6 +17475,30 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/posthog-js": {
"version": "1.184.2",
"resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.184.2.tgz",
"integrity": "sha512-n7OxFntH7m4sw/GsuUAliWGqBDV7g7IemvjwGISCQFQpf5cSqZgmvT2V2O3GHXpONiEgwL/Ud/+zWmhZbWLExg==",
"dev": true,
"license": "MIT",
"dependencies": {
"core-js": "^3.38.1",
"fflate": "^0.4.8",
"preact": "^10.19.3",
"web-vitals": "^4.2.0"
}
},
"node_modules/preact": {
"version": "10.24.3",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz",
"integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==",
"dev": true,
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/prebuild-install": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz",
@ -22143,6 +22187,13 @@
"integrity": "sha512-weOVgZ3aAARgdnb220GqYuh7+rZU0Ka9k9yfKtGAzEYMa6GgiCzW9JjQRJyCJakvibQW+dfjJdihjInKuuCAUQ==",
"dev": true
},
"node_modules/web-vitals": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz",
"integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",

View file

@ -214,6 +214,7 @@
"path-browserify": "^1.0.1",
"postcss": "^8.4.33",
"postcss-nesting": "^12.0.2",
"posthog-js": "^1.184.2",
"pump": "^1.0.1",
"rcedit": "^1.1.0",
"react": "^18.3.1",

View file

@ -1,12 +1,12 @@
import React, { JSX, useCallback, useEffect, useState } from "react"
import { marked, MarkedToken, Token } from "marked"
import { BlockCode } from "./BlockCode.js"
import React, { JSX, useCallback, useEffect, useState } from 'react'
import { marked, MarkedToken, Token } from 'marked'
import { BlockCode } from './BlockCode.js'
enum CopyButtonState {
Copy = "Copy",
Copied = "Copied!",
Error = "Could not copy",
Copy = 'Copy',
Copied = 'Copied!',
Error = 'Could not copy',
}
const COPY_FEEDBACK_TIMEOUT = 1000 // amount of time to say 'Copied!'

View file

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react'
import { mountFnGenerator } from '../util/mountFnGenerator'
import { mountFnGenerator } from '../util/mountFnGenerator.js'
import { SidebarSettings } from './SidebarSettings.js';
import { useSidebarState } from '../util/contextForServices.js';

View file

@ -1,5 +1,5 @@
import React from "react";
import { useThreadsState } from '../util/contextForServices';
import { useThreadsState } from '../util/contextForServices.js';
const truncate = (s: string) => {

View file

@ -1,6 +1,6 @@
import React from 'react';
import * as ReactDOM from 'react-dom/client'
import { AccessorProvider } from './contextForServices';
import { AccessorProvider } from './contextForServices.js';
import { ReactServicesType } from '../../../registerSidebar.js';

View file

@ -0,0 +1,6 @@
import posthog from 'posthog-js';
export { posthog }

View file

@ -2,10 +2,8 @@ import Anthropic from '@anthropic-ai/sdk';
import OpenAI from 'openai';
import { Ollama } from 'ollama/browser'
import { Content, GoogleGenerativeAI, GoogleGenerativeAIFetchError } from '@google/generative-ai';
import { VoidConfig } from '../../../registerConfig.js';
// import { VoidConfig } from '../webviews/common/contextForConfig'
// import { captureEvent } from '../webviews/common/posthog';
// import { ChatMessage } from './shared_types';
import { posthog } from 'posthog-js'
import type { VoidConfig } from '../../../registerConfig.js';
export type AbortRef = { current: (() => void) | null }
@ -325,13 +323,13 @@ export const sendLLMMessage: SendLLMMessageFnTypeExternal = ({
// only captures number of messages and message "shape", no actual code, instructions, prompts, etc
const captureChatEvent = (eventId: string, extras?: object) => {
// captureEvent(eventId, {
// whichApi: voidConfig.default['whichApi'],
// numMessages: messages?.length,
// messagesShape: messages?.map(msg => ({ role: msg.role, length: msg.content.length })),
// version: '2024-11-02',
// ...extras,
// })
posthog.capture(eventId, {
whichApi: voidConfig.default['whichApi'],
numMessages: messages?.length,
messagesShape: messages?.map(msg => ({ role: msg.role, length: msg.content.length })),
version: '2024-11-14',
...extras,
})
}
const submit_time = new Date()

View file

@ -2,11 +2,13 @@ import { defineConfig } from 'tsup'
export default defineConfig({
entry: [
'./src2/sidebar-tsx/Sidebar.tsx'
'./src2/sidebar-tsx/Sidebar.tsx',
'./src2/util/sendLLMMessage.ts',
'./src2/util/posthog.ts',
],
outDir: './out',
format: ['esm'],
// dts: true,
dts: true,
splitting: false,
// sourcemap: true,
clean: true,

View file

@ -6,8 +6,7 @@ import { ICodeEditor, IViewZone } from '../../../../editor/browser/editorBrowser
import { IUndoRedoElement, IUndoRedoService, UndoRedoElementType, UndoRedoGroup } from '../../../../platform/undoRedo/common/undoRedo.js';
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
import { IBulkEditService, ResourceTextEdit } from '../../../../editor/browser/services/bulkEditService.js';
import { sendLLMMessage } from './out/util/sendLLMMessage.js';
import { sendLLMMessage } from './react/out/util/sendLLMMessage.js';
import { throttle } from '../../../../base/common/decorators.js';
import { IFileService } from '../../../../platform/files/common/files.js';
import { URI } from '../../../../base/common/uri.js';
@ -127,7 +126,6 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
@IVoidConfigStateService private readonly _voidConfigStateService: IVoidConfigStateService,
@ICodeEditorService private readonly _editorService: ICodeEditorService,
@IUndoRedoService private readonly _undoRedoService: IUndoRedoService, // undoRedo service is the history of pressing ctrl+z
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
@IFileService private readonly _fileService: IFileService,
) {
@ -239,7 +237,9 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
private _addToHistory(uri: URI, editGroup?: UndoRedoGroup) {
private _addToHistory(model: ITextModel) {
const uri = model.uri
const beforeSnapshot: HistorySnapshot = {
diffAreaOfId: structuredClone(this.diffAreaOfId),
@ -257,26 +257,29 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
undo: () => {
// when the user undoes this element, revert to oldSnapshot
this.diffAreaOfId = structuredClone(beforeSnapshot.diffAreaOfId)
// TODO refresh diffs
this._refreshAllDiffsAndStyles(model)
this._refreshSweepStyles(model)
},
// called when restoring this state
redo: () => {
if (afterSnapshot === null) return
this.diffAreaOfId = structuredClone(afterSnapshot.diffAreaOfId)
// TODO refresh diffs
this._refreshAllDiffsAndStyles(model)
this._refreshSweepStyles(model)
}
}
const editGroup = new UndoRedoGroup()
this._undoRedoService.pushElement(elt, editGroup)
const finishHistorySnapshot = () => () => {
const onFinishEdit = () => () => {
if (afterSnapshot !== null) return
afterSnapshot = {
diffAreaOfId: structuredClone(this.diffAreaOfId),
type: 'ctrl+l',
}
}
return { finishHistorySnapshot }
return { onFinishEdit, editGroup }
}
@ -345,45 +348,43 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
}
private _refreshSweepStyles(model: ITextModel) {
const modelid = model.id;
// const model = editor.getModel()
// if (!model) return
// const modelid = model.id
// Create decorations for each diffArea
for (const diffareaid of this.diffAreasOfModelId[modelid] || new Set()) {
const diffArea = this.diffAreaOfId[diffareaid];
if (!diffArea._sweepLine) continue;
// const lightGrayDecoration = vscode.window.createTextEditorDecorationType({
// backgroundColor: 'rgba(218 218 218 / .2)',
// isWholeLine: true,
// })
// const darkGrayDecoration = vscode.window.createTextEditorDecorationType({
// backgroundColor: 'rgb(148 148 148 / .2)',
// isWholeLine: true,
// })
const lightGrayDecoration: IModelDeltaDecoration[] = [{
range: {
startLineNumber: diffArea._sweepLine + 1,
startColumn: 0,
endLineNumber: diffArea.endLine,
endColumn: Number.MAX_SAFE_INTEGER
},
options: {
className: 'sweep-light-gray',
description: 'sweep-light-gray',
isWholeLine: true
}
}];
const darkGrayDecoration: IModelDeltaDecoration[] = [{
range: {
startLineNumber: diffArea._sweepLine,
startColumn: 0,
endLineNumber: diffArea._sweepLine,
endColumn: Number.MAX_SAFE_INTEGER
},
options: {
className: 'sweep-dark-gray',
description: 'sweep-dark-gray',
isWholeLine: true
}
}];
// // for each diffArea, highlight its sweepIndex in dark gray
// editor.setDecorations(
// darkGrayDecoration,
// (this._diffAreasOfDocument[modelid]
// .filter(diffArea => diffArea.sweepIndex !== null)
// .map(diffArea => {
// let s = diffArea.sweepIndex!
// return new vscode.Range(s, 0, s, 0)
// })
// )
// )
// // for each diffArea, highlight sweepIndex+1...end in light gray
// editor.setDecorations(
// lightGrayDecoration,
// (this._diffAreasOfDocument[modelid]
// .filter(diffArea => diffArea.sweepIndex !== null)
// .map(diffArea => {
// return new vscode.Range(diffArea.sweepIndex! + 1, 0, diffArea.endLine, 0)
// })
// )
// )
model.deltaDecorations([], [...lightGrayDecoration, ...darkGrayDecoration]);
}
}
@ -467,8 +468,15 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
private _writeToModel(model: ITextModel, text: string, range: IRange, editorGroup: UndoRedoGroup) {
if (!model.isDisposed())
model.pushEditOperations(null, [{ range, text }], () => null, editorGroup)
}
@throttle(100)
private async _updateDiffAreaText(diffArea: DiffArea, llmCodeSoFar: string) {
private async _updateDiffAreaText(diffArea: DiffArea, llmCodeSoFar: string, editorGroup: UndoRedoGroup) {
// clear all diffs in this diffarea and recompute them
const modelid = diffArea._model.id
@ -518,12 +526,23 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
// applies edits without adding them to undo/redo stack
// model.applyEdits([{
// range: { startLineNumber: diffArea.startLine, startColumn: 0, endLineNumber: diffArea.endLine, endColumn: Number.MAX_SAFE_INTEGER, },
// text: newCode
// }])
// this._bulkEditService.apply([new ResourceTextEdit(model.uri, {
// range: { startLineNumber: diffArea.startLine, startColumn: 0, endLineNumber: diffArea.endLine, endColumn: Number.MAX_SAFE_INTEGER, },
// text: newCode
// })], { undoRedoGroupId: editorGroup.id }); // count all changes towards the group
const model = diffArea._model
if (!model.isDisposed())
model.applyEdits([{
range: { startLineNumber: diffArea.startLine, startColumn: 0, endLineNumber: diffArea.endLine, endColumn: Number.MAX_SAFE_INTEGER, },
text: newCode
}])
this._writeToModel(
model,
newCode,
{ startLineNumber: diffArea.startLine, startColumn: 0, endLineNumber: diffArea.endLine, endColumn: Number.MAX_SAFE_INTEGER, },
editorGroup
)
// TODO resize diffAreas?? Or is this handled already by the listener?
}
@ -531,7 +550,8 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
private async _initializeStream(model: ITextModel, diffRepr: string, streamingGroup: UndoRedoGroup) {
private async _initializeStream(model: ITextModel, diffRepr: string) {
const uri = model.uri
const modelid = uri.toString()
@ -559,7 +579,7 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
this._registerTextChangeListener(model)
// add to history
const { finishHistorySnapshot } = this._addToHistory(model.uri, streamingGroup)
const { onFinishEdit, editGroup } = this._addToHistory(model)
// create a diffArea for the stream
const diffareaid = this._diffareaidPool++
@ -613,26 +633,26 @@ Please finish writing the new file by applying the diff to the original file. Re
// TODO include more context too
{ role: 'user', content: promptContent, }
],
onText: (newText, fullText) => {
this._updateDiffAreaText(diffArea, fullText)
onText: (newText: string, fullText: string) => {
this._updateDiffAreaText(diffArea, fullText, editGroup)
this._refreshAllDiffsAndStyles(model)
this._refreshSweepStyles(model)
},
onFinalMessage: (fullText) => {
this._updateDiffAreaText(diffArea, fullText)
onFinalMessage: (fullText: string) => {
this._updateDiffAreaText(diffArea, fullText, editGroup)
this._refreshAllDiffsAndStyles(model)
this._refreshSweepStyles(model)
resolve();
},
onError: (e) => {
onError: (e: any) => {
console.error('Error rewriting file with diff', e);
resolve();
},
voidConfig,
abortRef,
abortRef: { current: null },
})
})
finishHistorySnapshot()
onFinishEdit()
}
@ -650,16 +670,19 @@ Please finish writing the new file by applying the diff to the original file. Re
if (!model) return
// update streaming state
const streamingGroup = new UndoRedoGroup()
const streamingState: StreamingState = { type: 'streaming' }
this.streamingStateOfModelId[model.id] = streamingState
// initialize stream
this._initializeStream(model, userMessage, streamingGroup)
this._initializeStream(model, userMessage)
}
interruptStreaming() {
// TODO add abort
}
@ -688,7 +711,7 @@ Please finish writing the new file by applying the diff to the original file. Re
if (currentFile === null) return
// add to history
const { finishHistorySnapshot } = this._addToHistory(uri)
const { onFinishEdit, editGroup: _editGroup } = this._addToHistory(model)
// Fixed: Handle newlines properly by splitting into lines and joining with proper newlines
const originalLines = originalFile.split('\n');
@ -722,7 +745,7 @@ Please finish writing the new file by applying the diff to the original file. Re
this._refreshAllDiffsAndStyles(model)
}
finishHistorySnapshot()
onFinishEdit()
}
@ -748,14 +771,15 @@ Please finish writing the new file by applying the diff to the original file. Re
// add to history
const { finishHistorySnapshot } = this._addToHistory(uri)
const { onFinishEdit, editGroup } = this._addToHistory(model)
// Apply the rejection by replacing with original code (without putting it on the undo/redo stack, this is OK because we put it on the stack ourselves)
if (!model.isDisposed())
model.applyEdits([{
range: { startLineNumber: diffArea.startLine, startColumn: 0, endLineNumber: diffArea.endLine, endColumn: Number.MAX_SAFE_INTEGER, },
text: diff.originalCode
}])
this._writeToModel(
model,
diff.originalCode,
{ startLineNumber: diffArea.startLine, startColumn: 0, endLineNumber: diffArea.endLine, endColumn: Number.MAX_SAFE_INTEGER, },
editGroup
)
// Check if diffArea should be removed
const currentLines = currentFile.split('\n');
@ -771,7 +795,7 @@ Please finish writing the new file by applying the diff to the original file. Re
if (editor?.getModel()?.id === modelid)
this._refreshAllDiffsAndStyles(model)
finishHistorySnapshot()
onFinishEdit()
}

View file

@ -1,43 +1,45 @@
// import { Disposable } from '../../../../base/common/lifecycle.js';
// import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions';
// import { createDecorator } from '../../../../platform/instantiation/common/instantiation';
// import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry';
import { Disposable } from '../../../../base/common/lifecycle.js';
import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions';
import { createDecorator } from '../../../../platform/instantiation/common/instantiation';
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry';
// interface IMetricsService {
// readonly _serviceBrand: undefined;
// }
import { posthog } from './react/out/util/posthog.js'
// const IMetricsService = createDecorator<IMetricsService>('inlineDiffService');
// class MetricsService extends Disposable implements IMetricsService {
// _serviceBrand: undefined;
interface IMetricsService {
readonly _serviceBrand: undefined;
}
// constructor(
// @ITelemetryService private readonly _telemetryService: ITelemetryService
// ) {
// super()
// }
const IMetricsService = createDecorator<IMetricsService>('inlineDiffService');
class MetricsService extends Disposable implements IMetricsService {
_serviceBrand: undefined;
// init() {
constructor(
@ITelemetryService private readonly _telemetryService: ITelemetryService
) {
super()
}
// posthog.init('phc_UanIdujHiLp55BkUTjB1AuBXcasVkdqRwgnwRlWESH2',
// {
// api_host: 'https://us.i.posthog.com',
// person_profiles: 'identified_only' // we only track events from identified users. We identify them in Sidebar
// }
// )
init() {
// const deviceId = this._telemetryService.devDeviceId
// console.debug('deviceId', deviceId)
posthog.init('phc_UanIdujHiLp55BkUTjB1AuBXcasVkdqRwgnwRlWESH2',
{
api_host: 'https://us.i.posthog.com',
person_profiles: 'identified_only' // we only track events from identified users. We identify them in Sidebar
}
)
// posthog.identify(deviceId)
const deviceId = this._telemetryService.devDeviceId
console.debug('deviceId', deviceId)
posthog.identify(deviceId)
// // export const captureEvent = (eventId: string, properties: object) => {
// // posthog.capture(eventId, properties)
// // }
// export const captureEvent = (eventId: string, properties: object) => {
// posthog.capture(eventId, properties)
// }
// }
}
// }
}
// registerSingleton(IMetricsService, MetricsService, InstantiationType.Eager);
registerSingleton(IMetricsService, MetricsService, InstantiationType.Eager);