@cat-factory/kernel 0.243.0 → 0.244.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/domain/agent-capabilities.d.ts +100 -1
- package/dist/domain/agent-capabilities.d.ts.map +1 -1
- package/dist/domain/agent-capabilities.js +4 -0
- package/dist/domain/agent-capabilities.js.map +1 -1
- package/dist/domain/audit-log.d.ts +95 -0
- package/dist/domain/audit-log.d.ts.map +1 -0
- package/dist/domain/audit-log.js +142 -0
- package/dist/domain/audit-log.js.map +1 -0
- package/dist/domain/tool-call-rollup.d.ts +53 -0
- package/dist/domain/tool-call-rollup.d.ts.map +1 -0
- package/dist/domain/tool-call-rollup.js +117 -0
- package/dist/domain/tool-call-rollup.js.map +1 -0
- package/dist/domain/workspace-cascade.d.ts +1 -1
- package/dist/domain/workspace-cascade.d.ts.map +1 -1
- package/dist/domain/workspace-cascade.js +1 -0
- package/dist/domain/workspace-cascade.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/ports/agent-tool-calls.d.ts +50 -2
- package/dist/ports/agent-tool-calls.d.ts.map +1 -1
- package/dist/ports/agent-tools.d.ts +63 -1
- package/dist/ports/agent-tools.d.ts.map +1 -1
- package/dist/ports/audit.d.ts +139 -0
- package/dist/ports/audit.d.ts.map +1 -0
- package/dist/ports/audit.js +10 -0
- package/dist/ports/audit.js.map +1 -0
- package/dist/ports/index.d.ts +5 -2
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +1 -0
- package/dist/ports/index.js.map +1 -1
- package/dist/ports/mcp-oauth-repositories.d.ts +58 -0
- package/dist/ports/mcp-oauth-repositories.d.ts.map +1 -0
- package/dist/ports/mcp-oauth-repositories.js +18 -0
- package/dist/ports/mcp-oauth-repositories.js.map +1 -0
- package/package.json +2 -2
|
@@ -129,6 +129,85 @@ export interface McpSecretRef {
|
|
|
129
129
|
*/
|
|
130
130
|
usage?: string;
|
|
131
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* How a REMOTE (`http`) tool server's access token is obtained, when the server authenticates with
|
|
134
|
+
* OAuth 2.1 rather than a static credential.
|
|
135
|
+
*
|
|
136
|
+
* This is the declaration half only: the deployment states which OAuth client it is and what it
|
|
137
|
+
* wants, and everything mutable (the tokens, their expiry, the refresh) lives per WORKSPACE in the
|
|
138
|
+
* sealed grant store. That split is deliberate and mirrors {@link McpSecretRef}: a static
|
|
139
|
+
* credential's declaration is a key NAME and its value is per-tenant, and an OAuth credential's
|
|
140
|
+
* declaration is a client and its GRANT is per-tenant. A deployment therefore registers a vendor's
|
|
141
|
+
* remote server once, and each board authorises its own account against it.
|
|
142
|
+
*
|
|
143
|
+
* The two grants cover the two shapes a remote server comes in, and they differ in whether a HUMAN
|
|
144
|
+
* is involved at all, which is why they are one field rather than two definitions:
|
|
145
|
+
*
|
|
146
|
+
* - `authorization_code` — the vendor case (Linear, Atlassian, Figma). Someone with
|
|
147
|
+
* `secrets.manage` presses Connect, authorises in the vendor's own UI, and the workspace holds
|
|
148
|
+
* the resulting refresh token. PKCE is always used, so a PUBLIC client (no
|
|
149
|
+
* {@link McpOAuthConfig.clientSecretKey}) is a supported and common shape.
|
|
150
|
+
* - `client_credentials` — a machine grant against an internal or partner server. No browser, no
|
|
151
|
+
* grant UI, nothing per-tenant except the client secret: the token is minted on demand and
|
|
152
|
+
* cached in the same store. This is what makes an OAuth-protected INTERNAL server reachable on a
|
|
153
|
+
* deployment that has no one to press a button (a cron-driven install, a CI environment).
|
|
154
|
+
*/
|
|
155
|
+
export interface McpOAuthConfig {
|
|
156
|
+
grant: 'authorization_code' | 'client_credentials';
|
|
157
|
+
/**
|
|
158
|
+
* The OAuth client id this deployment registered with the server's authorization server.
|
|
159
|
+
*
|
|
160
|
+
* Static on purpose: dynamic client registration (RFC 7591) is not performed, because a
|
|
161
|
+
* client registered at runtime is deployment state with no home in a composition-root
|
|
162
|
+
* registration and no operator-visible identity at the vendor. Register the client once in the
|
|
163
|
+
* vendor's console and name it here.
|
|
164
|
+
*/
|
|
165
|
+
clientId: string;
|
|
166
|
+
/**
|
|
167
|
+
* The LOOKUP key for the client SECRET, resolved through the very same `ToolSecretResolver`
|
|
168
|
+
* chain a {@link McpSecretRef} uses — so a workspace can bring its own OAuth client through the
|
|
169
|
+
* capability-credential checklist, and a single-tenant deployment can set an environment
|
|
170
|
+
* variable, with no second credential mechanism to learn.
|
|
171
|
+
*
|
|
172
|
+
* Omitted ⇒ a PUBLIC client: the token requests carry the client id and PKCE and no secret,
|
|
173
|
+
* which is what most remote MCP servers expect. Held to the same reserved-key floor as every
|
|
174
|
+
* other capability credential (`isReservedPlatformEnvKey`), for the same reason: a definition
|
|
175
|
+
* names both the key it wants and the endpoint that key is sent to.
|
|
176
|
+
*/
|
|
177
|
+
clientSecretKey?: string;
|
|
178
|
+
/**
|
|
179
|
+
* The authorization endpoint. Omitted ⇒ DISCOVERED from the server url (RFC 9728 protected
|
|
180
|
+
* resource metadata, then RFC 8414 authorization-server metadata), which is what the MCP
|
|
181
|
+
* authorization spec prescribes and what makes a vendor server connectable without an operator
|
|
182
|
+
* hunting endpoint URLs out of a changelog.
|
|
183
|
+
*
|
|
184
|
+
* Declared, it WINS over discovery: a deployment that pins its endpoints is stating that it does
|
|
185
|
+
* not want a third party's metadata document deciding where its tokens are sent.
|
|
186
|
+
*/
|
|
187
|
+
authorizationUrl?: string;
|
|
188
|
+
/** The token endpoint. Omitted ⇒ discovered, as {@link McpOAuthConfig.authorizationUrl}. */
|
|
189
|
+
tokenUrl?: string;
|
|
190
|
+
/** Scopes requested at authorization. Omitted ⇒ whatever the server grants by default. */
|
|
191
|
+
scopes?: string[];
|
|
192
|
+
/**
|
|
193
|
+
* The RFC 8707 `resource` indicator sent with the authorization and token requests, which the
|
|
194
|
+
* MCP authorization spec requires so a token minted for one MCP server cannot be replayed
|
|
195
|
+
* against another behind the same authorization server. Omitted ⇒ the server's own url, which is
|
|
196
|
+
* the right answer whenever the server is its own resource.
|
|
197
|
+
*/
|
|
198
|
+
resource?: string;
|
|
199
|
+
/**
|
|
200
|
+
* The request header the access token rides, and its template. Default `Authorization` /
|
|
201
|
+
* `Bearer {value}`, which is what every OAuth-protected MCP server expects; the override exists
|
|
202
|
+
* for a gateway that reads the token somewhere else, exactly as {@link McpSecretRef.header} does.
|
|
203
|
+
*/
|
|
204
|
+
header?: string;
|
|
205
|
+
headerTemplate?: string;
|
|
206
|
+
}
|
|
207
|
+
/** The header an OAuth access token rides when the declaration does not say otherwise. */
|
|
208
|
+
export declare const MCP_OAUTH_DEFAULT_HEADER = "Authorization";
|
|
209
|
+
/** The template that header's value uses when the declaration does not say otherwise. */
|
|
210
|
+
export declare const MCP_OAUTH_DEFAULT_HEADER_TEMPLATE = "Bearer {value}";
|
|
132
211
|
/**
|
|
133
212
|
* A tool server (MCP) an agent kind can be given. Registered on the `AgentKindRegistry` by id and
|
|
134
213
|
* referenced from any number of kinds, or declared inline on a single kind.
|
|
@@ -178,6 +257,17 @@ export interface McpServerDefinition {
|
|
|
178
257
|
harnesses?: HarnessKind[];
|
|
179
258
|
/** Credentials the server needs, by name. Resolved at dispatch; never rendered into a prompt. */
|
|
180
259
|
secretKeys?: McpSecretRef[];
|
|
260
|
+
/**
|
|
261
|
+
* OAuth, for a remote server that authenticates with a granted token rather than a static one.
|
|
262
|
+
* `http` transport only — a `stdio` server is a child process with no request to authorise, and
|
|
263
|
+
* boot validation refuses the combination rather than letting it read as configured.
|
|
264
|
+
*
|
|
265
|
+
* Composes with {@link McpServerDefinition.secretKeys} rather than replacing them: a server may
|
|
266
|
+
* want a granted token AND a static tenant header, and each rides the channel its own
|
|
267
|
+
* declaration named. The access token's header is the one place they can collide, which boot
|
|
268
|
+
* validation names.
|
|
269
|
+
*/
|
|
270
|
+
oauth?: McpOAuthConfig;
|
|
181
271
|
}
|
|
182
272
|
/**
|
|
183
273
|
* The prompt-facing projection of a tool server that was actually wired for this dispatch. Carried
|
|
@@ -213,8 +303,17 @@ export interface UnavailableToolServer {
|
|
|
213
303
|
* `harnesses` list, not a different harness.
|
|
214
304
|
* - `over_budget` says the server was declared, servable and credentialed, and lost to a cap.
|
|
215
305
|
* Nothing about the server is wrong; the KIND declares more than a job body carries.
|
|
306
|
+
* - `oauth_not_connected` is kept apart from `missing_secret` because the fix is not a value to
|
|
307
|
+
* type: nobody has AUTHORISED this workspace against the server yet, and the remedy is a
|
|
308
|
+
* person pressing Connect and signing in at the vendor. An operator who read "credential not
|
|
309
|
+
* configured" would go looking for a variable that does not exist.
|
|
310
|
+
* - `oauth_token_failed` says a grant (or a client-credentials client) IS on file and the
|
|
311
|
+
* platform could not turn it into an access token: a revoked or expired refresh token, an
|
|
312
|
+
* authorization server that would not answer, a rotated client secret. Apart from
|
|
313
|
+
* `oauth_not_connected` because "never connected" and "the connection stopped working" send an
|
|
314
|
+
* operator to different places, and only the second is ever transient.
|
|
216
315
|
*/
|
|
217
|
-
reason: 'harness_unsupported' | 'transport_unsupported' | 'missing_secret' | 'reserved_secret' | 'over_budget';
|
|
316
|
+
reason: 'harness_unsupported' | 'transport_unsupported' | 'missing_secret' | 'reserved_secret' | 'oauth_not_connected' | 'oauth_token_failed' | 'over_budget';
|
|
218
317
|
}
|
|
219
318
|
/**
|
|
220
319
|
* Which MCP transports each harness's CLI can actually reach. An exhaustive `Record` over
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-capabilities.d.ts","sourceRoot":"","sources":["../../src/domain/agent-capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAiB7D,0EAA0E;AAC1E,MAAM,WAAW,qBAAqB;IACpC,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAA;IACZ,uGAAuG;IACvG,OAAO,EAAE,MAAM,CAAA;IACf,2FAA2F;IAC3F,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,aAAa;IAC5B,0GAA0G;IAC1G,OAAO,EAAE,MAAM,CAAA;IACf,6GAA6G;IAC7G,MAAM,EAAE,SAAS,GAAG,SAAS,CAAA;IAC7B,4FAA4F;IAC5F,IAAI,EAAE,MAAM,CAAA;IACZ,kGAAkG;IAClG,WAAW,EAAE,MAAM,CAAA;IACnB,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAA;IACpB,qFAAqF;IACrF,SAAS,EAAE,qBAAqB,EAAE,CAAA;CACnC;AAED,iGAAiG;AACjG,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,GAAG,EAAE,MAAM,CAAA;CACZ;AAMD,oFAAoF;AACpF,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,0GAA0G;IAC1G,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC7B;AAED,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,0FAA0F;IAC1F,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC;AAED,MAAM,MAAM,YAAY,GAAG,iBAAiB,GAAG,gBAAgB,CAAA;AAE/D;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;;;;;;OAeG;IACH,GAAG,EAAE,MAAM,CAAA;IACX;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAA;IACV,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,YAAY,CAAA;IACvB;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,WAAW,EAAE,CAAA;IACzB,iGAAiG;IACjG,UAAU,CAAC,EAAE,YAAY,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"agent-capabilities.d.ts","sourceRoot":"","sources":["../../src/domain/agent-capabilities.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/** The header an OAuth access token rides when the declaration does not say otherwise. */
|
|
2
|
+
export const MCP_OAUTH_DEFAULT_HEADER = 'Authorization';
|
|
3
|
+
/** The template that header's value uses when the declaration does not say otherwise. */
|
|
4
|
+
export const MCP_OAUTH_DEFAULT_HEADER_TEMPLATE = 'Bearer {value}';
|
|
1
5
|
/**
|
|
2
6
|
* Which MCP transports each harness's CLI can actually reach. An exhaustive `Record` over
|
|
3
7
|
* `HarnessKind`, so a new harness cannot be added without stating its answer: an omitted entry
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-capabilities.js","sourceRoot":"","sources":["../../src/domain/agent-capabilities.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent-capabilities.js","sourceRoot":"","sources":["../../src/domain/agent-capabilities.ts"],"names":[],"mappings":"AA0OA,0FAA0F;AAC1F,MAAM,CAAC,MAAM,wBAAwB,GAAG,eAAe,CAAA;AACvD,yFAAyF;AACzF,MAAM,CAAC,MAAM,iCAAiC,GAAG,gBAAgB,CAAA;AAuHjE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAyD;IAC1F,EAAE,EAAE,EAAE;IACN,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC;IAChC,KAAK,EAAE,CAAC,OAAO,CAAC;CACjB,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAClC,MAAM,CAAC,IAAI,CAAC,sBAAsB,CACnC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;AAEjE;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB,CACtC,UAAkD,EAClD,OAAoB;IAEpB,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAA;IAC5D,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAC7E,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,yBAAyB,CACvC,OAAoB,EACpB,SAA+B;IAE/B,OAAO,sBAAsB,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;AAC5D,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAClC,UAAgE;IAEhE,OAAO,uBAAuB,CAAC,MAAM,CACnC,CAAC,OAAO,EAAE,EAAE,CACV,wBAAwB,CAAC,UAAU,EAAE,OAAO,CAAC;QAC7C,yBAAyB,CAAC,OAAO,EAAE,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAChE,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,gDAAgD;IAChD,UAAU,EAAE,EAAE;IACd,0EAA0E;IAC1E,aAAa,EAAE,MAAM;IACrB;;;;;;;OAOG;IACH,oBAAoB,EAAE,EAAE;CAChB,CAAA;AAEV;;;;;;;;;;GAUG;AACH,MAAM,UAAU,uBAAuB,CAAC,UAA+B;IACrE,MAAM,SAAS,GACb,UAAU,CAAC,SAAS,CAAC,IAAI,KAAK,OAAO;QACnC,CAAC,CAAC;YACE,OAAO,EAAE,UAAU,CAAC,SAAS,CAAC,OAAO;YACrC,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,IAAI;YAC/B,GAAG,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG;SAC9B;QACH,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC,SAAS,CAAC,OAAO,EAAE,CAAA;IAC9E,MAAM,IAAI,GAAG;QACX,EAAE,EAAE,UAAU,CAAC,EAAE;QACjB,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,IAAI;QACpC,GAAG,SAAS;QACZ,YAAY,EAAE,UAAU,CAAC,YAAY;KACtC,CAAA;IACD,OAAO,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;AAC7C,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,cAAc,CAAC,KAAa;IACnC,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACrC,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACxE,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,4BAA4B,CAAA;AAEjE,MAAM,UAAU,kBAAkB,CAAC,EAAU;IAC3C,OAAO,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AACvC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,oCAAoC,CAAA;AAEzE,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;IACnC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IACzB,OAAO,MAAM,CAAC,MAAM,KAAK,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AACjE,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;IACnC,OAAO,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;AACrD,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,GAAW;IAClC,MAAM,KAAK,GAAG,0BAA0B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAClD,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAA;IAC5B,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAE,CAAA;IAC3B,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;IAChE,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAC5C,MAAM,IAAI,GAAG,CACX,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,cAAc,KAAK,CAAC,CAAC;QAC/C,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,gCAAgC;QACpE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CACnC,CAAC,WAAW,EAAE,CAAA;IACf,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,CAAA;AAClD,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,KAAK,IAAI,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACpF,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { AuditEventDetails } from '@cat-factory/contracts';
|
|
2
|
+
import type { AuditActor, AuditEventRecord, AuditEventView } from '../ports/audit.js';
|
|
3
|
+
/** Default page size when a caller names none. */
|
|
4
|
+
export declare const AUDIT_PAGE_LIMIT_DEFAULT = 50;
|
|
5
|
+
/** Hard ceiling, so a caller-supplied `limit` can't ask for the whole table. */
|
|
6
|
+
export declare const AUDIT_PAGE_LIMIT_MAX = 200;
|
|
7
|
+
/** The (at, id) pair a cursor points just past. */
|
|
8
|
+
export interface AuditCursor {
|
|
9
|
+
at: number;
|
|
10
|
+
id: string;
|
|
11
|
+
}
|
|
12
|
+
/** Clamp a caller's requested page size into the allowed range. */
|
|
13
|
+
export declare function auditPageLimit(limit?: number): number;
|
|
14
|
+
/**
|
|
15
|
+
* Encode the last row of a page as the next page's cursor. `at` and `id` TOGETHER, because `at`
|
|
16
|
+
* alone is not unique: two events recorded in the same millisecond would straddle the boundary
|
|
17
|
+
* and be served twice or skipped.
|
|
18
|
+
*/
|
|
19
|
+
export declare function encodeAuditCursor(row: AuditCursor): string;
|
|
20
|
+
/**
|
|
21
|
+
* Decode a cursor, or null when there is none / it is unreadable.
|
|
22
|
+
*
|
|
23
|
+
* A malformed cursor reads as "start from the newest" rather than throwing: cursors are opaque
|
|
24
|
+
* and round-trip through a URL, so a truncated one is a client bug that should cost a page
|
|
25
|
+
* position, not a 500. It cannot widen a read either way, because the account scope is a
|
|
26
|
+
* separate argument that no cursor carries.
|
|
27
|
+
*/
|
|
28
|
+
export declare function decodeAuditCursor(cursor?: string | null): AuditCursor | null;
|
|
29
|
+
/**
|
|
30
|
+
* The persisted actor columns as a discriminated {@link AuditActor}.
|
|
31
|
+
*
|
|
32
|
+
* Anything that is not a complete `user` or `apiKey` principal reads as `system`: that is the
|
|
33
|
+
* honest rendering of "no principal is recorded on this row", and it never invents a user id,
|
|
34
|
+
* which is the single outcome that would misattribute an action to a person.
|
|
35
|
+
*/
|
|
36
|
+
export declare function rowToAuditActor(row: {
|
|
37
|
+
actor_kind: string;
|
|
38
|
+
actor_user_id: string | null;
|
|
39
|
+
actor_api_key_id: string | null;
|
|
40
|
+
}): AuditActor;
|
|
41
|
+
/** The two nullable actor columns for a principal, for an INSERT. */
|
|
42
|
+
export declare function auditActorColumns(actor: AuditActor): {
|
|
43
|
+
actor_kind: AuditActor['kind'];
|
|
44
|
+
actor_user_id: string | null;
|
|
45
|
+
actor_api_key_id: string | null;
|
|
46
|
+
};
|
|
47
|
+
/** An event's `details` as the single TEXT column both stores keep it in. */
|
|
48
|
+
export declare function encodeAuditDetails(details: AuditEventDetails): string;
|
|
49
|
+
/**
|
|
50
|
+
* The `details` column as fields again, or an EMPTY set when the blob is unreadable.
|
|
51
|
+
*
|
|
52
|
+
* Empty rather than a throw, deliberately, and it is the one place in this module where the
|
|
53
|
+
* lenient branch is the strict choice: who acted, on what, and when are the irreplaceable parts
|
|
54
|
+
* of an audit row, and losing the whole row (or the whole PAGE) because one event's values no
|
|
55
|
+
* longer parse is the single failure a viewer must not have. The values are what the viewer
|
|
56
|
+
* interpolates, so their absence shows up as a row that states less, never as a row that is not
|
|
57
|
+
* there. A non-object blob (`"null"`, `"3"`, `"[]"`) counts as unreadable for the same reason it
|
|
58
|
+
* would break interpolation.
|
|
59
|
+
*/
|
|
60
|
+
export declare function decodeAuditDetails(raw: string | null): AuditEventDetails;
|
|
61
|
+
/** The snake_case columns both stores keep an audit event in, as WRITTEN. */
|
|
62
|
+
export interface AuditEventColumns {
|
|
63
|
+
id: string;
|
|
64
|
+
account_id: string;
|
|
65
|
+
workspace_id: string | null;
|
|
66
|
+
actor_kind: string;
|
|
67
|
+
actor_user_id: string | null;
|
|
68
|
+
actor_api_key_id: string | null;
|
|
69
|
+
action: string;
|
|
70
|
+
target_type: string;
|
|
71
|
+
target_id: string;
|
|
72
|
+
details: string;
|
|
73
|
+
at: number;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The same row as READ BACK. Identical but for `details`, which the reader tolerates as NULL
|
|
77
|
+
* even though both schemas declare it NOT NULL: a driver, a hand-run statement or a future
|
|
78
|
+
* lineage can still hand one over, and the row is worth more than its values (see
|
|
79
|
+
* {@link decodeAuditDetails}). The WRITE type admits no null, so nothing here can produce one.
|
|
80
|
+
*/
|
|
81
|
+
export interface AuditEventRow extends Omit<AuditEventColumns, 'details'> {
|
|
82
|
+
details: string | null;
|
|
83
|
+
}
|
|
84
|
+
/** Every column of an audit event, for an INSERT. */
|
|
85
|
+
export declare function auditEventColumns(event: AuditEventRecord): AuditEventColumns;
|
|
86
|
+
/**
|
|
87
|
+
* A persisted row as the event a viewer renders.
|
|
88
|
+
*
|
|
89
|
+
* Shaped structurally (a plain snake_case object) rather than against either driver's row type,
|
|
90
|
+
* so both facades map through this one function. `action` and `target_type` go through the
|
|
91
|
+
* contracts readers, so a member retired since the row was written arrives NAMED as retired
|
|
92
|
+
* rather than dropped or guessed at.
|
|
93
|
+
*/
|
|
94
|
+
export declare function rowToAuditEventView(row: AuditEventRow): AuditEventView;
|
|
95
|
+
//# sourceMappingURL=audit-log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-log.d.ts","sourceRoot":"","sources":["../../src/domain/audit-log.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAiBrF,kDAAkD;AAClD,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAC1C,gFAAgF;AAChF,eAAO,MAAM,oBAAoB,MAAM,CAAA;AAEvC,mDAAmD;AACnD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;CACX;AAED,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAE1D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAO5E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE;IACnC,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;CAChC,GAAG,UAAU,CAQb;AAED,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG;IACpD,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;IAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;CAChC,CAMA;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAErE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,iBAAiB,CAWxE;AAED,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,EAAE,EAAE,MAAM,CAAA;CACX;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,iBAAiB,EAAE,SAAS,CAAC;IACvE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AAED,qDAAqD;AACrD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,CAY5E;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAYtE"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { readAuditAction, readAuditTargetType } from '@cat-factory/contracts';
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// The audit log's pure rules: how a page is bounded, how a cursor names the row it continues
|
|
4
|
+
// from, and how a persisted row reads back as an event.
|
|
5
|
+
//
|
|
6
|
+
// In kernel rather than in either facade because BOTH implement `AuditEventRepository` and must
|
|
7
|
+
// agree byte-for-byte about all of it. A cursor is opaque to its caller, which is exactly why a
|
|
8
|
+
// per-facade copy of its encoding is dangerous: nothing about a mismatched cursor looks wrong at
|
|
9
|
+
// the boundary, it just silently starts a page somewhere else. The row mapping is here for a
|
|
10
|
+
// related reason: it holds three decisions a reader could get subtly wrong on its own (which
|
|
11
|
+
// actor column belongs to which kind, what a retired vocabulary member renders as, what an
|
|
12
|
+
// unreadable `details` blob does), and a facade that re-derived any of them would diverge in a
|
|
13
|
+
// way only that runtime's users would ever see. The conformance suite drives both repositories
|
|
14
|
+
// through the same assertions, so a divergence would have to be a divergence in code they share.
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/** Default page size when a caller names none. */
|
|
17
|
+
export const AUDIT_PAGE_LIMIT_DEFAULT = 50;
|
|
18
|
+
/** Hard ceiling, so a caller-supplied `limit` can't ask for the whole table. */
|
|
19
|
+
export const AUDIT_PAGE_LIMIT_MAX = 200;
|
|
20
|
+
/** Clamp a caller's requested page size into the allowed range. */
|
|
21
|
+
export function auditPageLimit(limit) {
|
|
22
|
+
if (limit === undefined || !Number.isFinite(limit) || limit < 1)
|
|
23
|
+
return AUDIT_PAGE_LIMIT_DEFAULT;
|
|
24
|
+
return Math.min(Math.floor(limit), AUDIT_PAGE_LIMIT_MAX);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Encode the last row of a page as the next page's cursor. `at` and `id` TOGETHER, because `at`
|
|
28
|
+
* alone is not unique: two events recorded in the same millisecond would straddle the boundary
|
|
29
|
+
* and be served twice or skipped.
|
|
30
|
+
*/
|
|
31
|
+
export function encodeAuditCursor(row) {
|
|
32
|
+
return `${row.at}:${row.id}`;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Decode a cursor, or null when there is none / it is unreadable.
|
|
36
|
+
*
|
|
37
|
+
* A malformed cursor reads as "start from the newest" rather than throwing: cursors are opaque
|
|
38
|
+
* and round-trip through a URL, so a truncated one is a client bug that should cost a page
|
|
39
|
+
* position, not a 500. It cannot widen a read either way, because the account scope is a
|
|
40
|
+
* separate argument that no cursor carries.
|
|
41
|
+
*/
|
|
42
|
+
export function decodeAuditCursor(cursor) {
|
|
43
|
+
if (!cursor)
|
|
44
|
+
return null;
|
|
45
|
+
const split = cursor.indexOf(':');
|
|
46
|
+
if (split <= 0 || split === cursor.length - 1)
|
|
47
|
+
return null;
|
|
48
|
+
const at = Number(cursor.slice(0, split));
|
|
49
|
+
if (!Number.isSafeInteger(at))
|
|
50
|
+
return null;
|
|
51
|
+
return { at, id: cursor.slice(split + 1) };
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The persisted actor columns as a discriminated {@link AuditActor}.
|
|
55
|
+
*
|
|
56
|
+
* Anything that is not a complete `user` or `apiKey` principal reads as `system`: that is the
|
|
57
|
+
* honest rendering of "no principal is recorded on this row", and it never invents a user id,
|
|
58
|
+
* which is the single outcome that would misattribute an action to a person.
|
|
59
|
+
*/
|
|
60
|
+
export function rowToAuditActor(row) {
|
|
61
|
+
if (row.actor_kind === 'user' && row.actor_user_id) {
|
|
62
|
+
return { kind: 'user', userId: row.actor_user_id };
|
|
63
|
+
}
|
|
64
|
+
if (row.actor_kind === 'apiKey' && row.actor_api_key_id) {
|
|
65
|
+
return { kind: 'apiKey', apiKeyId: row.actor_api_key_id };
|
|
66
|
+
}
|
|
67
|
+
return { kind: 'system' };
|
|
68
|
+
}
|
|
69
|
+
/** The two nullable actor columns for a principal, for an INSERT. */
|
|
70
|
+
export function auditActorColumns(actor) {
|
|
71
|
+
return {
|
|
72
|
+
actor_kind: actor.kind,
|
|
73
|
+
actor_user_id: actor.kind === 'user' ? actor.userId : null,
|
|
74
|
+
actor_api_key_id: actor.kind === 'apiKey' ? actor.apiKeyId : null,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** An event's `details` as the single TEXT column both stores keep it in. */
|
|
78
|
+
export function encodeAuditDetails(details) {
|
|
79
|
+
return JSON.stringify(details);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The `details` column as fields again, or an EMPTY set when the blob is unreadable.
|
|
83
|
+
*
|
|
84
|
+
* Empty rather than a throw, deliberately, and it is the one place in this module where the
|
|
85
|
+
* lenient branch is the strict choice: who acted, on what, and when are the irreplaceable parts
|
|
86
|
+
* of an audit row, and losing the whole row (or the whole PAGE) because one event's values no
|
|
87
|
+
* longer parse is the single failure a viewer must not have. The values are what the viewer
|
|
88
|
+
* interpolates, so their absence shows up as a row that states less, never as a row that is not
|
|
89
|
+
* there. A non-object blob (`"null"`, `"3"`, `"[]"`) counts as unreadable for the same reason it
|
|
90
|
+
* would break interpolation.
|
|
91
|
+
*/
|
|
92
|
+
export function decodeAuditDetails(raw) {
|
|
93
|
+
if (!raw)
|
|
94
|
+
return {};
|
|
95
|
+
try {
|
|
96
|
+
const parsed = JSON.parse(raw);
|
|
97
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
98
|
+
return {};
|
|
99
|
+
return parsed;
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// An unparseable value blob must not cost the row it belongs to, and the empty result is
|
|
103
|
+
// itself the report: the viewer renders the action with no values.
|
|
104
|
+
return {};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Every column of an audit event, for an INSERT. */
|
|
108
|
+
export function auditEventColumns(event) {
|
|
109
|
+
return {
|
|
110
|
+
id: event.id,
|
|
111
|
+
account_id: event.accountId,
|
|
112
|
+
workspace_id: event.workspaceId ?? null,
|
|
113
|
+
...auditActorColumns(event.actor),
|
|
114
|
+
action: event.action,
|
|
115
|
+
target_type: event.targetType,
|
|
116
|
+
target_id: event.targetId,
|
|
117
|
+
details: encodeAuditDetails(event.details),
|
|
118
|
+
at: event.at,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* A persisted row as the event a viewer renders.
|
|
123
|
+
*
|
|
124
|
+
* Shaped structurally (a plain snake_case object) rather than against either driver's row type,
|
|
125
|
+
* so both facades map through this one function. `action` and `target_type` go through the
|
|
126
|
+
* contracts readers, so a member retired since the row was written arrives NAMED as retired
|
|
127
|
+
* rather than dropped or guessed at.
|
|
128
|
+
*/
|
|
129
|
+
export function rowToAuditEventView(row) {
|
|
130
|
+
return {
|
|
131
|
+
id: row.id,
|
|
132
|
+
accountId: row.account_id,
|
|
133
|
+
workspaceId: row.workspace_id,
|
|
134
|
+
actor: rowToAuditActor(row),
|
|
135
|
+
action: readAuditAction(row.action),
|
|
136
|
+
targetType: readAuditTargetType(row.target_type),
|
|
137
|
+
targetId: row.target_id,
|
|
138
|
+
details: decodeAuditDetails(row.details),
|
|
139
|
+
at: row.at,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=audit-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-log.js","sourceRoot":"","sources":["../../src/domain/audit-log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { AgentToolCallSummary } from '../ports/agent-tool-calls.js';
|
|
2
|
+
/** What every level of the tool-call rollup counts. */
|
|
3
|
+
export interface ToolCallRollupTotals {
|
|
4
|
+
calls: number;
|
|
5
|
+
/** Calls that came back `ok: false` — the tool itself failed, inside the container. */
|
|
6
|
+
failures: number;
|
|
7
|
+
}
|
|
8
|
+
/** One tool's calls, folded across the agent kinds that made them. */
|
|
9
|
+
export interface ToolCallToolRollup extends ToolCallRollupTotals {
|
|
10
|
+
tool: string;
|
|
11
|
+
}
|
|
12
|
+
/** One agent kind's calls, folded across the tools it used. */
|
|
13
|
+
export interface ToolCallKindRollup extends ToolCallRollupTotals {
|
|
14
|
+
agentKind: string;
|
|
15
|
+
}
|
|
16
|
+
/** Fold every cell into the run's totals. */
|
|
17
|
+
export declare function foldToolCallTotals(cells: readonly AgentToolCallSummary[]): ToolCallRollupTotals;
|
|
18
|
+
/**
|
|
19
|
+
* Fold the cells into one rollup per TOOL, most-failed first.
|
|
20
|
+
*
|
|
21
|
+
* Ordered by failures rather than by call count or store order, because the question this
|
|
22
|
+
* breakdown exists to answer is which tool to look at, and a run's busiest tool is almost
|
|
23
|
+
* never its broken one.
|
|
24
|
+
*/
|
|
25
|
+
export declare function foldToolCallsByTool(cells: readonly AgentToolCallSummary[]): ToolCallToolRollup[];
|
|
26
|
+
/** Fold the cells into one rollup per AGENT KIND, most-failed first (same ordering rule). */
|
|
27
|
+
export declare function foldToolCallsByAgentKind(cells: readonly AgentToolCallSummary[]): ToolCallKindRollup[];
|
|
28
|
+
/**
|
|
29
|
+
* The worst `(agentKind, tool)` cell that is itself a retry loop, or null when no cell is one.
|
|
30
|
+
*
|
|
31
|
+
* The finest grain the store keeps, which is the point: a run's failures are diagnostic when they
|
|
32
|
+
* CONCENTRATE (one agent kind retrying one tool that cannot work) and unremarkable when they
|
|
33
|
+
* scatter, and only a cell can tell those apart. Both breakdowns above have folded that
|
|
34
|
+
* concentration away by the time a reader sees them.
|
|
35
|
+
*
|
|
36
|
+
* FILTER FIRST, then rank. The reverse, ranking every failing cell and testing only the
|
|
37
|
+
* winner, reads as the same thing and is not: the ranking leads on failure COUNT, so a coder's
|
|
38
|
+
* 6 failures across 100 healthy `bash` calls outranks a fixer wedged 5-for-5 on one tool, and
|
|
39
|
+
* the run that is textbook stuck reports no loop at all. The qualifying cells are what the rule
|
|
40
|
+
* is about; the ranking only decides which of them to name.
|
|
41
|
+
*/
|
|
42
|
+
export declare function worstToolRetryLoop(cells: readonly AgentToolCallSummary[]): AgentToolCallSummary | null;
|
|
43
|
+
/**
|
|
44
|
+
* The share of a rollup's calls that failed, or NULL where it made none.
|
|
45
|
+
*
|
|
46
|
+
* Null rather than 0: a run that called no tools has no failure rate, and reporting one as a
|
|
47
|
+
* clean 0% would put it beside a run whose every call worked — the same number for "nothing
|
|
48
|
+
* happened" and "everything worked", which are different findings. A cell always has calls (it
|
|
49
|
+
* exists because rows were counted into it), so only the folded totals of an empty run reach
|
|
50
|
+
* the null.
|
|
51
|
+
*/
|
|
52
|
+
export declare function toolCallFailureRate(totals: ToolCallRollupTotals): number | null;
|
|
53
|
+
//# sourceMappingURL=tool-call-rollup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-call-rollup.d.ts","sourceRoot":"","sources":["../../src/domain/tool-call-rollup.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AAExE,uDAAuD;AACvD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,uFAAuF;IACvF,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,sEAAsE;AACtE,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,IAAI,EAAE,MAAM,CAAA;CACb;AAED,+DAA+D;AAC/D,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,SAAS,EAAE,MAAM,CAAA;CAClB;AAQD,6CAA6C;AAC7C,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG,oBAAoB,CAE/F;AAeD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG,kBAAkB,EAAE,CAOhG;AAED,6FAA6F;AAC7F,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GACrC,kBAAkB,EAAE,CAStB;AA2CD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GACrC,oBAAoB,GAAG,IAAI,CAE7B;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,GAAG,IAAI,CAE/E"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Pure folds over the TOOL-CALL rollup the telemetry stores compute.
|
|
2
|
+
//
|
|
3
|
+
// The sibling of `llm-rollup.ts`, and it follows the same rule for the same reason: the store
|
|
4
|
+
// aggregates ONE grain — `(agentKind, tool)` — and every coarser view (per tool, per agent
|
|
5
|
+
// kind, the run totals) is a fold over that same result set. A second aggregate over the same
|
|
6
|
+
// rows is a second chance to disagree with the breakdown printed beside it.
|
|
7
|
+
//
|
|
8
|
+
// These fold a handful of cells (the tools one run touched), NOT the rows they were computed
|
|
9
|
+
// from: the aggregation itself stays in SQL.
|
|
10
|
+
const EMPTY = { calls: 0, failures: 0 };
|
|
11
|
+
function merge(a, b) {
|
|
12
|
+
return { calls: a.calls + b.calls, failures: a.failures + b.failures };
|
|
13
|
+
}
|
|
14
|
+
/** Fold every cell into the run's totals. */
|
|
15
|
+
export function foldToolCallTotals(cells) {
|
|
16
|
+
return cells.reduce((acc, cell) => merge(acc, cell), EMPTY);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Order two folded rows most-broken first: failure COUNT, then the failure SHARE, then the
|
|
20
|
+
* name so the order is total (an order that varies between two reads of the same unchanged
|
|
21
|
+
* run reads to a caller as a change in the run).
|
|
22
|
+
*
|
|
23
|
+
* The share is compared by cross-multiplication rather than by dividing: both `calls` are
|
|
24
|
+
* positive on a folded row, so the two orderings agree, and this one cannot produce a NaN
|
|
25
|
+
* from a row an empty fold happened to reach.
|
|
26
|
+
*/
|
|
27
|
+
function mostBrokenFirst(a, b) {
|
|
28
|
+
return b.failures - a.failures || b.failures * a.calls - a.failures * b.calls;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Fold the cells into one rollup per TOOL, most-failed first.
|
|
32
|
+
*
|
|
33
|
+
* Ordered by failures rather than by call count or store order, because the question this
|
|
34
|
+
* breakdown exists to answer is which tool to look at, and a run's busiest tool is almost
|
|
35
|
+
* never its broken one.
|
|
36
|
+
*/
|
|
37
|
+
export function foldToolCallsByTool(cells) {
|
|
38
|
+
const byTool = new Map();
|
|
39
|
+
for (const cell of cells) {
|
|
40
|
+
const prev = byTool.get(cell.tool);
|
|
41
|
+
byTool.set(cell.tool, { tool: cell.tool, ...merge(prev ?? EMPTY, cell) });
|
|
42
|
+
}
|
|
43
|
+
return [...byTool.values()].sort((a, b) => mostBrokenFirst(a, b) || a.tool.localeCompare(b.tool));
|
|
44
|
+
}
|
|
45
|
+
/** Fold the cells into one rollup per AGENT KIND, most-failed first (same ordering rule). */
|
|
46
|
+
export function foldToolCallsByAgentKind(cells) {
|
|
47
|
+
const byKind = new Map();
|
|
48
|
+
for (const cell of cells) {
|
|
49
|
+
const prev = byKind.get(cell.agentKind);
|
|
50
|
+
byKind.set(cell.agentKind, { agentKind: cell.agentKind, ...merge(prev ?? EMPTY, cell) });
|
|
51
|
+
}
|
|
52
|
+
return [...byKind.values()].sort((a, b) => mostBrokenFirst(a, b) || a.agentKind.localeCompare(b.agentKind));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The single `(agentKind, tool)` cell most worth looking at among those given, or null when the
|
|
56
|
+
* set is empty or nothing in it failed.
|
|
57
|
+
*
|
|
58
|
+
* Ordered by the same rule as the breakdowns, so the row a reader is pointed at is the one that
|
|
59
|
+
* sorts first in them. Module-local: it RANKS a set someone else chose, which on its own answers
|
|
60
|
+
* no question a caller has. {@link worstToolRetryLoop} is the exported selector, and pairing the
|
|
61
|
+
* two here rather than at the call site is the whole point: ranking first and testing the winner
|
|
62
|
+
* afterwards silently drops every qualifying cell behind a busier one (see its note).
|
|
63
|
+
*/
|
|
64
|
+
function worstToolCallCell(cells) {
|
|
65
|
+
const failing = cells.filter((cell) => cell.failures > 0);
|
|
66
|
+
if (failing.length === 0)
|
|
67
|
+
return null;
|
|
68
|
+
return failing.sort((a, b) => mostBrokenFirst(a, b) ||
|
|
69
|
+
a.agentKind.localeCompare(b.agentKind) ||
|
|
70
|
+
a.tool.localeCompare(b.tool))[0];
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Failures on ONE `(agentKind, tool)` cell at or above this share of that cell's calls, once it
|
|
74
|
+
* has failed at least {@link RETRY_LOOP_MIN_FAILURES} times, read as an agent retrying something
|
|
75
|
+
* that cannot work rather than meeting the occasional failing command.
|
|
76
|
+
*
|
|
77
|
+
* Two conditions rather than one because each alone fires on a healthy run: a share alone flags
|
|
78
|
+
* the single `bash` call that legitimately returned non-zero, and a count alone flags a thorough
|
|
79
|
+
* agent that ran hundreds of tests. Both together are the shape a stuck loop makes.
|
|
80
|
+
*/
|
|
81
|
+
const RETRY_LOOP_FAILURE_RATE = 0.5;
|
|
82
|
+
const RETRY_LOOP_MIN_FAILURES = 5;
|
|
83
|
+
/** Whether one cell, on its own, has the shape of an agent stuck retrying a broken tool. */
|
|
84
|
+
function isToolRetryLoop(cell) {
|
|
85
|
+
return (cell.failures >= RETRY_LOOP_MIN_FAILURES &&
|
|
86
|
+
cell.failures / cell.calls >= RETRY_LOOP_FAILURE_RATE);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The worst `(agentKind, tool)` cell that is itself a retry loop, or null when no cell is one.
|
|
90
|
+
*
|
|
91
|
+
* The finest grain the store keeps, which is the point: a run's failures are diagnostic when they
|
|
92
|
+
* CONCENTRATE (one agent kind retrying one tool that cannot work) and unremarkable when they
|
|
93
|
+
* scatter, and only a cell can tell those apart. Both breakdowns above have folded that
|
|
94
|
+
* concentration away by the time a reader sees them.
|
|
95
|
+
*
|
|
96
|
+
* FILTER FIRST, then rank. The reverse, ranking every failing cell and testing only the
|
|
97
|
+
* winner, reads as the same thing and is not: the ranking leads on failure COUNT, so a coder's
|
|
98
|
+
* 6 failures across 100 healthy `bash` calls outranks a fixer wedged 5-for-5 on one tool, and
|
|
99
|
+
* the run that is textbook stuck reports no loop at all. The qualifying cells are what the rule
|
|
100
|
+
* is about; the ranking only decides which of them to name.
|
|
101
|
+
*/
|
|
102
|
+
export function worstToolRetryLoop(cells) {
|
|
103
|
+
return worstToolCallCell(cells.filter(isToolRetryLoop));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The share of a rollup's calls that failed, or NULL where it made none.
|
|
107
|
+
*
|
|
108
|
+
* Null rather than 0: a run that called no tools has no failure rate, and reporting one as a
|
|
109
|
+
* clean 0% would put it beside a run whose every call worked — the same number for "nothing
|
|
110
|
+
* happened" and "everything worked", which are different findings. A cell always has calls (it
|
|
111
|
+
* exists because rows were counted into it), so only the folded totals of an empty run reach
|
|
112
|
+
* the null.
|
|
113
|
+
*/
|
|
114
|
+
export function toolCallFailureRate(totals) {
|
|
115
|
+
return totals.calls > 0 ? totals.failures / totals.calls : null;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=tool-call-rollup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-call-rollup.js","sourceRoot":"","sources":["../../src/domain/tool-call-rollup.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* - Runtime-specific tables that only exist on one facade (e.g. the Cloudflare-only
|
|
19
19
|
* `live_containers` Durable-Object tracking table) are appended by that facade.
|
|
20
20
|
*/
|
|
21
|
-
export declare const WORKSPACE_SCOPED_TABLES: readonly ['agent_prompt_revisions', 'agent_runs', 'blocks', 'brainstorm_sessions', 'capability_credentials', 'clarity_reviews', 'consensus_groups', 'consensus_sessions', 'custom_manifest_types', 'doc_interview_sessions', 'document_connections', 'documents', 'environment_connections', 'environment_test_runs', 'environment_user_handlers', 'environments', 'gate_outcomes', 'github_branches', 'github_check_runs', 'github_commits', 'github_installations', 'github_issues', 'github_pull_requests', 'github_repos', 'incident_enrichment_connections', 'initiatives', 'kaizen_gradings', 'kaizen_verified_combos', 'merge_threshold_presets', 'merge_track_records', 'model_presets', 'notification_webhooks', 'notifications', 'observability_connections', 'package_registry_connections', 'pipeline_schedule_runs', 'pipeline_schedules', 'pipelines', 'platform_run_days', 'provider_model_catalog', 'provider_subscription_tokens', 'public_api_keys', 'reference_architectures', 'release_health_configs', 'requirement_reviews', 'review_question_posts', 'runner_pool_connections', 'shared_stacks', 'slack_settings', 'task_connections', 'task_source_settings', 'tasks', 'test_secrets', 'tracker_comment_ingests', 'token_usage', 'tracker_settings', 'validation_configs', 'workspace_agent_settings', 'workspace_fragment_defaults', 'workspace_members', 'workspace_settings'];
|
|
21
|
+
export declare const WORKSPACE_SCOPED_TABLES: readonly ['agent_prompt_revisions', 'agent_runs', 'blocks', 'brainstorm_sessions', 'capability_credentials', 'clarity_reviews', 'consensus_groups', 'consensus_sessions', 'custom_manifest_types', 'doc_interview_sessions', 'document_connections', 'documents', 'environment_connections', 'environment_test_runs', 'environment_user_handlers', 'environments', 'gate_outcomes', 'github_branches', 'github_check_runs', 'github_commits', 'github_installations', 'github_issues', 'github_pull_requests', 'github_repos', 'incident_enrichment_connections', 'initiatives', 'kaizen_gradings', 'kaizen_verified_combos', 'mcp_oauth_grants', 'merge_threshold_presets', 'merge_track_records', 'model_presets', 'notification_webhooks', 'notifications', 'observability_connections', 'package_registry_connections', 'pipeline_schedule_runs', 'pipeline_schedules', 'pipelines', 'platform_run_days', 'provider_model_catalog', 'provider_subscription_tokens', 'public_api_keys', 'reference_architectures', 'release_health_configs', 'requirement_reviews', 'review_question_posts', 'runner_pool_connections', 'shared_stacks', 'slack_settings', 'task_connections', 'task_source_settings', 'tasks', 'test_secrets', 'tracker_comment_ingests', 'token_usage', 'tracker_settings', 'validation_configs', 'workspace_agent_settings', 'workspace_fragment_defaults', 'workspace_members', 'workspace_settings'];
|
|
22
22
|
export type WorkspaceScopedTable = (typeof WORKSPACE_SCOPED_TABLES)[number];
|
|
23
23
|
/**
|
|
24
24
|
* Tables that carry a `workspace_id` column but are NOT in {@link WORKSPACE_SCOPED_TABLES}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-cascade.d.ts","sourceRoot":"","sources":["../../src/domain/workspace-cascade.ts"],"names":[],"mappings":"AAyBA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,uBAAuB,YAClC,wBAAwB,EACxB,YAAY,EACZ,QAAQ,EACR,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,EACtB,WAAW,EACX,yBAAyB,EACzB,uBAAuB,EACvB,2BAA2B,EAC3B,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,sBAAsB,EACtB,cAAc,EACd,iCAAiC,EACjC,aAAa,EACb,iBAAiB,EACjB,wBAAwB,EACxB,yBAAyB,EACzB,qBAAqB,EACrB,eAAe,EACf,uBAAuB,EACvB,eAAe,EACf,2BAA2B,EAC3B,8BAA8B,EAC9B,wBAAwB,EACxB,oBAAoB,EACpB,WAAW,EACX,mBAAmB,EACnB,wBAAwB,EACxB,8BAA8B,EAC9B,iBAAiB,EACjB,yBAAyB,EACzB,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,EACzB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,OAAO,EACP,cAAc,EACd,yBAAyB,EACzB,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,0BAA0B,EAC1B,6BAA6B,EAC7B,mBAAmB,EACnB,oBAAoB,CACZ,CAAA;AAEV,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE3E;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,YAAI,oBAAoB,EAAE,kBAAkB,CAAU,CAAA"}
|
|
1
|
+
{"version":3,"file":"workspace-cascade.d.ts","sourceRoot":"","sources":["../../src/domain/workspace-cascade.ts"],"names":[],"mappings":"AAyBA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,uBAAuB,YAClC,wBAAwB,EACxB,YAAY,EACZ,QAAQ,EACR,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,EACtB,WAAW,EACX,yBAAyB,EACzB,uBAAuB,EACvB,2BAA2B,EAC3B,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,sBAAsB,EACtB,cAAc,EACd,iCAAiC,EACjC,aAAa,EACb,iBAAiB,EACjB,wBAAwB,EACxB,kBAAkB,EAClB,yBAAyB,EACzB,qBAAqB,EACrB,eAAe,EACf,uBAAuB,EACvB,eAAe,EACf,2BAA2B,EAC3B,8BAA8B,EAC9B,wBAAwB,EACxB,oBAAoB,EACpB,WAAW,EACX,mBAAmB,EACnB,wBAAwB,EACxB,8BAA8B,EAC9B,iBAAiB,EACjB,yBAAyB,EACzB,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,EACzB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,OAAO,EACP,cAAc,EACd,yBAAyB,EACzB,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,0BAA0B,EAC1B,6BAA6B,EAC7B,mBAAmB,EACnB,oBAAoB,CACZ,CAAA;AAEV,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE3E;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,YAAI,oBAAoB,EAAE,kBAAkB,CAAU,CAAA"}
|