Skip to content

Commit d689c7d

Browse files
committed
Use job_start to run chat completion in background + markdown formatting in chat window
1 parent 4f165ce commit d689c7d

File tree

2 files changed

+65
-83
lines changed

2 files changed

+65
-83
lines changed

.devcontainer/vimrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ set rtp+=~/.vim/bundle/Vundle.vim
66
call vundle#begin()
77
Plugin 'VundleVim/Vundle.vim'
88
Plugin 'DanBradbury/copilot.vim'
9+
Plugin 'preservim/vim-markdown'
910
call vundle#end() " required
1011
filetype plugin indent on " required

plugin/copilot_chat.vim

Lines changed: 64 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ let s:plugin_dir = expand('<sfile>:p:h:h')
44
let s:device_token_file = s:plugin_dir . "/.device_token"
55
let s:chat_token_file = s:plugin_dir . "/.chat_token"
66

7-
87
function! CopilotChat()
98
" Open a new split window for the chat
109
split
@@ -15,33 +14,24 @@ function! CopilotChat()
1514
setlocal nonumber
1615
setlocal norelativenumber
1716
setlocal wrap
17+
set filetype=markdown
1818

1919
" Set the buffer name to indicate it's a chat window
2020
file CopilotChat
2121

22-
" Add initial message
2322
call append(0, 'Welcome to Copilot Chat! Type your message below:')
2423

25-
" Move cursor to the end of the buffer
2624
normal! G
2725
endfunction
2826

2927
function! SubmitChatMessage()
30-
" Get the last line of the buffer (user's message)
28+
" TODO: this should be grabbing the full prompt between the separators
3129
let l:message = getline('$')
3230

33-
" Call the CoPilot API to get a response
34-
let l:response = CopilotAPIRequest(l:message)
35-
36-
" Append the parsed response to the buffer
37-
call append(line('$'), split(l:response, "\n"))
38-
39-
" Move cursor to the end of the buffer
40-
normal! G
31+
call AsyncRequest(l:message)
4132
endfunction
4233

4334
function! GetBearerToken()
44-
" Replace with actual token setup and device registry logic
4535
let l:token_url = 'https://github.com/login/device/code'
4636

4737
let l:token_headers = [
@@ -137,7 +127,7 @@ function! GetChatToken(bearer_token)
137127

138128
" Execute the curl command
139129
let l:response = system(l:curl_cmd)
140-
echo l:response
130+
"echo l:response
141131

142132
" Check for errors in the response
143133
if v:shell_error != 0
@@ -151,85 +141,76 @@ function! GetChatToken(bearer_token)
151141
endfunction
152142

153143
function! CheckDeviceToken()
144+
" fetch models
145+
" if the call fails we should get a new chat token and update the file
154146
endfunction
155147

156-
function! CopilotAPIRequest(message)
157-
"CheckDeviceToken()
158-
let l:url = 'https://api.githubcopilot.com/chat/completions'
148+
function! AsyncRequest(message)
149+
let s:curl_output = []
150+
let l:url = 'https://api.githubcopilot.com/chat/completions'
159151

160-
if filereadable(s:device_token_file)
161-
echo "READING DEVICE TOKEN"
162-
let l:bearer_token = join(readfile(s:device_token_file), "\n")
163-
echo l:bearer_token
164-
else
165-
let l:bearer_token = GetBearerToken()
166-
endif
167-
168-
let l:chat_token = GetChatToken(l:bearer_token)
169-
let l:headers = [
170-
\ 'Content-Type: application/json',
171-
\ 'Authorization: Bearer ' . l:chat_token,
172-
\ 'Editor-Version: vscode/1.80.1'
173-
\ ]
174-
let l:messages = [{'content': a:message, 'role': 'user'}]
175-
let l:data = json_encode({
176-
\ 'intent': v:false,
177-
\ 'model': 'gpt-4o',
178-
\ 'temperature': 0,
179-
\ 'top_p': 1,
180-
\ 'n': 1,
181-
\ 'stream': v:true,
182-
\ 'messages': l:messages
183-
\ })
184-
185-
" Construct the curl command as a single string
186-
let l:curl_cmd = 'curl -s -X POST '
187-
for header in l:headers
188-
let l:curl_cmd .= '-H "' . header . '" '
189-
endfor
190-
let l:curl_cmd .= "-d '" . l:data . "' " . l:url
191-
192-
" Print the curl command for debugging
193-
echom l:curl_cmd
194-
195-
" Execute the curl command
196-
let l:response = system(l:curl_cmd)
197-
198-
" Print the raw response for debugging
199-
echom 'Response: ' . l:response
152+
if filereadable(s:device_token_file)
153+
let l:bearer_token = join(readfile(s:device_token_file), "\n")
154+
else
155+
let l:bearer_token = GetBearerToken()
156+
endif
157+
158+
let l:chat_token = GetChatToken(l:bearer_token)
159+
let l:messages = [{'content': a:message, 'role': 'user'}]
160+
let l:data = json_encode({
161+
\ 'intent': v:false,
162+
\ 'model': 'gpt-4o',
163+
\ 'temperature': 0,
164+
\ 'top_p': 1,
165+
\ 'n': 1,
166+
\ 'stream': v:true,
167+
\ 'messages': l:messages
168+
\ })
169+
170+
let l:curl_cmd = [
171+
\ "curl",
172+
\ "-s",
173+
\ "-X",
174+
\ "POST",
175+
\ "-H",
176+
\ "Content-Type: application/json",
177+
\ "-H", "Authorization: Bearer " . l:chat_token,
178+
\ "-H", "Editor-Version: vscode/1.80.1",
179+
\ "-d",
180+
\ l:data,
181+
\ l:url]
182+
183+
let job = job_start(l:curl_cmd, {'out_cb': function('HandleCurlOutput'), 'exit_cb': function('HandleCurlClose'), 'err_cb': function('HandleCurlError')})
184+
return job
185+
endfunction
200186

201-
" Check for errors in the response
202-
if v:shell_error != 0
203-
echom 'Error: ' . v:shell_error
204-
return 'Error: ' . l:response
205-
endif
187+
function! HandleCurlError(channel, msg)
188+
echom "handling curl error"
189+
echom a:msg
190+
endfunction
206191

207-
" Parse the response
208-
let l:result = ''
209-
let l:resp_text_lines = split(l:response, "\n")
210-
for line in l:resp_text_lines
211-
if line =~ '^data: {'
212-
let l:json_completion = json_decode(line[6:])
213-
try
214-
let l:result .= l:json_completion.choices[0].delta.content
215-
catch
216-
let l:result .= "\n"
217-
endtry
218-
endif
219-
endfor
192+
function! HandleCurlClose(channel, msg)
193+
let l:result = ''
194+
for line in s:curl_output
195+
if line =~ '^data: {'
196+
let l:json_completion = json_decode(line[6:])
197+
try
198+
let l:result .= l:json_completion.choices[0].delta.content
199+
catch
200+
let l:result .= "\n"
201+
endtry
202+
endif
203+
endfor
204+
call append(line('$'), split(l:result, "\n"))
205+
normal! G
206+
endfunction
220207

221-
" Return the parsed response
222-
return l:result
208+
function! HandleCurlOutput(channel, msg)
209+
call add(s:curl_output, a:msg)
223210
endfunction
224211

225-
" Map the command to open the chat
226212
command! CopilotChat call CopilotChat()
227-
228-
" Map the command to submit a chat message
229213
command! SubmitChatMessage call SubmitChatMessage()
230214

231-
" Add key mapping to submit chat message
232215
nnoremap <buffer> <leader>cs :SubmitChatMessage<CR>
233-
234-
" Add key mapping to open Copilot Chat
235216
nnoremap <leader>cc :CopilotChat<CR>

0 commit comments

Comments
 (0)