Skip to content

Commit f1c5c78

Browse files
committed
Replace custom API calls progress modal with VSCode native progress notification
- each ongonig request should also have a native notification - translate queued - translate [Fragment] - if possible 'receiving...' should transform to a variant with details like speed and totals, e.g. 'reveived 40 tokens at 10 tok/s...' - add translations [Fragment] - 'sent request' translation should be put in 'services - we can't see clearly when app finishes building in watch mode - this piece of logic is now not used and should be deteled const [api_calls_modal_height, set_api_calls_modal_height] = useState(0) - move shared messages to `apps/editor/src/views/chats/types/messages.ts`, removing shared message file - use [Fragment] for all - use `packages/shared/src/utils/display-token-count.ts` in the notification for total received tokens ├── apps │ └── editor │ ├── package.json │ └── src │ ├── commands │ │ └── code-at-cursor-command │ │ ├── code-at-cursor-commands.ts │ │ ├── index.ts │ │ └── utils │ │ ├── get-code-at-cursor-config.ts │ │ ├── perform-code-at-cursor.ts │ │ └── show-ghost-text.ts │ ├── i18n │ │ └── translations │ │ ├── common.ts │ │ └── services │ │ ├── index.ts │ │ ├── prompt-view-api-calls-manager.ts │ │ └── websocket-manager.ts │ ├── services │ │ └── prompt-view-api-calls-manager.ts │ └── views │ ├── chats │ │ └── types │ │ └── messages.ts │ └── prompt │ ├── backend │ │ └── message-handlers │ │ └── handle-make-api-call.ts │ └── frontend │ ├── Home │ │ └── Home.tsx │ ├── Main │ │ ├── Main.tsx │ │ └── MainView │ │ └── MainView.tsx │ └── Prompt.tsx └── packages ├── shared │ └── src │ └── utils │ └── display-token-count.ts └── ui └── src └── components └── editor └── prompt └── modals └── OngoingApiCallsModal └── OngoingApiCallsModal.tsx
1 parent 392b8bc commit f1c5c78

13 files changed

Lines changed: 223 additions & 252 deletions

File tree

‎apps/editor/src/i18n/translations/common.ts‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,24 @@ export const translations = {
701701
hu: 'Ugrás a fájlhoz',
702702
bg: 'Отиди на файла'
703703
},
704+
'common.progress.queued': {
705+
en: 'queued...',
706+
pl: 'w kolejce...',
707+
'zh-cn': '排队中...',
708+
ja: 'キュー待機中...',
709+
'zh-tw': '排隊中...',
710+
de: 'in der Warteschlange...',
711+
es: 'en cola...',
712+
fr: "en file d'attente...",
713+
'pt-br': 'na fila...',
714+
ru: 'в очереди...',
715+
ko: '대기열에서 대기 중...',
716+
it: 'in coda...',
717+
tr: 'sırada...',
718+
cs: 've frontě...',
719+
hu: 'sorba állítva...',
720+
bg: 'на опашката...'
721+
},
704722
'common.progress.waiting-for-server': {
705723
en: 'waiting for server...',
706724
pl: 'oczekiwanie na serwer...',
@@ -755,6 +773,24 @@ export const translations = {
755773
hu: 'fogadás...',
756774
bg: 'получаване...'
757775
},
776+
'common.progress.receiving-stats': {
777+
en: 'received {total_tokens} tokens at {tokens_per_second} tok/s...',
778+
pl: 'odebrano {total_tokens} tokenów ({tokens_per_second} tok/s)...',
779+
'zh-cn': '已接收 {total_tokens} 个 token ({tokens_per_second} tok/s)...',
780+
ja: '{total_tokens} トークンを受信しました ({tokens_per_second} tok/s)...',
781+
'zh-tw': '已接收 {total_tokens} 個 token ({tokens_per_second} tok/s)...',
782+
de: '{total_tokens} Tokens empfangen ({tokens_per_second} tok/s)...',
783+
es: 'recibidos {total_tokens} tokens a {tokens_per_second} tok/s...',
784+
fr: '{total_tokens} tokens reçus à {tokens_per_second} tok/s...',
785+
'pt-br': '{total_tokens} tokens recebidos a {tokens_per_second} tok/s...',
786+
ru: 'получено {total_tokens} токенов ({tokens_per_second} tok/s)...',
787+
ko: '{total_tokens} 토큰 수신됨 ({tokens_per_second} tok/s)...',
788+
it: 'ricevuti {total_tokens} token a {tokens_per_second} tok/s...',
789+
tr: '{total_tokens} token alındı ({tokens_per_second} tok/s)...',
790+
cs: 'přijato {total_tokens} tokenů ({tokens_per_second} tok/s)...',
791+
hu: '{total_tokens} token fogadva ({tokens_per_second} tok/s)...',
792+
bg: 'получени {total_tokens} токена ({tokens_per_second} ток/сек)...'
793+
},
758794
'common.progress.thinking': {
759795
en: 'thinking...',
760796
pl: 'myślenie...',
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { translations as websocket_manager } from './websocket-manager'
2+
import { translations as prompt_view_api_calls_manager } from './prompt-view-api-calls-manager'
23

34
export const translations = {
4-
...websocket_manager
5+
...websocket_manager,
6+
...prompt_view_api_calls_manager
57
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export const translations = {
2+
'service.prompt-view-api-calls-manager.sent-request': {
3+
en: 'Sent request',
4+
pl: 'Wysłano request',
5+
'zh-cn': '已发送请求',
6+
ja: 'リクエストを送信しました',
7+
'zh-tw': '已發送請求',
8+
de: 'Anfrage gesendet',
9+
es: 'Solicitud enviada',
10+
fr: 'Requête envoyée',
11+
'pt-br': 'Solicitação enviada',
12+
ru: 'Запрос отправлен',
13+
ko: '요청 전송됨',
14+
it: 'Richiesta inviata',
15+
tr: 'İstek gönderildi',
16+
cs: 'Požadavek odeslán',
17+
hu: 'Kérés elküldve',
18+
bg: 'Изпратена заявка'
19+
}
20+
} as const

‎apps/editor/src/services/prompt-view-api-calls-manager.ts‎

Lines changed: 134 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import { PromptViewProvider } from '@/views/prompt/backend/prompt-view-provider'
22
import { ChatsViewProvider } from '@/views/chats/backend/chats-view-provider'
33
import { send_llm_message } from '@/utils/send-llm-message'
44
import { randomUUID, createHash } from 'crypto'
5+
import { display_token_count } from '@shared/utils/display-token-count'
56
import { Logger } from '@shared/utils/logger'
7+
import * as vscode from 'vscode'
8+
import { t } from '@/i18n'
69

710
const CHAIN_RESOLUTION_DELAY_MS = 5000
811

@@ -76,122 +79,155 @@ export class PromptViewApiCallsManager {
7679
})
7780
}
7881

79-
try {
80-
const is_queued =
81-
previous_waiting && previous_waiting.body_hash == body_hash
82-
83-
this.broadcast_message({
84-
command: 'SHOW_PROMPT_VIEW_API_CALLS_MANAGER_PROGRESS',
85-
id: request_id,
86-
status: is_queued ? 'Queued...' : 'Waiting for server...',
87-
provider_name: params.provider_name,
88-
model: params.model,
89-
reasoning_effort: params.reasoning_effort
90-
})
91-
92-
if (is_queued) {
93-
if (abort_controller.signal.aborted) {
94-
throw abort_controller.signal.reason
95-
}
96-
97-
const abort_promise = new Promise<void>((_, reject) => {
98-
abort_controller.signal.addEventListener(
99-
'abort',
100-
() => {
101-
reject(abort_controller.signal.reason)
102-
},
103-
{ once: true }
104-
)
82+
return await vscode.window.withProgress(
83+
{
84+
location: vscode.ProgressLocation.Notification,
85+
title: t('service.prompt-view-api-calls-manager.sent-request'),
86+
cancellable: true
87+
},
88+
async (progress, token) => {
89+
token.onCancellationRequested(() => {
90+
this.cancel_api_call(request_id)
10591
})
10692

107-
await Promise.race([previous_waiting.promise, abort_promise])
93+
try {
94+
const is_queued =
95+
previous_waiting && previous_waiting.body_hash == body_hash
10896

109-
this.broadcast_message({
110-
command: 'SHOW_PROMPT_VIEW_API_CALLS_MANAGER_PROGRESS',
111-
id: request_id,
112-
status: 'Waiting for server...',
113-
provider_name: params.provider_name,
114-
model: params.model,
115-
reasoning_effort: params.reasoning_effort
116-
})
117-
}
97+
const queued_msg = t('common.progress.queued')
98+
const waiting_msg = t('common.progress.waiting-for-server')
99+
const thinking_msg = t('common.progress.thinking')
100+
const receiving_msg = t('common.progress.receiving')
101+
102+
progress.report({ message: is_queued ? queued_msg : waiting_msg })
118103

119-
const result = await send_llm_message({
120-
base_url: params.base_url,
121-
api_key: params.api_key,
122-
body: params.body,
123-
abort_signal: abort_controller.signal,
124-
on_thinking_chunk: () => {
125-
schedule_chain_resolution()
126-
this.broadcast_message({
127-
command: 'SHOW_PROMPT_VIEW_API_CALLS_MANAGER_PROGRESS',
128-
id: request_id,
129-
status: 'Thinking...',
130-
provider_name: params.provider_name,
131-
model: params.model,
132-
reasoning_effort: params.reasoning_effort
133-
})
134-
},
135-
on_chunk: (tokens_per_second, total_tokens) => {
136-
schedule_chain_resolution()
137104
this.broadcast_message({
138105
command: 'SHOW_PROMPT_VIEW_API_CALLS_MANAGER_PROGRESS',
139106
id: request_id,
140-
status: 'Receiving...',
141-
tokens_per_second,
142-
total_tokens,
107+
status: is_queued ? queued_msg : waiting_msg,
143108
provider_name: params.provider_name,
144109
model: params.model,
145110
reasoning_effort: params.reasoning_effort
146111
})
147-
}
148-
})
149-
150-
if (result) {
151-
this.chats_view_provider.add_chat({
152-
timestamp: Date.now(),
153-
provider_name: params.provider_name,
154-
model: params.model,
155-
reasoning_effort: params.reasoning_effort,
156-
raw_instructions: params.raw_instructions,
157-
response: result.response,
158-
thoughts: result.thoughts
159-
})
160-
}
161112

162-
return result
163-
} catch (error: any) {
164-
if (abort_controller.signal.aborted) {
165-
throw error
166-
}
113+
if (is_queued) {
114+
if (abort_controller.signal.aborted) {
115+
throw abort_controller.signal.reason
116+
}
117+
118+
const abort_promise = new Promise<void>((_, reject) => {
119+
abort_controller.signal.addEventListener(
120+
'abort',
121+
() => {
122+
reject(abort_controller.signal.reason)
123+
},
124+
{ once: true }
125+
)
126+
})
127+
128+
await Promise.race([previous_waiting.promise, abort_promise])
129+
130+
progress.report({ message: waiting_msg })
131+
132+
this.broadcast_message({
133+
command: 'SHOW_PROMPT_VIEW_API_CALLS_MANAGER_PROGRESS',
134+
id: request_id,
135+
status: waiting_msg,
136+
provider_name: params.provider_name,
137+
model: params.model,
138+
reasoning_effort: params.reasoning_effort
139+
})
140+
}
141+
142+
const result = await send_llm_message({
143+
base_url: params.base_url,
144+
api_key: params.api_key,
145+
body: params.body,
146+
abort_signal: abort_controller.signal,
147+
on_thinking_chunk: () => {
148+
schedule_chain_resolution()
149+
progress.report({ message: thinking_msg })
150+
this.broadcast_message({
151+
command: 'SHOW_PROMPT_VIEW_API_CALLS_MANAGER_PROGRESS',
152+
id: request_id,
153+
status: thinking_msg,
154+
provider_name: params.provider_name,
155+
model: params.model,
156+
reasoning_effort: params.reasoning_effort
157+
})
158+
},
159+
on_chunk: (tokens_per_second, total_tokens) => {
160+
schedule_chain_resolution()
161+
162+
const msg =
163+
tokens_per_second && total_tokens
164+
? t('common.progress.receiving-stats', {
165+
total_tokens: display_token_count(total_tokens),
166+
tokens_per_second: Math.round(tokens_per_second)
167+
})
168+
: receiving_msg
169+
170+
progress.report({ message: msg })
171+
this.broadcast_message({
172+
command: 'SHOW_PROMPT_VIEW_API_CALLS_MANAGER_PROGRESS',
173+
id: request_id,
174+
status: msg,
175+
tokens_per_second,
176+
total_tokens,
177+
provider_name: params.provider_name,
178+
model: params.model,
179+
reasoning_effort: params.reasoning_effort
180+
})
181+
}
182+
})
167183

168-
Logger.error({
169-
function_name: 'send_llm_message',
170-
message: 'API call error',
171-
data: error
172-
})
184+
if (result) {
185+
this.chats_view_provider.add_chat({
186+
timestamp: Date.now(),
187+
provider_name: params.provider_name,
188+
model: params.model,
189+
reasoning_effort: params.reasoning_effort,
190+
raw_instructions: params.raw_instructions,
191+
response: result.response,
192+
thoughts: result.thoughts
193+
})
194+
}
195+
196+
return result
197+
} catch (error: any) {
198+
if (abort_controller.signal.aborted) {
199+
throw error
200+
}
201+
202+
Logger.error({
203+
function_name: 'send_llm_message',
204+
message: 'API call error',
205+
data: error
206+
})
173207

174-
return null
175-
} finally {
176-
if (!is_chain_resolution_scheduled) {
177-
resolve_current()
178-
}
208+
return null
209+
} finally {
210+
if (!is_chain_resolution_scheduled) {
211+
resolve_current()
212+
}
179213

180-
this.broadcast_message({
181-
command: 'HIDE_PROMPT_VIEW_API_CALLS_MANAGER_PROGRESS',
182-
id: request_id
183-
})
184-
this.abort_controllers.delete(request_id)
214+
this.broadcast_message({
215+
command: 'HIDE_PROMPT_VIEW_API_CALLS_MANAGER_PROGRESS',
216+
id: request_id
217+
})
218+
this.abort_controllers.delete(request_id)
185219

186-
const now = Date.now()
187-
const wait_until = Math.max(now, this.next_allowed_finish_time)
188-
const delay = wait_until - now
189-
this.next_allowed_finish_time = wait_until + 500
220+
const now = Date.now()
221+
const wait_until = Math.max(now, this.next_allowed_finish_time)
222+
const delay = wait_until - now
223+
this.next_allowed_finish_time = wait_until + 500
190224

191-
if (delay > 0) {
192-
await new Promise((resolve) => setTimeout(resolve, delay))
225+
if (delay > 0) {
226+
await new Promise((resolve) => setTimeout(resolve, delay))
227+
}
228+
}
193229
}
194-
}
230+
)
195231
}
196232

197233
public cancel_api_call(request_id: string) {

‎apps/editor/src/views/chats/types/messages.ts‎

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
1-
import {
2-
CancelPromptViewApiCallsManagerRequestMessage,
3-
ShowPromptViewApiCallsManagerProgressMessage,
4-
HidePromptViewApiCallsManagerProgressMessage
5-
} from '@/views/shared/types/messages'
1+
type BaseMessage = {
2+
command: string
3+
}
4+
5+
interface CancelPromptViewApiCallsManagerRequestMessage extends BaseMessage {
6+
command: 'CANCEL_PROMPT_VIEW_API_CALLS_MANAGER_REQUEST'
7+
id: string
8+
}
9+
10+
interface ShowPromptViewApiCallsManagerProgressMessage extends BaseMessage {
11+
command: 'SHOW_PROMPT_VIEW_API_CALLS_MANAGER_PROGRESS'
12+
id: string
13+
status: string
14+
tokens_per_second?: number
15+
total_tokens?: number
16+
provider_name: string
17+
model?: string
18+
reasoning_effort?: string
19+
}
20+
21+
interface HidePromptViewApiCallsManagerProgressMessage extends BaseMessage {
22+
command: 'HIDE_PROMPT_VIEW_API_CALLS_MANAGER_PROGRESS'
23+
id: string
24+
}
625

7-
export type GetChatsMessage = {
26+
export interface GetChatsMessage extends BaseMessage {
827
command: 'GET_CHATS'
928
}
1029

11-
export type DeleteChatMessage = {
30+
export interface DeleteChatMessage extends BaseMessage {
1231
command: 'DELETE_CHAT'
1332
timestamp: number
1433
}
1534

16-
export type ChatsMessage = {
35+
export interface ChatsMessage extends BaseMessage {
1736
command: 'CHATS'
1837
chats: { timestamp: number }[]
1938
}

0 commit comments

Comments
 (0)