Открыть боковую панель
code
vscode
Коммиты
27ada980
Не подтверждена
Коммит
27ada980
создал
Фев 22, 2025
по автору
Benjamin Pasero
Зафиксировано автором
GitHub
Фев 22, 2025
Просмотр файлов
chat status tweaks (#241561)
владелец
92803a9d
Изменения
6
Развернуть все
Скрыть пробелы
Построчно
Рядом
src/vs/workbench/contrib/chat/browser/actions/chatActions.ts
Просмотр файла @
27ada980
Это отличие свёрнуто
Нажмите, чтобы развернуть
src/vs/workbench/contrib/chat/browser/chat.contribution.ts
Просмотр файла @
27ada980
...
...
@@ -80,7 +80,8 @@ import { ChatPasteProvidersFeature } from './chatPasteProviders.js';
import
{
QuickChatService
}
from
'
./chatQuick.js
'
;
import
{
ChatQuotasService
,
IChatQuotasService
}
from
'
../common/chatQuotasService.js
'
;
import
{
ChatResponseAccessibleView
}
from
'
./chatResponseAccessibleView.js
'
;
import
{
ChatSetupContribution
}
from
'
./chatSetup.js
'
;
import
{
ChatEntitlementsService
,
ChatSetupContribution
}
from
'
./chatSetup.js
'
;
import
{
IChatEntitlementsService
}
from
'
../common/chatEntitlementsService.js
'
;
import
{
ChatVariablesService
}
from
'
./chatVariables.js
'
;
import
{
ChatWidgetService
}
from
'
./chatWidget.js
'
;
import
{
ChatCodeBlockContextProviderService
}
from
'
./codeBlockContextProviderService.js
'
;
...
...
@@ -469,5 +470,6 @@ registerSingleton(IChatEditingService, ChatEditingService, InstantiationType.Del
registerSingleton
(
IChatMarkdownAnchorService
,
ChatMarkdownAnchorService
,
InstantiationType
.
Delayed
);
registerSingleton
(
ILanguageModelIgnoredFilesService
,
LanguageModelIgnoredFilesService
,
InstantiationType
.
Delayed
);
registerSingleton
(
IChatQuotasService
,
ChatQuotasService
,
InstantiationType
.
Delayed
);
registerSingleton
(
IChatEntitlementsService
,
ChatEntitlementsService
,
InstantiationType
.
Delayed
);
registerSingleton
(
IPromptsService
,
PromptsService
,
InstantiationType
.
Delayed
);
src/vs/workbench/contrib/chat/browser/chatSetup.ts
Просмотр файла @
27ada980
...
...
@@ -69,6 +69,7 @@ import { IQuickInputService } from '../../../../platform/quickinput/common/quick
import
{
ILifecycleService
}
from
'
../../../services/lifecycle/common/lifecycle.js
'
;
import
{
equalsIgnoreCase
}
from
'
../../../../base/common/strings.js
'
;
import
{
IWorkbenchAssignmentService
}
from
'
../../../services/assignment/common/assignmentService.js
'
;
import
{
ChatEntitlement
,
IChatEntitlements
,
IChatEntitlementsService
}
from
'
../common/chatEntitlementsService.js
'
;
const
defaultChat
=
{
extensionId
:
product
.
defaultChatAgent
?.
extensionId
??
''
,
...
...
@@ -91,21 +92,40 @@ const defaultChat = {
manageSettingsUrl
:
product
.
defaultChatAgent
?.
manageSettingsUrl
??
''
,
};
enum
ChatEntitlement
{
/** Signed out */
Unknown
=
1
,
/** Signed in but not yet resolved */
Unresolved
,
/** Signed in and entitled to Limited */
Available
,
/** Signed in but not entitled to Limited */
Unavailable
,
/** Signed-up to Limited */
Limited
,
/** Signed-up to Pro */
Pro
//#region Service
export
class
ChatEntitlementsService
extends
Disposable
implements
IChatEntitlementsService
{
declare
_serviceBrand
:
undefined
;
readonly
context
:
ChatSetupContext
|
undefined
;
readonly
requests
:
ChatSetupRequests
|
undefined
;
constructor
(
@
IInstantiationService
instantiationService
:
IInstantiationService
,
@
IProductService
productService
:
IProductService
,
@
IWorkbenchEnvironmentService
environmentService
:
IWorkbenchEnvironmentService
)
{
super
();
if
(
!
productService
.
defaultChatAgent
||
// needs product config
(
isWeb
&&
!
environmentService
.
remoteAuthority
)
// only enabled locally or a remote backend
)
{
return
;
}
this
.
context
=
this
.
_register
(
instantiationService
.
createInstance
(
ChatSetupContext
));
this
.
requests
=
this
.
_register
(
instantiationService
.
createInstance
(
ChatSetupRequests
,
this
.
context
));
}
async
resolve
(
token
:
CancellationToken
):
Promise
<
IChatEntitlements
|
undefined
>
{
return
this
.
requests
?.
forceResolveEntitlement
(
undefined
,
token
);
}
}
//#endregion
//#region Contribution
export
class
ChatSetupContribution
extends
Disposable
implements
IWorkbenchContribution
{
...
...
@@ -115,22 +135,19 @@ export class ChatSetupContribution extends Disposable implements IWorkbenchContr
constructor
(
@
IProductService
private
readonly
productService
:
IProductService
,
@
IInstantiationService
private
readonly
instantiationService
:
IInstantiationService
,
@
IWorkbenchEnvironmentService
private
readonly
environmentService
:
IWorkbenchEnvironmentService
,
@
ICommandService
private
readonly
commandService
:
ICommandService
,
@
ITelemetryService
private
readonly
telemetryService
:
ITelemetryService
,
@
IWorkbenchAssignmentService
private
readonly
experimentService
:
IWorkbenchAssignmentService
,
@
IChatEntitlementsService
chatEntitlementsService
:
ChatEntitlementsService
,
)
{
super
();
if
(
!
this
.
productService
.
defaultChatAgent
||
// needs product config
(
isWeb
&&
!
this
.
environmentService
.
remoteAuthority
)
// only enabled locally or a remote backend
)
{
return
;
const
context
=
chatEntitlementsService
.
context
;
const
requests
=
chatEntitlementsService
.
requests
;
if
(
!
context
||
!
requests
)
{
return
;
// disabled
}
const
context
=
this
.
_register
(
this
.
instantiationService
.
createInstance
(
ChatSetupContext
));
const
requests
=
this
.
_register
(
this
.
instantiationService
.
createInstance
(
ChatSetupRequests
,
context
));
const
controller
=
new
Lazy
(()
=>
this
.
_register
(
this
.
instantiationService
.
createInstance
(
ChatSetupController
,
context
,
requests
)));
this
.
registerChatWelcome
(
controller
,
context
);
...
...
@@ -285,8 +302,8 @@ export class ChatSetupContribution extends Disposable implements IWorkbenchContr
if
(
focus
)
{
windowFocusListener
.
clear
();
const
entitlement
=
await
requests
.
forceResolveEntitlement
(
undefined
);
if
(
entitlement
===
ChatEntitlement
.
Pro
)
{
const
entitlement
s
=
await
requests
.
forceResolveEntitlement
(
undefined
);
if
(
entitlement
s
?.
entitlement
===
ChatEntitlement
.
Pro
)
{
refreshTokens
(
commandService
);
}
}
...
...
@@ -384,21 +401,6 @@ interface IEntitlementsResponse {
readonly
limited_user_reset_date
:
string
;
}
interface
IQuotas
{
readonly
chatTotal
?:
number
;
readonly
completionsTotal
?:
number
;
readonly
chatRemaining
?:
number
;
readonly
completionsRemaining
?:
number
;
readonly
resetDate
?:
string
;
}
interface
IChatEntitlements
{
readonly
entitlement
:
ChatEntitlement
;
readonly
quotas
?:
IQuotas
;
}
class
ChatSetupRequests
extends
Disposable
{
static
providerId
(
configurationService
:
IConfigurationService
):
string
{
...
...
@@ -525,14 +527,14 @@ class ChatSetupRequests extends Disposable {
return
scopes
.
length
===
expectedScopes
.
length
&&
expectedScopes
.
every
(
scope
=>
scopes
.
includes
(
scope
));
}
private
async
resolveEntitlement
(
session
:
AuthenticationSession
,
token
:
CancellationToken
):
Promise
<
ChatEntitlement
|
undefined
>
{
private
async
resolveEntitlement
(
session
:
AuthenticationSession
,
token
:
CancellationToken
):
Promise
<
I
ChatEntitlement
s
|
undefined
>
{
const
entitlements
=
await
this
.
doResolveEntitlement
(
session
,
token
);
if
(
typeof
entitlements
?.
entitlement
===
'
number
'
&&
!
token
.
isCancellationRequested
)
{
this
.
didResolveEntitlements
=
true
;
this
.
update
(
entitlements
);
}
return
entitlements
?.
entitlement
;
return
entitlements
;
}
private
async
doResolveEntitlement
(
session
:
AuthenticationSession
,
token
:
CancellationToken
):
Promise
<
IChatEntitlements
|
undefined
>
{
...
...
@@ -656,16 +658,16 @@ class ChatSetupRequests extends Disposable {
}
}
async
forceResolveEntitlement
(
session
:
AuthenticationSession
|
undefined
):
Promise
<
ChatEntitlement
|
undefined
>
{
async
forceResolveEntitlement
(
session
:
AuthenticationSession
|
undefined
,
token
=
CancellationToken
.
None
):
Promise
<
I
ChatEntitlement
s
|
undefined
>
{
if
(
!
session
)
{
session
=
await
this
.
findMatchingProviderSession
(
CancellationToken
.
None
);
session
=
await
this
.
findMatchingProviderSession
(
token
);
}
if
(
!
session
)
{
return
undefined
;
}
return
this
.
resolveEntitlement
(
session
,
CancellationToken
.
None
);
return
this
.
resolveEntitlement
(
session
,
token
);
}
async
signUpLimited
(
session
:
AuthenticationSession
):
Promise
<
true
/* signed up */
|
false
/* already signed up */
|
{
errorCode
:
number
}
/* error */
>
{
...
...
@@ -907,7 +909,7 @@ class ChatSetupController extends Disposable {
private
async
signIn
(
providerId
:
string
):
Promise
<
{
session
:
AuthenticationSession
|
undefined
;
entitlement
:
ChatEntitlement
|
undefined
}
>
{
let
session
:
AuthenticationSession
|
undefined
;
let
entitlement
:
ChatEntitlement
|
undefined
;
let
entitlement
s
:
I
ChatEntitlement
s
|
undefined
;
try
{
showCopilotView
(
this
.
viewsService
,
this
.
layoutService
);
...
...
@@ -916,7 +918,7 @@ class ChatSetupController extends Disposable {
this
.
authenticationExtensionsService
.
updateAccountPreference
(
defaultChat
.
extensionId
,
providerId
,
session
.
account
);
this
.
authenticationExtensionsService
.
updateAccountPreference
(
defaultChat
.
chatExtensionId
,
providerId
,
session
.
account
);
entitlement
=
await
this
.
requests
.
forceResolveEntitlement
(
session
);
entitlement
s
=
await
this
.
requests
.
forceResolveEntitlement
(
session
);
}
catch
(
e
)
{
this
.
logService
.
error
(
`[chat setup] signIn: error
${
e
}
`
);
}
...
...
@@ -934,7 +936,7 @@ class ChatSetupController extends Disposable {
}
}
return
{
session
,
entitlement
};
return
{
session
,
entitlement
:
entitlements
?.
entitlement
};
}
private
async
install
(
session
:
AuthenticationSession
|
undefined
,
entitlement
:
ChatEntitlement
,
providerId
:
string
,
watch
:
StopWatch
,):
Promise
<
void
>
{
...
...
src/vs/workbench/contrib/chat/browser/chatStatus.ts
Просмотр файла @
27ada980
...
...
@@ -3,7 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
IMarkdownString
,
MarkdownString
}
from
'
../../../../base/common/htmlContent.js
'
;
import
{
IManagedHoverTooltipMarkdownString
}
from
'
../../../../base/browser/ui/hover/hover.js
'
;
import
{
MarkdownString
}
from
'
../../../../base/common/htmlContent.js
'
;
import
{
Disposable
}
from
'
../../../../base/common/lifecycle.js
'
;
import
{
localize
}
from
'
../../../../nls.js
'
;
import
{
IContextKeyService
}
from
'
../../../../platform/contextkey/common/contextkey.js
'
;
...
...
@@ -13,8 +14,9 @@ import { IWorkbenchContribution } from '../../../common/contributions.js';
import
{
IWorkbenchAssignmentService
}
from
'
../../../services/assignment/common/assignmentService.js
'
;
import
{
IStatusbarEntry
,
IStatusbarEntryAccessor
,
IStatusbarService
,
StatusbarAlignment
}
from
'
../../../services/statusbar/browser/statusbar.js
'
;
import
{
ChatContextKeys
}
from
'
../common/chatContextKeys.js
'
;
import
{
IChatEntitlementsService
}
from
'
../common/chatEntitlementsService.js
'
;
import
{
IChatQuotasService
}
from
'
../common/chatQuotasService.js
'
;
import
{
quotaToButtonMessage
,
OPEN_CHAT_QUOTA_EXCEEDED_DIALOG
,
CHAT_SETUP_ACTION_
ID
,
CHAT_SETUP_ACTION_LABEL
,
CHAT_OPEN
_ACTION_ID
}
from
'
./actions/chatActions.js
'
;
import
{
quotaToButtonMessage
,
OPEN_CHAT_QUOTA_EXCEEDED_DIALOG
,
CHAT_SETUP_ACTION_
LABEL
,
TOGGLE_CHAT
_ACTION_ID
}
from
'
./actions/chatActions.js
'
;
export
class
ChatStatusBarEntry
extends
Disposable
implements
IWorkbenchContribution
{
...
...
@@ -27,6 +29,7 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu
constructor
(
@
IStatusbarService
private
readonly
statusbarService
:
IStatusbarService
,
@
IChatQuotasService
private
readonly
chatQuotasService
:
IChatQuotasService
,
@
IChatEntitlementsService
private
readonly
chatEntitlementsService
:
IChatEntitlementsService
,
@
IContextKeyService
private
readonly
contextKeyService
:
IContextKeyService
,
@
IWorkbenchAssignmentService
private
readonly
assignmentService
:
IWorkbenchAssignmentService
,
@
IProductService
private
readonly
productService
:
IProductService
,
...
...
@@ -73,14 +76,14 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu
this
.
statusbarService
.
updateEntryVisibility
(
ChatStatusBarEntry
.
ID
,
!
this
.
contextKeyService
.
getContextKeyValue
<
boolean
>
(
ChatContextKeys
.
Setup
.
hidden
.
key
));
}));
this
.
_register
(
this
.
chatQuotasService
.
onDidChangeQuota
s
(()
=>
this
.
entry
?.
update
(
this
.
getEntryProps
())));
this
.
_register
(
this
.
chatQuotasService
.
onDidChangeQuota
Exceeded
(()
=>
this
.
entry
?.
update
(
this
.
getEntryProps
())));
}
private
getEntryProps
():
IStatusbarEntry
{
let
text
=
'
$(copilot)
'
;
let
ariaLabel
=
localize
(
'
chatStatus
'
,
"
Copilot Status
"
);
let
command
=
CHAT_OPEN
_ACTION_ID
;
let
tooltip
:
string
|
IMarkdownString
=
localize
(
'
openChat
'
,
"
Open Chat ({0})
"
,
this
.
keybindingService
.
lookupKeybinding
(
command
)?.
getLabel
()
??
''
);
let
command
=
TOGGLE_CHAT
_ACTION_ID
;
let
tooltip
:
string
|
IMa
nagedHoverTooltipMa
rkdownString
=
localize
(
'
openChat
'
,
"
Open Chat ({0})
"
,
this
.
keybindingService
.
lookupKeybinding
(
command
)?.
getLabel
()
??
''
);
// Quota Exceeded
const
{
chatQuotaExceeded
,
completionsQuotaExceeded
}
=
this
.
chatQuotasService
.
quotas
;
...
...
@@ -105,7 +108,6 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu
this
.
contextKeyService
.
getContextKeyValue
<
boolean
>
(
ChatContextKeys
.
Setup
.
installed
.
key
)
===
false
||
this
.
contextKeyService
.
getContextKeyValue
<
boolean
>
(
ChatContextKeys
.
Setup
.
canSignUp
.
key
)
===
true
)
{
command
=
CHAT_SETUP_ACTION_ID
;
tooltip
=
CHAT_SETUP_ACTION_LABEL
.
value
;
}
...
...
@@ -118,15 +120,29 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu
// Copilot Limited User
else
if
(
this
.
contextKeyService
.
getContextKeyValue
<
boolean
>
(
ChatContextKeys
.
Setup
.
limited
.
key
)
===
true
)
{
const
{
chatTotal
,
chatRemaining
,
completionsTotal
,
completionsRemaining
}
=
this
.
chatQuotasService
.
quotas
;
if
(
typeof
chatRemaining
===
'
number
'
&&
typeof
chatTotal
===
'
number
'
&&
typeof
completionsRemaining
===
'
number
'
&&
typeof
completionsTotal
===
'
number
'
)
{
tooltip
=
new
MarkdownString
([
localize
(
'
limitTitle
'
,
"
You are currently using Copilot Free
"
),
'
---
'
,
localize
(
'
limitChatQuota
'
,
"
<code>{0}</code> of <code>{1}</code> chats remaining
"
,
chatRemaining
,
chatTotal
),
localize
(
'
limitCompletionsQuota
'
,
"
<code>{0}</code> of <code>{1}</code> code completions remaining
"
,
completionsRemaining
,
completionsTotal
),
].
join
(
'
\n\n
'
),
{
supportHtml
:
true
});
}
const
that
=
this
;
tooltip
=
{
async
markdown
(
token
)
{
const
entitlements
=
await
that
.
chatEntitlementsService
.
resolve
(
token
);
if
(
token
.
isCancellationRequested
||
!
entitlements
?.
quotas
)
{
return
;
}
const
{
chatTotal
,
chatRemaining
,
completionsTotal
,
completionsRemaining
}
=
entitlements
.
quotas
;
if
(
typeof
chatRemaining
===
'
number
'
&&
typeof
chatTotal
===
'
number
'
&&
typeof
completionsRemaining
===
'
number
'
&&
typeof
completionsTotal
===
'
number
'
)
{
return
new
MarkdownString
([
localize
(
'
limitTitle
'
,
"
You are currently using Copilot Free
"
),
'
---
'
,
localize
(
'
limitChatQuota
'
,
"
<code>{0}</code> of <code>{1}</code> chats remaining
"
,
chatRemaining
,
chatTotal
),
localize
(
'
limitCompletionsQuota
'
,
"
<code>{0}</code> of <code>{1}</code> code completions remaining
"
,
completionsRemaining
,
completionsTotal
),
].
join
(
'
\n\n
'
),
{
supportHtml
:
true
});
}
return
undefined
;
},
markdownNotSupportedFallback
:
undefined
};
}
return
{
...
...
src/vs/workbench/contrib/chat/common/chatEntitlementsService.ts
0 → 100644
Просмотр файла @
27ada980
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
CancellationToken
}
from
'
../../../../base/common/cancellation.js
'
;
import
{
createDecorator
}
from
'
../../../../platform/instantiation/common/instantiation.js
'
;
export
const
IChatEntitlementsService
=
createDecorator
<
IChatEntitlementsService
>
(
'
chatEntitlementsService
'
);
export
enum
ChatEntitlement
{
/** Signed out */
Unknown
=
1
,
/** Signed in but not yet resolved */
Unresolved
,
/** Signed in and entitled to Limited */
Available
,
/** Signed in but not entitled to Limited */
Unavailable
,
/** Signed-up to Limited */
Limited
,
/** Signed-up to Pro */
Pro
}
export
interface
IChatEntitlements
{
readonly
entitlement
:
ChatEntitlement
;
readonly
quotas
?:
IQuotas
;
}
export
interface
IQuotas
{
readonly
chatTotal
?:
number
;
readonly
completionsTotal
?:
number
;
readonly
chatRemaining
?:
number
;
readonly
completionsRemaining
?:
number
;
readonly
resetDate
?:
string
;
}
export
interface
IChatEntitlementsService
{
_serviceBrand
:
undefined
;
resolve
(
token
:
CancellationToken
):
Promise
<
IChatEntitlements
|
undefined
>
;
}
src/vs/workbench/contrib/chat/common/chatQuotasService.ts
Просмотр файла @
27ada980
...
...
@@ -15,7 +15,9 @@ export interface IChatQuotasService {
_serviceBrand
:
undefined
;
readonly
onDidChangeQuotas
:
Event
<
void
>
;
readonly
onDidChangeQuotaExceeded
:
Event
<
void
>
;
readonly
onDidChangeQuotaRemaining
:
Event
<
void
>
;
readonly
quotas
:
IChatQuotas
;
acceptQuotas
(
quotas
:
IChatQuotas
):
void
;
...
...
@@ -38,8 +40,11 @@ export class ChatQuotasService extends Disposable implements IChatQuotasService
declare
_serviceBrand
:
undefined
;
private
readonly
_onDidChangeQuotas
=
this
.
_register
(
new
Emitter
<
void
>
());
readonly
onDidChangeQuotas
:
Event
<
void
>
=
this
.
_onDidChangeQuotas
.
event
;
private
readonly
_onDidChangeQuotaExceeded
=
this
.
_register
(
new
Emitter
<
void
>
());
readonly
onDidChangeQuotaExceeded
=
this
.
_onDidChangeQuotaExceeded
.
event
;
private
readonly
_onDidChangeQuotaRemaining
=
this
.
_register
(
new
Emitter
<
void
>
());
readonly
onDidChangeQuotaRemaining
=
this
.
_onDidChangeQuotaRemaining
.
event
;
private
_quotas
:
IChatQuotas
=
{
chatQuotaExceeded
:
false
,
completionsQuotaExceeded
:
false
,
quotaResetDate
:
undefined
};
get
quotas
():
IChatQuotas
{
return
this
.
_quotas
;
}
...
...
@@ -84,16 +89,29 @@ export class ChatQuotasService extends Disposable implements IChatQuotasService
if
(
changed
)
{
this
.
updateContextKeys
();
this
.
_onDidChangeQuota
s
.
fire
();
this
.
_onDidChangeQuota
Exceeded
.
fire
();
}
}));
}
acceptQuotas
(
quotas
:
IChatQuotas
):
void
{
const
oldQuota
=
this
.
_quotas
;
this
.
_quotas
=
this
.
massageQuotas
(
quotas
);
this
.
updateContextKeys
();
this
.
_onDidChangeQuotas
.
fire
();
if
(
oldQuota
.
chatQuotaExceeded
!==
this
.
_quotas
.
chatQuotaExceeded
||
oldQuota
.
completionsQuotaExceeded
!==
this
.
_quotas
.
completionsQuotaExceeded
)
{
this
.
_onDidChangeQuotaExceeded
.
fire
();
}
if
(
oldQuota
.
chatRemaining
!==
this
.
_quotas
.
chatRemaining
||
oldQuota
.
completionsRemaining
!==
this
.
_quotas
.
completionsRemaining
)
{
this
.
_onDidChangeQuotaRemaining
.
fire
();
}
}
private
massageQuotas
(
quotas
:
IChatQuotas
):
IChatQuotas
{
...
...
Редактирование
Предварительный просмотр
Поддерживает Markdown
0%
Попробовать снова
или
прикрепить новый файл
.
Отмена
You are about to add
0
people
to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Отмена
Пожалуйста,
зарегистрируйтесь
или
войдите
чтобы прокомментировать