-
Notifications
You must be signed in to change notification settings - Fork 2
feat(ai): Scope file-editor assistant to the deployment and cover env vars #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -745,7 +745,8 @@ const editorExtensions = [yaml(), oneDark]; | |||||||||||||||||||||||||||||
| const fileModified = computed(() => fileContent.value !== originalContent.value); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const editorAssistContext = computed<AssistContext>(() => ({ | ||||||||||||||||||||||||||||||
| scope: "system", | ||||||||||||||||||||||||||||||
| scope: props.deploymentName ? "deployment" : "system", | ||||||||||||||||||||||||||||||
| deployment: props.deploymentName || undefined, | ||||||||||||||||||||||||||||||
| subject: editingFile.value?.path || editingFile.value?.name || "file", | ||||||||||||||||||||||||||||||
| seedContext: fileContent.value, | ||||||||||||||||||||||||||||||
| })); | ||||||||||||||||||||||||||||||
|
|
@@ -1165,6 +1166,8 @@ const viewFile = async (file: FileInfo) => { | |||||||||||||||||||||||||||||
| loadingFileContent.value = true; | ||||||||||||||||||||||||||||||
| fileContent.value = ""; | ||||||||||||||||||||||||||||||
| originalContent.value = ""; | ||||||||||||||||||||||||||||||
| // Writes from an earlier conversation are already in the file being loaded. | ||||||||||||||||||||||||||||||
| seenAssistWrites.value = assistWritesToOpenFile(); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||
| const response = await fileApi.value.getContent(file.path); | ||||||||||||||||||||||||||||||
|
|
@@ -1186,6 +1189,8 @@ const openFileEditor = async (file: FileInfo) => { | |||||||||||||||||||||||||||||
| loadingFileContent.value = true; | ||||||||||||||||||||||||||||||
| fileContent.value = ""; | ||||||||||||||||||||||||||||||
| originalContent.value = ""; | ||||||||||||||||||||||||||||||
| // Writes from an earlier conversation are already in the file being loaded. | ||||||||||||||||||||||||||||||
| seenAssistWrites.value = assistWritesToOpenFile(); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||
| const response = await fileApi.value.getContent(file.path); | ||||||||||||||||||||||||||||||
|
|
@@ -1232,6 +1237,63 @@ const saveFile = async () => { | |||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // A file write by the assistant leaves the open editor buffer stale, and a | ||||||||||||||||||||||||||||||
| // later manual save would clobber it. Track completed assistant writes to the | ||||||||||||||||||||||||||||||
| // open file and reload the buffer, unless the operator has unsaved edits. | ||||||||||||||||||||||||||||||
| const seenAssistWrites = ref(0); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const assistWritesToOpenFile = (): number => { | ||||||||||||||||||||||||||||||
| const session = assistStore.session; | ||||||||||||||||||||||||||||||
| const open = (editingFile.value?.path || "").replace(/^\/+/, ""); | ||||||||||||||||||||||||||||||
| if (!session || !open) return 0; | ||||||||||||||||||||||||||||||
| let count = 0; | ||||||||||||||||||||||||||||||
| for (const turn of session.messages) { | ||||||||||||||||||||||||||||||
| for (const step of turn.tool_steps || []) { | ||||||||||||||||||||||||||||||
| if (step.name !== "write_deployment_file" || !step.result || step.result.startsWith("Error")) continue; | ||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||
| const target = String(JSON.parse(step.arguments || "{}").path || "").replace(/^\/+/, ""); | ||||||||||||||||||||||||||||||
| if (target && (target === open || open.endsWith("/" + target))) count++; | ||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||
| // Unparseable arguments cannot name the open file. | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| return count; | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const reloadEditorContent = async () => { | ||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current implementation of
Suggested change
|
||||||||||||||||||||||||||||||
| if (!editingFile.value) return; | ||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||
| const response = await fileApi.value.getContent(editingFile.value.path); | ||||||||||||||||||||||||||||||
| fileContent.value = response.data; | ||||||||||||||||||||||||||||||
| originalContent.value = response.data; | ||||||||||||||||||||||||||||||
| notifications.info("File updated", `${editingFile.value.name} was reloaded with the assistant's change`); | ||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||
| // Keep the buffer; reopening the file re-reads it. | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| watch( | ||||||||||||||||||||||||||||||
| () => assistStore.session, | ||||||||||||||||||||||||||||||
| async () => { | ||||||||||||||||||||||||||||||
| if (!showEditorModal.value || !editingFile.value) return; | ||||||||||||||||||||||||||||||
| const count = assistWritesToOpenFile(); | ||||||||||||||||||||||||||||||
| if (count <= seenAssistWrites.value) { | ||||||||||||||||||||||||||||||
| seenAssistWrites.value = count; | ||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| seenAssistWrites.value = count; | ||||||||||||||||||||||||||||||
| if (!viewOnly.value && fileModified.value) { | ||||||||||||||||||||||||||||||
| notifications.warning( | ||||||||||||||||||||||||||||||
| "File changed on disk", | ||||||||||||||||||||||||||||||
| "The assistant updated this file, but you have unsaved edits. Saving now would overwrite its change.", | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| await reloadEditorContent(); | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| watch(currentPath, () => { | ||||||||||||||||||||||||||||||
|
Comment on lines
+1296
to
1297
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When the editor modal is opened,
Suggested change
|
||||||||||||||||||||||||||||||
| fetchFiles(); | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic for parsing tool arguments should account for cases where
step.argumentsmight already be an object (depending on how the store handles the API response). Additionally, scanning the entire session history can be optimized by ensuringJSON.parseisn't called if the result is already known to be irrelevant.