agentfootprint 6.21.0 → 6.22.0
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/adapters/identity/agentcore.js +54 -8
- package/dist/adapters/identity/agentcore.js.map +1 -1
- package/dist/esm/adapters/identity/agentcore.js +54 -8
- package/dist/esm/adapters/identity/agentcore.js.map +1 -1
- package/dist/esm/identity/withCredentialRetry.js +98 -0
- package/dist/esm/identity/withCredentialRetry.js.map +1 -0
- package/dist/esm/identity.js +1 -0
- package/dist/esm/identity.js.map +1 -1
- package/dist/esm/resilience/withRetry.js +6 -1
- package/dist/esm/resilience/withRetry.js.map +1 -1
- package/dist/identity/withCredentialRetry.js +102 -0
- package/dist/identity/withCredentialRetry.js.map +1 -0
- package/dist/identity.js +3 -1
- package/dist/identity.js.map +1 -1
- package/dist/resilience/withRetry.js +7 -1
- package/dist/resilience/withRetry.js.map +1 -1
- package/dist/types/adapters/identity/agentcore.d.ts +46 -2
- package/dist/types/adapters/identity/agentcore.d.ts.map +1 -1
- package/dist/types/identity/withCredentialRetry.d.ts +65 -0
- package/dist/types/identity/withCredentialRetry.d.ts.map +1 -0
- package/dist/types/identity.d.ts +1 -0
- package/dist/types/identity.d.ts.map +1 -1
- package/dist/types/resilience/withRetry.d.ts +18 -3
- package/dist/types/resilience/withRetry.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -10,12 +10,30 @@
|
|
|
10
10
|
* `GetResourceOauth2Token` (the SDK's `@requires_access_token` underneath):
|
|
11
11
|
* - request.mode 'machine' → `M2M`; 'user' → `USER_FEDERATION`
|
|
12
12
|
* - request.service → the configured OAuth2 credential-provider name
|
|
13
|
+
* - request.identity → (per-request workload identity scoping; see below)
|
|
13
14
|
* - a returned access token → `{ status: 'issued', credential: bearer(token) }`
|
|
14
15
|
* - a returned auth URL → `{ status: 'authorization-required' }` (3LO consent)
|
|
15
16
|
*
|
|
16
17
|
* The token vault + refresh-token handling live in AgentCore, so repeat calls
|
|
17
18
|
* usually return a token directly (no consent round-trip).
|
|
18
19
|
*
|
|
20
|
+
* **Per-request identity forwarding (workload identity scoping).**
|
|
21
|
+
* `GetResourceOauth2Token` carries NO user/tenant field — in AgentCore the
|
|
22
|
+
* user identity is bound EARLIER, at workload-token acquisition:
|
|
23
|
+
* `GetWorkloadAccessTokenForUserId(workloadName, userId)` returns a workload
|
|
24
|
+
* access token scoped to that user, and AgentCore keys its token vault + 3LO
|
|
25
|
+
* grants per (workload, user). So this adapter forwards `req.identity` (the
|
|
26
|
+
* `runIdentity` that the agent threads through `getCredential`) by resolving a
|
|
27
|
+
* per-user workload token first, then vending with it. Engages only when ALL of:
|
|
28
|
+
* - `req.mode === 'user'` (USER_FEDERATION — M2M is the workload's own identity),
|
|
29
|
+
* - a userId derives from `req.identity` (default `identity.principal`;
|
|
30
|
+
* override via `userIdFor`), and
|
|
31
|
+
* - `options.workloadName` is configured (the opt-in).
|
|
32
|
+
* Otherwise the static `options.workloadIdentityToken` flows exactly as before.
|
|
33
|
+
* `tenant` has no native AgentCore field and is NOT forwarded by default —
|
|
34
|
+
* tenant isolation derives from the workload identity itself (per-tenant
|
|
35
|
+
* workloads), or encode it via `userIdFor` (e.g. `${tenant}:${principal}`).
|
|
36
|
+
*
|
|
19
37
|
* Pattern: Adapter (GoF) + lazy peer-dep load — the AWS SDK is required only when
|
|
20
38
|
* `getCredential` first runs (or never, if you inject `_client`). NOTE: confirm
|
|
21
39
|
* the SDK command/field names against your installed
|
|
@@ -44,28 +62,56 @@ function resolveClient(options) {
|
|
|
44
62
|
}
|
|
45
63
|
return {
|
|
46
64
|
getResourceOauth2Token: (input) => client.getResourceOauth2Token(input),
|
|
65
|
+
// Duck-typed like the primary call — only wired when the SDK exposes it
|
|
66
|
+
// (used only when `workloadName` is configured).
|
|
67
|
+
...(typeof client.getWorkloadAccessTokenForUserId === 'function' && {
|
|
68
|
+
getWorkloadAccessTokenForUserId: (input) => client.getWorkloadAccessTokenForUserId(input),
|
|
69
|
+
}),
|
|
47
70
|
};
|
|
48
71
|
}
|
|
72
|
+
const defaultUserIdFor = (identity) => identity.principal;
|
|
49
73
|
/** Build a {@link CredentialProvider} backed by AWS Bedrock AgentCore Identity. */
|
|
50
74
|
function agentCoreIdentity(options = {}) {
|
|
51
75
|
let client;
|
|
52
76
|
const getClient = () => (client ??= resolveClient(options));
|
|
77
|
+
const userIdFor = options.userIdFor ?? defaultUserIdFor;
|
|
78
|
+
// Per-request identity forwarding (workload identity scoping) — see module
|
|
79
|
+
// header. `GetResourceOauth2Token` has no user field; the user is bound at
|
|
80
|
+
// workload-token acquisition, so a `mode: 'user'` request carrying an
|
|
81
|
+
// identity exchanges (workloadName, userId) for a USER-SCOPED workload token
|
|
82
|
+
// and vends with that. Requires `workloadName` (the opt-in); without it the
|
|
83
|
+
// static `workloadIdentityToken` flows unchanged (pre-forwarding behavior).
|
|
84
|
+
const resolveWorkloadToken = async (req) => {
|
|
85
|
+
const userId = req.mode === 'user' && req.identity !== undefined ? userIdFor(req.identity) : undefined;
|
|
86
|
+
if (userId === undefined || !options.workloadName)
|
|
87
|
+
return options.workloadIdentityToken;
|
|
88
|
+
const c = getClient();
|
|
89
|
+
if (typeof c.getWorkloadAccessTokenForUserId !== 'function') {
|
|
90
|
+
// Explicit config must not silently degrade to workload-level tokens.
|
|
91
|
+
throw new Error('agentCoreIdentity: `workloadName` is configured for per-user workload scoping, ' +
|
|
92
|
+
'but the client has no getWorkloadAccessTokenForUserId. Confirm the ' +
|
|
93
|
+
'@aws-sdk/client-bedrock-agentcore version, or pass `_client`.');
|
|
94
|
+
}
|
|
95
|
+
const res = await c.getWorkloadAccessTokenForUserId({
|
|
96
|
+
workloadName: options.workloadName,
|
|
97
|
+
userId,
|
|
98
|
+
});
|
|
99
|
+
if (!res.workloadAccessToken) {
|
|
100
|
+
throw new Error('agentCoreIdentity: GetWorkloadAccessTokenForUserId returned no workloadAccessToken ' +
|
|
101
|
+
'for per-user scoped vending.');
|
|
102
|
+
}
|
|
103
|
+
return res.workloadAccessToken;
|
|
104
|
+
};
|
|
53
105
|
return {
|
|
54
106
|
id: options.id ?? 'agentcore-identity',
|
|
55
107
|
async getCredential(req) {
|
|
56
|
-
|
|
57
|
-
// yet — tenant isolation here derives solely from `workloadIdentityToken`
|
|
58
|
-
// (the AgentCore-injected workload identity). Don't assume the threaded
|
|
59
|
-
// principal/tenant is enforced at the IdP until a future release maps it
|
|
60
|
-
// onto the user-federation subject.
|
|
108
|
+
const workloadIdentityToken = await resolveWorkloadToken(req);
|
|
61
109
|
const res = await getClient().getResourceOauth2Token({
|
|
62
110
|
resourceCredentialProviderName: req.service,
|
|
63
111
|
scopes: req.scopes ?? [],
|
|
64
112
|
oauth2Flow: req.mode === 'user' ? 'USER_FEDERATION' : 'M2M',
|
|
65
113
|
forceAuthentication: req.forceReauth ?? false,
|
|
66
|
-
...(
|
|
67
|
-
workloadIdentityToken: options.workloadIdentityToken,
|
|
68
|
-
}),
|
|
114
|
+
...(workloadIdentityToken && { workloadIdentityToken }),
|
|
69
115
|
});
|
|
70
116
|
if (res.accessToken) {
|
|
71
117
|
// AgentCore Identity vends OAuth access tokens → a bearer credential.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentcore.js","sourceRoot":"","sources":["../../../src/adapters/identity/agentcore.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"agentcore.js","sourceRoot":"","sources":["../../../src/adapters/identity/agentcore.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;;;AAEH,6DAAuD;AAMvD,sDAAiD;AA0DjD,SAAS,aAAa,CAAC,OAAiC;IACtD,IAAI,OAAO,CAAC,OAAO;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC;IAC5C,iFAAiF;IACjF,MAAM,GAAG,GAAG,IAAA,4BAAW,EAA0B,mCAAmC,CAAC,CAAC;IACtF,MAAM,IAAI,GAAG,GAAG,CAAC,sBAEJ,CAAC;IACd,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACb,8FAA8F;YAC5F,sEAAsE,CACzE,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,CAG5E,CAAC;IACF,IAAI,OAAO,MAAM,CAAC,sBAAsB,KAAK,UAAU,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CACb,+EAA+E;YAC7E,+DAA+D,CAClE,CAAC;IACJ,CAAC;IACD,OAAO;QACL,sBAAsB,EAAE,CAAC,KAAK,EAAE,EAAE,CAChC,MAAM,CAAC,sBAAuB,CAAC,KAAK,CAAoC;QAC1E,wEAAwE;QACxE,iDAAiD;QACjD,GAAG,CAAC,OAAO,MAAM,CAAC,+BAA+B,KAAK,UAAU,IAAI;YAClE,+BAA+B,EAAE,CAAC,KAA+C,EAAE,EAAE,CACnF,MAAM,CAAC,+BAAgC,CAAC,KAAK,CAAC;SACjD,CAAC;KACH,CAAC;AACJ,CAAC;AAED,MAAM,gBAAgB,GAAG,CAAC,QAAyC,EAAsB,EAAE,CACzF,QAAQ,CAAC,SAAS,CAAC;AAErB,mFAAmF;AACnF,SAAgB,iBAAiB,CAAC,UAAoC,EAAE;IACtE,IAAI,MAA+C,CAAC;IACpD,MAAM,SAAS,GAAG,GAAgC,EAAE,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IACzF,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,gBAAgB,CAAC;IAExD,2EAA2E;IAC3E,2EAA2E;IAC3E,sEAAsE;IACtE,6EAA6E;IAC7E,4EAA4E;IAC5E,4EAA4E;IAC5E,MAAM,oBAAoB,GAAG,KAAK,EAAE,GAAsB,EAA+B,EAAE;QACzF,MAAM,MAAM,GACV,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1F,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,YAAY;YAAE,OAAO,OAAO,CAAC,qBAAqB,CAAC;QAExF,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;QACtB,IAAI,OAAO,CAAC,CAAC,+BAA+B,KAAK,UAAU,EAAE,CAAC;YAC5D,sEAAsE;YACtE,MAAM,IAAI,KAAK,CACb,iFAAiF;gBAC/E,qEAAqE;gBACrE,+DAA+D,CAClE,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,+BAA+B,CAAC;YAClD,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,MAAM;SACP,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CACb,qFAAqF;gBACnF,8BAA8B,CACjC,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,CAAC,mBAAmB,CAAC;IACjC,CAAC,CAAC;IAEF,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,oBAAoB;QACtC,KAAK,CAAC,aAAa,CAAC,GAAsB;YACxC,MAAM,qBAAqB,GAAG,MAAM,oBAAoB,CAAC,GAAG,CAAC,CAAC;YAC9D,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,sBAAsB,CAAC;gBACnD,8BAA8B,EAAE,GAAG,CAAC,OAAO;gBAC3C,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE;gBACxB,UAAU,EAAE,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,KAAK;gBAC3D,mBAAmB,EAAE,GAAG,CAAC,WAAW,IAAI,KAAK;gBAC7C,GAAG,CAAC,qBAAqB,IAAI,EAAE,qBAAqB,EAAE,CAAC;aACxD,CAAC,CAAC;YAEH,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;gBACpB,sEAAsE;gBACtE,OAAO;oBACL,MAAM,EAAE,QAAQ;oBAChB,UAAU,EAAE,IAAA,iBAAM,EAAC,GAAG,CAAC,WAAW,CAAC;oBACnC,GAAG,CAAC,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;iBACjE,CAAC;YACJ,CAAC;YACD,IAAI,GAAG,CAAC,gBAAgB,EAAE,CAAC;gBACzB,OAAO;oBACL,MAAM,EAAE,wBAAwB;oBAChC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;oBACtC,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE;iBAC/B,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,KAAK,CACb,kDAAkD,GAAG,CAAC,OAAO,qBAAqB;gBAChF,2CAA2C,CAC9C,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAvED,8CAuEC"}
|
|
@@ -9,12 +9,30 @@
|
|
|
9
9
|
* `GetResourceOauth2Token` (the SDK's `@requires_access_token` underneath):
|
|
10
10
|
* - request.mode 'machine' → `M2M`; 'user' → `USER_FEDERATION`
|
|
11
11
|
* - request.service → the configured OAuth2 credential-provider name
|
|
12
|
+
* - request.identity → (per-request workload identity scoping; see below)
|
|
12
13
|
* - a returned access token → `{ status: 'issued', credential: bearer(token) }`
|
|
13
14
|
* - a returned auth URL → `{ status: 'authorization-required' }` (3LO consent)
|
|
14
15
|
*
|
|
15
16
|
* The token vault + refresh-token handling live in AgentCore, so repeat calls
|
|
16
17
|
* usually return a token directly (no consent round-trip).
|
|
17
18
|
*
|
|
19
|
+
* **Per-request identity forwarding (workload identity scoping).**
|
|
20
|
+
* `GetResourceOauth2Token` carries NO user/tenant field — in AgentCore the
|
|
21
|
+
* user identity is bound EARLIER, at workload-token acquisition:
|
|
22
|
+
* `GetWorkloadAccessTokenForUserId(workloadName, userId)` returns a workload
|
|
23
|
+
* access token scoped to that user, and AgentCore keys its token vault + 3LO
|
|
24
|
+
* grants per (workload, user). So this adapter forwards `req.identity` (the
|
|
25
|
+
* `runIdentity` that the agent threads through `getCredential`) by resolving a
|
|
26
|
+
* per-user workload token first, then vending with it. Engages only when ALL of:
|
|
27
|
+
* - `req.mode === 'user'` (USER_FEDERATION — M2M is the workload's own identity),
|
|
28
|
+
* - a userId derives from `req.identity` (default `identity.principal`;
|
|
29
|
+
* override via `userIdFor`), and
|
|
30
|
+
* - `options.workloadName` is configured (the opt-in).
|
|
31
|
+
* Otherwise the static `options.workloadIdentityToken` flows exactly as before.
|
|
32
|
+
* `tenant` has no native AgentCore field and is NOT forwarded by default —
|
|
33
|
+
* tenant isolation derives from the workload identity itself (per-tenant
|
|
34
|
+
* workloads), or encode it via `userIdFor` (e.g. `${tenant}:${principal}`).
|
|
35
|
+
*
|
|
18
36
|
* Pattern: Adapter (GoF) + lazy peer-dep load — the AWS SDK is required only when
|
|
19
37
|
* `getCredential` first runs (or never, if you inject `_client`). NOTE: confirm
|
|
20
38
|
* the SDK command/field names against your installed
|
|
@@ -41,28 +59,56 @@ function resolveClient(options) {
|
|
|
41
59
|
}
|
|
42
60
|
return {
|
|
43
61
|
getResourceOauth2Token: (input) => client.getResourceOauth2Token(input),
|
|
62
|
+
// Duck-typed like the primary call — only wired when the SDK exposes it
|
|
63
|
+
// (used only when `workloadName` is configured).
|
|
64
|
+
...(typeof client.getWorkloadAccessTokenForUserId === 'function' && {
|
|
65
|
+
getWorkloadAccessTokenForUserId: (input) => client.getWorkloadAccessTokenForUserId(input),
|
|
66
|
+
}),
|
|
44
67
|
};
|
|
45
68
|
}
|
|
69
|
+
const defaultUserIdFor = (identity) => identity.principal;
|
|
46
70
|
/** Build a {@link CredentialProvider} backed by AWS Bedrock AgentCore Identity. */
|
|
47
71
|
export function agentCoreIdentity(options = {}) {
|
|
48
72
|
let client;
|
|
49
73
|
const getClient = () => (client ??= resolveClient(options));
|
|
74
|
+
const userIdFor = options.userIdFor ?? defaultUserIdFor;
|
|
75
|
+
// Per-request identity forwarding (workload identity scoping) — see module
|
|
76
|
+
// header. `GetResourceOauth2Token` has no user field; the user is bound at
|
|
77
|
+
// workload-token acquisition, so a `mode: 'user'` request carrying an
|
|
78
|
+
// identity exchanges (workloadName, userId) for a USER-SCOPED workload token
|
|
79
|
+
// and vends with that. Requires `workloadName` (the opt-in); without it the
|
|
80
|
+
// static `workloadIdentityToken` flows unchanged (pre-forwarding behavior).
|
|
81
|
+
const resolveWorkloadToken = async (req) => {
|
|
82
|
+
const userId = req.mode === 'user' && req.identity !== undefined ? userIdFor(req.identity) : undefined;
|
|
83
|
+
if (userId === undefined || !options.workloadName)
|
|
84
|
+
return options.workloadIdentityToken;
|
|
85
|
+
const c = getClient();
|
|
86
|
+
if (typeof c.getWorkloadAccessTokenForUserId !== 'function') {
|
|
87
|
+
// Explicit config must not silently degrade to workload-level tokens.
|
|
88
|
+
throw new Error('agentCoreIdentity: `workloadName` is configured for per-user workload scoping, ' +
|
|
89
|
+
'but the client has no getWorkloadAccessTokenForUserId. Confirm the ' +
|
|
90
|
+
'@aws-sdk/client-bedrock-agentcore version, or pass `_client`.');
|
|
91
|
+
}
|
|
92
|
+
const res = await c.getWorkloadAccessTokenForUserId({
|
|
93
|
+
workloadName: options.workloadName,
|
|
94
|
+
userId,
|
|
95
|
+
});
|
|
96
|
+
if (!res.workloadAccessToken) {
|
|
97
|
+
throw new Error('agentCoreIdentity: GetWorkloadAccessTokenForUserId returned no workloadAccessToken ' +
|
|
98
|
+
'for per-user scoped vending.');
|
|
99
|
+
}
|
|
100
|
+
return res.workloadAccessToken;
|
|
101
|
+
};
|
|
50
102
|
return {
|
|
51
103
|
id: options.id ?? 'agentcore-identity',
|
|
52
104
|
async getCredential(req) {
|
|
53
|
-
|
|
54
|
-
// yet — tenant isolation here derives solely from `workloadIdentityToken`
|
|
55
|
-
// (the AgentCore-injected workload identity). Don't assume the threaded
|
|
56
|
-
// principal/tenant is enforced at the IdP until a future release maps it
|
|
57
|
-
// onto the user-federation subject.
|
|
105
|
+
const workloadIdentityToken = await resolveWorkloadToken(req);
|
|
58
106
|
const res = await getClient().getResourceOauth2Token({
|
|
59
107
|
resourceCredentialProviderName: req.service,
|
|
60
108
|
scopes: req.scopes ?? [],
|
|
61
109
|
oauth2Flow: req.mode === 'user' ? 'USER_FEDERATION' : 'M2M',
|
|
62
110
|
forceAuthentication: req.forceReauth ?? false,
|
|
63
|
-
...(
|
|
64
|
-
workloadIdentityToken: options.workloadIdentityToken,
|
|
65
|
-
}),
|
|
111
|
+
...(workloadIdentityToken && { workloadIdentityToken }),
|
|
66
112
|
});
|
|
67
113
|
if (res.accessToken) {
|
|
68
114
|
// AgentCore Identity vends OAuth access tokens → a bearer credential.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentcore.js","sourceRoot":"","sources":["../../../../src/adapters/identity/agentcore.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"agentcore.js","sourceRoot":"","sources":["../../../../src/adapters/identity/agentcore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* withCredentialRetry — CredentialProvider decorator that retries transient
|
|
3
|
+
* `getCredential` failures with exponential backoff.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: Decorator (GoF) — the credential twin of `withRetry` (resilience)
|
|
6
|
+
* for LLM providers. SAME option vocabulary (`maxAttempts` /
|
|
7
|
+
* `initialDelayMs` / `backoffFactor` / `maxDelayMs` / `shouldRetry` /
|
|
8
|
+
* `onRetry`) and the SAME default transience policy (the shared
|
|
9
|
+
* `defaultShouldRetry`: skip AbortError + 4xx except 429; retry 5xx,
|
|
10
|
+
* network errors, unknown shapes). AgentCore's documented transient
|
|
11
|
+
* errors (`InternalServerException` 500, `ThrottlingException` 429)
|
|
12
|
+
* retry out of the box.
|
|
13
|
+
*
|
|
14
|
+
* Why a decorator and not a reliability rule: the rules-based reliability
|
|
15
|
+
* subsystem (`Agent.create(...).reliability({...})`) is LLM-call-scoped —
|
|
16
|
+
* `ReliabilityScope` carries `request: LLMRequest` and the gate chart loops
|
|
17
|
+
* around the CallLLM stage with provider failover. Credential resolution
|
|
18
|
+
* happens at a different boundary (the tool-dispatch loop, declare-and-push);
|
|
19
|
+
* promoting it to a chart-level gate is the deferred `sf-credential` node.
|
|
20
|
+
* Until that exists, retry is a TRANSPORT property of the credential provider
|
|
21
|
+
* — exactly like `withRetry` is for LLM transports.
|
|
22
|
+
*
|
|
23
|
+
* Semantics:
|
|
24
|
+
* • Only THROWN errors retry. Both result branches return immediately:
|
|
25
|
+
* `issued` is success; `authorization-required` is a HUMAN flow (3LO
|
|
26
|
+
* consent), not a transient fault — retrying it would hammer the IdP
|
|
27
|
+
* without the user having authorized anything.
|
|
28
|
+
* • After retries exhaust, the LAST error is rethrown — the call site
|
|
29
|
+
* behaves byte-identically to an unwrapped provider (fail-closed:
|
|
30
|
+
* `agentfootprint.credential.failed` emit + error tool result; the tool
|
|
31
|
+
* does NOT run).
|
|
32
|
+
* • Visibility: the agent trace brackets the whole retried resolution with
|
|
33
|
+
* `credential.requested` → `credential.acquired` / `credential.failed`.
|
|
34
|
+
* Per-attempt visibility is consumer-wired via `onRetry` — the established
|
|
35
|
+
* decorator contract (same as `withRetry`; the `agentfootprint.error.*`
|
|
36
|
+
* event family is reserved for these decorators, see events/payloads.ts).
|
|
37
|
+
* No new event types.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* import { agentCoreIdentity, withCredentialRetry } from 'agentfootprint/identity';
|
|
41
|
+
*
|
|
42
|
+
* const credentials = withCredentialRetry(agentCoreIdentity({ region: 'us-east-1' }), {
|
|
43
|
+
* maxAttempts: 3,
|
|
44
|
+
* onRetry: (err, attempt, ms) => console.warn(`credential retry ${attempt} in ${ms}ms`, err),
|
|
45
|
+
* });
|
|
46
|
+
* const agent = Agent.create({ provider, model, credentials }).tools([...]).build();
|
|
47
|
+
*/
|
|
48
|
+
import { defaultShouldRetry } from '../resilience/withRetry.js';
|
|
49
|
+
/**
|
|
50
|
+
* Wrap a {@link CredentialProvider} so transient `getCredential` failures
|
|
51
|
+
* retry with exponential backoff before failing closed.
|
|
52
|
+
*
|
|
53
|
+
* Defaults mirror `withRetry`: 3 attempts total, 200ms → 400ms → 800ms
|
|
54
|
+
* backoff capped at 10s, retry on 5xx/429/network/unknown, never on
|
|
55
|
+
* AbortError or other 4xx.
|
|
56
|
+
*/
|
|
57
|
+
export function withCredentialRetry(provider, options = {}) {
|
|
58
|
+
const maxAttempts = Math.max(1, options.maxAttempts ?? 3);
|
|
59
|
+
const initialDelayMs = options.initialDelayMs ?? 200;
|
|
60
|
+
const backoffFactor = options.backoffFactor ?? 2;
|
|
61
|
+
const maxDelayMs = options.maxDelayMs ?? 10_000;
|
|
62
|
+
const shouldRetry = options.shouldRetry ?? defaultShouldRetry;
|
|
63
|
+
const onRetry = options.onRetry;
|
|
64
|
+
return {
|
|
65
|
+
id: `${provider.id}+retry`,
|
|
66
|
+
async getCredential(req) {
|
|
67
|
+
let lastError;
|
|
68
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
69
|
+
try {
|
|
70
|
+
// Both result branches return as-is (same object — the wrapper never
|
|
71
|
+
// clones or serializes the credential): `issued` is success;
|
|
72
|
+
// `authorization-required` is consent, not a fault — never retried.
|
|
73
|
+
return await provider.getCredential(req);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
lastError = err;
|
|
77
|
+
if (attempt >= maxAttempts || !shouldRetry(err, attempt)) {
|
|
78
|
+
throw err;
|
|
79
|
+
}
|
|
80
|
+
const delay = Math.min(maxDelayMs, initialDelayMs * Math.pow(backoffFactor, attempt - 1));
|
|
81
|
+
onRetry?.(err, attempt + 1, delay);
|
|
82
|
+
await sleep(delay);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Unreachable — the last attempt either returned or threw above.
|
|
86
|
+
throw lastError;
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
// `CredentialRequest` carries no AbortSignal (port contract), so this sleep is
|
|
91
|
+
// the signal-less twin of withRetry's. If the port ever grows a signal, mirror
|
|
92
|
+
// withRetry's abort-aware sleep here.
|
|
93
|
+
function sleep(ms) {
|
|
94
|
+
if (ms <= 0)
|
|
95
|
+
return Promise.resolve();
|
|
96
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=withCredentialRetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withCredentialRetry.js","sourceRoot":"","sources":["../../../src/identity/withCredentialRetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,OAAO,EAAE,kBAAkB,EAAyB,MAAM,4BAA4B,CAAC;AAUvF;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAA4B,EAC5B,UAAsC,EAAE;IAExC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAC1D,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,GAAG,CAAC;IACrD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC;IAChD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,kBAAkB,CAAC;IAC9D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAEhC,OAAO;QACL,EAAE,EAAE,GAAG,QAAQ,CAAC,EAAE,QAAQ;QAC1B,KAAK,CAAC,aAAa,CAAC,GAAsB;YACxC,IAAI,SAAkB,CAAC;YACvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;gBACxD,IAAI,CAAC;oBACH,qEAAqE;oBACrE,6DAA6D;oBAC7D,oEAAoE;oBACpE,OAAO,MAAM,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;gBAC3C,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,SAAS,GAAG,GAAG,CAAC;oBAChB,IAAI,OAAO,IAAI,WAAW,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC;wBACzD,MAAM,GAAG,CAAC;oBACZ,CAAC;oBACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;oBAC1F,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;oBACnC,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;gBACrB,CAAC;YACH,CAAC;YACD,iEAAiE;YACjE,MAAM,SAAS,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,+EAA+E;AAC/E,sCAAsC;AACtC,SAAS,KAAK,CAAC,EAAU;IACvB,IAAI,EAAE,IAAI,CAAC;QAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IACtC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
package/dist/esm/identity.js
CHANGED
|
@@ -26,5 +26,6 @@
|
|
|
26
26
|
export { isCredentialIssued, unconfiguredCredentialProvider } from './identity/types.js';
|
|
27
27
|
export { bearer, apiKey, basic, headers, } from './identity/kinds.js';
|
|
28
28
|
export { staticTokens } from './identity/staticTokens.js';
|
|
29
|
+
export { withCredentialRetry, } from './identity/withCredentialRetry.js';
|
|
29
30
|
export { agentCoreIdentity, } from './adapters/identity/agentcore.js';
|
|
30
31
|
//# sourceMappingURL=identity.js.map
|
package/dist/esm/identity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAWH,OAAO,EAAE,kBAAkB,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AACzF,OAAO,EACL,MAAM,EACN,MAAM,EACN,KAAK,EACL,OAAO,GAKR,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,YAAY,EAA4B,MAAM,4BAA4B,CAAC;AACpF,OAAO,EACL,iBAAiB,GAIlB,MAAM,kCAAkC,CAAC"}
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAWH,OAAO,EAAE,kBAAkB,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AACzF,OAAO,EACL,MAAM,EACN,MAAM,EACN,KAAK,EACL,OAAO,GAKR,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,YAAY,EAA4B,MAAM,4BAA4B,CAAC;AACpF,OAAO,EACL,mBAAmB,GAEpB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,iBAAiB,GAIlB,MAAM,kCAAkC,CAAC"}
|
|
@@ -75,8 +75,13 @@ export function withRetry(provider, options = {}) {
|
|
|
75
75
|
* surface HTTP status should set `error.status` for this to work; the
|
|
76
76
|
* predicate falls back to retrying when status is unknown (better to
|
|
77
77
|
* retry once than to surface a flaky failure).
|
|
78
|
+
*
|
|
79
|
+
* Exported (module-level, NOT on the resilience barrel) as the single
|
|
80
|
+
* source of truth for the decorators' transience policy — shared by
|
|
81
|
+
* `withCredentialRetry` (identity) so "what counts as transient" never
|
|
82
|
+
* drifts between the LLM and credential retry wrappers.
|
|
78
83
|
*/
|
|
79
|
-
function defaultShouldRetry(err, _attempt) {
|
|
84
|
+
export function defaultShouldRetry(err, _attempt) {
|
|
80
85
|
if (isAbortError(err))
|
|
81
86
|
return false;
|
|
82
87
|
const status = err?.status ??
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withRetry.js","sourceRoot":"","sources":["../../../src/resilience/withRetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;
|
|
1
|
+
{"version":3,"file":"withRetry.js","sourceRoot":"","sources":["../../../src/resilience/withRetry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* withCredentialRetry — CredentialProvider decorator that retries transient
|
|
4
|
+
* `getCredential` failures with exponential backoff.
|
|
5
|
+
*
|
|
6
|
+
* Pattern: Decorator (GoF) — the credential twin of `withRetry` (resilience)
|
|
7
|
+
* for LLM providers. SAME option vocabulary (`maxAttempts` /
|
|
8
|
+
* `initialDelayMs` / `backoffFactor` / `maxDelayMs` / `shouldRetry` /
|
|
9
|
+
* `onRetry`) and the SAME default transience policy (the shared
|
|
10
|
+
* `defaultShouldRetry`: skip AbortError + 4xx except 429; retry 5xx,
|
|
11
|
+
* network errors, unknown shapes). AgentCore's documented transient
|
|
12
|
+
* errors (`InternalServerException` 500, `ThrottlingException` 429)
|
|
13
|
+
* retry out of the box.
|
|
14
|
+
*
|
|
15
|
+
* Why a decorator and not a reliability rule: the rules-based reliability
|
|
16
|
+
* subsystem (`Agent.create(...).reliability({...})`) is LLM-call-scoped —
|
|
17
|
+
* `ReliabilityScope` carries `request: LLMRequest` and the gate chart loops
|
|
18
|
+
* around the CallLLM stage with provider failover. Credential resolution
|
|
19
|
+
* happens at a different boundary (the tool-dispatch loop, declare-and-push);
|
|
20
|
+
* promoting it to a chart-level gate is the deferred `sf-credential` node.
|
|
21
|
+
* Until that exists, retry is a TRANSPORT property of the credential provider
|
|
22
|
+
* — exactly like `withRetry` is for LLM transports.
|
|
23
|
+
*
|
|
24
|
+
* Semantics:
|
|
25
|
+
* • Only THROWN errors retry. Both result branches return immediately:
|
|
26
|
+
* `issued` is success; `authorization-required` is a HUMAN flow (3LO
|
|
27
|
+
* consent), not a transient fault — retrying it would hammer the IdP
|
|
28
|
+
* without the user having authorized anything.
|
|
29
|
+
* • After retries exhaust, the LAST error is rethrown — the call site
|
|
30
|
+
* behaves byte-identically to an unwrapped provider (fail-closed:
|
|
31
|
+
* `agentfootprint.credential.failed` emit + error tool result; the tool
|
|
32
|
+
* does NOT run).
|
|
33
|
+
* • Visibility: the agent trace brackets the whole retried resolution with
|
|
34
|
+
* `credential.requested` → `credential.acquired` / `credential.failed`.
|
|
35
|
+
* Per-attempt visibility is consumer-wired via `onRetry` — the established
|
|
36
|
+
* decorator contract (same as `withRetry`; the `agentfootprint.error.*`
|
|
37
|
+
* event family is reserved for these decorators, see events/payloads.ts).
|
|
38
|
+
* No new event types.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* import { agentCoreIdentity, withCredentialRetry } from 'agentfootprint/identity';
|
|
42
|
+
*
|
|
43
|
+
* const credentials = withCredentialRetry(agentCoreIdentity({ region: 'us-east-1' }), {
|
|
44
|
+
* maxAttempts: 3,
|
|
45
|
+
* onRetry: (err, attempt, ms) => console.warn(`credential retry ${attempt} in ${ms}ms`, err),
|
|
46
|
+
* });
|
|
47
|
+
* const agent = Agent.create({ provider, model, credentials }).tools([...]).build();
|
|
48
|
+
*/
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.withCredentialRetry = void 0;
|
|
51
|
+
const withRetry_js_1 = require("../resilience/withRetry.js");
|
|
52
|
+
/**
|
|
53
|
+
* Wrap a {@link CredentialProvider} so transient `getCredential` failures
|
|
54
|
+
* retry with exponential backoff before failing closed.
|
|
55
|
+
*
|
|
56
|
+
* Defaults mirror `withRetry`: 3 attempts total, 200ms → 400ms → 800ms
|
|
57
|
+
* backoff capped at 10s, retry on 5xx/429/network/unknown, never on
|
|
58
|
+
* AbortError or other 4xx.
|
|
59
|
+
*/
|
|
60
|
+
function withCredentialRetry(provider, options = {}) {
|
|
61
|
+
const maxAttempts = Math.max(1, options.maxAttempts ?? 3);
|
|
62
|
+
const initialDelayMs = options.initialDelayMs ?? 200;
|
|
63
|
+
const backoffFactor = options.backoffFactor ?? 2;
|
|
64
|
+
const maxDelayMs = options.maxDelayMs ?? 10_000;
|
|
65
|
+
const shouldRetry = options.shouldRetry ?? withRetry_js_1.defaultShouldRetry;
|
|
66
|
+
const onRetry = options.onRetry;
|
|
67
|
+
return {
|
|
68
|
+
id: `${provider.id}+retry`,
|
|
69
|
+
async getCredential(req) {
|
|
70
|
+
let lastError;
|
|
71
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
72
|
+
try {
|
|
73
|
+
// Both result branches return as-is (same object — the wrapper never
|
|
74
|
+
// clones or serializes the credential): `issued` is success;
|
|
75
|
+
// `authorization-required` is consent, not a fault — never retried.
|
|
76
|
+
return await provider.getCredential(req);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
lastError = err;
|
|
80
|
+
if (attempt >= maxAttempts || !shouldRetry(err, attempt)) {
|
|
81
|
+
throw err;
|
|
82
|
+
}
|
|
83
|
+
const delay = Math.min(maxDelayMs, initialDelayMs * Math.pow(backoffFactor, attempt - 1));
|
|
84
|
+
onRetry?.(err, attempt + 1, delay);
|
|
85
|
+
await sleep(delay);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Unreachable — the last attempt either returned or threw above.
|
|
89
|
+
throw lastError;
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
exports.withCredentialRetry = withCredentialRetry;
|
|
94
|
+
// `CredentialRequest` carries no AbortSignal (port contract), so this sleep is
|
|
95
|
+
// the signal-less twin of withRetry's. If the port ever grows a signal, mirror
|
|
96
|
+
// withRetry's abort-aware sleep here.
|
|
97
|
+
function sleep(ms) {
|
|
98
|
+
if (ms <= 0)
|
|
99
|
+
return Promise.resolve();
|
|
100
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=withCredentialRetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withCredentialRetry.js","sourceRoot":"","sources":["../../src/identity/withCredentialRetry.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;;;AAEH,6DAAuF;AAUvF;;;;;;;GAOG;AACH,SAAgB,mBAAmB,CACjC,QAA4B,EAC5B,UAAsC,EAAE;IAExC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAC1D,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,GAAG,CAAC;IACrD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC;IAChD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,iCAAkB,CAAC;IAC9D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAEhC,OAAO;QACL,EAAE,EAAE,GAAG,QAAQ,CAAC,EAAE,QAAQ;QAC1B,KAAK,CAAC,aAAa,CAAC,GAAsB;YACxC,IAAI,SAAkB,CAAC;YACvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;gBACxD,IAAI,CAAC;oBACH,qEAAqE;oBACrE,6DAA6D;oBAC7D,oEAAoE;oBACpE,OAAO,MAAM,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;gBAC3C,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,SAAS,GAAG,GAAG,CAAC;oBAChB,IAAI,OAAO,IAAI,WAAW,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC;wBACzD,MAAM,GAAG,CAAC;oBACZ,CAAC;oBACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;oBAC1F,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;oBACnC,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;gBACrB,CAAC;YACH,CAAC;YACD,iEAAiE;YACjE,MAAM,SAAS,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC;AAnCD,kDAmCC;AAED,+EAA+E;AAC/E,+EAA+E;AAC/E,sCAAsC;AACtC,SAAS,KAAK,CAAC,EAAU;IACvB,IAAI,EAAE,IAAI,CAAC;QAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IACtC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
package/dist/identity.js
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* ```
|
|
26
26
|
*/
|
|
27
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
-
exports.agentCoreIdentity = exports.staticTokens = exports.headers = exports.basic = exports.apiKey = exports.bearer = exports.unconfiguredCredentialProvider = exports.isCredentialIssued = void 0;
|
|
28
|
+
exports.agentCoreIdentity = exports.withCredentialRetry = exports.staticTokens = exports.headers = exports.basic = exports.apiKey = exports.bearer = exports.unconfiguredCredentialProvider = exports.isCredentialIssued = void 0;
|
|
29
29
|
var types_js_1 = require("./identity/types.js");
|
|
30
30
|
Object.defineProperty(exports, "isCredentialIssued", { enumerable: true, get: function () { return types_js_1.isCredentialIssued; } });
|
|
31
31
|
Object.defineProperty(exports, "unconfiguredCredentialProvider", { enumerable: true, get: function () { return types_js_1.unconfiguredCredentialProvider; } });
|
|
@@ -36,6 +36,8 @@ Object.defineProperty(exports, "basic", { enumerable: true, get: function () { r
|
|
|
36
36
|
Object.defineProperty(exports, "headers", { enumerable: true, get: function () { return kinds_js_1.headers; } });
|
|
37
37
|
var staticTokens_js_1 = require("./identity/staticTokens.js");
|
|
38
38
|
Object.defineProperty(exports, "staticTokens", { enumerable: true, get: function () { return staticTokens_js_1.staticTokens; } });
|
|
39
|
+
var withCredentialRetry_js_1 = require("./identity/withCredentialRetry.js");
|
|
40
|
+
Object.defineProperty(exports, "withCredentialRetry", { enumerable: true, get: function () { return withCredentialRetry_js_1.withCredentialRetry; } });
|
|
39
41
|
var agentcore_js_1 = require("./adapters/identity/agentcore.js");
|
|
40
42
|
Object.defineProperty(exports, "agentCoreIdentity", { enumerable: true, get: function () { return agentcore_js_1.agentCoreIdentity; } });
|
|
41
43
|
//# sourceMappingURL=identity.js.map
|
package/dist/identity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;;AAWH,gDAAyF;AAAhF,8GAAA,kBAAkB,OAAA;AAAE,0HAAA,8BAA8B,OAAA;AAC3D,gDAS6B;AAR3B,kGAAA,MAAM,OAAA;AACN,kGAAA,MAAM,OAAA;AACN,iGAAA,KAAK,OAAA;AACL,mGAAA,OAAO,OAAA;AAMT,8DAAoF;AAA3E,+GAAA,YAAY,OAAA;AACrB,iEAK0C;AAJxC,iHAAA,iBAAiB,OAAA"}
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;;AAWH,gDAAyF;AAAhF,8GAAA,kBAAkB,OAAA;AAAE,0HAAA,8BAA8B,OAAA;AAC3D,gDAS6B;AAR3B,kGAAA,MAAM,OAAA;AACN,kGAAA,MAAM,OAAA;AACN,iGAAA,KAAK,OAAA;AACL,mGAAA,OAAO,OAAA;AAMT,8DAAoF;AAA3E,+GAAA,YAAY,OAAA;AACrB,4EAG2C;AAFzC,6HAAA,mBAAmB,OAAA;AAGrB,iEAK0C;AAJxC,iHAAA,iBAAiB,OAAA"}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* network errors, and unknown shapes.
|
|
21
21
|
*/
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.withRetry = void 0;
|
|
23
|
+
exports.defaultShouldRetry = exports.withRetry = void 0;
|
|
24
24
|
/**
|
|
25
25
|
* Wrap a provider so its `complete()` retries transient failures.
|
|
26
26
|
*
|
|
@@ -79,6 +79,11 @@ exports.withRetry = withRetry;
|
|
|
79
79
|
* surface HTTP status should set `error.status` for this to work; the
|
|
80
80
|
* predicate falls back to retrying when status is unknown (better to
|
|
81
81
|
* retry once than to surface a flaky failure).
|
|
82
|
+
*
|
|
83
|
+
* Exported (module-level, NOT on the resilience barrel) as the single
|
|
84
|
+
* source of truth for the decorators' transience policy — shared by
|
|
85
|
+
* `withCredentialRetry` (identity) so "what counts as transient" never
|
|
86
|
+
* drifts between the LLM and credential retry wrappers.
|
|
82
87
|
*/
|
|
83
88
|
function defaultShouldRetry(err, _attempt) {
|
|
84
89
|
if (isAbortError(err))
|
|
@@ -91,6 +96,7 @@ function defaultShouldRetry(err, _attempt) {
|
|
|
91
96
|
}
|
|
92
97
|
return true;
|
|
93
98
|
}
|
|
99
|
+
exports.defaultShouldRetry = defaultShouldRetry;
|
|
94
100
|
function isAbortError(err) {
|
|
95
101
|
if (!err || typeof err !== 'object')
|
|
96
102
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withRetry.js","sourceRoot":"","sources":["../../src/resilience/withRetry.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;
|
|
1
|
+
{"version":3,"file":"withRetry.js","sourceRoot":"","sources":["../../src/resilience/withRetry.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,12 +9,30 @@
|
|
|
9
9
|
* `GetResourceOauth2Token` (the SDK's `@requires_access_token` underneath):
|
|
10
10
|
* - request.mode 'machine' → `M2M`; 'user' → `USER_FEDERATION`
|
|
11
11
|
* - request.service → the configured OAuth2 credential-provider name
|
|
12
|
+
* - request.identity → (per-request workload identity scoping; see below)
|
|
12
13
|
* - a returned access token → `{ status: 'issued', credential: bearer(token) }`
|
|
13
14
|
* - a returned auth URL → `{ status: 'authorization-required' }` (3LO consent)
|
|
14
15
|
*
|
|
15
16
|
* The token vault + refresh-token handling live in AgentCore, so repeat calls
|
|
16
17
|
* usually return a token directly (no consent round-trip).
|
|
17
18
|
*
|
|
19
|
+
* **Per-request identity forwarding (workload identity scoping).**
|
|
20
|
+
* `GetResourceOauth2Token` carries NO user/tenant field — in AgentCore the
|
|
21
|
+
* user identity is bound EARLIER, at workload-token acquisition:
|
|
22
|
+
* `GetWorkloadAccessTokenForUserId(workloadName, userId)` returns a workload
|
|
23
|
+
* access token scoped to that user, and AgentCore keys its token vault + 3LO
|
|
24
|
+
* grants per (workload, user). So this adapter forwards `req.identity` (the
|
|
25
|
+
* `runIdentity` that the agent threads through `getCredential`) by resolving a
|
|
26
|
+
* per-user workload token first, then vending with it. Engages only when ALL of:
|
|
27
|
+
* - `req.mode === 'user'` (USER_FEDERATION — M2M is the workload's own identity),
|
|
28
|
+
* - a userId derives from `req.identity` (default `identity.principal`;
|
|
29
|
+
* override via `userIdFor`), and
|
|
30
|
+
* - `options.workloadName` is configured (the opt-in).
|
|
31
|
+
* Otherwise the static `options.workloadIdentityToken` flows exactly as before.
|
|
32
|
+
* `tenant` has no native AgentCore field and is NOT forwarded by default —
|
|
33
|
+
* tenant isolation derives from the workload identity itself (per-tenant
|
|
34
|
+
* workloads), or encode it via `userIdFor` (e.g. `${tenant}:${principal}`).
|
|
35
|
+
*
|
|
18
36
|
* Pattern: Adapter (GoF) + lazy peer-dep load — the AWS SDK is required only when
|
|
19
37
|
* `getCredential` first runs (or never, if you inject `_client`). NOTE: confirm
|
|
20
38
|
* the SDK command/field names against your installed
|
|
@@ -31,7 +49,8 @@ export interface AgentCoreOauthResponse {
|
|
|
31
49
|
/** Unix seconds. */
|
|
32
50
|
readonly expiresAt?: number;
|
|
33
51
|
}
|
|
34
|
-
/** The minimal client surface the adapter calls — wraps `GetResourceOauth2Token
|
|
52
|
+
/** The minimal client surface the adapter calls — wraps `GetResourceOauth2Token`
|
|
53
|
+
* and (for per-user workload scoping) `GetWorkloadAccessTokenForUserId`.
|
|
35
54
|
* The real AWS SDK client is adapted to this; tests inject a fake via `_client`. */
|
|
36
55
|
export interface AgentCoreIdentityClientLike {
|
|
37
56
|
getResourceOauth2Token(input: {
|
|
@@ -41,12 +60,37 @@ export interface AgentCoreIdentityClientLike {
|
|
|
41
60
|
readonly forceAuthentication: boolean;
|
|
42
61
|
readonly workloadIdentityToken?: string;
|
|
43
62
|
}): Promise<AgentCoreOauthResponse>;
|
|
63
|
+
/** Optional — required only when `workloadName` is configured. Exchanges
|
|
64
|
+
* (workloadName, userId) for a USER-SCOPED workload access token; AgentCore
|
|
65
|
+
* keys its token vault + 3LO grants per (workload, user). */
|
|
66
|
+
getWorkloadAccessTokenForUserId?(input: {
|
|
67
|
+
readonly workloadName: string;
|
|
68
|
+
readonly userId: string;
|
|
69
|
+
}): Promise<{
|
|
70
|
+
readonly workloadAccessToken?: string;
|
|
71
|
+
}>;
|
|
44
72
|
}
|
|
45
73
|
export interface AgentCoreIdentityOptions {
|
|
46
74
|
readonly region?: string;
|
|
47
75
|
/** The agent's workload access token (AgentCore Runtime injects one in-container;
|
|
48
|
-
* supply it explicitly when running elsewhere).
|
|
76
|
+
* supply it explicitly when running elsewhere). Used as-is unless a per-user
|
|
77
|
+
* workload token is resolved (see `workloadName`). */
|
|
49
78
|
readonly workloadIdentityToken?: string;
|
|
79
|
+
/** The AgentCore workload identity name — the OPT-IN for per-request identity
|
|
80
|
+
* scoping. When set, `mode: 'user'` requests carrying `req.identity` resolve a
|
|
81
|
+
* per-user workload access token via `GetWorkloadAccessTokenForUserId(workloadName,
|
|
82
|
+
* userId)` before vending, so AgentCore's token vault + 3LO grants are keyed per
|
|
83
|
+
* (workload, user) instead of per workload. Omit → today's static-token behavior. */
|
|
84
|
+
readonly workloadName?: string;
|
|
85
|
+
/** Map `req.identity` → the AgentCore `userId`. Default: `identity.principal`.
|
|
86
|
+
* `tenant` has no native AgentCore field — encode it here if you need
|
|
87
|
+
* tenant-scoped vault entries (e.g. ``({ tenant, principal }) =>
|
|
88
|
+
* tenant && principal ? `${tenant}:${principal}` : principal``). Return
|
|
89
|
+
* `undefined` to skip per-user scoping for that request. */
|
|
90
|
+
readonly userIdFor?: (identity: {
|
|
91
|
+
readonly principal?: string;
|
|
92
|
+
readonly tenant?: string;
|
|
93
|
+
}) => string | undefined;
|
|
50
94
|
/** Stable provider id (default 'agentcore-identity'). */
|
|
51
95
|
readonly id?: string;
|
|
52
96
|
/** Test seam — inject a client implementing {@link AgentCoreIdentityClientLike}. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentcore.d.ts","sourceRoot":"","sources":["../../../../src/adapters/identity/agentcore.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"agentcore.d.ts","sourceRoot":"","sources":["../../../../src/adapters/identity/agentcore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAGH,OAAO,KAAK,EACV,kBAAkB,EAGnB,MAAM,yBAAyB,CAAC;AAGjC,sEAAsE;AACtE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB;IACpB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;qFAEqF;AACrF,MAAM,WAAW,2BAA2B;IAC1C,sBAAsB,CAAC,KAAK,EAAE;QAC5B,QAAQ,CAAC,8BAA8B,EAAE,MAAM,CAAC;QAChD,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;QACnC,QAAQ,CAAC,UAAU,EAAE,KAAK,GAAG,iBAAiB,CAAC;QAC/C,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;QACtC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;KACzC,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACpC;;kEAE8D;IAC9D,+BAA+B,CAAC,CAAC,KAAK,EAAE;QACtC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACzB,GAAG,OAAO,CAAC;QAAE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;2DAEuD;IACvD,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC;;;;0FAIsF;IACtF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;iEAI6D;IAC7D,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE;QAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;KAC1B,KAAK,MAAM,GAAG,SAAS,CAAC;IACzB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,QAAQ,CAAC,OAAO,CAAC,EAAE,2BAA2B,CAAC;CAChD;AAwCD,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,kBAAkB,CAuE5F"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* withCredentialRetry — CredentialProvider decorator that retries transient
|
|
3
|
+
* `getCredential` failures with exponential backoff.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: Decorator (GoF) — the credential twin of `withRetry` (resilience)
|
|
6
|
+
* for LLM providers. SAME option vocabulary (`maxAttempts` /
|
|
7
|
+
* `initialDelayMs` / `backoffFactor` / `maxDelayMs` / `shouldRetry` /
|
|
8
|
+
* `onRetry`) and the SAME default transience policy (the shared
|
|
9
|
+
* `defaultShouldRetry`: skip AbortError + 4xx except 429; retry 5xx,
|
|
10
|
+
* network errors, unknown shapes). AgentCore's documented transient
|
|
11
|
+
* errors (`InternalServerException` 500, `ThrottlingException` 429)
|
|
12
|
+
* retry out of the box.
|
|
13
|
+
*
|
|
14
|
+
* Why a decorator and not a reliability rule: the rules-based reliability
|
|
15
|
+
* subsystem (`Agent.create(...).reliability({...})`) is LLM-call-scoped —
|
|
16
|
+
* `ReliabilityScope` carries `request: LLMRequest` and the gate chart loops
|
|
17
|
+
* around the CallLLM stage with provider failover. Credential resolution
|
|
18
|
+
* happens at a different boundary (the tool-dispatch loop, declare-and-push);
|
|
19
|
+
* promoting it to a chart-level gate is the deferred `sf-credential` node.
|
|
20
|
+
* Until that exists, retry is a TRANSPORT property of the credential provider
|
|
21
|
+
* — exactly like `withRetry` is for LLM transports.
|
|
22
|
+
*
|
|
23
|
+
* Semantics:
|
|
24
|
+
* • Only THROWN errors retry. Both result branches return immediately:
|
|
25
|
+
* `issued` is success; `authorization-required` is a HUMAN flow (3LO
|
|
26
|
+
* consent), not a transient fault — retrying it would hammer the IdP
|
|
27
|
+
* without the user having authorized anything.
|
|
28
|
+
* • After retries exhaust, the LAST error is rethrown — the call site
|
|
29
|
+
* behaves byte-identically to an unwrapped provider (fail-closed:
|
|
30
|
+
* `agentfootprint.credential.failed` emit + error tool result; the tool
|
|
31
|
+
* does NOT run).
|
|
32
|
+
* • Visibility: the agent trace brackets the whole retried resolution with
|
|
33
|
+
* `credential.requested` → `credential.acquired` / `credential.failed`.
|
|
34
|
+
* Per-attempt visibility is consumer-wired via `onRetry` — the established
|
|
35
|
+
* decorator contract (same as `withRetry`; the `agentfootprint.error.*`
|
|
36
|
+
* event family is reserved for these decorators, see events/payloads.ts).
|
|
37
|
+
* No new event types.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* import { agentCoreIdentity, withCredentialRetry } from 'agentfootprint/identity';
|
|
41
|
+
*
|
|
42
|
+
* const credentials = withCredentialRetry(agentCoreIdentity({ region: 'us-east-1' }), {
|
|
43
|
+
* maxAttempts: 3,
|
|
44
|
+
* onRetry: (err, attempt, ms) => console.warn(`credential retry ${attempt} in ${ms}ms`, err),
|
|
45
|
+
* });
|
|
46
|
+
* const agent = Agent.create({ provider, model, credentials }).tools([...]).build();
|
|
47
|
+
*/
|
|
48
|
+
import { type WithRetryOptions } from '../resilience/withRetry.js';
|
|
49
|
+
import type { CredentialProvider } from './types.js';
|
|
50
|
+
/**
|
|
51
|
+
* Same vocabulary as the LLM-provider `withRetry` — one retry language across
|
|
52
|
+
* both decorators. `shouldRetry` sees only THROWN errors (never an
|
|
53
|
+
* `authorization-required` result, which returns immediately).
|
|
54
|
+
*/
|
|
55
|
+
export type WithCredentialRetryOptions = WithRetryOptions;
|
|
56
|
+
/**
|
|
57
|
+
* Wrap a {@link CredentialProvider} so transient `getCredential` failures
|
|
58
|
+
* retry with exponential backoff before failing closed.
|
|
59
|
+
*
|
|
60
|
+
* Defaults mirror `withRetry`: 3 attempts total, 200ms → 400ms → 800ms
|
|
61
|
+
* backoff capped at 10s, retry on 5xx/429/network/unknown, never on
|
|
62
|
+
* AbortError or other 4xx.
|
|
63
|
+
*/
|
|
64
|
+
export declare function withCredentialRetry(provider: CredentialProvider, options?: WithCredentialRetryOptions): CredentialProvider;
|
|
65
|
+
//# sourceMappingURL=withCredentialRetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withCredentialRetry.d.ts","sourceRoot":"","sources":["../../../src/identity/withCredentialRetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACvF,OAAO,KAAK,EAAE,kBAAkB,EAAuC,MAAM,YAAY,CAAC;AAE1F;;;;GAIG;AACH,MAAM,MAAM,0BAA0B,GAAG,gBAAgB,CAAC;AAE1D;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,GAAE,0BAA+B,GACvC,kBAAkB,CAgCpB"}
|
package/dist/types/identity.d.ts
CHANGED
|
@@ -27,5 +27,6 @@ export type { Credential, CredentialProvider, CredentialRequest, CredentialResul
|
|
|
27
27
|
export { isCredentialIssued, unconfiguredCredentialProvider } from './identity/types.js';
|
|
28
28
|
export { bearer, apiKey, basic, headers, type BearerCredential, type ApiKeyCredential, type BasicCredential, type HeadersCredential, } from './identity/kinds.js';
|
|
29
29
|
export { staticTokens, type StaticTokensOptions } from './identity/staticTokens.js';
|
|
30
|
+
export { withCredentialRetry, type WithCredentialRetryOptions, } from './identity/withCredentialRetry.js';
|
|
30
31
|
export { agentCoreIdentity, type AgentCoreIdentityOptions, type AgentCoreIdentityClientLike, type AgentCoreOauthResponse, } from './adapters/identity/agentcore.js';
|
|
31
32
|
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,YAAY,EACV,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,+BAA+B,EAC/B,cAAc,GACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AACzF,OAAO,EACL,MAAM,EACN,MAAM,EACN,KAAK,EACL,OAAO,EACP,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACpF,OAAO,EACL,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,GAC5B,MAAM,kCAAkC,CAAC"}
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,YAAY,EACV,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,+BAA+B,EAC/B,cAAc,GACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AACzF,OAAO,EACL,MAAM,EACN,MAAM,EACN,KAAK,EACL,OAAO,EACP,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACpF,OAAO,EACL,mBAAmB,EACnB,KAAK,0BAA0B,GAChC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,GAC5B,MAAM,kCAAkC,CAAC"}
|
|
@@ -35,9 +35,11 @@ export interface WithRetryOptions {
|
|
|
35
35
|
*/
|
|
36
36
|
readonly shouldRetry?: (error: unknown, attempt: number) => boolean;
|
|
37
37
|
/**
|
|
38
|
-
* Hook invoked before each retry. Useful for logging or
|
|
39
|
-
* `agentfootprint.
|
|
40
|
-
*
|
|
38
|
+
* Hook invoked before each retry. Useful for logging or an
|
|
39
|
+
* `agentfootprint.error.retried` emit (the event family reserved for
|
|
40
|
+
* the standalone provider decorators — see events/payloads.ts).
|
|
41
|
+
* Receives the attempt number that's about to start (so attempt 2 =
|
|
42
|
+
* first retry).
|
|
41
43
|
*/
|
|
42
44
|
readonly onRetry?: (error: unknown, attempt: number, delayMs: number) => void;
|
|
43
45
|
}
|
|
@@ -54,4 +56,17 @@ export interface WithRetryOptions {
|
|
|
54
56
|
* });
|
|
55
57
|
*/
|
|
56
58
|
export declare function withRetry(provider: LLMProvider, options?: WithRetryOptions): LLMProvider;
|
|
59
|
+
/**
|
|
60
|
+
* Skip retry for AbortError + 4xx-class errors. Retry on everything
|
|
61
|
+
* else (network errors, 5xx, unknown shapes). Provider adapters that
|
|
62
|
+
* surface HTTP status should set `error.status` for this to work; the
|
|
63
|
+
* predicate falls back to retrying when status is unknown (better to
|
|
64
|
+
* retry once than to surface a flaky failure).
|
|
65
|
+
*
|
|
66
|
+
* Exported (module-level, NOT on the resilience barrel) as the single
|
|
67
|
+
* source of truth for the decorators' transience policy — shared by
|
|
68
|
+
* `withCredentialRetry` (identity) so "what counts as transient" never
|
|
69
|
+
* drifts between the LLM and credential retry wrappers.
|
|
70
|
+
*/
|
|
71
|
+
export declare function defaultShouldRetry(err: unknown, _attempt: number): boolean;
|
|
57
72
|
//# sourceMappingURL=withRetry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withRetry.d.ts","sourceRoot":"","sources":["../../../src/resilience/withRetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAY,WAAW,EAA2B,MAAM,sBAAsB,CAAC;AAE3F,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,+DAA+D;IAC/D,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,sEAAsE;IACtE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,+CAA+C;IAC/C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACpE
|
|
1
|
+
{"version":3,"file":"withRetry.d.ts","sourceRoot":"","sources":["../../../src/resilience/withRetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAY,WAAW,EAA2B,MAAM,sBAAsB,CAAC;AAE3F,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,+DAA+D;IAC/D,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,sEAAsE;IACtE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,+CAA+C;IAC/C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACpE;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,GAAE,gBAAqB,GAAG,WAAW,CAuC5F;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAU1E"}
|
package/package.json
CHANGED