pilotswarm-sdk 0.5.48 → 0.5.49
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/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/management-client.d.ts +16 -0
- package/dist/management-client.d.ts.map +1 -1
- package/dist/management-client.js +50 -5
- package/dist/management-client.js.map +1 -1
- package/dist/model-providers.d.ts +36 -5
- package/dist/model-providers.d.ts.map +1 -1
- package/dist/model-providers.js +41 -6
- package/dist/model-providers.js.map +1 -1
- package/dist/provider-catalog.d.ts.map +1 -1
- package/dist/provider-catalog.js +58 -10
- package/dist/provider-catalog.js.map +1 -1
- package/dist/provider-store.d.ts +21 -1
- package/dist/provider-store.d.ts.map +1 -1
- package/dist/provider-store.js +35 -2
- package/dist/provider-store.js.map +1 -1
- package/dist/provider-tools.d.ts +8 -0
- package/dist/provider-tools.d.ts.map +1 -1
- package/dist/provider-tools.js +12 -1
- package/dist/provider-tools.js.map +1 -1
- package/dist/session-manager.d.ts.map +1 -1
- package/dist/session-manager.js +28 -5
- package/dist/session-manager.js.map +1 -1
- package/dist/wif-credentials.d.ts +181 -0
- package/dist/wif-credentials.d.ts.map +1 -0
- package/dist/wif-credentials.js +382 -0
- package/dist/wif-credentials.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workload Identity Federation for the Anthropic API — no API key anywhere.
|
|
3
|
+
*
|
|
4
|
+
* A provider declared `type: "anthropic-wif"` carries no credential at all.
|
|
5
|
+
* The worker proves who it is with an identity token its platform already
|
|
6
|
+
* issues, trades that for a short-lived Anthropic access token, and sends the
|
|
7
|
+
* result as `Authorization: Bearer`. Nothing is stored, so nothing can leak
|
|
8
|
+
* from the database and nothing has to be rotated.
|
|
9
|
+
*
|
|
10
|
+
* Two shapes of identity token are understood, chosen by what the environment
|
|
11
|
+
* actually provides:
|
|
12
|
+
*
|
|
13
|
+
* ```
|
|
14
|
+
* ANTHROPIC_IDENTITY_TOKEN_FILE (or _TOKEN) one hop
|
|
15
|
+
* the file already holds a JWT the federation rule trusts
|
|
16
|
+
* → POST /v1/oauth/token
|
|
17
|
+
*
|
|
18
|
+
* AZURE_FEDERATED_TOKEN_FILE + AZURE_TENANT_ID two hops
|
|
19
|
+
* the file holds a Kubernetes-projected token, which Microsoft Entra ID
|
|
20
|
+
* does not accept as an assertion for anyone but itself
|
|
21
|
+
* → POST login.microsoftonline.com/<tenant>/oauth2/v2.0/token (Entra JWT)
|
|
22
|
+
* → POST /v1/oauth/token
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* Both token files are re-read on every exchange: a projected token rotates
|
|
26
|
+
* on disk under the process, and a copy cached in memory goes stale.
|
|
27
|
+
*
|
|
28
|
+
* WHY A CALLBACK RATHER THAN A STORED KEY. The access token expires — an hour
|
|
29
|
+
* by default, a day at most — while a PilotSwarm session outlives any of that
|
|
30
|
+
* and may be resumed on a different worker days later. So the token is never
|
|
31
|
+
* put in the session config; `@github/copilot-sdk` takes a `bearerTokenProvider`
|
|
32
|
+
* callback instead and asks for a token before each outbound request. The
|
|
33
|
+
* runtime caches nothing, which is why the caching below is not an
|
|
34
|
+
* optimisation: without it every single request would mint two fresh tokens.
|
|
35
|
+
*
|
|
36
|
+
* @module
|
|
37
|
+
*/
|
|
38
|
+
const DEFAULT_BASE_URL = "https://api.anthropic.com";
|
|
39
|
+
/**
|
|
40
|
+
* The three ids that name the rule, the organization and the identity the
|
|
41
|
+
* minted token acts as. All three are required whichever identity source is
|
|
42
|
+
* used, and none of them is a secret.
|
|
43
|
+
*/
|
|
44
|
+
const REQUIRED_VARS = [
|
|
45
|
+
"ANTHROPIC_FEDERATION_RULE_ID",
|
|
46
|
+
"ANTHROPIC_ORGANIZATION_ID",
|
|
47
|
+
"ANTHROPIC_SERVICE_ACCOUNT_ID",
|
|
48
|
+
];
|
|
49
|
+
function trimmed(value) {
|
|
50
|
+
return typeof value === "string" ? value.trim() : "";
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Read the settings out of the worker's environment.
|
|
54
|
+
*
|
|
55
|
+
* Returns the missing variable names rather than throwing, so a worker whose
|
|
56
|
+
* deployment declares the type but has not configured identity yet can say
|
|
57
|
+
* which line is absent instead of failing an unrelated turn later.
|
|
58
|
+
*/
|
|
59
|
+
export function readAnthropicWifSettings(env = process.env) {
|
|
60
|
+
const missing = REQUIRED_VARS.filter((name) => !trimmed(env[name]));
|
|
61
|
+
const identity = readIdentitySource(env);
|
|
62
|
+
if (!identity) {
|
|
63
|
+
missing.push("ANTHROPIC_IDENTITY_TOKEN_FILE (or ANTHROPIC_IDENTITY_TOKEN, or AZURE_FEDERATED_TOKEN_FILE with AZURE_TENANT_ID)");
|
|
64
|
+
}
|
|
65
|
+
if (missing.length > 0 || !identity)
|
|
66
|
+
return { ok: false, missing };
|
|
67
|
+
const workspaceId = trimmed(env.ANTHROPIC_WORKSPACE_ID);
|
|
68
|
+
return {
|
|
69
|
+
ok: true,
|
|
70
|
+
settings: {
|
|
71
|
+
federationRuleId: trimmed(env.ANTHROPIC_FEDERATION_RULE_ID),
|
|
72
|
+
organizationId: trimmed(env.ANTHROPIC_ORGANIZATION_ID),
|
|
73
|
+
serviceAccountId: trimmed(env.ANTHROPIC_SERVICE_ACCOUNT_ID),
|
|
74
|
+
...(workspaceId ? { workspaceId } : {}),
|
|
75
|
+
// The assertion posted to this host is a signed identity token, so
|
|
76
|
+
// where it goes is worth naming deliberately. ANTHROPIC_BASE_URL is
|
|
77
|
+
// honoured because it is the conventional override and a worker
|
|
78
|
+
// that sets it means it — but a deployment that points that at a
|
|
79
|
+
// gateway for unrelated reasons can pin the exchange back with
|
|
80
|
+
// ANTHROPIC_WIF_TOKEN_URL.
|
|
81
|
+
baseUrl: (trimmed(env.ANTHROPIC_WIF_TOKEN_URL)
|
|
82
|
+
|| trimmed(env.ANTHROPIC_BASE_URL)
|
|
83
|
+
|| DEFAULT_BASE_URL).replace(/\/+$/, ""),
|
|
84
|
+
identity,
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* A ready-made assertion wins over one that has to be fetched: a deployment
|
|
90
|
+
* that sets `ANTHROPIC_IDENTITY_TOKEN_FILE` has said which token it means,
|
|
91
|
+
* and Azure's own variables may be present on the same pod for unrelated
|
|
92
|
+
* reasons (a sidecar, a storage credential) without being the intended path.
|
|
93
|
+
*/
|
|
94
|
+
function readIdentitySource(env) {
|
|
95
|
+
const literal = trimmed(env.ANTHROPIC_IDENTITY_TOKEN);
|
|
96
|
+
if (literal)
|
|
97
|
+
return { kind: "literal", token: literal };
|
|
98
|
+
const file = trimmed(env.ANTHROPIC_IDENTITY_TOKEN_FILE);
|
|
99
|
+
if (file)
|
|
100
|
+
return { kind: "file", path: file };
|
|
101
|
+
const azureFile = trimmed(env.AZURE_FEDERATED_TOKEN_FILE);
|
|
102
|
+
const tenantId = trimmed(env.AZURE_TENANT_ID);
|
|
103
|
+
if (!azureFile || !tenantId)
|
|
104
|
+
return null;
|
|
105
|
+
// The identity to claim is not always the one the platform injected: a
|
|
106
|
+
// pod may run under its cluster's own identity while the federation rule
|
|
107
|
+
// names another that the same projected token is allowed to redeem. So an
|
|
108
|
+
// explicit override wins, and the injected value is only the default.
|
|
109
|
+
const clientId = trimmed(env.ANTHROPIC_WIF_AZURE_CLIENT_ID) || trimmed(env.AZURE_CLIENT_ID);
|
|
110
|
+
if (!clientId)
|
|
111
|
+
return null;
|
|
112
|
+
// The audience asked for. Defaulting to the identity's own id covers a
|
|
113
|
+
// rule that matches the identity as its own audience; a deployment with a
|
|
114
|
+
// separate audience app registration sets the scope explicitly.
|
|
115
|
+
const scope = trimmed(env.ANTHROPIC_WIF_AZURE_SCOPE) || `${clientId}/.default`;
|
|
116
|
+
return { kind: "entra", tokenFile: azureFile, tenantId, clientId, scope };
|
|
117
|
+
}
|
|
118
|
+
/** Anything a provider type may declare that authenticates without a stored key. */
|
|
119
|
+
export class WifExchangeError extends Error {
|
|
120
|
+
status;
|
|
121
|
+
requestId;
|
|
122
|
+
code = "WIF_EXCHANGE_FAILED";
|
|
123
|
+
constructor(message, status, requestId) {
|
|
124
|
+
super(message);
|
|
125
|
+
this.status = status;
|
|
126
|
+
this.requestId = requestId;
|
|
127
|
+
this.name = "WifExchangeError";
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* How early a token is replaced. A token used at the instant it expires is a
|
|
132
|
+
* failed request: the clock on the far side is not this one, and the request
|
|
133
|
+
* still has to travel. Half the lifetime is the ceiling so that a deliberately
|
|
134
|
+
* short-lived token (the rule may set 60 seconds) is still cached for a while
|
|
135
|
+
* rather than re-minted for every single request.
|
|
136
|
+
*/
|
|
137
|
+
const REFRESH_MARGIN_MS = 5 * 60_000;
|
|
138
|
+
function marginFor(lifetimeMs) {
|
|
139
|
+
return Math.min(REFRESH_MARGIN_MS, Math.max(0, Math.floor(lifetimeMs / 2)));
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* What a lifetime is assumed to be when the response does not say.
|
|
143
|
+
*
|
|
144
|
+
* `expires_in` is optional in the type and could arrive absent, zero, or
|
|
145
|
+
* unparseable. Treating that as "expires now" silently turns the cache OFF —
|
|
146
|
+
* and because the callback runs before EVERY outbound request, that is one
|
|
147
|
+
* token exchange per LLM request, for ever, until the endpoint throttles.
|
|
148
|
+
* A minute is the shortest lifetime a federation rule may be configured for,
|
|
149
|
+
* so assuming it can never outlive the real token.
|
|
150
|
+
*/
|
|
151
|
+
const ASSUMED_LIFETIME_MS = 60_000;
|
|
152
|
+
/**
|
|
153
|
+
* The longest a token is trusted, however long it says it is valid.
|
|
154
|
+
*
|
|
155
|
+
* Nothing tells this process that a token was revoked: the rule is disabled or
|
|
156
|
+
* the service account deleted, and the only symptom is that requests start
|
|
157
|
+
* failing. A token cached for its full 24 hours would keep failing for 24
|
|
158
|
+
* hours. Re-minting hourly costs one exchange per worker per hour and bounds
|
|
159
|
+
* how long a revoked credential can keep a worker down.
|
|
160
|
+
*/
|
|
161
|
+
const MAX_CACHE_MS = 60 * 60_000;
|
|
162
|
+
/** When to replace a token, from whatever the endpoint claimed. */
|
|
163
|
+
function expiryFrom(now, expiresIn) {
|
|
164
|
+
const seconds = Number(expiresIn);
|
|
165
|
+
const claimed = Number.isFinite(seconds) && seconds > 0 ? seconds * 1000 : ASSUMED_LIFETIME_MS;
|
|
166
|
+
const lifetimeMs = Math.min(claimed, MAX_CACHE_MS);
|
|
167
|
+
return now + Math.max(0, lifetimeMs - marginFor(lifetimeMs));
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Mints and caches the Anthropic access token for one set of settings.
|
|
171
|
+
*
|
|
172
|
+
* One instance serves every session on the worker. The callback is invoked
|
|
173
|
+
* once per outbound request — several turns running at once is the normal
|
|
174
|
+
* case, not the exception — so concurrent callers share a single exchange
|
|
175
|
+
* rather than each starting their own. A failure is never cached: the next
|
|
176
|
+
* request tries again, which is what recovers a worker that started before
|
|
177
|
+
* its token file was mounted.
|
|
178
|
+
*/
|
|
179
|
+
export class AnthropicWifCredentials {
|
|
180
|
+
settings;
|
|
181
|
+
access = null;
|
|
182
|
+
assertion = null;
|
|
183
|
+
inflight = null;
|
|
184
|
+
/** Bumped by reset(), so a mint that started earlier does not store its result. */
|
|
185
|
+
generation = 0;
|
|
186
|
+
fetchImpl;
|
|
187
|
+
readFileImpl;
|
|
188
|
+
now;
|
|
189
|
+
constructor(settings, deps = {}) {
|
|
190
|
+
this.settings = settings;
|
|
191
|
+
this.fetchImpl = deps.fetch ?? globalThis.fetch;
|
|
192
|
+
this.readFileImpl = deps.readFile ?? (async (p) => {
|
|
193
|
+
const { readFile } = await import("node:fs/promises");
|
|
194
|
+
return readFile(p, "utf8");
|
|
195
|
+
});
|
|
196
|
+
this.now = deps.now ?? Date.now;
|
|
197
|
+
}
|
|
198
|
+
/** A valid Anthropic access token, minted or from cache. */
|
|
199
|
+
async getToken() {
|
|
200
|
+
const cached = this.access;
|
|
201
|
+
if (cached && this.now() < cached.expiresAtMs)
|
|
202
|
+
return cached.token;
|
|
203
|
+
if (this.inflight)
|
|
204
|
+
return this.inflight;
|
|
205
|
+
const startedIn = this.generation;
|
|
206
|
+
const run = this.mint()
|
|
207
|
+
.then((minted) => {
|
|
208
|
+
// Discarded by a reset() that landed while this was in flight:
|
|
209
|
+
// the token is still returned to whoever asked for it, but it
|
|
210
|
+
// is not written into a cache that was deliberately emptied.
|
|
211
|
+
if (this.generation === startedIn)
|
|
212
|
+
this.access = minted;
|
|
213
|
+
return minted.token;
|
|
214
|
+
})
|
|
215
|
+
.finally(() => {
|
|
216
|
+
if (this.generation === startedIn)
|
|
217
|
+
this.inflight = null;
|
|
218
|
+
});
|
|
219
|
+
this.inflight = run;
|
|
220
|
+
return run;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Drop what is cached. For tests, and for a caller that saw a 401.
|
|
224
|
+
*
|
|
225
|
+
* The generation bump is the point. Clearing the fields alone does not
|
|
226
|
+
* work while an exchange is in flight: that exchange resolves afterwards
|
|
227
|
+
* and writes the very token this was called to discard straight back into
|
|
228
|
+
* the cache. A mint only stores its result if the generation it started
|
|
229
|
+
* in is still current.
|
|
230
|
+
*/
|
|
231
|
+
reset() {
|
|
232
|
+
this.access = null;
|
|
233
|
+
this.assertion = null;
|
|
234
|
+
this.generation += 1;
|
|
235
|
+
this.inflight = null;
|
|
236
|
+
}
|
|
237
|
+
async mint() {
|
|
238
|
+
const assertion = await this.identityToken();
|
|
239
|
+
const body = {
|
|
240
|
+
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
241
|
+
assertion,
|
|
242
|
+
federation_rule_id: this.settings.federationRuleId,
|
|
243
|
+
organization_id: this.settings.organizationId,
|
|
244
|
+
service_account_id: this.settings.serviceAccountId,
|
|
245
|
+
};
|
|
246
|
+
// Sending an empty workspace is not the same as not naming one: the
|
|
247
|
+
// exchange validates the shape of the value it is given.
|
|
248
|
+
if (this.settings.workspaceId)
|
|
249
|
+
body.workspace_id = this.settings.workspaceId;
|
|
250
|
+
const response = await this.fetchImpl(`${this.settings.baseUrl}/v1/oauth/token`, {
|
|
251
|
+
method: "POST",
|
|
252
|
+
headers: { "content-type": "application/json" },
|
|
253
|
+
body: JSON.stringify(body),
|
|
254
|
+
});
|
|
255
|
+
if (!response.ok) {
|
|
256
|
+
// Throw the cached assertion away with it. That token is what was
|
|
257
|
+
// just refused, and it may be cached for hours — without this a
|
|
258
|
+
// retrying worker keeps presenting the same rejected assertion
|
|
259
|
+
// until it expires on its own.
|
|
260
|
+
this.assertion = null;
|
|
261
|
+
// Every denial is the same opaque 401 with the same sentence —
|
|
262
|
+
// which check failed is recorded against the request id in the
|
|
263
|
+
// Anthropic console's authentication history, and is unknowable
|
|
264
|
+
// from here. Carrying the id is the difference between a
|
|
265
|
+
// diagnosable failure and a shrug.
|
|
266
|
+
const requestId = response.headers?.get?.("request-id") ?? null;
|
|
267
|
+
throw new WifExchangeError(`Anthropic token exchange failed with HTTP ${response.status}`
|
|
268
|
+
+ `${requestId ? ` (request id ${requestId})` : ""}.`
|
|
269
|
+
+ " Check the authentication history in the Anthropic console for the reason.", response.status, requestId);
|
|
270
|
+
}
|
|
271
|
+
// Guarded like the Entra hop: a 200 carrying something that is not
|
|
272
|
+
// JSON (an intercepting proxy, an HTML error page) must still surface
|
|
273
|
+
// as a WifExchangeError with the guidance below, not a raw SyntaxError.
|
|
274
|
+
const payload = await response.json().catch(() => ({}));
|
|
275
|
+
const token = typeof payload.access_token === "string" ? payload.access_token : "";
|
|
276
|
+
if (!token) {
|
|
277
|
+
throw new WifExchangeError("Anthropic token exchange returned no access_token.", response.status);
|
|
278
|
+
}
|
|
279
|
+
return { token, expiresAtMs: expiryFrom(this.now(), payload.expires_in) };
|
|
280
|
+
}
|
|
281
|
+
/** The JWT presented to Anthropic as the assertion. */
|
|
282
|
+
async identityToken() {
|
|
283
|
+
const source = this.settings.identity;
|
|
284
|
+
if (source.kind === "literal")
|
|
285
|
+
return source.token;
|
|
286
|
+
if (source.kind === "file")
|
|
287
|
+
return (await this.readFileImpl(source.path)).trim();
|
|
288
|
+
const cached = this.assertion;
|
|
289
|
+
if (cached && this.now() < cached.expiresAtMs)
|
|
290
|
+
return cached.token;
|
|
291
|
+
const minted = await this.entraToken(source);
|
|
292
|
+
this.assertion = minted;
|
|
293
|
+
return minted.token;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Redeem the Kubernetes-projected token for an Entra-issued one.
|
|
297
|
+
*
|
|
298
|
+
* The projected token is read fresh every time: Kubernetes rewrites that
|
|
299
|
+
* file as it rotates, and the copy this process read at startup stops
|
|
300
|
+
* verifying the moment it does.
|
|
301
|
+
*/
|
|
302
|
+
async entraToken(source) {
|
|
303
|
+
const projected = (await this.readFileImpl(source.tokenFile)).trim();
|
|
304
|
+
const form = new URLSearchParams({
|
|
305
|
+
grant_type: "client_credentials",
|
|
306
|
+
client_id: source.clientId,
|
|
307
|
+
scope: source.scope,
|
|
308
|
+
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
|
|
309
|
+
client_assertion: projected,
|
|
310
|
+
});
|
|
311
|
+
const response = await this.fetchImpl(`https://login.microsoftonline.com/${encodeURIComponent(source.tenantId)}/oauth2/v2.0/token`, {
|
|
312
|
+
method: "POST",
|
|
313
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
314
|
+
body: form.toString(),
|
|
315
|
+
});
|
|
316
|
+
const payload = await response.json().catch(() => ({}));
|
|
317
|
+
if (!response.ok || !payload.access_token) {
|
|
318
|
+
// Entra says exactly what is wrong (a missing audience app, an
|
|
319
|
+
// unfederated service account), and its first line is the useful
|
|
320
|
+
// one — the rest is a stack of correlation ids.
|
|
321
|
+
const detail = String(payload.error_description ?? payload.error ?? "").split("\n")[0];
|
|
322
|
+
throw new WifExchangeError(`Microsoft Entra token request failed with HTTP ${response.status}${detail ? `: ${detail}` : "."}`, response.status);
|
|
323
|
+
}
|
|
324
|
+
return { token: payload.access_token, expiresAtMs: expiryFrom(this.now(), payload.expires_in) };
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* The worker's own credentials, made once and shared.
|
|
329
|
+
*
|
|
330
|
+
* Keyed by the settings themselves so that a test which changes the
|
|
331
|
+
* environment gets a fresh instance, while every session in a running worker
|
|
332
|
+
* shares one cache and one in-flight exchange.
|
|
333
|
+
*/
|
|
334
|
+
const instances = new Map();
|
|
335
|
+
export function anthropicWifCredentials(settings, deps = {}) {
|
|
336
|
+
const key = JSON.stringify(settings);
|
|
337
|
+
let found = instances.get(key);
|
|
338
|
+
if (!found) {
|
|
339
|
+
found = new AnthropicWifCredentials(settings, deps);
|
|
340
|
+
instances.set(key, found);
|
|
341
|
+
}
|
|
342
|
+
return found;
|
|
343
|
+
}
|
|
344
|
+
/** Forget every shared instance. Tests only. */
|
|
345
|
+
export function resetAnthropicWifCredentials() {
|
|
346
|
+
instances.clear();
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Give a workload-identity provider the callback that authenticates it.
|
|
350
|
+
*
|
|
351
|
+
* Every other provider reaches the Copilot SDK carrying its own key. This one
|
|
352
|
+
* carries a function, because the token it would carry instead expires long
|
|
353
|
+
* before the session does — a session resumed days later on another worker
|
|
354
|
+
* would come back with a dead credential baked into its config. The SDK keeps
|
|
355
|
+
* the callback client-side and asks for a token before each outbound request,
|
|
356
|
+
* so a token lives only as long as the call it authenticates.
|
|
357
|
+
*
|
|
358
|
+
* Called on the path that builds the SDK options and nowhere earlier: that
|
|
359
|
+
* object is rebuilt from the registry on every create and resume, and is
|
|
360
|
+
* never persisted. (`providerFingerprint` hashes the same object through
|
|
361
|
+
* JSON.stringify, which drops function-valued keys, so the fingerprint stays
|
|
362
|
+
* stable and a resume does not read as a provider change.)
|
|
363
|
+
*
|
|
364
|
+
* A provider that is not workload-identity is returned untouched, by
|
|
365
|
+
* identity, so this is safe to call on the whole path.
|
|
366
|
+
*/
|
|
367
|
+
export function attachWorkloadIdentity(resolved, deps = {}) {
|
|
368
|
+
const provider = resolved.sdkProvider;
|
|
369
|
+
if (!resolved.usesWorkloadIdentity)
|
|
370
|
+
return provider;
|
|
371
|
+
// Said once at session creation, naming the variables that are absent,
|
|
372
|
+
// rather than as an opaque 401 on the first turn of every session that
|
|
373
|
+
// ever names this provider.
|
|
374
|
+
const found = readAnthropicWifSettings(deps.env ?? process.env);
|
|
375
|
+
if (!found.ok) {
|
|
376
|
+
throw new Error(`Provider "${resolved.providerId}" authenticates with workload identity, `
|
|
377
|
+
+ `but the worker is missing ${found.missing.join(", ")}.`);
|
|
378
|
+
}
|
|
379
|
+
const credentials = (deps.credentials ?? anthropicWifCredentials)(found.settings);
|
|
380
|
+
return { ...provider, bearerTokenProvider: () => credentials.getToken() };
|
|
381
|
+
}
|
|
382
|
+
//# sourceMappingURL=wif-credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wif-credentials.js","sourceRoot":"","sources":["../src/wif-credentials.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pilotswarm-sdk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.49",
|
|
4
4
|
"description": "A durable execution runtime for GitHub Copilot SDK agents. Crash recovery, durable timers, session dehydration, and multi-node scaling — powered by duroxide.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"pg": "^8.18.0"
|
|
89
89
|
},
|
|
90
90
|
"peerDependencies": {
|
|
91
|
-
"pilotswarm-horizon-store": "0.5.
|
|
91
|
+
"pilotswarm-horizon-store": "0.5.49"
|
|
92
92
|
},
|
|
93
93
|
"peerDependenciesMeta": {
|
|
94
94
|
"pilotswarm-horizon-store": {
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"devDependencies": {
|
|
99
99
|
"@types/node": "^22.0.0",
|
|
100
100
|
"@types/pg": "^8.16.0",
|
|
101
|
-
"pilotswarm-horizon-store": "0.5.
|
|
101
|
+
"pilotswarm-horizon-store": "0.5.49",
|
|
102
102
|
"typescript": "^5.0.0",
|
|
103
103
|
"vitest": "^4.1.0"
|
|
104
104
|
},
|