clanka 0.0.4 → 0.0.5
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.
- package/dist/Agent.d.ts +45 -19
- package/dist/Agent.d.ts.map +1 -1
- package/dist/Agent.js +172 -66
- package/dist/Agent.js.map +1 -1
- package/dist/Codex.d.ts +6 -1
- package/dist/Codex.d.ts.map +1 -1
- package/dist/Codex.js +16 -3
- package/dist/Codex.js.map +1 -1
- package/dist/GithubCopilot.d.ts +11 -0
- package/dist/GithubCopilot.d.ts.map +1 -0
- package/dist/GithubCopilot.js +14 -0
- package/dist/GithubCopilot.js.map +1 -0
- package/dist/GithubCopilotAuth.d.ts +57 -0
- package/dist/GithubCopilotAuth.d.ts.map +1 -0
- package/dist/GithubCopilotAuth.js +218 -0
- package/dist/GithubCopilotAuth.js.map +1 -0
- package/dist/GithubCopilotAuth.test.d.ts +2 -0
- package/dist/GithubCopilotAuth.test.d.ts.map +1 -0
- package/dist/GithubCopilotAuth.test.js +267 -0
- package/dist/GithubCopilotAuth.test.js.map +1 -0
- package/dist/OutputFormatter.d.ts +2 -1
- package/dist/OutputFormatter.d.ts.map +1 -1
- package/dist/OutputFormatter.js +8 -2
- package/dist/OutputFormatter.js.map +1 -1
- package/dist/ScriptExtraction.d.ts +34 -0
- package/dist/ScriptExtraction.d.ts.map +1 -0
- package/dist/ScriptExtraction.js +68 -0
- package/dist/ScriptExtraction.js.map +1 -0
- package/dist/ScriptExtraction.test.d.ts +2 -0
- package/dist/ScriptExtraction.test.d.ts.map +1 -0
- package/dist/ScriptExtraction.test.js +64 -0
- package/dist/ScriptExtraction.test.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
- package/src/Agent.ts +247 -87
- package/src/Codex.ts +18 -3
- package/src/GithubCopilot.ts +14 -0
- package/src/GithubCopilotAuth.test.ts +469 -0
- package/src/GithubCopilotAuth.ts +441 -0
- package/src/OutputFormatter.ts +11 -4
- package/src/ScriptExtraction.test.ts +96 -0
- package/src/ScriptExtraction.ts +75 -0
- package/src/index.ts +5 -0
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import { assert, describe, it } from "@effect/vitest"
|
|
2
|
+
import { Deferred, Effect, Fiber, Option, Ref } from "effect"
|
|
3
|
+
import {
|
|
4
|
+
HttpClient,
|
|
5
|
+
HttpClientRequest,
|
|
6
|
+
HttpClientResponse,
|
|
7
|
+
} from "effect/unstable/http"
|
|
8
|
+
import { KeyValueStore } from "effect/unstable/persistence"
|
|
9
|
+
import {
|
|
10
|
+
COPILOT_VISION_REQUEST_HEADER,
|
|
11
|
+
DEFAULT_OPENAI_INTENT,
|
|
12
|
+
DEFAULT_USER_AGENT,
|
|
13
|
+
GithubCopilotAuth,
|
|
14
|
+
GithubCopilotAuthError,
|
|
15
|
+
INITIATOR_HEADER,
|
|
16
|
+
ISSUER,
|
|
17
|
+
OPENAI_INTENT_HEADER,
|
|
18
|
+
STORE_PREFIX,
|
|
19
|
+
STORE_TOKEN_KEY,
|
|
20
|
+
TokenData,
|
|
21
|
+
toGithubCopilotAuthKeyValueStore,
|
|
22
|
+
toTokenStore,
|
|
23
|
+
} from "./GithubCopilotAuth.ts"
|
|
24
|
+
|
|
25
|
+
const jsonResponse = (body: unknown, status = 200): Response =>
|
|
26
|
+
new Response(JSON.stringify(body), {
|
|
27
|
+
status,
|
|
28
|
+
headers: {
|
|
29
|
+
"content-type": "application/json",
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const getBody = (request: HttpClientRequest.HttpClientRequest): string => {
|
|
34
|
+
if (request.body._tag !== "Uint8Array") {
|
|
35
|
+
throw new Error("Expected request body to be a Uint8Array payload")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return new TextDecoder().decode(request.body.body)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const makeClient = Effect.fn("makeClient")(function* (
|
|
42
|
+
handler: (
|
|
43
|
+
request: HttpClientRequest.HttpClientRequest,
|
|
44
|
+
attempt: number,
|
|
45
|
+
) => Response,
|
|
46
|
+
) {
|
|
47
|
+
const attempts = yield* Ref.make(0)
|
|
48
|
+
const requests = yield* Ref.make<Array<HttpClientRequest.HttpClientRequest>>(
|
|
49
|
+
[],
|
|
50
|
+
)
|
|
51
|
+
const client = HttpClient.make((request) =>
|
|
52
|
+
Effect.gen(function* () {
|
|
53
|
+
const attempt = yield* Ref.updateAndGet(attempts, (count) => count + 1)
|
|
54
|
+
yield* Ref.update(requests, (current) => [...current, request])
|
|
55
|
+
return HttpClientResponse.fromWeb(request, handler(request, attempt))
|
|
56
|
+
}),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
attempts,
|
|
61
|
+
client,
|
|
62
|
+
requests,
|
|
63
|
+
} as const
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
const makeEffectClient = Effect.fn("makeEffectClient")(function* (
|
|
67
|
+
handler: (
|
|
68
|
+
request: HttpClientRequest.HttpClientRequest,
|
|
69
|
+
attempt: number,
|
|
70
|
+
) => Effect.Effect<Response>,
|
|
71
|
+
) {
|
|
72
|
+
const attempts = yield* Ref.make(0)
|
|
73
|
+
const requests = yield* Ref.make<Array<HttpClientRequest.HttpClientRequest>>(
|
|
74
|
+
[],
|
|
75
|
+
)
|
|
76
|
+
const client = HttpClient.make((request) =>
|
|
77
|
+
Effect.gen(function* () {
|
|
78
|
+
const attempt = yield* Ref.updateAndGet(attempts, (count) => count + 1)
|
|
79
|
+
yield* Ref.update(requests, (current) => [...current, request])
|
|
80
|
+
return HttpClientResponse.fromWeb(
|
|
81
|
+
request,
|
|
82
|
+
yield* handler(request, attempt),
|
|
83
|
+
)
|
|
84
|
+
}),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
attempts,
|
|
89
|
+
client,
|
|
90
|
+
requests,
|
|
91
|
+
} as const
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe("GithubCopilotAuth", () => {
|
|
95
|
+
it.effect(
|
|
96
|
+
"persists token data through the prefixed schema store",
|
|
97
|
+
Effect.fn(function* () {
|
|
98
|
+
const kvs = yield* KeyValueStore.KeyValueStore
|
|
99
|
+
const tokenStore = toTokenStore(kvs)
|
|
100
|
+
const token = new TokenData({
|
|
101
|
+
access: "copilot-access-token",
|
|
102
|
+
expires: 0,
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
yield* Effect.orDie(tokenStore.set(STORE_TOKEN_KEY, token))
|
|
106
|
+
|
|
107
|
+
const stored = yield* Effect.orDie(tokenStore.get(STORE_TOKEN_KEY))
|
|
108
|
+
|
|
109
|
+
assert.strictEqual(Option.isSome(stored), true)
|
|
110
|
+
if (Option.isNone(stored)) {
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
assert.strictEqual(stored.value.access, token.access)
|
|
115
|
+
assert.strictEqual(stored.value.expires, token.expires)
|
|
116
|
+
|
|
117
|
+
const rawValue = yield* Effect.orDie(
|
|
118
|
+
kvs.get(`${STORE_PREFIX}${STORE_TOKEN_KEY}`),
|
|
119
|
+
)
|
|
120
|
+
const unprefixedValue = yield* Effect.orDie(kvs.get(STORE_TOKEN_KEY))
|
|
121
|
+
|
|
122
|
+
assert.strictEqual(typeof rawValue, "string")
|
|
123
|
+
assert.strictEqual(unprefixedValue, undefined)
|
|
124
|
+
}, Effect.provide(KeyValueStore.layerMemory)),
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
it("treats expires=0 as non-expiring", () => {
|
|
128
|
+
const nonExpiring = new TokenData({
|
|
129
|
+
access: "copilot-access-token",
|
|
130
|
+
expires: 0,
|
|
131
|
+
})
|
|
132
|
+
const expired = new TokenData({
|
|
133
|
+
access: "copilot-access-token",
|
|
134
|
+
expires: Date.now() - 1_000,
|
|
135
|
+
})
|
|
136
|
+
const valid = new TokenData({
|
|
137
|
+
access: "copilot-access-token",
|
|
138
|
+
expires: Date.now() + 60_000,
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
assert.strictEqual(nonExpiring.isExpired(), false)
|
|
142
|
+
assert.strictEqual(expired.isExpired(), true)
|
|
143
|
+
assert.strictEqual(valid.isExpired(), false)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it("constructs GithubCopilotAuthError with the expected tagged shape", () => {
|
|
147
|
+
const error = new GithubCopilotAuthError({
|
|
148
|
+
reason: "DeviceFlowFailed",
|
|
149
|
+
message: "Could not authenticate with GitHub Copilot",
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
assert.strictEqual(error._tag, "GithubCopilotAuthError")
|
|
153
|
+
assert.strictEqual(error.reason, "DeviceFlowFailed")
|
|
154
|
+
assert.strictEqual(
|
|
155
|
+
error.message,
|
|
156
|
+
"Could not authenticate with GitHub Copilot",
|
|
157
|
+
)
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
it.effect("returns a cached token without performing any requests", () =>
|
|
161
|
+
Effect.gen(function* () {
|
|
162
|
+
const kvs = yield* KeyValueStore.KeyValueStore
|
|
163
|
+
const tokenStore = toTokenStore(kvs)
|
|
164
|
+
yield* Effect.orDie(
|
|
165
|
+
tokenStore.set(
|
|
166
|
+
STORE_TOKEN_KEY,
|
|
167
|
+
new TokenData({
|
|
168
|
+
access: "cached-copilot-token",
|
|
169
|
+
expires: 0,
|
|
170
|
+
}),
|
|
171
|
+
),
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
const { attempts, client } = yield* makeClient(
|
|
175
|
+
() => new Response(null, { status: 500 }),
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
const auth = yield* GithubCopilotAuth.make.pipe(
|
|
179
|
+
Effect.provideService(HttpClient.HttpClient, client),
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
const token = yield* auth.get
|
|
183
|
+
|
|
184
|
+
assert.strictEqual(token.access, "cached-copilot-token")
|
|
185
|
+
assert.strictEqual(yield* Ref.get(attempts), 0)
|
|
186
|
+
}).pipe(Effect.provide(KeyValueStore.layerMemory)),
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
it.effect(
|
|
190
|
+
"authenticates, persists the token, and clears memory plus storage on logout",
|
|
191
|
+
() =>
|
|
192
|
+
Effect.gen(function* () {
|
|
193
|
+
const kvs = yield* KeyValueStore.KeyValueStore
|
|
194
|
+
const tokenStore = toTokenStore(kvs)
|
|
195
|
+
|
|
196
|
+
let authCount = 0
|
|
197
|
+
const { attempts, client, requests } = yield* makeClient((request) => {
|
|
198
|
+
if (request.url === `${ISSUER}/login/device/code`) {
|
|
199
|
+
authCount += 1
|
|
200
|
+
return jsonResponse({
|
|
201
|
+
device_code: `device-code-${authCount}`,
|
|
202
|
+
user_code: `USER-${authCount}`,
|
|
203
|
+
verification_uri: `${ISSUER}/login/device`,
|
|
204
|
+
interval: 1,
|
|
205
|
+
})
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (request.url === `${ISSUER}/login/oauth/access_token`) {
|
|
209
|
+
return jsonResponse({
|
|
210
|
+
access_token: `copilot-token-${authCount}`,
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return new Response(null, { status: 500 })
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
const auth = yield* GithubCopilotAuth.make.pipe(
|
|
218
|
+
Effect.provideService(HttpClient.HttpClient, client),
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
const authenticated = yield* auth.authenticate
|
|
222
|
+
assert.strictEqual(authenticated.access, "copilot-token-1")
|
|
223
|
+
assert.strictEqual(yield* Ref.get(attempts), 2)
|
|
224
|
+
|
|
225
|
+
const stored = yield* Effect.orDie(tokenStore.get(STORE_TOKEN_KEY))
|
|
226
|
+
assert.strictEqual(Option.isSome(stored), true)
|
|
227
|
+
if (Option.isSome(stored)) {
|
|
228
|
+
assert.strictEqual(stored.value.access, "copilot-token-1")
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
yield* auth.logout
|
|
232
|
+
const storedAfterLogout = yield* Effect.orDie(
|
|
233
|
+
tokenStore.get(STORE_TOKEN_KEY),
|
|
234
|
+
)
|
|
235
|
+
assert.strictEqual(Option.isNone(storedAfterLogout), true)
|
|
236
|
+
|
|
237
|
+
const tokenAfterLogout = yield* auth.get
|
|
238
|
+
assert.strictEqual(tokenAfterLogout.access, "copilot-token-2")
|
|
239
|
+
assert.strictEqual(yield* Ref.get(attempts), 4)
|
|
240
|
+
|
|
241
|
+
const seenRequests = yield* Ref.get(requests)
|
|
242
|
+
assert.strictEqual(seenRequests.length, 4)
|
|
243
|
+
assert.strictEqual(seenRequests[0]?.url, `${ISSUER}/login/device/code`)
|
|
244
|
+
assert.strictEqual(
|
|
245
|
+
getBody(seenRequests[0]!).includes(
|
|
246
|
+
`"client_id":"Ov23li8tweQw6odWQebz"`,
|
|
247
|
+
),
|
|
248
|
+
true,
|
|
249
|
+
)
|
|
250
|
+
}).pipe(Effect.provide(KeyValueStore.layerMemory)),
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
it.effect("clears corrupted persisted tokens before re-authenticating", () =>
|
|
254
|
+
Effect.gen(function* () {
|
|
255
|
+
const kvs = yield* KeyValueStore.KeyValueStore
|
|
256
|
+
yield* Effect.orDie(
|
|
257
|
+
kvs.set(`${STORE_PREFIX}${STORE_TOKEN_KEY}`, "not-json"),
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
const { attempts, client } = yield* makeClient((request) => {
|
|
261
|
+
if (request.url === `${ISSUER}/login/device/code`) {
|
|
262
|
+
return jsonResponse({
|
|
263
|
+
device_code: "device-code",
|
|
264
|
+
user_code: "ABCD-EFGH",
|
|
265
|
+
verification_uri: `${ISSUER}/login/device`,
|
|
266
|
+
interval: 1,
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (request.url === `${ISSUER}/login/oauth/access_token`) {
|
|
271
|
+
return jsonResponse({
|
|
272
|
+
access_token: "fresh-copilot-token",
|
|
273
|
+
})
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return new Response(null, { status: 500 })
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
const auth = yield* GithubCopilotAuth.make.pipe(
|
|
280
|
+
Effect.provideService(HttpClient.HttpClient, client),
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
assert.strictEqual(
|
|
284
|
+
yield* Effect.orDie(kvs.get(`${STORE_PREFIX}${STORE_TOKEN_KEY}`)),
|
|
285
|
+
undefined,
|
|
286
|
+
)
|
|
287
|
+
assert.strictEqual(yield* Ref.get(attempts), 0)
|
|
288
|
+
|
|
289
|
+
const token = yield* auth.get
|
|
290
|
+
|
|
291
|
+
assert.strictEqual(token.access, "fresh-copilot-token")
|
|
292
|
+
assert.strictEqual(yield* Ref.get(attempts), 2)
|
|
293
|
+
}).pipe(Effect.provide(KeyValueStore.layerMemory)),
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
it.effect("serializes concurrent get calls behind one authentication", () =>
|
|
297
|
+
Effect.gen(function* () {
|
|
298
|
+
const authStarted = yield* Deferred.make<void>()
|
|
299
|
+
const releaseAuth = yield* Deferred.make<void>()
|
|
300
|
+
const { attempts, client } = yield* makeEffectClient((request) => {
|
|
301
|
+
if (request.url === `${ISSUER}/login/device/code`) {
|
|
302
|
+
return Effect.succeed(
|
|
303
|
+
jsonResponse({
|
|
304
|
+
device_code: "device-code",
|
|
305
|
+
user_code: "ABCD-EFGH",
|
|
306
|
+
verification_uri: `${ISSUER}/login/device`,
|
|
307
|
+
interval: 1,
|
|
308
|
+
}),
|
|
309
|
+
)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (request.url === `${ISSUER}/login/oauth/access_token`) {
|
|
313
|
+
return Effect.gen(function* () {
|
|
314
|
+
yield* Deferred.succeed(authStarted, void 0)
|
|
315
|
+
yield* Deferred.await(releaseAuth)
|
|
316
|
+
return jsonResponse({
|
|
317
|
+
access_token: "shared-copilot-token",
|
|
318
|
+
})
|
|
319
|
+
})
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return Effect.succeed(new Response(null, { status: 500 }))
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
const auth = yield* GithubCopilotAuth.make.pipe(
|
|
326
|
+
Effect.provideService(HttpClient.HttpClient, client),
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
const firstFiber = yield* auth.get.pipe(
|
|
330
|
+
Effect.forkChild({ startImmediately: true }),
|
|
331
|
+
)
|
|
332
|
+
yield* Deferred.await(authStarted)
|
|
333
|
+
|
|
334
|
+
const secondFiber = yield* auth.get.pipe(
|
|
335
|
+
Effect.forkChild({ startImmediately: true }),
|
|
336
|
+
)
|
|
337
|
+
yield* Effect.yieldNow
|
|
338
|
+
|
|
339
|
+
assert.strictEqual(yield* Ref.get(attempts), 2)
|
|
340
|
+
|
|
341
|
+
yield* Deferred.succeed(releaseAuth, void 0)
|
|
342
|
+
|
|
343
|
+
const first = yield* Fiber.join(firstFiber)
|
|
344
|
+
const second = yield* Fiber.join(secondFiber)
|
|
345
|
+
|
|
346
|
+
assert.strictEqual(yield* Ref.get(attempts), 2)
|
|
347
|
+
assert.strictEqual(first.access, "shared-copilot-token")
|
|
348
|
+
assert.strictEqual(second.access, "shared-copilot-token")
|
|
349
|
+
}).pipe(Effect.provide(KeyValueStore.layerMemory)),
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
it.effect(
|
|
353
|
+
"injects Copilot auth and request metadata headers through the client layer",
|
|
354
|
+
() =>
|
|
355
|
+
Effect.gen(function* () {
|
|
356
|
+
const kvs = yield* KeyValueStore.KeyValueStore
|
|
357
|
+
const tokenStore = toTokenStore(kvs)
|
|
358
|
+
yield* Effect.orDie(
|
|
359
|
+
tokenStore.set(
|
|
360
|
+
STORE_TOKEN_KEY,
|
|
361
|
+
new TokenData({
|
|
362
|
+
access: "copilot-token",
|
|
363
|
+
expires: 0,
|
|
364
|
+
}),
|
|
365
|
+
),
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
const { client, requests } = yield* makeClient(() =>
|
|
369
|
+
jsonResponse({ ok: true }),
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
const wrappedClient = yield* Effect.gen(function* () {
|
|
373
|
+
return yield* HttpClient.HttpClient
|
|
374
|
+
}).pipe(
|
|
375
|
+
Effect.provide(GithubCopilotAuth.layerClientNoDeps),
|
|
376
|
+
Effect.provideService(HttpClient.HttpClient, client),
|
|
377
|
+
Effect.provideService(
|
|
378
|
+
GithubCopilotAuth,
|
|
379
|
+
yield* GithubCopilotAuth.make.pipe(
|
|
380
|
+
Effect.provideService(HttpClient.HttpClient, client),
|
|
381
|
+
),
|
|
382
|
+
),
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
yield* HttpClientRequest.post(
|
|
386
|
+
"https://api.githubcopilot.com/chat/completions",
|
|
387
|
+
).pipe(
|
|
388
|
+
HttpClientRequest.bodyJsonUnsafe({
|
|
389
|
+
model: "gpt-4.1",
|
|
390
|
+
messages: [
|
|
391
|
+
{
|
|
392
|
+
role: "user",
|
|
393
|
+
content: [
|
|
394
|
+
{
|
|
395
|
+
type: "text",
|
|
396
|
+
text: "describe this image",
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
type: "image_url",
|
|
400
|
+
image_url: {
|
|
401
|
+
url: "https://example.com/image.png",
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
],
|
|
405
|
+
},
|
|
406
|
+
],
|
|
407
|
+
}),
|
|
408
|
+
wrappedClient.execute,
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
yield* HttpClientRequest.post(
|
|
412
|
+
"https://api.githubcopilot.com/chat/completions",
|
|
413
|
+
).pipe(
|
|
414
|
+
HttpClientRequest.bodyJsonUnsafe({
|
|
415
|
+
model: "gpt-4.1",
|
|
416
|
+
messages: [
|
|
417
|
+
{
|
|
418
|
+
role: "assistant",
|
|
419
|
+
content: "running tools",
|
|
420
|
+
},
|
|
421
|
+
],
|
|
422
|
+
}),
|
|
423
|
+
wrappedClient.execute,
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
const seenRequests = yield* Ref.get(requests)
|
|
427
|
+
const visionRequest = seenRequests[0]!
|
|
428
|
+
const agentRequest = seenRequests[1]!
|
|
429
|
+
|
|
430
|
+
assert.strictEqual(
|
|
431
|
+
visionRequest.headers.authorization,
|
|
432
|
+
"Bearer copilot-token",
|
|
433
|
+
)
|
|
434
|
+
assert.strictEqual(
|
|
435
|
+
visionRequest.headers["user-agent"],
|
|
436
|
+
DEFAULT_USER_AGENT,
|
|
437
|
+
)
|
|
438
|
+
assert.strictEqual(
|
|
439
|
+
visionRequest.headers[OPENAI_INTENT_HEADER.toLowerCase()],
|
|
440
|
+
DEFAULT_OPENAI_INTENT,
|
|
441
|
+
)
|
|
442
|
+
assert.strictEqual(visionRequest.headers[INITIATOR_HEADER], "user")
|
|
443
|
+
assert.strictEqual(
|
|
444
|
+
visionRequest.headers[COPILOT_VISION_REQUEST_HEADER.toLowerCase()],
|
|
445
|
+
"true",
|
|
446
|
+
)
|
|
447
|
+
assert.strictEqual(agentRequest.headers[INITIATOR_HEADER], "agent")
|
|
448
|
+
}).pipe(Effect.provide(KeyValueStore.layerMemory)),
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
it.effect(
|
|
452
|
+
"exposes the prefixed store helper",
|
|
453
|
+
Effect.fn(function* () {
|
|
454
|
+
const kvs = yield* KeyValueStore.KeyValueStore
|
|
455
|
+
const prefixedStore = toGithubCopilotAuthKeyValueStore(kvs)
|
|
456
|
+
|
|
457
|
+
yield* Effect.orDie(prefixedStore.set(STORE_TOKEN_KEY, "raw-token"))
|
|
458
|
+
|
|
459
|
+
assert.strictEqual(
|
|
460
|
+
yield* Effect.orDie(kvs.get(`${STORE_PREFIX}${STORE_TOKEN_KEY}`)),
|
|
461
|
+
"raw-token",
|
|
462
|
+
)
|
|
463
|
+
assert.strictEqual(
|
|
464
|
+
yield* Effect.orDie(kvs.get(STORE_TOKEN_KEY)),
|
|
465
|
+
undefined,
|
|
466
|
+
)
|
|
467
|
+
}, Effect.provide(KeyValueStore.layerMemory)),
|
|
468
|
+
)
|
|
469
|
+
})
|