@agentforge-io/sdk-console 0.2.0 → 0.4.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/README.md +3 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -1
- package/dist/resources/connectors.d.ts +7 -1
- package/dist/resources/connectors.js +12 -1
- package/dist/resources/trace.d.ts +16 -0
- package/dist/resources/trace.js +39 -0
- package/dist/trace-types.d.ts +423 -0
- package/dist/trace-types.js +10 -0
- package/dist/types.d.ts +10 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -135,11 +135,14 @@ Resource → methods → HTTP route (all JSON, bearer auth unless marked *public
|
|
|
135
135
|
| `t.teams` | `list` `create` `get` `update` `delete` | `:T/teams[/:id]` (`list({ excludeTemplateSources })`; teams carry `templateSourceOf`) |
|
|
136
136
|
| | `publication` / `listPublication` / `publish` | `GET :T/teams/:id/publication` · `GET :T/teams/publication` · `POST :T/teams/:id/publish` |
|
|
137
137
|
| `t.teams.humanMembers` | `list` `add` `update` `remove` | `:T/teams/:id/human-members[/:userId]` |
|
|
138
|
+
| `t.trace` | `listConversations` / `getConversation` | `GET :T/trace/conversations[?agentId&teamId&surface&model&toolName&hasError&q&from&to&cursor&limit]` · `GET :T/trace/conversations/:id` |
|
|
139
|
+
| | `stats` / `timeseries` | `GET :T/trace/stats` · `GET :T/trace/timeseries[?bucket=hour\|day]` (same filters; `from`/`to` max 31 days) |
|
|
138
140
|
| `t.variables` | `list` `get` `upsert` `remove` | `GET /tenants/:tid/variables[?q=]` · `GET\|PUT\|DELETE /tenants/:tid/variables/:key` (config has `value`; secrets only `valueHint`) |
|
|
139
141
|
| `t.tools` | `grouped` | `GET /tools/grouped?tenantId=` |
|
|
140
142
|
| `t.connectors` | `directory` / `facets` (sends `X-Tenant-Id`) | `GET /connectors/oauth/directory[/facets]` |
|
|
141
143
|
| | `authorize` | `POST /connectors/oauth/:id/authorize?tenantId=&postAuthRedirect=` |
|
|
142
144
|
| | `saveApiKey` | `POST /connectors/oauth/:id/api-key?tenantId=` |
|
|
145
|
+
| | `disconnect` | `DELETE /connectors/oauth/:id?tenantId=` |
|
|
143
146
|
| `templates` | `listPublic` / `getPublic` (public) | `GET /public/templates[/:id]` |
|
|
144
147
|
| | `get` / `updateListing` / `listVersions` | `GET` / `PATCH /templates/:id` · `GET /templates/:id/versions` |
|
|
145
148
|
| | `signListingAsset` | `POST /templates/:id/listing-assets/sign` |
|
package/dist/client.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { ConnectorsResource } from './resources/connectors';
|
|
|
6
6
|
import { InvitesResource, MembersResource, PublicInvitesResource } from './resources/members';
|
|
7
7
|
import { MarketplaceResource } from './resources/marketplace';
|
|
8
8
|
import { PlaygroundResource } from './resources/playground';
|
|
9
|
+
import { TraceResource } from './resources/trace';
|
|
9
10
|
import { TeamsResource } from './resources/teams';
|
|
10
11
|
import { TemplatesResource, TenantTemplatesResource } from './resources/templates';
|
|
11
12
|
import { TenantsResource } from './resources/tenants';
|
|
@@ -23,6 +24,8 @@ export declare class TenantScope {
|
|
|
23
24
|
readonly templates: TenantTemplatesResource;
|
|
24
25
|
readonly apps: AppsResource;
|
|
25
26
|
readonly playground: PlaygroundResource;
|
|
27
|
+
/** Agent / team activity (conversations + span trace) and performance stats. */
|
|
28
|
+
readonly trace: TraceResource;
|
|
26
29
|
/** Business data of the workspace (`{{config:KEY}}` / `{{secret:KEY}}`). */
|
|
27
30
|
readonly variables: VariablesResource;
|
|
28
31
|
constructor(http: HttpCore, tenantId: string);
|
package/dist/client.js
CHANGED
|
@@ -16,6 +16,7 @@ const connectors_1 = require("./resources/connectors");
|
|
|
16
16
|
const members_1 = require("./resources/members");
|
|
17
17
|
const marketplace_1 = require("./resources/marketplace");
|
|
18
18
|
const playground_1 = require("./resources/playground");
|
|
19
|
+
const trace_1 = require("./resources/trace");
|
|
19
20
|
const teams_1 = require("./resources/teams");
|
|
20
21
|
const templates_1 = require("./resources/templates");
|
|
21
22
|
const tenants_1 = require("./resources/tenants");
|
|
@@ -36,6 +37,7 @@ class TenantScope {
|
|
|
36
37
|
this.templates = new templates_1.TenantTemplatesResource(http, tenantId);
|
|
37
38
|
this.apps = new apps_1.AppsResource(http, tenantId);
|
|
38
39
|
this.playground = new playground_1.PlaygroundResource(http, tenantId);
|
|
40
|
+
this.trace = new trace_1.TraceResource(http, tenantId);
|
|
39
41
|
this.variables = new variables_1.VariablesResource(http, tenantId);
|
|
40
42
|
}
|
|
41
43
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { parseOAuthReturn } from './oauth';
|
|
|
6
6
|
export type { OAuthCrypto, OAuthReturn } from './oauth';
|
|
7
7
|
export type { ConsoleClientOptions, FetchLike, QueryValue, RequestOptions, SignedOutReason } from './http';
|
|
8
8
|
export * from './types';
|
|
9
|
+
export * from './trace-types';
|
|
9
10
|
export { AgentsResource, ChatTokensResource } from './resources/agents';
|
|
10
11
|
export { AppsResource } from './resources/apps';
|
|
11
12
|
export { AuthResource } from './resources/auth';
|
|
@@ -18,3 +19,4 @@ export { TemplatesResource, TenantTemplatesResource } from './resources/template
|
|
|
18
19
|
export { TenantsResource } from './resources/tenants';
|
|
19
20
|
export { ToolsResource } from './resources/tools';
|
|
20
21
|
export { VariablesResource } from './resources/variables';
|
|
22
|
+
export { TraceResource } from './resources/trace';
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.VariablesResource = exports.ToolsResource = exports.TenantsResource = exports.TenantTemplatesResource = exports.TemplatesResource = exports.TeamsResource = exports.TeamHumanMembersResource = exports.PlaygroundResource = exports.MarketplaceResource = exports.PublicInvitesResource = exports.MembersResource = exports.InvitesResource = exports.ConnectorsResource = exports.AuthResource = exports.AppsResource = exports.ChatTokensResource = exports.AgentsResource = exports.parseOAuthReturn = exports.MemoryTokenStore = exports.isApiError = exports.ApiError = exports.TenantScope = exports.ConsoleClient = void 0;
|
|
17
|
+
exports.TraceResource = exports.VariablesResource = exports.ToolsResource = exports.TenantsResource = exports.TenantTemplatesResource = exports.TemplatesResource = exports.TeamsResource = exports.TeamHumanMembersResource = exports.PlaygroundResource = exports.MarketplaceResource = exports.PublicInvitesResource = exports.MembersResource = exports.InvitesResource = exports.ConnectorsResource = exports.AuthResource = exports.AppsResource = exports.ChatTokensResource = exports.AgentsResource = exports.parseOAuthReturn = exports.MemoryTokenStore = exports.isApiError = exports.ApiError = exports.TenantScope = exports.ConsoleClient = void 0;
|
|
18
18
|
var client_1 = require("./client");
|
|
19
19
|
Object.defineProperty(exports, "ConsoleClient", { enumerable: true, get: function () { return client_1.ConsoleClient; } });
|
|
20
20
|
Object.defineProperty(exports, "TenantScope", { enumerable: true, get: function () { return client_1.TenantScope; } });
|
|
@@ -26,6 +26,7 @@ Object.defineProperty(exports, "MemoryTokenStore", { enumerable: true, get: func
|
|
|
26
26
|
var oauth_1 = require("./oauth");
|
|
27
27
|
Object.defineProperty(exports, "parseOAuthReturn", { enumerable: true, get: function () { return oauth_1.parseOAuthReturn; } });
|
|
28
28
|
__exportStar(require("./types"), exports);
|
|
29
|
+
__exportStar(require("./trace-types"), exports);
|
|
29
30
|
var agents_1 = require("./resources/agents");
|
|
30
31
|
Object.defineProperty(exports, "AgentsResource", { enumerable: true, get: function () { return agents_1.AgentsResource; } });
|
|
31
32
|
Object.defineProperty(exports, "ChatTokensResource", { enumerable: true, get: function () { return agents_1.ChatTokensResource; } });
|
|
@@ -55,3 +56,5 @@ var tools_1 = require("./resources/tools");
|
|
|
55
56
|
Object.defineProperty(exports, "ToolsResource", { enumerable: true, get: function () { return tools_1.ToolsResource; } });
|
|
56
57
|
var variables_1 = require("./resources/variables");
|
|
57
58
|
Object.defineProperty(exports, "VariablesResource", { enumerable: true, get: function () { return variables_1.VariablesResource; } });
|
|
59
|
+
var trace_1 = require("./resources/trace");
|
|
60
|
+
Object.defineProperty(exports, "TraceResource", { enumerable: true, get: function () { return trace_1.TraceResource; } });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { HttpCore } from '../http';
|
|
2
|
-
import type { AuthorizeConnectorInput, ConnectorFacets, ConnectorStatus, ListConnectorsInput } from '../types';
|
|
2
|
+
import type { AuthorizeConnectorInput, ConnectorFacets, ConnectorStatus, DisconnectConnectorResult, ListConnectorsInput } from '../types';
|
|
3
3
|
export declare class ConnectorsResource {
|
|
4
4
|
private readonly http;
|
|
5
5
|
private readonly tenantId;
|
|
@@ -22,4 +22,10 @@ export declare class ConnectorsResource {
|
|
|
22
22
|
saveApiKey(connectorId: string, apiKey: string): Promise<{
|
|
23
23
|
connectorId: string;
|
|
24
24
|
}>;
|
|
25
|
+
/** `DELETE /connectors/oauth/:id?tenantId=`: removes this workspace's
|
|
26
|
+
* connection (owner/admin; best-effort revoke at the provider). Idempotent:
|
|
27
|
+
* `disconnected: false` when there was nothing to remove. A
|
|
28
|
+
* `postAuthRedirect` outside the platform allow-list makes `authorize`
|
|
29
|
+
* fail with `ApiError` code `post_auth_redirect_not_allowed`. */
|
|
30
|
+
disconnect(connectorId: string): Promise<DisconnectConnectorResult>;
|
|
25
31
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// connectors for one workspace (`forTenant(id).connectors`): the directory
|
|
3
|
-
// with per-workspace `connected` flags,
|
|
3
|
+
// with per-workspace `connected` flags, the OAuth / API-key connect flow and
|
|
4
|
+
// disconnect.
|
|
4
5
|
//
|
|
5
6
|
// The directory resolves the workspace from the `X-Tenant-Id` header (the JWT
|
|
6
7
|
// carries no tenant), so these calls send it. A browser therefore needs CORS
|
|
@@ -43,5 +44,15 @@ class ConnectorsResource {
|
|
|
43
44
|
body: { apiKey },
|
|
44
45
|
});
|
|
45
46
|
}
|
|
47
|
+
/** `DELETE /connectors/oauth/:id?tenantId=`: removes this workspace's
|
|
48
|
+
* connection (owner/admin; best-effort revoke at the provider). Idempotent:
|
|
49
|
+
* `disconnected: false` when there was nothing to remove. A
|
|
50
|
+
* `postAuthRedirect` outside the platform allow-list makes `authorize`
|
|
51
|
+
* fail with `ApiError` code `post_auth_redirect_not_allowed`. */
|
|
52
|
+
async disconnect(connectorId) {
|
|
53
|
+
return this.http.request('DELETE', `/connectors/oauth/${(0, http_1.seg)(connectorId)}`, {
|
|
54
|
+
query: { tenantId: this.tenantId },
|
|
55
|
+
});
|
|
56
|
+
}
|
|
46
57
|
}
|
|
47
58
|
exports.ConnectorsResource = ConnectorsResource;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HttpCore } from '../http';
|
|
2
|
+
import type { TraceConversationDetail, TraceConversationList, TraceConversationListQuery, TraceStats, TraceStatsQuery, TraceTimeseries, TraceTimeseriesQuery } from '../trace-types';
|
|
3
|
+
export declare class TraceResource {
|
|
4
|
+
private readonly http;
|
|
5
|
+
private readonly tenantId;
|
|
6
|
+
constructor(http: HttpCore, tenantId: string);
|
|
7
|
+
private get base();
|
|
8
|
+
/** `GET .../trace/conversations`: keyset-paginated, last activity desc. 400 on a bad window/cursor. */
|
|
9
|
+
listConversations(query?: TraceConversationListQuery): Promise<TraceConversationList>;
|
|
10
|
+
/** `GET .../trace/conversations/:conversationId`: transcript + per-turn span tree. 404 if not in this workspace. */
|
|
11
|
+
getConversation(conversationId: string): Promise<TraceConversationDetail>;
|
|
12
|
+
/** `GET .../trace/stats`: tool / model / latency / sanitizer aggregates over a window. */
|
|
13
|
+
stats(query?: TraceStatsQuery): Promise<TraceStats>;
|
|
14
|
+
/** `GET .../trace/timeseries`: per-bucket volume, latency percentiles, phases, outcomes, models, plus previous window. */
|
|
15
|
+
timeseries(query?: TraceTimeseriesQuery): Promise<TraceTimeseries>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Agent / team activity of one workspace (`forTenant(id).trace`): traced
|
|
3
|
+
// conversations with the per-turn span tree, and performance aggregates.
|
|
4
|
+
// Read-only. Roles owner | admin | member; members get no span bodies,
|
|
5
|
+
// sanitizer texts or non-channel transcripts (the fields are absent).
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.TraceResource = void 0;
|
|
8
|
+
const http_1 = require("../http");
|
|
9
|
+
const iso = (d) => (d instanceof Date ? d.toISOString() : d);
|
|
10
|
+
/** Serialize a query: `Date` -> ISO string, undefined dropped by buildQuery. */
|
|
11
|
+
function toQuery(q) {
|
|
12
|
+
return { ...q, from: iso(q.from), to: iso(q.to) };
|
|
13
|
+
}
|
|
14
|
+
class TraceResource {
|
|
15
|
+
constructor(http, tenantId) {
|
|
16
|
+
this.http = http;
|
|
17
|
+
this.tenantId = tenantId;
|
|
18
|
+
}
|
|
19
|
+
get base() {
|
|
20
|
+
return `/admin/tenants/${(0, http_1.seg)(this.tenantId)}/trace`;
|
|
21
|
+
}
|
|
22
|
+
/** `GET .../trace/conversations`: keyset-paginated, last activity desc. 400 on a bad window/cursor. */
|
|
23
|
+
async listConversations(query = {}) {
|
|
24
|
+
return this.http.request('GET', `${this.base}/conversations`, { query: toQuery({ ...query }) });
|
|
25
|
+
}
|
|
26
|
+
/** `GET .../trace/conversations/:conversationId`: transcript + per-turn span tree. 404 if not in this workspace. */
|
|
27
|
+
async getConversation(conversationId) {
|
|
28
|
+
return this.http.request('GET', `${this.base}/conversations/${(0, http_1.seg)(conversationId)}`);
|
|
29
|
+
}
|
|
30
|
+
/** `GET .../trace/stats`: tool / model / latency / sanitizer aggregates over a window. */
|
|
31
|
+
async stats(query = {}) {
|
|
32
|
+
return this.http.request('GET', `${this.base}/stats`, { query: toQuery({ ...query }) });
|
|
33
|
+
}
|
|
34
|
+
/** `GET .../trace/timeseries`: per-bucket volume, latency percentiles, phases, outcomes, models, plus previous window. */
|
|
35
|
+
async timeseries(query = {}) {
|
|
36
|
+
return this.http.request('GET', `${this.base}/timeseries`, { query: toQuery({ ...query }) });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.TraceResource = TraceResource;
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
export type TraceSpanKind = 'turn' | 'llm_call' | 'tool_call' | 'delegation' | 'router_decision' | 'sanitizer' | 'gate' | 'approval' | 'error';
|
|
2
|
+
export type TraceSpanStatus = 'ok' | 'error' | 'skipped' | 'deduped' | 'blocked' | 'denied' | 'aborted' | 'rejected';
|
|
3
|
+
/** A date as ISO-8601 string or `Date` (serialized with `toISOString()`). Window max 31 days; default last 7. */
|
|
4
|
+
export type TraceDateInput = string | Date;
|
|
5
|
+
/** Filters shared by list / stats / timeseries. All optional. */
|
|
6
|
+
export interface TraceFilterQuery {
|
|
7
|
+
agentId?: string;
|
|
8
|
+
/** uuid */
|
|
9
|
+
teamId?: string;
|
|
10
|
+
surface?: string;
|
|
11
|
+
/** Matches served OR requested model. */
|
|
12
|
+
model?: string;
|
|
13
|
+
toolName?: string;
|
|
14
|
+
hasError?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface TraceWindowQuery {
|
|
17
|
+
/** Inclusive. Default: `to` - 7 days. */
|
|
18
|
+
from?: TraceDateInput;
|
|
19
|
+
/** Exclusive. Default: now. */
|
|
20
|
+
to?: TraceDateInput;
|
|
21
|
+
}
|
|
22
|
+
/** `GET trace/conversations`. `surface`/`model`/`toolName`/`hasError` select CONVERSATIONS here. */
|
|
23
|
+
export interface TraceConversationListQuery extends TraceFilterQuery, TraceWindowQuery {
|
|
24
|
+
/** Text search over messages, 2-100 chars; only effective for owner/admin. */
|
|
25
|
+
q?: string;
|
|
26
|
+
/** `nextCursor` of the previous page. */
|
|
27
|
+
cursor?: string;
|
|
28
|
+
/** 1..100, default 25. */
|
|
29
|
+
limit?: number;
|
|
30
|
+
}
|
|
31
|
+
/** `GET trace/stats`. Per-turn filters select ROOT TURNS. */
|
|
32
|
+
export interface TraceStatsQuery extends TraceFilterQuery, TraceWindowQuery {
|
|
33
|
+
}
|
|
34
|
+
/** `GET trace/timeseries`. Default bucket: hour for windows <= 48h, else day (max 744 buckets). */
|
|
35
|
+
export interface TraceTimeseriesQuery extends TraceFilterQuery, TraceWindowQuery {
|
|
36
|
+
bucket?: TraceBucketUnit;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* How a turn ended (AGF-RUN-TRACE-2c; mirrors core's `TurnOutcome`).
|
|
40
|
+
*
|
|
41
|
+
* Error semantics of the list (`errorCount` / `hasError` / `emptyCount`):
|
|
42
|
+
* - `errorCount` counts spans with status error | rejected | blocked, EXCEPT
|
|
43
|
+
* the ones that are an expected gate rather than a failure: a turn span whose
|
|
44
|
+
* outcome is `awaiting_approval` / `tool_blocked` (core reports those as
|
|
45
|
+
* `status:'error'` on non-stream paths), and the `blocked` tool_call spans
|
|
46
|
+
* of a trace that is `awaiting_approval` (an approval request is not an error).
|
|
47
|
+
* A policy-blocked tool (`tool_blocked`) still counts as an error.
|
|
48
|
+
* - `empty_response` turns (the model finished without text) are their own
|
|
49
|
+
* category, `emptyCount`, NOT part of `errorCount`, but `hasError=true`
|
|
50
|
+
* includes them (and `hasError=false` excludes them).
|
|
51
|
+
*/
|
|
52
|
+
export type TraceTurnOutcome = 'replied' | 'empty_response' | 'awaiting_approval' | 'tool_blocked' | 'error' | 'aborted';
|
|
53
|
+
export interface TraceConversationItem {
|
|
54
|
+
conversationId: string;
|
|
55
|
+
/** Agent of the first root turn (slug or uuid, as the runtime reported it). */
|
|
56
|
+
agentId: string | null;
|
|
57
|
+
agentName: string | null;
|
|
58
|
+
teamId: string | null;
|
|
59
|
+
surface: string | null;
|
|
60
|
+
/** Earliest / latest span activity INSIDE the requested window. */
|
|
61
|
+
firstAt: string;
|
|
62
|
+
lastAt: string;
|
|
63
|
+
/** Root turns only (member turns are not counted). */
|
|
64
|
+
turnCount: number;
|
|
65
|
+
llmCallCount: number;
|
|
66
|
+
toolCallCount: number;
|
|
67
|
+
/** Failing spans (see `TraceTurnOutcome` for the exact rule; approval gates are not errors). */
|
|
68
|
+
errorCount: number;
|
|
69
|
+
/** Root turns that ended `empty_response`. Included by the `hasError` filter, not in `errorCount`. */
|
|
70
|
+
emptyCount: number;
|
|
71
|
+
/** Distinct served model, falling back to the requested one. */
|
|
72
|
+
models: string[];
|
|
73
|
+
totalCostMicros: number | null;
|
|
74
|
+
inputTokens: number;
|
|
75
|
+
outputTokens: number;
|
|
76
|
+
/** p50 of root-turn durations (ms), null when no turn has a duration. */
|
|
77
|
+
p50TurnMs: number | null;
|
|
78
|
+
/** Last message text (<= 200 chars); null when not readable by this viewer or no message. */
|
|
79
|
+
lastMessagePreview: string | null;
|
|
80
|
+
lastMessageRole: string | null;
|
|
81
|
+
}
|
|
82
|
+
export interface TraceConversationList {
|
|
83
|
+
items: TraceConversationItem[];
|
|
84
|
+
/** Opaque; pass back as `cursor`. null when there is no further page. */
|
|
85
|
+
nextCursor: string | null;
|
|
86
|
+
window: {
|
|
87
|
+
from: string;
|
|
88
|
+
to: string;
|
|
89
|
+
};
|
|
90
|
+
/** Present when `q` was used: the search scans at most this many most-recent conversations per page. */
|
|
91
|
+
qScanCap?: number;
|
|
92
|
+
}
|
|
93
|
+
export interface TraceSpanView {
|
|
94
|
+
id: string;
|
|
95
|
+
seq: number;
|
|
96
|
+
kind: TraceSpanKind;
|
|
97
|
+
/** null for span kinds this server version does not know, when viewed below full payload access. */
|
|
98
|
+
name: string | null;
|
|
99
|
+
phase: string | null;
|
|
100
|
+
iteration: number | null;
|
|
101
|
+
startedAt: string;
|
|
102
|
+
durationMs: number | null;
|
|
103
|
+
status: TraceSpanStatus;
|
|
104
|
+
modelRequested: string | null;
|
|
105
|
+
modelServed: string | null;
|
|
106
|
+
routeReason: string | null;
|
|
107
|
+
routeTrigger: string | null;
|
|
108
|
+
keyOrigin: string | null;
|
|
109
|
+
inputTokens: number | null;
|
|
110
|
+
outputTokens: number | null;
|
|
111
|
+
cacheReadTokens: number | null;
|
|
112
|
+
cacheCreationTokens: number | null;
|
|
113
|
+
costMicros: number | null;
|
|
114
|
+
stopReason: string | null;
|
|
115
|
+
toolCount: number | null;
|
|
116
|
+
/**
|
|
117
|
+
* Phase timings (AGF-AGENT-PERF-CHARTS); all null on rows written before they
|
|
118
|
+
* existed and wherever the platform could not measure them.
|
|
119
|
+
* - llm_call: `providerWaitMs` = platform provider entry -> vendor call (BYOK
|
|
120
|
+
* lookup + provider resolution), `ttftMs` = vendor call -> first token.
|
|
121
|
+
* Both are part of `durationMs`.
|
|
122
|
+
* - root turn: `prepMs` = request/webhook accept -> runtime turn start (NOT part
|
|
123
|
+
* of `durationMs`), `firstTextMs` = accept -> first user-visible text.
|
|
124
|
+
*/
|
|
125
|
+
providerWaitMs: number | null;
|
|
126
|
+
ttftMs: number | null;
|
|
127
|
+
prepMs: number | null;
|
|
128
|
+
firstTextMs: number | null;
|
|
129
|
+
/** turn spans: how the turn ended; null on other spans and on turn rows written before core reported it. */
|
|
130
|
+
outcome: TraceTurnOutcome | null;
|
|
131
|
+
/** delegation spans: the member's trace id; `memberTrace` is that trace when present in this conversation. */
|
|
132
|
+
childTraceId: string | null;
|
|
133
|
+
memberTrace?: TraceNode;
|
|
134
|
+
input?: unknown;
|
|
135
|
+
output?: unknown;
|
|
136
|
+
errorMessage?: string | null;
|
|
137
|
+
}
|
|
138
|
+
export interface TraceRollup {
|
|
139
|
+
/** Root turn span duration, else derived (first span start -> last span end). */
|
|
140
|
+
durationMs: number | null;
|
|
141
|
+
costMicros: number | null;
|
|
142
|
+
inputTokens: number;
|
|
143
|
+
outputTokens: number;
|
|
144
|
+
models: string[];
|
|
145
|
+
llmCallCount: number;
|
|
146
|
+
toolCallCount: number;
|
|
147
|
+
errorCount: number;
|
|
148
|
+
/** Turns (own + nested members) that ended `empty_response`. */
|
|
149
|
+
emptyCount: number;
|
|
150
|
+
/** Turn span status; `incomplete` ONLY when no turn span was recorded (e.g. the process died mid-turn). */
|
|
151
|
+
status: TraceSpanStatus | 'incomplete';
|
|
152
|
+
/** Root turn outcome (`empty_response`, `awaiting_approval`, ... never `incomplete`); null when
|
|
153
|
+
* there is no turn span or it predates outcome reporting. Prefer `outcome ?? status` for display. */
|
|
154
|
+
outcome: TraceTurnOutcome | null;
|
|
155
|
+
}
|
|
156
|
+
export interface TraceNode {
|
|
157
|
+
traceId: string;
|
|
158
|
+
parentTraceId: string | null;
|
|
159
|
+
agentId: string | null;
|
|
160
|
+
agentName: string | null;
|
|
161
|
+
surface: string | null;
|
|
162
|
+
/** Inbound message that triggered the turn (traceContext.messageId), when known. */
|
|
163
|
+
messageId: string | null;
|
|
164
|
+
/** Same as `rollup.outcome` of the turn span of THIS trace (not of nested members). */
|
|
165
|
+
outcome: TraceTurnOutcome | null;
|
|
166
|
+
startedAt: string;
|
|
167
|
+
/** Own spans + nested member traces, ordered by seq. */
|
|
168
|
+
spans: TraceSpanView[];
|
|
169
|
+
/** Rollup including nested member traces. */
|
|
170
|
+
rollup: TraceRollup;
|
|
171
|
+
/** Member turn whose parent trace is not in this conversation's data (aged out / dropped). */
|
|
172
|
+
orphan?: boolean;
|
|
173
|
+
/** Members whose parent exists but no delegation span points at them. */
|
|
174
|
+
unlinkedMembers?: TraceNode[];
|
|
175
|
+
/** Channel gate verdict for the message that triggered this turn. */
|
|
176
|
+
gate?: TraceSpanView;
|
|
177
|
+
/**
|
|
178
|
+
* Link to the transcript (root turns only). `turn_id` = exact: the assistant row whose
|
|
179
|
+
* `metadata.turnId` equals this trace id (and/or the ids the turn span recorded);
|
|
180
|
+
* `time_window` = best-effort fallback for turns without any exact id (written before core
|
|
181
|
+
* stamped `metadata.turnId`).
|
|
182
|
+
*/
|
|
183
|
+
link?: {
|
|
184
|
+
userMessageId: string | null;
|
|
185
|
+
assistantMessageId: string | null;
|
|
186
|
+
method: 'turn_id' | 'time_window';
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
export interface TraceMessageView {
|
|
190
|
+
id: string;
|
|
191
|
+
role: string;
|
|
192
|
+
/** null (and `contentVisible:false`) when this viewer may not read the transcript. */
|
|
193
|
+
content: string | null;
|
|
194
|
+
contentVisible: boolean;
|
|
195
|
+
createdAt: string;
|
|
196
|
+
}
|
|
197
|
+
export interface TraceConversationDetail {
|
|
198
|
+
conversationId: string;
|
|
199
|
+
agentId: string | null;
|
|
200
|
+
agentName: string | null;
|
|
201
|
+
teamId: string | null;
|
|
202
|
+
surface: string | null;
|
|
203
|
+
/** Prefix of the conversation owner key: channel | chat-token | inbox | whatsapp | voice | app-user | ... */
|
|
204
|
+
userKind: string | null;
|
|
205
|
+
messages: TraceMessageView[];
|
|
206
|
+
turns: TraceNode[];
|
|
207
|
+
/** True when the 5000-span cap was hit (the most recent spans were cut). */
|
|
208
|
+
truncated: boolean;
|
|
209
|
+
}
|
|
210
|
+
export interface TraceToolStat {
|
|
211
|
+
tool: string;
|
|
212
|
+
calls: number;
|
|
213
|
+
errors: number;
|
|
214
|
+
deduped: number;
|
|
215
|
+
blocked: number;
|
|
216
|
+
/** Over executed calls (status ok|error); deduped/blocked excluded. */
|
|
217
|
+
p50Ms: number | null;
|
|
218
|
+
p95Ms: number | null;
|
|
219
|
+
}
|
|
220
|
+
export interface TraceModelStat {
|
|
221
|
+
/** Served model, falling back to the requested one when attribution was unavailable. */
|
|
222
|
+
model: string;
|
|
223
|
+
calls: number;
|
|
224
|
+
inputTokens: number;
|
|
225
|
+
outputTokens: number;
|
|
226
|
+
costMicros: number | null;
|
|
227
|
+
}
|
|
228
|
+
export interface TraceStats {
|
|
229
|
+
window: {
|
|
230
|
+
from: string;
|
|
231
|
+
to: string;
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* Without per-turn filters exactly `{ agentId, teamId }` (the response is
|
|
235
|
+
* unchanged from before AGF-PERF-FILTER-TURN). With any of them it also
|
|
236
|
+
* carries `surface` / `model` / `toolName` / `hasError`.
|
|
237
|
+
*/
|
|
238
|
+
filter: {
|
|
239
|
+
agentId: string | null;
|
|
240
|
+
teamId: string | null;
|
|
241
|
+
surface?: string | null;
|
|
242
|
+
model?: string | null;
|
|
243
|
+
toolName?: string | null;
|
|
244
|
+
hasError?: boolean | null;
|
|
245
|
+
};
|
|
246
|
+
/**
|
|
247
|
+
* Present only when a per-turn filter is set: every aggregate counts only
|
|
248
|
+
* the spans of the matching root turns' families (own trace + delegated
|
|
249
|
+
* member traces, one hop); spans outside any root turn are left out.
|
|
250
|
+
*/
|
|
251
|
+
filterScope?: 'turn';
|
|
252
|
+
tools: TraceToolStat[];
|
|
253
|
+
models: {
|
|
254
|
+
mix: TraceModelStat[];
|
|
255
|
+
llmCalls: number;
|
|
256
|
+
/** llm_calls with a served model attributed. */
|
|
257
|
+
attributed: number;
|
|
258
|
+
/**
|
|
259
|
+
* Calls the router or the provider moved off what was asked: a route
|
|
260
|
+
* reason is set, or a concrete requested id was served by another model.
|
|
261
|
+
* An `adaptive:*` tier resolving to its model, or a dated id of the same
|
|
262
|
+
* model (`claude-haiku-4-5` -> `claude-haiku-4-5-20251001`), is not one.
|
|
263
|
+
*/
|
|
264
|
+
servedDiffersFromRequested: number;
|
|
265
|
+
routeReasons: Array<{
|
|
266
|
+
reason: string;
|
|
267
|
+
count: number;
|
|
268
|
+
}>;
|
|
269
|
+
/** Top requested -> served pairs (<= 50). */
|
|
270
|
+
pairs: Array<{
|
|
271
|
+
requested: string | null;
|
|
272
|
+
served: string;
|
|
273
|
+
reason: string | null;
|
|
274
|
+
count: number;
|
|
275
|
+
}>;
|
|
276
|
+
};
|
|
277
|
+
turns: {
|
|
278
|
+
count: number;
|
|
279
|
+
p50Ms: number | null;
|
|
280
|
+
p95Ms: number | null;
|
|
281
|
+
byStatus: Array<{
|
|
282
|
+
status: string;
|
|
283
|
+
count: number;
|
|
284
|
+
}>;
|
|
285
|
+
/** Root turns by outcome; turn rows without one (pre-2c) are grouped as `unknown`. */
|
|
286
|
+
byOutcome: Array<{
|
|
287
|
+
outcome: string;
|
|
288
|
+
count: number;
|
|
289
|
+
}>;
|
|
290
|
+
};
|
|
291
|
+
sanitizer: Array<{
|
|
292
|
+
status: string;
|
|
293
|
+
count: number;
|
|
294
|
+
changed: number;
|
|
295
|
+
avgMs: number | null;
|
|
296
|
+
inputTokens: number;
|
|
297
|
+
outputTokens: number;
|
|
298
|
+
}>;
|
|
299
|
+
errorTurns: {
|
|
300
|
+
count: number;
|
|
301
|
+
recent: Array<{
|
|
302
|
+
traceId: string;
|
|
303
|
+
conversationId: string | null;
|
|
304
|
+
agentId: string | null;
|
|
305
|
+
startedAt: string;
|
|
306
|
+
/** Full access only. */
|
|
307
|
+
errorMessage?: string | null;
|
|
308
|
+
}>;
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
export type TraceBucketUnit = 'hour' | 'day';
|
|
312
|
+
/**
|
|
313
|
+
* Same names as the Conversations list filters, but `surface` / `model` /
|
|
314
|
+
* `toolName` / `hasError` select ROOT TURNS here (`filterScope: 'turn'`), while
|
|
315
|
+
* the list keeps selecting conversations.
|
|
316
|
+
*/
|
|
317
|
+
export interface TraceTimeseriesFilter {
|
|
318
|
+
agentId: string | null;
|
|
319
|
+
teamId: string | null;
|
|
320
|
+
surface: string | null;
|
|
321
|
+
model: string | null;
|
|
322
|
+
toolName: string | null;
|
|
323
|
+
/** `true` = only turns with a failing span (own or delegated) / empty reply, `false` = exclude them, `null` = all. */
|
|
324
|
+
hasError: boolean | null;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* p50 (ms) of where a root turn's time goes, over the turns that have phase
|
|
328
|
+
* data (`phaseSamples`). A turn's phases add up to its `totalMs`:
|
|
329
|
+
* totalMs = prep + providerWait + ttft + generation + tools + sanitizer + rest
|
|
330
|
+
* with `rest` the remainder (never negative): runtime work before the first LLM
|
|
331
|
+
* call (history load, connector tools resolution), orchestrator planning calls
|
|
332
|
+
* (not measured around the platform provider), persistence and delivery.
|
|
333
|
+
* - `tools` is the wall-clock UNION of the turn's tool calls and delegated
|
|
334
|
+
* member runs (parallel calls are not double counted).
|
|
335
|
+
* - a phase a turn does not have counts as 0 (a turn without tools has tools = 0).
|
|
336
|
+
* p50s of different phases do not add up to the p50 of the total; they describe
|
|
337
|
+
* the typical turn phase by phase.
|
|
338
|
+
*/
|
|
339
|
+
export interface TracePhaseP50 {
|
|
340
|
+
prep: number | null;
|
|
341
|
+
providerWait: number | null;
|
|
342
|
+
ttft: number | null;
|
|
343
|
+
generation: number | null;
|
|
344
|
+
tools: number | null;
|
|
345
|
+
sanitizer: number | null;
|
|
346
|
+
rest: number | null;
|
|
347
|
+
}
|
|
348
|
+
/** Stats of a set of root turns (one bucket, the whole window, or the previous window). */
|
|
349
|
+
export interface TraceTimeseriesStats {
|
|
350
|
+
/** Root turns (member runs excluded). */
|
|
351
|
+
turns: number;
|
|
352
|
+
/** Root turns that failed (status error, excluding approval / policy gates). */
|
|
353
|
+
errors: number;
|
|
354
|
+
/** Time from accept to the first user-visible text. Over `firstTextSamples` turns; null without samples. */
|
|
355
|
+
p50FirstTextMs: number | null;
|
|
356
|
+
p95FirstTextMs: number | null;
|
|
357
|
+
firstTextSamples: number;
|
|
358
|
+
/** Full reply time: accept -> end of turn (`prep` + `duration`; `duration` alone where `prep` is unknown). */
|
|
359
|
+
p50TotalMs: number | null;
|
|
360
|
+
p95TotalMs: number | null;
|
|
361
|
+
phases: TracePhaseP50;
|
|
362
|
+
/** Turns with phase data; rows written before the phase fields existed are excluded from `phases`. */
|
|
363
|
+
phaseSamples: number;
|
|
364
|
+
/** Root turns by surface (`unknown` when none was recorded). */
|
|
365
|
+
bySurface: Record<string, number>;
|
|
366
|
+
/** Root turns by outcome (`unknown` for rows that predate outcome reporting). */
|
|
367
|
+
byOutcome: Record<string, number>;
|
|
368
|
+
/** LLM calls (root turns + their delegated members) by served model, falling back to the requested one. */
|
|
369
|
+
byModel: Record<string, number>;
|
|
370
|
+
/** LLM calls the router or the provider moved off the requested model (same rule as `stats`). */
|
|
371
|
+
reroutes: number;
|
|
372
|
+
/** owner / admin / platform admin only; ABSENT for members. Integer micro-USD at list price. null = no price configured. */
|
|
373
|
+
costMicros?: number | null;
|
|
374
|
+
/** owner / admin / platform admin only; ABSENT for members. cache_read / (input + cache_read + cache_creation), 0..1; null without LLM tokens. */
|
|
375
|
+
cacheReadRatio?: number | null;
|
|
376
|
+
}
|
|
377
|
+
export interface TraceTimeseriesBucket extends TraceTimeseriesStats {
|
|
378
|
+
/** ISO-8601 UTC start of the bucket (hour or day, aligned in UTC). Empty buckets are present with zero turns. */
|
|
379
|
+
start: string;
|
|
380
|
+
}
|
|
381
|
+
export interface TraceTimeseriesAgentRow {
|
|
382
|
+
agentId: string;
|
|
383
|
+
agentName: string | null;
|
|
384
|
+
turns: number;
|
|
385
|
+
errors: number;
|
|
386
|
+
/** errors / turns, 0..1. */
|
|
387
|
+
errorRate: number;
|
|
388
|
+
p50FirstTextMs: number | null;
|
|
389
|
+
p95FirstTextMs: number | null;
|
|
390
|
+
p50TotalMs: number | null;
|
|
391
|
+
/** owner / admin / platform admin only; ABSENT for members. */
|
|
392
|
+
costMicros?: number | null;
|
|
393
|
+
}
|
|
394
|
+
/** Window-level stats: the bucket stats plus how many root turns the filters kept. */
|
|
395
|
+
export interface TraceTimeseriesWindowStats extends TraceTimeseriesStats {
|
|
396
|
+
/**
|
|
397
|
+
* Root turns of the same window + agent / team scope with NO surface /
|
|
398
|
+
* model / toolName / hasError filter. Equals `turns` when none is set.
|
|
399
|
+
*/
|
|
400
|
+
unfilteredTurns: number;
|
|
401
|
+
}
|
|
402
|
+
export interface TraceTimeseries {
|
|
403
|
+
window: {
|
|
404
|
+
from: string;
|
|
405
|
+
to: string;
|
|
406
|
+
};
|
|
407
|
+
bucket: TraceBucketUnit;
|
|
408
|
+
filter: TraceTimeseriesFilter;
|
|
409
|
+
/** The filters select root turns, not conversations (always `'turn'`). */
|
|
410
|
+
filterScope: 'turn';
|
|
411
|
+
buckets: TraceTimeseriesBucket[];
|
|
412
|
+
/** The whole window. */
|
|
413
|
+
summary: TraceTimeseriesWindowStats;
|
|
414
|
+
/** The window of the same length right before `window`, for deltas. */
|
|
415
|
+
previous: TraceTimeseriesWindowStats & {
|
|
416
|
+
window: {
|
|
417
|
+
from: string;
|
|
418
|
+
to: string;
|
|
419
|
+
};
|
|
420
|
+
};
|
|
421
|
+
/** Global scope only (no agentId / teamId): per-agent comparison, top 50 by turns. */
|
|
422
|
+
agents?: TraceTimeseriesAgentRow[];
|
|
423
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Wire types of the trace read API (`admin/tenants/:tenantId/trace/*`). Mirrors
|
|
3
|
+
// agentforge-platform apps/server/src/modules/trace/trace-read.types.ts.
|
|
4
|
+
//
|
|
5
|
+
// Conventions: timestamps are ISO-8601 UTC strings; `*Micros` are integer
|
|
6
|
+
// micro-USD at LIST price (null = no price configured); `T | null` = not
|
|
7
|
+
// recorded. "Payload" fields (`input`, `output`, `errorMessage`, sanitizer
|
|
8
|
+
// texts, cost on some aggregates) are ABSENT (not null) for workspace members
|
|
9
|
+
// below owner/admin: see `TraceConversationDetail.messages[].contentVisible`.
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
package/dist/types.d.ts
CHANGED
|
@@ -1007,3 +1007,13 @@ export interface PublisherErrorBody {
|
|
|
1007
1007
|
message: string;
|
|
1008
1008
|
issues?: TeamPublicationIssue[];
|
|
1009
1009
|
}
|
|
1010
|
+
/** `DELETE /connectors/oauth/:id` result. */
|
|
1011
|
+
export interface DisconnectConnectorResult {
|
|
1012
|
+
ok: true;
|
|
1013
|
+
connectorId: string;
|
|
1014
|
+
tenantId: string;
|
|
1015
|
+
/** False when the workspace had no connection (idempotent). */
|
|
1016
|
+
disconnected: boolean;
|
|
1017
|
+
/** True when the provider confirmed the token revoke (best effort). */
|
|
1018
|
+
revokedAtProvider: boolean;
|
|
1019
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentforge-io/sdk-console",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "User-session SDK for admin clients of the AgentForge platform (Expo / React Native, web, Node). Dashboard JWT auth with refresh, tenant scoping, typed resources.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|