@theia/ai-copilot 1.76.0-next.4 → 1.76.0-next.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +87 -14
  2. package/lib/browser/copilot-auth-dialog.d.ts.map +1 -1
  3. package/lib/browser/copilot-auth-dialog.js +19 -11
  4. package/lib/browser/copilot-auth-dialog.js.map +1 -1
  5. package/lib/browser/copilot-frontend-application-contribution.d.ts +21 -1
  6. package/lib/browser/copilot-frontend-application-contribution.d.ts.map +1 -1
  7. package/lib/browser/copilot-frontend-application-contribution.js +129 -26
  8. package/lib/browser/copilot-frontend-application-contribution.js.map +1 -1
  9. package/lib/common/copilot-auth-service.d.ts +27 -24
  10. package/lib/common/copilot-auth-service.d.ts.map +1 -1
  11. package/lib/common/copilot-language-models-manager.d.ts +6 -22
  12. package/lib/common/copilot-language-models-manager.d.ts.map +1 -1
  13. package/lib/common/copilot-language-models-manager.js +1 -13
  14. package/lib/common/copilot-language-models-manager.js.map +1 -1
  15. package/lib/common/copilot-preferences.d.ts +1 -0
  16. package/lib/common/copilot-preferences.d.ts.map +1 -1
  17. package/lib/common/copilot-preferences.js +24 -6
  18. package/lib/common/copilot-preferences.js.map +1 -1
  19. package/lib/common/index.d.ts +0 -1
  20. package/lib/common/index.d.ts.map +1 -1
  21. package/lib/common/index.js +0 -1
  22. package/lib/common/index.js.map +1 -1
  23. package/lib/node/copilot-auth-service-impl.d.ts +25 -16
  24. package/lib/node/copilot-auth-service-impl.d.ts.map +1 -1
  25. package/lib/node/copilot-auth-service-impl.js +67 -183
  26. package/lib/node/copilot-auth-service-impl.js.map +1 -1
  27. package/lib/node/copilot-auth-service-impl.spec.js +104 -168
  28. package/lib/node/copilot-auth-service-impl.spec.js.map +1 -1
  29. package/lib/node/copilot-backend-module.d.ts.map +1 -1
  30. package/lib/node/copilot-backend-module.js +10 -2
  31. package/lib/node/copilot-backend-module.js.map +1 -1
  32. package/lib/node/copilot-cli-auth-provider.d.ts +146 -0
  33. package/lib/node/copilot-cli-auth-provider.d.ts.map +1 -0
  34. package/lib/node/copilot-cli-auth-provider.js +430 -0
  35. package/lib/node/copilot-cli-auth-provider.js.map +1 -0
  36. package/lib/node/copilot-cli-auth-provider.spec.d.ts +2 -0
  37. package/lib/node/copilot-cli-auth-provider.spec.d.ts.map +1 -0
  38. package/lib/node/copilot-cli-auth-provider.spec.js +249 -0
  39. package/lib/node/copilot-cli-auth-provider.spec.js.map +1 -0
  40. package/lib/node/copilot-cli-locator.d.ts +120 -0
  41. package/lib/node/copilot-cli-locator.d.ts.map +1 -0
  42. package/lib/node/copilot-cli-locator.js +348 -0
  43. package/lib/node/copilot-cli-locator.js.map +1 -0
  44. package/lib/node/copilot-cli-locator.spec.d.ts +2 -0
  45. package/lib/node/copilot-cli-locator.spec.d.ts.map +1 -0
  46. package/lib/node/copilot-cli-locator.spec.js +327 -0
  47. package/lib/node/copilot-cli-locator.spec.js.map +1 -0
  48. package/lib/node/copilot-credential-store.d.ts +45 -0
  49. package/lib/node/copilot-credential-store.d.ts.map +1 -0
  50. package/lib/node/copilot-credential-store.js +96 -0
  51. package/lib/node/copilot-credential-store.js.map +1 -0
  52. package/lib/node/copilot-credential-store.spec.d.ts +2 -0
  53. package/lib/node/copilot-credential-store.spec.d.ts.map +1 -0
  54. package/lib/node/copilot-credential-store.spec.js +93 -0
  55. package/lib/node/copilot-credential-store.spec.js.map +1 -0
  56. package/lib/node/copilot-language-models-manager-impl.d.ts +44 -20
  57. package/lib/node/copilot-language-models-manager-impl.d.ts.map +1 -1
  58. package/lib/node/copilot-language-models-manager-impl.js +112 -65
  59. package/lib/node/copilot-language-models-manager-impl.js.map +1 -1
  60. package/lib/node/copilot-language-models-manager-impl.spec.d.ts +2 -0
  61. package/lib/node/copilot-language-models-manager-impl.spec.d.ts.map +1 -0
  62. package/lib/node/copilot-language-models-manager-impl.spec.js +162 -0
  63. package/lib/node/copilot-language-models-manager-impl.spec.js.map +1 -0
  64. package/lib/node/copilot-runtime-env.d.ts +20 -0
  65. package/lib/node/copilot-runtime-env.d.ts.map +1 -0
  66. package/lib/node/copilot-runtime-env.js +49 -0
  67. package/lib/node/copilot-runtime-env.js.map +1 -0
  68. package/lib/node/copilot-sdk-client-provider.d.ts +103 -0
  69. package/lib/node/copilot-sdk-client-provider.d.ts.map +1 -0
  70. package/lib/node/copilot-sdk-client-provider.js +247 -0
  71. package/lib/node/copilot-sdk-client-provider.js.map +1 -0
  72. package/lib/node/copilot-sdk-client-provider.spec.d.ts +2 -0
  73. package/lib/node/copilot-sdk-client-provider.spec.d.ts.map +1 -0
  74. package/lib/node/copilot-sdk-client-provider.spec.js +215 -0
  75. package/lib/node/copilot-sdk-client-provider.spec.js.map +1 -0
  76. package/lib/node/copilot-sdk-language-model.d.ts +85 -0
  77. package/lib/node/copilot-sdk-language-model.d.ts.map +1 -0
  78. package/lib/node/copilot-sdk-language-model.js +301 -0
  79. package/lib/node/copilot-sdk-language-model.js.map +1 -0
  80. package/lib/node/copilot-sdk-language-model.spec.d.ts +2 -0
  81. package/lib/node/copilot-sdk-language-model.spec.d.ts.map +1 -0
  82. package/lib/node/copilot-sdk-language-model.spec.js +315 -0
  83. package/lib/node/copilot-sdk-language-model.spec.js.map +1 -0
  84. package/lib/node/copilot-sdk-loader.d.ts +57 -0
  85. package/lib/node/copilot-sdk-loader.d.ts.map +1 -0
  86. package/lib/node/copilot-sdk-loader.js +133 -0
  87. package/lib/node/copilot-sdk-loader.js.map +1 -0
  88. package/lib/node/copilot-sdk-loader.spec.d.ts +2 -0
  89. package/lib/node/copilot-sdk-loader.spec.d.ts.map +1 -0
  90. package/lib/node/copilot-sdk-loader.spec.js +113 -0
  91. package/lib/node/copilot-sdk-loader.spec.js.map +1 -0
  92. package/lib/node/copilot-sdk-mappers.d.ts +54 -0
  93. package/lib/node/copilot-sdk-mappers.d.ts.map +1 -0
  94. package/lib/node/copilot-sdk-mappers.js +158 -0
  95. package/lib/node/copilot-sdk-mappers.js.map +1 -0
  96. package/lib/node/copilot-sdk-mappers.spec.d.ts +2 -0
  97. package/lib/node/copilot-sdk-mappers.spec.d.ts.map +1 -0
  98. package/lib/node/copilot-sdk-mappers.spec.js +168 -0
  99. package/lib/node/copilot-sdk-mappers.spec.js.map +1 -0
  100. package/lib/node/copilot-sdk-types.d.ts +208 -0
  101. package/lib/node/copilot-sdk-types.d.ts.map +1 -0
  102. package/lib/{common/copilot-oauth-config.js → node/copilot-sdk-types.js} +2 -13
  103. package/lib/node/copilot-sdk-types.js.map +1 -0
  104. package/lib/node/index.d.ts +9 -1
  105. package/lib/node/index.d.ts.map +1 -1
  106. package/lib/node/index.js +9 -1
  107. package/lib/node/index.js.map +1 -1
  108. package/package.json +4 -6
  109. package/src/browser/copilot-auth-dialog.tsx +20 -16
  110. package/src/browser/copilot-frontend-application-contribution.ts +144 -31
  111. package/src/common/copilot-auth-service.ts +28 -24
  112. package/src/common/copilot-language-models-manager.ts +6 -29
  113. package/src/common/copilot-preferences.ts +24 -5
  114. package/src/common/index.ts +0 -1
  115. package/src/node/copilot-auth-service-impl.spec.ts +122 -207
  116. package/src/node/copilot-auth-service-impl.ts +63 -218
  117. package/src/node/copilot-backend-module.ts +11 -2
  118. package/src/node/copilot-cli-auth-provider.spec.ts +315 -0
  119. package/src/node/copilot-cli-auth-provider.ts +444 -0
  120. package/src/node/copilot-cli-locator.spec.ts +386 -0
  121. package/src/node/copilot-cli-locator.ts +363 -0
  122. package/src/node/copilot-credential-store.spec.ts +106 -0
  123. package/src/node/copilot-credential-store.ts +99 -0
  124. package/src/node/copilot-language-models-manager-impl.spec.ts +188 -0
  125. package/src/node/copilot-language-models-manager-impl.ts +131 -84
  126. package/src/node/copilot-runtime-env.ts +46 -0
  127. package/src/node/copilot-sdk-client-provider.spec.ts +253 -0
  128. package/src/node/copilot-sdk-client-provider.ts +241 -0
  129. package/src/node/copilot-sdk-language-model.spec.ts +377 -0
  130. package/src/node/copilot-sdk-language-model.ts +330 -0
  131. package/src/node/copilot-sdk-loader.spec.ts +126 -0
  132. package/src/node/copilot-sdk-loader.ts +142 -0
  133. package/src/node/copilot-sdk-mappers.spec.ts +190 -0
  134. package/src/node/copilot-sdk-mappers.ts +172 -0
  135. package/src/node/copilot-sdk-types.ts +290 -0
  136. package/src/node/index.ts +9 -1
  137. package/lib/common/copilot-oauth-config.d.ts +0 -33
  138. package/lib/common/copilot-oauth-config.d.ts.map +0 -1
  139. package/lib/common/copilot-oauth-config.js.map +0 -1
  140. package/lib/node/copilot-language-model.d.ts +0 -34
  141. package/lib/node/copilot-language-model.d.ts.map +0 -1
  142. package/lib/node/copilot-language-model.js +0 -236
  143. package/lib/node/copilot-language-model.js.map +0 -1
  144. package/lib/node/copilot-language-model.spec.d.ts +0 -2
  145. package/lib/node/copilot-language-model.spec.d.ts.map +0 -1
  146. package/lib/node/copilot-language-model.spec.js +0 -89
  147. package/lib/node/copilot-language-model.spec.js.map +0 -1
  148. package/src/common/copilot-oauth-config.ts +0 -55
  149. package/src/node/copilot-language-model.spec.ts +0 -106
  150. package/src/node/copilot-language-model.ts +0 -273
@@ -0,0 +1,208 @@
1
+ /**
2
+ * The part of the Copilot SDK API this integration uses, mirrored by hand.
3
+ *
4
+ * Mirrored from `@github/copilot-sdk` 1.0.9 (protocol version 3), which the Copilot CLI 1.0.79 ships.
5
+ * The package is deliberately not a dependency: it depends on the CLI, a large proprietary binary that
6
+ * would end up in the tree and the lockfile of every application. The CLI is a prerequisite on the
7
+ * backend host instead, see `CopilotCliLocator`, and the SDK is loaded from it at runtime, see
8
+ * `CopilotSdkLoader`.
9
+ *
10
+ * Only what this integration passes to the SDK or reads from it is declared, so a drift shows up as a
11
+ * compile error here rather than at runtime. `scripts/copilot-sdk-mirror` checks the mirror against a
12
+ * released SDK and runs in CI on a schedule; update the version above along with the declarations.
13
+ */
14
+ export interface ModelPolicy {
15
+ state: 'enabled' | 'disabled' | 'unconfigured';
16
+ }
17
+ /** A model as reported by {@link CopilotClient.listModels}. */
18
+ export interface ModelInfo {
19
+ /** Model identifier, for example `claude-sonnet-4.5`. */
20
+ id: string;
21
+ policy?: ModelPolicy;
22
+ }
23
+ /** The sections the runtime assembles its system prompt from. Unknown ids are a silent no-op there. */
24
+ export type SystemMessageSection = 'preamble' | 'identity' | 'tone' | 'tool_efficiency' | 'environment_context' | 'code_change_rules' | 'guidelines' | 'safety' | 'tool_instructions' | 'custom_instructions' | 'runtime_instructions' | 'last_instructions';
25
+ export type SectionTransformFn = (currentContent: string) => string | Promise<string>;
26
+ export type SectionOverrideAction = 'replace' | 'remove' | 'append' | 'prepend' | 'preserve' | SectionTransformFn;
27
+ export interface SectionOverride {
28
+ action: SectionOverrideAction;
29
+ content?: string;
30
+ }
31
+ /** The SDK foundation plus the given content. */
32
+ export interface SystemMessageAppendConfig {
33
+ mode?: 'append';
34
+ content?: string;
35
+ }
36
+ /** The given content as the entire system message. */
37
+ export interface SystemMessageReplaceConfig {
38
+ mode: 'replace';
39
+ content: string;
40
+ }
41
+ /** The SDK structure with section-level overrides, which is what this integration uses. */
42
+ export interface SystemMessageCustomizeConfig {
43
+ mode: 'customize';
44
+ sections?: Partial<Record<SystemMessageSection, SectionOverride>>;
45
+ content?: string;
46
+ }
47
+ export type SystemMessageConfig = SystemMessageAppendConfig | SystemMessageReplaceConfig | SystemMessageCustomizeConfig;
48
+ /** What the runtime tells a tool handler about its invocation. */
49
+ export interface ToolInvocation {
50
+ sessionId: string;
51
+ toolCallId: string;
52
+ toolName: string;
53
+ arguments: unknown;
54
+ }
55
+ export type ToolHandler = (args: unknown, invocation: ToolInvocation) => Promise<unknown> | unknown;
56
+ /** A tool declared to the runtime. `parameters` also accepts a Zod schema upstream. */
57
+ export interface Tool {
58
+ name: string;
59
+ description?: string;
60
+ parameters?: Record<string, unknown>;
61
+ handler?: ToolHandler;
62
+ /** When true, the tool runs without a permission prompt of the runtime. */
63
+ skipPermission?: boolean;
64
+ }
65
+ /**
66
+ * A permission request of the runtime, upstream a union over the kind of operation with its own fields.
67
+ * Only `managedApprovalRequired` is read, which managed policy sets for a request it reserves for the
68
+ * user.
69
+ */
70
+ export interface PermissionRequest {
71
+ readonly kind: string;
72
+ readonly managedApprovalRequired?: boolean;
73
+ }
74
+ /** The decisions this integration can return. Upstream also has scopes that outlive a request. */
75
+ export type PermissionRequestResult = {
76
+ kind: 'approve-once';
77
+ } | {
78
+ kind: 'reject';
79
+ feedback?: string;
80
+ }
81
+ /** No user is available to confirm the request. */
82
+ | {
83
+ kind: 'user-not-available';
84
+ }
85
+ /** Leaves the request pending, so that another connected client can answer it. */
86
+ | {
87
+ kind: 'no-result';
88
+ };
89
+ export type PermissionHandler = (request: PermissionRequest, invocation: {
90
+ sessionId: string;
91
+ managedSettingsEnabled?: boolean;
92
+ }) => Promise<PermissionRequestResult> | PermissionRequestResult;
93
+ /** The envelope every session event comes in. */
94
+ export interface SessionEvent<T extends string, D> {
95
+ readonly type: T;
96
+ readonly data: D;
97
+ }
98
+ /** The session events this integration listens to, keyed by their type discriminator. */
99
+ export interface CopilotSessionEvents {
100
+ 'assistant.message_delta': SessionEvent<'assistant.message_delta', {
101
+ readonly deltaContent: string;
102
+ }>;
103
+ 'assistant.reasoning_delta': SessionEvent<'assistant.reasoning_delta', {
104
+ readonly deltaContent: string;
105
+ }>;
106
+ 'assistant.message': SessionEvent<'assistant.message', {
107
+ readonly content: string;
108
+ readonly outputTokens?: number;
109
+ }>;
110
+ 'assistant.usage': SessionEvent<'assistant.usage', {
111
+ readonly inputTokens?: number;
112
+ readonly outputTokens?: number;
113
+ }>;
114
+ /** Nothing of its payload is read, the event itself is the signal that the turn is over. */
115
+ 'session.idle': SessionEvent<'session.idle', unknown>;
116
+ 'session.error': SessionEvent<'session.error', {
117
+ readonly errorType: string;
118
+ readonly message: string;
119
+ readonly statusCode?: number;
120
+ readonly stack?: string;
121
+ }>;
122
+ }
123
+ export type CopilotSessionEventType = keyof CopilotSessionEvents;
124
+ /** The one attachment kind this integration produces: an inline image, from `MessageOptions['attachments']`. */
125
+ export interface BlobMessageAttachment {
126
+ type: 'blob';
127
+ data: string;
128
+ mimeType: string;
129
+ displayName?: string;
130
+ }
131
+ /** The options this integration passes to {@link CopilotSession.send}. */
132
+ export interface MessageOptions {
133
+ prompt: string;
134
+ attachments?: BlobMessageAttachment[];
135
+ }
136
+ /** A conversation with the runtime, upstream a class with resume, fork and sharing on top. */
137
+ export interface CopilotSession {
138
+ readonly sessionId: string;
139
+ /**
140
+ * Registers a handler for one type of event and returns the function that removes it again.
141
+ */
142
+ on<K extends CopilotSessionEventType>(eventType: K, handler: (event: CopilotSessionEvents[K]) => void): () => void;
143
+ /** Sends a turn and resolves with the id of the message it created. */
144
+ send(options: MessageOptions): Promise<string>;
145
+ /** Stops the turn in flight. */
146
+ abort(): Promise<void>;
147
+ /** Releases the session in memory, leaving what it persisted in place. */
148
+ disconnect(): Promise<void>;
149
+ }
150
+ /** How the SDK reaches the runtime. This integration always spawns the CLI it located. */
151
+ export interface StdioRuntimeConnection {
152
+ readonly kind: 'stdio';
153
+ readonly path?: string;
154
+ readonly args?: readonly string[];
155
+ readonly env?: Record<string, string>;
156
+ }
157
+ export type RuntimeConnection = StdioRuntimeConnection;
158
+ /** The `RuntimeConnection` value of the SDK, of which only the stdio factory is used. */
159
+ export interface RuntimeConnectionFactory {
160
+ readonly forStdio: (options?: {
161
+ path?: string;
162
+ args?: readonly string[];
163
+ env?: Record<string, string>;
164
+ }) => StdioRuntimeConnection;
165
+ }
166
+ /**
167
+ * Selects the defaults of the runtime: `copilot-cli` brings the ambient behaviour of the CLI along,
168
+ * `empty` requires the application to opt into what it needs.
169
+ */
170
+ export type CopilotClientMode = 'empty' | 'copilot-cli';
171
+ /** The client options this integration sets. */
172
+ export interface CopilotClientOptions {
173
+ connection?: RuntimeConnection;
174
+ mode?: CopilotClientMode;
175
+ /** Copilot home of the runtime, which becomes its `COPILOT_HOME`. Required in `empty` mode. */
176
+ baseDirectory?: string;
177
+ logLevel?: 'none' | 'error' | 'warning' | 'info' | 'debug' | 'all';
178
+ env?: Record<string, string | undefined>;
179
+ gitHubToken?: string;
180
+ /** When false, only an explicit token is used and no sign-in found on the host. */
181
+ useLoggedInUser?: boolean;
182
+ }
183
+ /** The session configuration this integration passes. */
184
+ export interface SessionConfig {
185
+ model?: string;
186
+ streaming?: boolean;
187
+ tools?: Tool[];
188
+ systemMessage?: SystemMessageConfig;
189
+ /**
190
+ * The tools to enable, as source-qualified patterns such as `custom:*` or `builtin:<name>`.
191
+ * Required in `empty` mode.
192
+ */
193
+ availableTools?: string[];
194
+ onPermissionRequest?: PermissionHandler;
195
+ }
196
+ /** The runtime as seen by this integration, upstream a class with the full session and status API. */
197
+ export interface CopilotClient {
198
+ /** Starts the runtime and connects to it. */
199
+ start(): Promise<void>;
200
+ /** Stops the runtime and resolves with the errors its cleanup ran into, if any. */
201
+ stop(): Promise<Error[]>;
202
+ listModels(): Promise<ModelInfo[]>;
203
+ createSession(config: SessionConfig): Promise<CopilotSession>;
204
+ /** Removes a session and what it persisted in the Copilot home. */
205
+ deleteSession(sessionId: string): Promise<void>;
206
+ }
207
+ export type CopilotClientConstructor = new (options?: CopilotClientOptions) => CopilotClient;
208
+ //# sourceMappingURL=copilot-sdk-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot-sdk-types.d.ts","sourceRoot":"","sources":["../../src/node/copilot-sdk-types.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  // *****************************************************************************
3
- // Copyright (C) 2026 Lonti.com Pty Ltd.
3
+ // Copyright (C) 2026 EclipseSource GmbH and others.
4
4
  //
5
5
  // This program and the accompanying materials are made available under the
6
6
  // terms of the Eclipse Public License v. 2.0 which is available at
@@ -15,15 +15,4 @@
15
15
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
16
  // *****************************************************************************
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.DEFAULT_COPILOT_OAUTH_CONFIG = exports.CopilotOAuthConfig = void 0;
19
- exports.CopilotOAuthConfig = Symbol('CopilotOAuthConfig');
20
- /**
21
- * Default OAuth configuration for the built-in Theia Copilot integration.
22
- */
23
- exports.DEFAULT_COPILOT_OAUTH_CONFIG = {
24
- clientId: 'Ov23liS2vINy9VOAweyv',
25
- userAgent: 'Theia-Copilot/1.0.0',
26
- keystoreService: 'theia-copilot-auth',
27
- keystoreAccount: 'github-copilot'
28
- };
29
- //# sourceMappingURL=copilot-oauth-config.js.map
18
+ //# sourceMappingURL=copilot-sdk-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot-sdk-types.js","sourceRoot":"","sources":["../../src/node/copilot-sdk-types.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,oDAAoD;AACpD,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF"}
@@ -1,4 +1,12 @@
1
1
  export * from './copilot-auth-service-impl';
2
- export * from './copilot-language-model';
3
2
  export * from './copilot-language-models-manager-impl';
3
+ export * from './copilot-cli-auth-provider';
4
+ export * from './copilot-cli-locator';
5
+ export * from './copilot-credential-store';
6
+ export * from './copilot-runtime-env';
7
+ export * from './copilot-sdk-client-provider';
8
+ export * from './copilot-sdk-loader';
9
+ export * from './copilot-sdk-mappers';
10
+ export * from './copilot-sdk-language-model';
11
+ export * from './copilot-sdk-types';
4
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAgBA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,wCAAwC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAgBA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wCAAwC,CAAC;AACvD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC"}
package/lib/node/index.js CHANGED
@@ -17,6 +17,14 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  const tslib_1 = require("tslib");
19
19
  tslib_1.__exportStar(require("./copilot-auth-service-impl"), exports);
20
- tslib_1.__exportStar(require("./copilot-language-model"), exports);
21
20
  tslib_1.__exportStar(require("./copilot-language-models-manager-impl"), exports);
21
+ tslib_1.__exportStar(require("./copilot-cli-auth-provider"), exports);
22
+ tslib_1.__exportStar(require("./copilot-cli-locator"), exports);
23
+ tslib_1.__exportStar(require("./copilot-credential-store"), exports);
24
+ tslib_1.__exportStar(require("./copilot-runtime-env"), exports);
25
+ tslib_1.__exportStar(require("./copilot-sdk-client-provider"), exports);
26
+ tslib_1.__exportStar(require("./copilot-sdk-loader"), exports);
27
+ tslib_1.__exportStar(require("./copilot-sdk-mappers"), exports);
28
+ tslib_1.__exportStar(require("./copilot-sdk-language-model"), exports);
29
+ tslib_1.__exportStar(require("./copilot-sdk-types"), exports);
22
30
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;AAEhF,sEAA4C;AAC5C,mEAAyC;AACzC,iFAAuD"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;AAEhF,sEAA4C;AAC5C,iFAAuD;AACvD,sEAA4C;AAC5C,gEAAsC;AACtC,qEAA2C;AAC3C,gEAAsC;AACtC,wEAA8C;AAC9C,+DAAqC;AACrC,gEAAsC;AACtC,uEAA6C;AAC7C,8DAAoC"}
package/package.json CHANGED
@@ -1,12 +1,10 @@
1
1
  {
2
2
  "name": "@theia/ai-copilot",
3
- "version": "1.76.0-next.4+21b9b5342",
3
+ "version": "1.76.0-next.42+b0f9e63a6",
4
4
  "description": "Theia - GitHub Copilot Integration",
5
5
  "dependencies": {
6
- "@theia/ai-core": "1.76.0-next.4+21b9b5342",
7
- "@theia/ai-openai": "1.76.0-next.4+21b9b5342",
8
- "@theia/core": "1.76.0-next.4+21b9b5342",
9
- "openai": "^6.49.0",
6
+ "@theia/ai-core": "1.76.0-next.42+b0f9e63a6",
7
+ "@theia/core": "1.76.0-next.42+b0f9e63a6",
10
8
  "tslib": "^2.8.1"
11
9
  },
12
10
  "publishConfig": {
@@ -48,5 +46,5 @@
48
46
  "nyc": {
49
47
  "extends": "../../configs/nyc.json"
50
48
  },
51
- "gitHead": "21b9b534224c55152fca0b67af7f8a8283dad2bd"
49
+ "gitHead": "b0f9e63a6d331135265869a341dce7c7f1eef158"
52
50
  }
@@ -16,7 +16,7 @@
16
16
 
17
17
  import * as React from '@theia/core/shared/react';
18
18
  import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
19
- import { DialogProps, DialogError } from '@theia/core/lib/browser/dialogs';
19
+ import { DialogProps, DialogError, Dialog } from '@theia/core/lib/browser/dialogs';
20
20
  import { ReactDialog } from '@theia/core/lib/browser/dialogs/react-dialog';
21
21
  import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
22
22
  import { WindowService } from '@theia/core/lib/browser/window/window-service';
@@ -68,28 +68,30 @@ export class CopilotAuthDialog extends ReactDialog<boolean> {
68
68
  protected init(): void {
69
69
  this.titleNode.textContent = this.props.title;
70
70
  this.appendAcceptButton(nls.localize('theia/ai/copilot/auth/authorize', 'I have authorized'));
71
- this.appendCloseButton(nls.localizeByDefault('Cancel'));
71
+ this.appendCloseButton(Dialog.CANCEL);
72
72
  }
73
73
 
74
74
  protected updateButtonStates(): void {
75
75
  const isPolling = this.state === 'polling';
76
76
  const isSuccess = this.state === 'success';
77
+ // Singleton dialog: button state survives close, so reset it on every render.
77
78
  if (this.acceptButton) {
78
79
  this.acceptButton.disabled = isPolling || isSuccess;
79
- if (isSuccess) {
80
- this.acceptButton.style.display = 'none';
81
- }
80
+ this.acceptButton.style.display = isSuccess ? 'none' : '';
82
81
  }
83
82
  if (this.closeButton) {
84
- if (isSuccess) {
85
- this.closeButton.textContent = nls.localizeByDefault('Close');
86
- }
83
+ this.closeButton.textContent = isSuccess ? nls.localizeByDefault('Close') : Dialog.CANCEL;
87
84
  }
88
85
  }
89
86
 
90
87
  override async open(): Promise<boolean | undefined> {
91
88
  this.initiateFlow();
92
- return super.open();
89
+ const result = await super.open();
90
+ if (this.state !== 'success') {
91
+ // Leave no Copilot CLI process behind when the dialog is dismissed or retried.
92
+ await this.authService.cancelSignIn();
93
+ }
94
+ return result;
93
95
  }
94
96
 
95
97
  override update(): void {
@@ -100,9 +102,12 @@ export class CopilotAuthDialog extends ReactDialog<boolean> {
100
102
  protected async initiateFlow(): Promise<void> {
101
103
  try {
102
104
  this.state = 'loading';
105
+ this.deviceCodeResponse = undefined;
106
+ this.errorMessage = undefined;
107
+ this.copied = false;
103
108
  this.update();
104
109
 
105
- this.deviceCodeResponse = await this.authService.initiateDeviceFlow(this.props.enterpriseUrl);
110
+ this.deviceCodeResponse = await this.authService.startSignIn(this.props.enterpriseUrl);
106
111
  this.state = 'waiting';
107
112
  this.update();
108
113
  } catch (error) {
@@ -121,11 +126,7 @@ export class CopilotAuthDialog extends ReactDialog<boolean> {
121
126
  this.update();
122
127
 
123
128
  try {
124
- const success = await this.authService.pollForToken(
125
- this.deviceCodeResponse.device_code,
126
- this.deviceCodeResponse.interval,
127
- this.props.enterpriseUrl
128
- );
129
+ const success = await this.authService.waitForSignIn();
129
130
 
130
131
  if (success) {
131
132
  this.state = 'success';
@@ -149,7 +150,10 @@ export class CopilotAuthDialog extends ReactDialog<boolean> {
149
150
 
150
151
  protected override isValid(_value: boolean, _mode: DialogError): DialogError {
151
152
  if (this.state === 'error') {
152
- return this.errorMessage ?? 'An error occurred';
153
+ // The error is shown in the dialog body by renderError, where it can wrap. Returning only a
154
+ // failed result keeps the accept button disabled without repeating the (often long) message
155
+ // next to it, where it does not fit.
156
+ return { result: false, message: '' };
153
157
  }
154
158
  return '';
155
159
  }
@@ -19,9 +19,12 @@ import { CommandService, nls, PreferenceService } from '@theia/core';
19
19
  import { FrontendApplicationContribution } from '@theia/core/lib/browser';
20
20
  import { MessageService } from '@theia/core/lib/common/message-service';
21
21
  import { CopilotAuthService, CopilotLanguageModelsManager, CopilotModelDescription, COPILOT_PROVIDER_ID } from '../common';
22
- import { COPILOT_ENABLED_PREF, COPILOT_MODEL_OVERRIDES_PREF, COPILOT_ENTERPRISE_URL_PREF } from '../common/copilot-preferences';
22
+ import { COPILOT_ENABLED_PREF, COPILOT_ENTERPRISE_URL_PREF, COPILOT_EXECUTABLE_PATH_PREF, COPILOT_MODEL_OVERRIDES_PREF } from '../common/copilot-preferences';
23
23
  import { AICorePreferences, PREFERENCE_NAME_MAX_RETRIES } from '@theia/ai-core/lib/common/ai-core-preferences';
24
24
  import { CopilotCommands } from './copilot-command-contribution';
25
+ import { ModelDiscoveryStatusService } from '@theia/ai-core/lib/browser';
26
+
27
+ const COPILOT_PROVIDER_LABEL = 'GitHub Copilot';
25
28
 
26
29
  @injectable()
27
30
  export class CopilotFrontendApplicationContribution implements FrontendApplicationContribution {
@@ -44,29 +47,49 @@ export class CopilotFrontendApplicationContribution implements FrontendApplicati
44
47
  @inject(CommandService)
45
48
  protected readonly commandService: CommandService;
46
49
 
50
+ @inject(ModelDiscoveryStatusService)
51
+ protected readonly discoveryStatus: ModelDiscoveryStatusService;
52
+
47
53
  protected prevModels: string[] = [];
48
54
  protected useAutoDiscovery = false;
49
55
 
50
56
  onStart(): void {
51
57
  this.preferenceService.ready.then(async () => {
52
- const enterpriseUrl = this.preferenceService.get<string>(COPILOT_ENTERPRISE_URL_PREF);
53
- this.manager.setEnterpriseUrl(enterpriseUrl || undefined);
54
-
58
+ this.discoveryStatus.registerProvider({
59
+ providerId: COPILOT_PROVIDER_ID,
60
+ label: COPILOT_PROVIDER_LABEL,
61
+ refresh: () => this.initializeModels()
62
+ });
63
+ // Before anything reaches for the CLI: the backend cannot read the preferences itself.
64
+ await this.updateExecutablePath();
55
65
  if (this.isCopilotEnabled()) {
56
66
  const authState = await this.authService.getAuthState();
57
67
  if (authState.migrationRequired) {
58
- this.notifyTokenMigration();
68
+ this.notifySignInRequired();
59
69
  }
60
- await this.initializeModels();
61
70
  }
71
+ // Also when disabled: that is a state of its own on the provider's page, not the absence of one.
72
+ await this.initializeModels();
62
73
 
63
74
  this.preferenceService.onPreferenceChanged(event => {
64
- if (event.preferenceName === COPILOT_ENABLED_PREF) {
75
+ if (event.preferenceName === COPILOT_EXECUTABLE_PATH_PREF) {
76
+ this.updateExecutablePath().then(() => {
77
+ if (this.isCopilotEnabled() && this.useAutoDiscovery) {
78
+ // A CLI that could not be found before may be reachable now.
79
+ this.discoverAndRegisterModels();
80
+ }
81
+ });
82
+ } else if (event.preferenceName === COPILOT_ENABLED_PREF) {
65
83
  if (this.isCopilotEnabled()) {
66
84
  this.initializeModels();
67
85
  } else {
68
86
  this.removeAllCopilotModels();
87
+ this.initializeModels();
69
88
  }
89
+ } else if (event.preferenceName === COPILOT_ENTERPRISE_URL_PREF) {
90
+ // The domain is only read at sign-in time, so a change while signed in has no effect
91
+ // until the next sign-in. Let the user know instead of silently ignoring it.
92
+ this.notifyEnterpriseUrlChanged();
70
93
  } else if (event.preferenceName === COPILOT_MODEL_OVERRIDES_PREF && this.isCopilotEnabled()) {
71
94
  const newModels = this.preferenceService.get<string[]>(COPILOT_MODEL_OVERRIDES_PREF, []);
72
95
  if (newModels.length > 0) {
@@ -77,15 +100,6 @@ export class CopilotFrontendApplicationContribution implements FrontendApplicati
77
100
  this.removeAllCopilotModels();
78
101
  this.discoverAndRegisterModels();
79
102
  }
80
- } else if (event.preferenceName === COPILOT_ENTERPRISE_URL_PREF && this.isCopilotEnabled()) {
81
- const url = this.preferenceService.get<string>(COPILOT_ENTERPRISE_URL_PREF);
82
- this.manager.setEnterpriseUrl(url || undefined);
83
- if (this.useAutoDiscovery) {
84
- this.removeAllCopilotModels();
85
- this.discoverAndRegisterModels();
86
- } else {
87
- this.manager.refreshModelsStatus();
88
- }
89
103
  }
90
104
  });
91
105
 
@@ -95,6 +109,7 @@ export class CopilotFrontendApplicationContribution implements FrontendApplicati
95
109
  await this.discoverAndRegisterModels();
96
110
  } else {
97
111
  this.removeAllCopilotModels();
112
+ this.setSignInRequiredStatus();
98
113
  }
99
114
  }
100
115
  });
@@ -111,9 +126,87 @@ export class CopilotFrontendApplicationContribution implements FrontendApplicati
111
126
  return this.preferenceService.get<boolean>(COPILOT_ENABLED_PREF, true);
112
127
  }
113
128
 
129
+ /**
130
+ * Hands the configured location of the Copilot CLI to the backend, which searches for it when
131
+ * none is configured.
132
+ */
133
+ protected async updateExecutablePath(): Promise<void> {
134
+ const executablePath = this.preferenceService.get<string>(COPILOT_EXECUTABLE_PATH_PREF, '').trim();
135
+ await this.authService.setExecutablePath(executablePath || undefined);
136
+ }
137
+
138
+ /**
139
+ * Tells the user why they are signed out after an update, since the sign-in of the previous
140
+ * version cannot be carried over: it belonged to an OAuth application that is no longer used.
141
+ */
142
+ protected async notifySignInRequired(): Promise<void> {
143
+ const signIn = nls.localize('theia/ai/copilot/commands/signIn', 'Sign in to GitHub Copilot');
144
+ const action = await this.messageService.info(
145
+ nls.localize('theia/ai/copilot/signInAgain',
146
+ 'GitHub Copilot now signs in through the GitHub Copilot CLI. Your previous sign-in could not be carried over and has been '
147
+ + 'removed, please sign in again to use Copilot models.'),
148
+ signIn
149
+ );
150
+ if (action === signIn) {
151
+ this.commandService.executeCommand(CopilotCommands.SIGN_IN.id);
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Tells the user that a changed GitHub Copilot domain only takes effect on the next sign-in, since
157
+ * the domain is read when signing in and not while a session is already established.
158
+ */
159
+ protected async notifyEnterpriseUrlChanged(): Promise<void> {
160
+ const authState = await this.authService.getAuthState();
161
+ if (!authState.isAuthenticated) {
162
+ return;
163
+ }
164
+ const signIn = nls.localize('theia/ai/copilot/commands/signIn', 'Sign in to GitHub Copilot');
165
+ const action = await this.messageService.info(
166
+ nls.localize('theia/ai/copilot/enterpriseUrlChanged',
167
+ 'The GitHub Copilot domain changed. Sign in again for it to take effect.'),
168
+ signIn
169
+ );
170
+ if (action === signIn) {
171
+ this.commandService.executeCommand(CopilotCommands.SIGN_IN.id);
172
+ }
173
+ }
174
+
175
+ /** The state of a provider whose credential is a sign-in that has not happened, with the way to fix it. */
176
+ protected setSignInRequiredStatus(): void {
177
+ this.discoveryStatus.updateStatus(COPILOT_PROVIDER_ID, {
178
+ state: 'no-credentials',
179
+ // What Copilot lacks is a sign-in, not an API key, so it says so rather than letting the
180
+ // state speak for it.
181
+ stateLabel: nls.localizeByDefault('Not signed in'),
182
+ message: nls.localize('theia/ai/copilot/discovery/signedOut',
183
+ 'Not signed in to GitHub Copilot. Sign in to discover the models it offers.'),
184
+ action: { label: CopilotCommands.SIGN_IN.label!, commandId: CopilotCommands.SIGN_IN.id }
185
+ });
186
+ }
187
+
114
188
  protected async initializeModels(): Promise<void> {
189
+ if (!this.isCopilotEnabled()) {
190
+ this.discoveryStatus.updateStatus(COPILOT_PROVIDER_ID, {
191
+ state: 'no-credentials',
192
+ stateLabel: nls.localizeByDefault('Disabled'),
193
+ message: nls.localize('theia/ai/copilot/discovery/disabled', 'The GitHub Copilot provider is disabled. Enable it to discover models.'),
194
+ action: undefined
195
+ });
196
+ return;
197
+ }
115
198
  const configuredModels = this.preferenceService.get<string[]>(COPILOT_MODEL_OVERRIDES_PREF, []);
116
199
  if (configuredModels.length > 0) {
200
+ this.discoveryStatus.updateStatus(COPILOT_PROVIDER_ID, {
201
+ state: 'overridden',
202
+ stateLabel: undefined,
203
+ discovered: configuredModels.map(id => ({ id })),
204
+ message: nls.localize('theia/ai/copilot/discovery/overridden',
205
+ 'The model list is configured manually. Clear the model overrides to discover the models from GitHub Copilot again.'),
206
+ lastFetch: undefined,
207
+ fromCache: false,
208
+ action: undefined
209
+ });
117
210
  this.useAutoDiscovery = false;
118
211
  this.manager.createOrUpdateLanguageModels(
119
212
  ...configuredModels.map((modelId: string) => this.createCopilotModelDescription(modelId))
@@ -126,7 +219,32 @@ export class CopilotFrontendApplicationContribution implements FrontendApplicati
126
219
  }
127
220
 
128
221
  protected async discoverAndRegisterModels(): Promise<void> {
129
- const modelIds = await this.manager.fetchAvailableModelIds();
222
+ // Runs are queued rather than overlapped: startup, a key change and a manual refresh can all
223
+ // ask within a moment of each other, and two runs in flight would compute what to unregister
224
+ // from the same stale list and leave the registry disagreeing with the provider.
225
+ this.discovering = this.discovering.then(() => this.runDiscovery().catch(error => this.discoveryStatus.reportError(COPILOT_PROVIDER_ID, error)));
226
+ return this.discovering;
227
+ }
228
+
229
+ protected discovering: Promise<void> = Promise.resolve();
230
+
231
+ protected async runDiscovery(): Promise<void> {
232
+ // Signing in is Copilot's equivalent of setting an API key, so a missing sign-in reads like a
233
+ // missing credential rather than like a failure: the CLI would answer the list call with an
234
+ // authorization error, which says the same thing in a way nobody can act on.
235
+ if (!(await this.authService.getAuthState()).isAuthenticated) {
236
+ this.setSignInRequiredStatus();
237
+ return;
238
+ }
239
+ this.discoveryStatus.updateStatus(COPILOT_PROVIDER_ID, { state: 'fetching', stateLabel: undefined, message: undefined, action: undefined });
240
+ const { models, error } = await this.manager.fetchAvailableModels();
241
+ if (error) {
242
+ // The models of an earlier discovery stay registered; the manager already marks them
243
+ // unavailable, so they are visible as such rather than silently gone.
244
+ this.discoveryStatus.updateStatus(COPILOT_PROVIDER_ID, { state: 'error', stateLabel: undefined, message: error, action: undefined });
245
+ return;
246
+ }
247
+ const modelIds = models.map(model => model.id);
130
248
  if (modelIds.length > 0) {
131
249
  const modelsToRemove = this.prevModels.filter(m => !modelIds.includes(m));
132
250
  if (modelsToRemove.length > 0) {
@@ -139,6 +257,15 @@ export class CopilotFrontendApplicationContribution implements FrontendApplicati
139
257
  );
140
258
  this.prevModels = [...modelIds];
141
259
  }
260
+ this.discoveryStatus.updateStatus(COPILOT_PROVIDER_ID, {
261
+ state: 'ready',
262
+ stateLabel: undefined,
263
+ discovered: models,
264
+ message: undefined,
265
+ lastFetch: Date.now(),
266
+ fromCache: false,
267
+ action: undefined
268
+ });
142
269
  }
143
270
 
144
271
  protected removeAllCopilotModels(): void {
@@ -171,18 +298,6 @@ export class CopilotFrontendApplicationContribution implements FrontendApplicati
171
298
  this.manager.createOrUpdateLanguageModels(...models.map((modelId: string) => this.createCopilotModelDescription(modelId)));
172
299
  }
173
300
 
174
- protected async notifyTokenMigration(): Promise<void> {
175
- const signIn = nls.localize('theia/ai/copilot/commands/signIn', 'Sign in to GitHub Copilot');
176
- const action = await this.messageService.info(
177
- nls.localize('theia/ai/copilot/tokenMigration',
178
- 'Your GitHub Copilot session used an outdated authentication method and has been cleared. Please sign in again to access all available models.'),
179
- signIn
180
- );
181
- if (action === signIn) {
182
- this.commandService.executeCommand(CopilotCommands.SIGN_IN.id);
183
- }
184
- }
185
-
186
301
  protected createCopilotModelDescription(modelId: string): CopilotModelDescription {
187
302
  const id = `${COPILOT_PROVIDER_ID}/${modelId}`;
188
303
  const maxRetries = this.aiCorePreferences.get(PREFERENCE_NAME_MAX_RETRIES) ?? 3;
@@ -190,8 +305,6 @@ export class CopilotFrontendApplicationContribution implements FrontendApplicati
190
305
  return {
191
306
  id,
192
307
  model: modelId,
193
- enableStreaming: true,
194
- supportsStructuredOutput: true,
195
308
  maxRetries
196
309
  };
197
310
  }