@agentforge-io/sdk-server 4.6.0 → 4.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -4
- package/dist/resources/analytics.d.ts +21 -54
- package/dist/resources/analytics.js +31 -39
- package/dist/resources/apps.d.ts +17 -1
- package/dist/resources/apps.js +18 -0
- package/dist/resources/inbox.d.ts +65 -107
- package/dist/resources/inbox.js +67 -105
- package/dist/resources/provisioning.d.ts +31 -0
- package/dist/resources/provisioning.js +25 -0
- package/dist/types.d.ts +99 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2,19 +2,19 @@ export { AgentForgeClient } from './client';
|
|
|
2
2
|
export type { AgentForgeClientOptions, RequestOptions } from './client';
|
|
3
3
|
export { AgentForgeError, AgentForgeAuthError, AgentForgeNotFoundError, AgentForgeNetworkError, } from './errors';
|
|
4
4
|
export { TOOL_CALLBACK_HEADERS, ToolCallbackSignatureError, signToolCallbackPayload, verifyToolCallbackSignature, } from './webhooks';
|
|
5
|
-
export type { AgentMe, AgentSummary, AppUserConnectorStatus, ApprovalCopyBundle, ChannelContext, ChatStreamChunk, ChatStreamEvent, ChatTokenRecord, ConnectorDefaultsResult, ConnectorDefaultsSource, ConnectorResourceItem, ConnectorStatus, ConnectorToolInfo, ConversationHistory, ConversationStatus, CreateAgentInput, CreateClickupTaskInput, CreateClickupTaskResult, ExternalToolSummary, IssueChatTokenInput, ListAgentsResult, ListConnectorResourcesResult, McpServerConfig, MessageRecord, MessageRole, PublicAppBranding, AppSelf, AppSelfConnector, AppSelfConnectors, RegisterToolInput, RegisterToolsInput, RegisterToolsResult, ToolCallbackPayload, ToolCallRecord, ToolPermission, ToolPermissionMode, TokenUsage, TenantSecretEntry, UpdateAgentInput, } from './types';
|
|
5
|
+
export type { AgentMe, AgentSummary, AppUserConnectorStatus, ApprovalCopyBundle, ChannelContext, ChatStreamChunk, ChatStreamEvent, ChatTokenRecord, ConnectorDefaultsResult, ConnectorDefaultsSource, ConnectorResourceItem, ConnectorStatus, ConnectorToolInfo, ConversationHistory, ConversationStatus, CreateAgentInput, CreateClickupTaskInput, CreateClickupTaskResult, ExternalToolSummary, IssueChatTokenInput, ListAgentsResult, ListConnectorResourcesResult, McpServerConfig, MessageRecord, MessageRole, PublicAppBranding, AppSelf, AppSelfConnector, AppSelfConnectors, AppSelfConnectorTools, AppSelfConnectorToolsResponse, RegisterToolInput, RegisterToolsInput, RegisterToolsResult, ToolCallbackPayload, ToolCallRecord, ToolPermission, ToolPermissionMode, TokenUsage, TenantSecretEntry, UpdateAgentInput, InboxThreadMode, InboxMessageDirection, InboxMessageSource, InboxMessageType, InboxThreadCustomerProfileView, InboxThreadView, InboxMessageView, SupportKpiTotals, SupportKpiResponse, AgentAttentionLogRow, } from './types';
|
|
6
6
|
export { AgentsResource } from './resources/agents';
|
|
7
7
|
export { AnalyticsResource } from './resources/analytics';
|
|
8
|
-
export type {
|
|
8
|
+
export type { GetSupportKpisInput, GetAgentAttentionLogInput, } from './resources/analytics';
|
|
9
9
|
export { AppsResource } from './resources/apps';
|
|
10
10
|
export { ChatResource } from './resources/chat';
|
|
11
11
|
export type { AnthropicClientOptions, StreamMessageInput } from './resources/chat';
|
|
12
12
|
export { ConnectorsResource } from './resources/connectors';
|
|
13
13
|
export type { InboxChannelView } from './resources/connectors';
|
|
14
14
|
export { InboxResource } from './resources/inbox';
|
|
15
|
-
export type {
|
|
15
|
+
export type { ListThreadsOptions, SendMessageInput, AssignThreadInput, UnassignThreadInput, SetThreadModeInput, CloseThreadInput, } from './resources/inbox';
|
|
16
16
|
export { ProvisioningResource } from './resources/provisioning';
|
|
17
|
-
export type { ProvisionedTenant, ProvisionedApp, } from './resources/provisioning';
|
|
17
|
+
export type { ProvisionedTenant, ProvisionedApp, ProvisionedTeam, } from './resources/provisioning';
|
|
18
18
|
export { SecretsResource } from './resources/secrets';
|
|
19
19
|
export { ToolsResource } from './resources/tools';
|
|
20
20
|
export type { RespondToCallbackInput, VerifyCallbackInput } from './resources/tools';
|
|
@@ -1,72 +1,39 @@
|
|
|
1
1
|
import type { AgentForgeClient } from '../client';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
avgResolutionMs: number | null;
|
|
11
|
-
avgFrtMs: number | null;
|
|
12
|
-
avgTimeToAssignMs: number | null;
|
|
13
|
-
}
|
|
14
|
-
export interface SupportKpiResponse {
|
|
15
|
-
tenantId: string;
|
|
16
|
-
from: string;
|
|
17
|
-
to: string;
|
|
18
|
-
totals: SupportKpiTotals;
|
|
19
|
-
byDimension: Array<SupportKpiTotals & {
|
|
20
|
-
dimensionType: 'agent' | 'operator';
|
|
21
|
-
dimensionKey: string;
|
|
22
|
-
}>;
|
|
23
|
-
}
|
|
24
|
-
export interface AgentAttentionLogRow {
|
|
25
|
-
dimensionType: 'agent' | 'operator';
|
|
26
|
-
dimensionKey: string;
|
|
27
|
-
metricDate: string;
|
|
28
|
-
receivedCount: number;
|
|
29
|
-
aiResponsesCount: number;
|
|
30
|
-
humanMessagesCount: number;
|
|
31
|
-
escalationsCount: number;
|
|
32
|
-
aiResolvedCount: number;
|
|
33
|
-
humanHandledCount: number;
|
|
34
|
-
assignmentsCount: number;
|
|
35
|
-
avgResolutionMs: number | null;
|
|
36
|
-
avgFrtMs: number | null;
|
|
37
|
-
avgTimeToAssignMs: number | null;
|
|
2
|
+
import type { SupportKpiResponse, AgentAttentionLogRow } from '../types';
|
|
3
|
+
export interface GetSupportKpisInput {
|
|
4
|
+
/** Window start (inclusive). ISO 8601 or Date. */
|
|
5
|
+
from: string | Date;
|
|
6
|
+
/** Window end (exclusive). ISO 8601 or Date. */
|
|
7
|
+
to: string | Date;
|
|
8
|
+
agentId?: string;
|
|
9
|
+
operatorUserId?: string;
|
|
38
10
|
}
|
|
39
|
-
export interface
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
/** ISO date string. Required. */
|
|
43
|
-
to: string;
|
|
44
|
-
/** Narrow to one agent's rows (`byDimension`/`items` filtered to
|
|
45
|
-
* `dimensionType: 'agent', dimensionKey: agentId`). */
|
|
11
|
+
export interface GetAgentAttentionLogInput {
|
|
12
|
+
from: string | Date;
|
|
13
|
+
to: string | Date;
|
|
46
14
|
agentId?: string;
|
|
47
|
-
/** Narrow to one operator's rows. */
|
|
48
15
|
operatorUserId?: string;
|
|
49
16
|
}
|
|
50
17
|
export declare class AnalyticsResource {
|
|
51
18
|
private readonly client;
|
|
52
19
|
constructor(client: AgentForgeClient);
|
|
53
20
|
/**
|
|
54
|
-
* `GET /apps/me/support-kpis` — totals + per-agent
|
|
55
|
-
* the
|
|
21
|
+
* `GET /apps/me/support-kpis` — totals + per-(agent|operator)
|
|
22
|
+
* breakdown for the App's tenant, in the given window.
|
|
56
23
|
*
|
|
57
24
|
* @example
|
|
58
|
-
* const
|
|
59
|
-
* from: '2026-08-01T00:00:
|
|
60
|
-
* to:
|
|
25
|
+
* const { totals, byDimension } = await af.analytics.getSupportKpis({
|
|
26
|
+
* from: '2026-08-01T00:00:00Z',
|
|
27
|
+
* to: '2026-08-08T00:00:00Z',
|
|
61
28
|
* });
|
|
62
29
|
*/
|
|
63
|
-
getSupportKpis(
|
|
30
|
+
getSupportKpis(input: GetSupportKpisInput): Promise<SupportKpiResponse>;
|
|
64
31
|
/**
|
|
65
|
-
* `GET /apps/me/support-attention-log` —
|
|
66
|
-
*
|
|
32
|
+
* `GET /apps/me/support-attention-log` — per-day rows for
|
|
33
|
+
* the "atención por agente" table/chart (SD-11).
|
|
67
34
|
*/
|
|
68
|
-
getAgentAttentionLog(
|
|
35
|
+
getAgentAttentionLog(input: GetAgentAttentionLogInput): Promise<{
|
|
69
36
|
items: AgentAttentionLogRow[];
|
|
70
37
|
}>;
|
|
71
|
-
private
|
|
38
|
+
private buildQuery;
|
|
72
39
|
}
|
|
@@ -1,26 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// analytics resource (AGF-SD-
|
|
3
|
-
//
|
|
4
|
-
// `GET /apps/me/support
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// narrowing.
|
|
2
|
+
// analytics resource (AGF-SD-5) — App-scoped read surface for the support
|
|
3
|
+
// KPIs materialized by SD-3 (`af_support_metrics`). Wraps SD-3b's
|
|
4
|
+
// `AppSupportAnalyticsController` (`GET /apps/me/support-*`), which follows
|
|
5
|
+
// the `me/*` precedent of `AppsController`: the `sk_live_` IS the identity,
|
|
6
|
+
// so there is no `:agentId` in the path and no `tenantId` in the query.
|
|
8
7
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// appSecret-only client; see `connectors.ts`'s file header for the same
|
|
14
|
-
// gotcha on the App-user scope methods there), so `authHeaders()` can pick
|
|
15
|
-
// either credential for the `Authorization: Bearer` header. `tenantId` is
|
|
16
|
-
// NEVER a param here (SDD §4.5) — the server resolves it exclusively from
|
|
17
|
-
// the credential.
|
|
18
|
-
//
|
|
19
|
-
// `from`/`to` are REQUIRED on both methods — the platform rejects a
|
|
20
|
-
// missing/malformed/inverted/too-wide range with 400 (no implicit default
|
|
21
|
-
// window). This wrapper does no validation of its own; it forwards
|
|
22
|
-
// whatever `Date` the caller passes as an ISO string and lets the server
|
|
23
|
-
// be the single source of truth for what's a valid range.
|
|
8
|
+
// Both methods are single-tenant reads: `tenantId` is resolved from the
|
|
9
|
+
// caller's auth context on the server (never from input), so the SDK
|
|
10
|
+
// signature only takes the query knobs. `agentId`/`operatorUserId` are
|
|
11
|
+
// optional filters within that tenant.
|
|
24
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
13
|
exports.AnalyticsResource = void 0;
|
|
26
14
|
class AnalyticsResource {
|
|
@@ -28,32 +16,36 @@ class AnalyticsResource {
|
|
|
28
16
|
this.client = client;
|
|
29
17
|
}
|
|
30
18
|
/**
|
|
31
|
-
* `GET /apps/me/support-kpis` — totals + per-agent
|
|
32
|
-
* the
|
|
19
|
+
* `GET /apps/me/support-kpis` — totals + per-(agent|operator)
|
|
20
|
+
* breakdown for the App's tenant, in the given window.
|
|
33
21
|
*
|
|
34
22
|
* @example
|
|
35
|
-
* const
|
|
36
|
-
* from: '2026-08-01T00:00:
|
|
37
|
-
* to:
|
|
23
|
+
* const { totals, byDimension } = await af.analytics.getSupportKpis({
|
|
24
|
+
* from: '2026-08-01T00:00:00Z',
|
|
25
|
+
* to: '2026-08-08T00:00:00Z',
|
|
38
26
|
* });
|
|
39
27
|
*/
|
|
40
|
-
async getSupportKpis(
|
|
41
|
-
|
|
28
|
+
async getSupportKpis(input) {
|
|
29
|
+
const qs = this.buildQuery(input);
|
|
30
|
+
return this.client.request('GET', `/apps/me/support-kpis?${qs}`);
|
|
42
31
|
}
|
|
43
32
|
/**
|
|
44
|
-
* `GET /apps/me/support-attention-log` —
|
|
45
|
-
*
|
|
33
|
+
* `GET /apps/me/support-attention-log` — per-day rows for
|
|
34
|
+
* the "atención por agente" table/chart (SD-11).
|
|
46
35
|
*/
|
|
47
|
-
async getAgentAttentionLog(
|
|
48
|
-
|
|
36
|
+
async getAgentAttentionLog(input) {
|
|
37
|
+
const qs = this.buildQuery(input);
|
|
38
|
+
return this.client.request('GET', `/apps/me/support-attention-log?${qs}`);
|
|
49
39
|
}
|
|
50
|
-
|
|
51
|
-
const params = new URLSearchParams(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
params.set('
|
|
56
|
-
|
|
40
|
+
buildQuery(input) {
|
|
41
|
+
const params = new URLSearchParams();
|
|
42
|
+
params.set('from', input.from instanceof Date ? input.from.toISOString() : input.from);
|
|
43
|
+
params.set('to', input.to instanceof Date ? input.to.toISOString() : input.to);
|
|
44
|
+
if (input.agentId)
|
|
45
|
+
params.set('agentId', input.agentId);
|
|
46
|
+
if (input.operatorUserId)
|
|
47
|
+
params.set('operatorUserId', input.operatorUserId);
|
|
48
|
+
return params.toString();
|
|
57
49
|
}
|
|
58
50
|
}
|
|
59
51
|
exports.AnalyticsResource = AnalyticsResource;
|
package/dist/resources/apps.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentForgeClient } from '../client';
|
|
2
|
-
import type { PublicAppBranding, AppSelf, AppSelfConnectors } from '../types';
|
|
2
|
+
import type { PublicAppBranding, AppSelf, AppSelfConnectors, AppSelfConnectorToolsResponse } from '../types';
|
|
3
3
|
export declare class AppsResource {
|
|
4
4
|
private readonly client;
|
|
5
5
|
constructor(client: AgentForgeClient);
|
|
@@ -41,5 +41,21 @@ export declare class AppsResource {
|
|
|
41
41
|
* by the App at runtime.
|
|
42
42
|
*/
|
|
43
43
|
list: () => Promise<AppSelfConnectors>;
|
|
44
|
+
/**
|
|
45
|
+
* `GET /apps/me/connector-tools` (AGF-CTG-1) — flat tool-name catalog
|
|
46
|
+
* contributed by the connectors ENABLED for the App this client
|
|
47
|
+
* authenticated AS. App-level granularity ONLY: this is NOT narrowed
|
|
48
|
+
* per-end-user — that narrowing already happens downstream at runtime
|
|
49
|
+
* via `toolsForAppUser ∩ agent.tools[]`.
|
|
50
|
+
*
|
|
51
|
+
* Use it to build a whitelist of tool names an App may reference (e.g.
|
|
52
|
+
* the SOP Architect's bootstrap), so a prompt cannot name a connector
|
|
53
|
+
* tool the App has no connector enabled for.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* const { toolNames } = await af.apps.connectors.tools();
|
|
57
|
+
* const allowed = new Set(toolNames);
|
|
58
|
+
*/
|
|
59
|
+
tools: () => Promise<AppSelfConnectorToolsResponse>;
|
|
44
60
|
};
|
|
45
61
|
}
|
package/dist/resources/apps.js
CHANGED
|
@@ -35,6 +35,24 @@ class AppsResource {
|
|
|
35
35
|
list: async () => {
|
|
36
36
|
return this.client.request('GET', '/apps/me/connectors');
|
|
37
37
|
},
|
|
38
|
+
/**
|
|
39
|
+
* `GET /apps/me/connector-tools` (AGF-CTG-1) — flat tool-name catalog
|
|
40
|
+
* contributed by the connectors ENABLED for the App this client
|
|
41
|
+
* authenticated AS. App-level granularity ONLY: this is NOT narrowed
|
|
42
|
+
* per-end-user — that narrowing already happens downstream at runtime
|
|
43
|
+
* via `toolsForAppUser ∩ agent.tools[]`.
|
|
44
|
+
*
|
|
45
|
+
* Use it to build a whitelist of tool names an App may reference (e.g.
|
|
46
|
+
* the SOP Architect's bootstrap), so a prompt cannot name a connector
|
|
47
|
+
* tool the App has no connector enabled for.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* const { toolNames } = await af.apps.connectors.tools();
|
|
51
|
+
* const allowed = new Set(toolNames);
|
|
52
|
+
*/
|
|
53
|
+
tools: async () => {
|
|
54
|
+
return this.client.request('GET', '/apps/me/connector-tools');
|
|
55
|
+
},
|
|
38
56
|
};
|
|
39
57
|
}
|
|
40
58
|
/**
|
|
@@ -1,113 +1,71 @@
|
|
|
1
1
|
import type { AgentForgeClient } from '../client';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* `GET /connectors/inbox/agents/:agentId/inbox/threads` — threads for this
|
|
7
|
-
* agent's support inbox. Optional `channelId` narrows to one channel.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* const { items } = await af.inbox.listThreads(agentId);
|
|
11
|
-
*/
|
|
12
|
-
listThreads(agentId: string, opts?: {
|
|
13
|
-
channelId?: string;
|
|
14
|
-
}): Promise<{
|
|
15
|
-
items: InboxThreadView[];
|
|
16
|
-
}>;
|
|
17
|
-
/**
|
|
18
|
-
* `GET /connectors/inbox/agents/:agentId/inbox/threads/:threadId` — a
|
|
19
|
-
* single thread.
|
|
20
|
-
*/
|
|
21
|
-
getThread(agentId: string, threadId: string): Promise<InboxThreadView>;
|
|
22
|
-
/**
|
|
23
|
-
* `GET /connectors/inbox/agents/:agentId/inbox/threads/:threadId/messages`
|
|
24
|
-
* — full message history for a thread.
|
|
25
|
-
*/
|
|
26
|
-
listMessages(agentId: string, threadId: string): Promise<{
|
|
27
|
-
items: InboxMessageView[];
|
|
28
|
-
}>;
|
|
29
|
-
/**
|
|
30
|
-
* `POST .../threads/:threadId/messages` — send a message as the operator.
|
|
31
|
-
* `pauseAgent` defaults `true` server-side (pass `false` to reply without
|
|
32
|
-
* taking the thread away from the agent). `operatorId` is the App's own
|
|
33
|
-
* opaque identifier for the acting human rep — see file header.
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* await af.inbox.sendOperatorMessage(agentId, threadId, {
|
|
37
|
-
* text: 'Un momento, reviso tu caso.',
|
|
38
|
-
* operatorId: 'scrappydoc-rep-42',
|
|
39
|
-
* });
|
|
40
|
-
*/
|
|
41
|
-
sendOperatorMessage(agentId: string, threadId: string, input: {
|
|
42
|
-
text: string;
|
|
43
|
-
pauseAgent?: boolean;
|
|
44
|
-
operatorId?: string;
|
|
45
|
-
}): Promise<void>;
|
|
46
|
-
/**
|
|
47
|
-
* `POST .../threads/:threadId/assign` — claim a thread for an operator.
|
|
48
|
-
* `operatorId` is required (the server rejects a missing one with 401).
|
|
49
|
-
*/
|
|
50
|
-
assignThread(agentId: string, threadId: string, input: {
|
|
51
|
-
operatorId: string;
|
|
52
|
-
}): Promise<void>;
|
|
53
|
-
/**
|
|
54
|
-
* `DELETE .../threads/:threadId/assign` — release a thread claim
|
|
55
|
-
* (handback). `operatorId`, when given, must match the current assignee
|
|
56
|
-
* server-side.
|
|
57
|
-
*/
|
|
58
|
-
handback(agentId: string, threadId: string, opts?: {
|
|
59
|
-
operatorId?: string;
|
|
60
|
-
}): Promise<void>;
|
|
61
|
-
/**
|
|
62
|
-
* `POST .../threads/:threadId/mode` — switch a thread between agent/human
|
|
63
|
-
* mode.
|
|
64
|
-
*/
|
|
65
|
-
setThreadMode(agentId: string, threadId: string, mode: InboxThreadMode): Promise<void>;
|
|
66
|
-
/**
|
|
67
|
-
* `POST .../threads/:threadId/close` — close a human-mode thread.
|
|
68
|
-
*/
|
|
69
|
-
closeThread(agentId: string, threadId: string, opts?: {
|
|
70
|
-
notes?: string;
|
|
71
|
-
operatorId?: string;
|
|
72
|
-
}): Promise<void>;
|
|
2
|
+
import type { InboxThreadView, InboxMessageView, InboxThreadMode } from '../types';
|
|
3
|
+
export interface ListThreadsOptions {
|
|
4
|
+
/** Optional filter to threads on a single channel of the agent. */
|
|
5
|
+
channelId?: string;
|
|
73
6
|
}
|
|
74
|
-
export
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
7
|
+
export interface SendMessageInput {
|
|
8
|
+
/** The operator's text. */
|
|
9
|
+
text: string;
|
|
10
|
+
/** Default true. Toggle off when the operator wants to chime in
|
|
11
|
+
* without taking the thread away from the agent. */
|
|
12
|
+
pauseAgent?: boolean;
|
|
13
|
+
/** App-minted operator identity (see file header). */
|
|
14
|
+
operatorId?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface AssignThreadInput {
|
|
17
|
+
/** App-minted operator identity — required for assign. Same string
|
|
18
|
+
* re-sent proves ownership of a prior claim. */
|
|
19
|
+
operatorId: string;
|
|
20
|
+
}
|
|
21
|
+
export interface UnassignThreadInput {
|
|
22
|
+
/** App-minted operator identity — must match the current assignee. */
|
|
23
|
+
operatorId: string;
|
|
83
24
|
}
|
|
84
|
-
export interface
|
|
85
|
-
id: string;
|
|
86
|
-
channelId: string;
|
|
87
|
-
externalId: string;
|
|
88
|
-
displayName?: string;
|
|
25
|
+
export interface SetThreadModeInput {
|
|
89
26
|
mode: InboxThreadMode;
|
|
90
|
-
unreadCount: number;
|
|
91
|
-
lastMessageAt?: string;
|
|
92
|
-
lastMessagePreview?: string;
|
|
93
|
-
assignedHumanUserId?: string;
|
|
94
|
-
closedAt?: string;
|
|
95
|
-
closeNotes?: string;
|
|
96
|
-
closedByUserId?: string;
|
|
97
|
-
customerProfileId?: string;
|
|
98
|
-
customerProfile?: InboxThreadCustomerProfileView;
|
|
99
|
-
createdAt: string;
|
|
100
|
-
updatedAt: string;
|
|
101
27
|
}
|
|
102
|
-
export interface
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
28
|
+
export interface CloseThreadInput {
|
|
29
|
+
/** Free-text notes the operator leaves on close. Persisted as
|
|
30
|
+
* `af_inbox_threads.close_notes` — later consumed by AGF-BRAIN as
|
|
31
|
+
* institutional knowledge. */
|
|
32
|
+
notes?: string;
|
|
33
|
+
/** App-minted operator identity — recorded on `closed_by_user_id`. */
|
|
34
|
+
operatorId?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Agent-scoped inbox operator surface. Every method takes the `agentId`
|
|
38
|
+
* whose threads the App is operating; the App-ownership boundary is
|
|
39
|
+
* enforced server-side (404 on mismatch, mirroring
|
|
40
|
+
* `assertAgentOwnedByApp` in the identity-side controllers).
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const inbox = af.inbox.forAgent(agentId);
|
|
44
|
+
* const { items: threads } = await inbox.listThreads();
|
|
45
|
+
* const { items: messages } = await inbox.listMessages(threads[0].id);
|
|
46
|
+
* await inbox.sendMessage(threads[0].id, {
|
|
47
|
+
* text: 'Hi, jumping in to help',
|
|
48
|
+
* operatorId: 'rep_alice',
|
|
49
|
+
* });
|
|
50
|
+
*/
|
|
51
|
+
export declare class InboxResource {
|
|
52
|
+
private readonly client;
|
|
53
|
+
constructor(client: AgentForgeClient);
|
|
54
|
+
/** Bind an agent id and return a helper with one method per
|
|
55
|
+
* `AppInboxController` route. Avoids threading `agentId` through
|
|
56
|
+
* every call. */
|
|
57
|
+
forAgent(agentId: string): {
|
|
58
|
+
listThreads: (opts?: ListThreadsOptions) => Promise<{
|
|
59
|
+
items: InboxThreadView[];
|
|
60
|
+
}>;
|
|
61
|
+
getThread: (threadId: string) => Promise<InboxThreadView>;
|
|
62
|
+
listMessages: (threadId: string) => Promise<{
|
|
63
|
+
items: InboxMessageView[];
|
|
64
|
+
}>;
|
|
65
|
+
sendMessage: (threadId: string, input: SendMessageInput) => Promise<void>;
|
|
66
|
+
assign: (threadId: string, input: AssignThreadInput) => Promise<void>;
|
|
67
|
+
unassign: (threadId: string, input: UnassignThreadInput) => Promise<void>;
|
|
68
|
+
setMode: (threadId: string, input: SetThreadModeInput) => Promise<void>;
|
|
69
|
+
close: (threadId: string, input?: CloseThreadInput) => Promise<void>;
|
|
70
|
+
};
|
|
113
71
|
}
|
package/dist/resources/inbox.js
CHANGED
|
@@ -1,118 +1,80 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// inbox resource (AGF-SD-
|
|
3
|
-
// `AppInboxController` (`connectors/inbox/agents/:agentId
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// agent-scoped `ak_live_` — never a human dashboard session.
|
|
2
|
+
// inbox resource (AGF-SD-5) — App-scoped operator surface. Wraps the
|
|
3
|
+
// platform's `AppInboxController` (AGF-SD-1, `connectors/inbox/agents/:agentId`),
|
|
4
|
+
// exposing list/read/reply/assign/close for the threads of an agent the
|
|
5
|
+
// calling App owns.
|
|
7
6
|
//
|
|
8
|
-
// Auth: `
|
|
9
|
-
// `
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// that file's header), inbox operator routes are meant to be called by an
|
|
13
|
-
// App itself. So this resource uses plain `this.client.request()`, whose
|
|
14
|
-
// `authHeaders()` picks `apiKey` OR `appSecret` for the `Authorization:
|
|
15
|
-
// Bearer` header (chatToken, if present instead, is rejected server-side
|
|
16
|
-
// with 401 since the route requires `auth.isApiKey`). Every method takes
|
|
17
|
-
// `agentId` explicitly (unlike `af.agents.me()`) because the platform
|
|
18
|
-
// route itself is per-agent and validates ownership server-side
|
|
19
|
-
// (`assertOwnedAgent` — 404, not 403, on a foreign agent).
|
|
7
|
+
// Auth: `ApiKeyGuard` on the server accepts BOTH `ak_live_` and `sk_live_`.
|
|
8
|
+
// The SDK's `authHeaders()` already sends whichever the client was
|
|
9
|
+
// constructed with on the `Authorization: Bearer` header — no per-call
|
|
10
|
+
// wiring needed here.
|
|
20
11
|
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
12
|
+
// `operatorId` semantics: SD-1's header comment flags this explicitly — an
|
|
13
|
+
// App has no `af_users.id`, so `operatorId` is whatever stable string the
|
|
14
|
+
// App mints for its own end of the conversation. The SDK exposes it as an
|
|
15
|
+
// optional param on `send()`, `assign()`, `unassign()`, `close()` and
|
|
16
|
+
// passes it through verbatim. The server's assignment guard still enforces
|
|
17
|
+
// "same operatorId re-sent = same claimant".
|
|
23
18
|
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
// `userId`. See `AppInboxController`'s file header on the platform for the
|
|
29
|
-
// full rationale.
|
|
30
|
-
//
|
|
31
|
-
// NOT covered here (left for a future extension — see file bottom for
|
|
32
|
-
// what's deliberately excluded and why):
|
|
33
|
-
// - `af.inbox.channels.get`/`update` — no App-scoped single-channel-read
|
|
34
|
-
// or update route exists on the platform today (`ApiKeyInboxController`
|
|
35
|
-
// only has list/create/delete). `list`/`create`/`destroy` already live
|
|
36
|
-
// on `af.connectors.*` (see `connectors.ts`) — not duplicated here.
|
|
37
|
-
// - operator online/offline status (`PUT teams/:teamId/operator/status`)
|
|
38
|
-
// — lives on `OperatorStatusController`, gated by the GLOBAL
|
|
39
|
-
// `JwtAuthGuard` (human dashboard session), not `ApiKeyGuard`. No
|
|
40
|
-
// `@Public()`, not reachable with `sk_live_`/`ak_live_` at all.
|
|
19
|
+
// NOTE — chip AGF-INBOX-OPERATORID-UUID: SD-1's free-string `operatorId`
|
|
20
|
+
// collides with UUID columns on assign/close (open follow-up on the
|
|
21
|
+
// platform side). Callers passing arbitrary strings should not be
|
|
22
|
+
// surprised by a 500 today; the shape convergence lands separately.
|
|
41
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
24
|
exports.InboxResource = void 0;
|
|
25
|
+
/**
|
|
26
|
+
* Agent-scoped inbox operator surface. Every method takes the `agentId`
|
|
27
|
+
* whose threads the App is operating; the App-ownership boundary is
|
|
28
|
+
* enforced server-side (404 on mismatch, mirroring
|
|
29
|
+
* `assertAgentOwnedByApp` in the identity-side controllers).
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* const inbox = af.inbox.forAgent(agentId);
|
|
33
|
+
* const { items: threads } = await inbox.listThreads();
|
|
34
|
+
* const { items: messages } = await inbox.listMessages(threads[0].id);
|
|
35
|
+
* await inbox.sendMessage(threads[0].id, {
|
|
36
|
+
* text: 'Hi, jumping in to help',
|
|
37
|
+
* operatorId: 'rep_alice',
|
|
38
|
+
* });
|
|
39
|
+
*/
|
|
43
40
|
class InboxResource {
|
|
44
41
|
constructor(client) {
|
|
45
42
|
this.client = client;
|
|
46
43
|
}
|
|
47
|
-
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
* await af.inbox.sendOperatorMessage(agentId, threadId, {
|
|
82
|
-
* text: 'Un momento, reviso tu caso.',
|
|
83
|
-
* operatorId: 'scrappydoc-rep-42',
|
|
84
|
-
* });
|
|
85
|
-
*/
|
|
86
|
-
async sendOperatorMessage(agentId, threadId, input) {
|
|
87
|
-
await this.client.request('POST', `/connectors/inbox/agents/${encodeURIComponent(agentId)}/inbox/threads/${encodeURIComponent(threadId)}/messages`, input);
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* `POST .../threads/:threadId/assign` — claim a thread for an operator.
|
|
91
|
-
* `operatorId` is required (the server rejects a missing one with 401).
|
|
92
|
-
*/
|
|
93
|
-
async assignThread(agentId, threadId, input) {
|
|
94
|
-
await this.client.request('POST', `/connectors/inbox/agents/${encodeURIComponent(agentId)}/inbox/threads/${encodeURIComponent(threadId)}/assign`, input);
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* `DELETE .../threads/:threadId/assign` — release a thread claim
|
|
98
|
-
* (handback). `operatorId`, when given, must match the current assignee
|
|
99
|
-
* server-side.
|
|
100
|
-
*/
|
|
101
|
-
async handback(agentId, threadId, opts) {
|
|
102
|
-
await this.client.request('DELETE', `/connectors/inbox/agents/${encodeURIComponent(agentId)}/inbox/threads/${encodeURIComponent(threadId)}/assign`, opts);
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* `POST .../threads/:threadId/mode` — switch a thread between agent/human
|
|
106
|
-
* mode.
|
|
107
|
-
*/
|
|
108
|
-
async setThreadMode(agentId, threadId, mode) {
|
|
109
|
-
await this.client.request('POST', `/connectors/inbox/agents/${encodeURIComponent(agentId)}/inbox/threads/${encodeURIComponent(threadId)}/mode`, { mode });
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* `POST .../threads/:threadId/close` — close a human-mode thread.
|
|
113
|
-
*/
|
|
114
|
-
async closeThread(agentId, threadId, opts) {
|
|
115
|
-
await this.client.request('POST', `/connectors/inbox/agents/${encodeURIComponent(agentId)}/inbox/threads/${encodeURIComponent(threadId)}/close`, opts);
|
|
44
|
+
/** Bind an agent id and return a helper with one method per
|
|
45
|
+
* `AppInboxController` route. Avoids threading `agentId` through
|
|
46
|
+
* every call. */
|
|
47
|
+
forAgent(agentId) {
|
|
48
|
+
const base = `/connectors/inbox/agents/${encodeURIComponent(agentId)}/inbox`;
|
|
49
|
+
return {
|
|
50
|
+
listThreads: async (opts = {}) => {
|
|
51
|
+
const qs = opts.channelId
|
|
52
|
+
? `?channelId=${encodeURIComponent(opts.channelId)}`
|
|
53
|
+
: '';
|
|
54
|
+
return this.client.request('GET', `${base}/threads${qs}`);
|
|
55
|
+
},
|
|
56
|
+
getThread: async (threadId) => {
|
|
57
|
+
return this.client.request('GET', `${base}/threads/${encodeURIComponent(threadId)}`);
|
|
58
|
+
},
|
|
59
|
+
listMessages: async (threadId) => {
|
|
60
|
+
return this.client.request('GET', `${base}/threads/${encodeURIComponent(threadId)}/messages`);
|
|
61
|
+
},
|
|
62
|
+
sendMessage: async (threadId, input) => {
|
|
63
|
+
await this.client.request('POST', `${base}/threads/${encodeURIComponent(threadId)}/messages`, input);
|
|
64
|
+
},
|
|
65
|
+
assign: async (threadId, input) => {
|
|
66
|
+
await this.client.request('POST', `${base}/threads/${encodeURIComponent(threadId)}/assign`, input);
|
|
67
|
+
},
|
|
68
|
+
unassign: async (threadId, input) => {
|
|
69
|
+
await this.client.request('DELETE', `${base}/threads/${encodeURIComponent(threadId)}/assign`, input);
|
|
70
|
+
},
|
|
71
|
+
setMode: async (threadId, input) => {
|
|
72
|
+
await this.client.request('POST', `${base}/threads/${encodeURIComponent(threadId)}/mode`, input);
|
|
73
|
+
},
|
|
74
|
+
close: async (threadId, input = {}) => {
|
|
75
|
+
await this.client.request('POST', `${base}/threads/${encodeURIComponent(threadId)}/close`, input);
|
|
76
|
+
},
|
|
77
|
+
};
|
|
116
78
|
}
|
|
117
79
|
}
|
|
118
80
|
exports.InboxResource = InboxResource;
|
|
@@ -11,6 +11,14 @@ export interface ProvisionedApp {
|
|
|
11
11
|
publicKey: string;
|
|
12
12
|
appSecret: string;
|
|
13
13
|
}
|
|
14
|
+
/** `POST /platform/host-teams` result — a team-orchestrator's identity
|
|
15
|
+
* (AGF-SD-6a). No secret to reveal here (unlike `tenant()`/`app()`) — a
|
|
16
|
+
* team has no credential of its own, it's addressed through the
|
|
17
|
+
* tenant's `ak_live_` / App's `sk_live_`. */
|
|
18
|
+
export interface ProvisionedTeam {
|
|
19
|
+
teamId: string;
|
|
20
|
+
orchestratorAgentId: string;
|
|
21
|
+
}
|
|
14
22
|
export declare class ProvisioningResource {
|
|
15
23
|
private readonly client;
|
|
16
24
|
constructor(client: AgentForgeClient);
|
|
@@ -49,4 +57,27 @@ export declare class ProvisioningResource {
|
|
|
49
57
|
hostApp: string;
|
|
50
58
|
hostRef?: string;
|
|
51
59
|
}): Promise<ProvisionedApp>;
|
|
60
|
+
/**
|
|
61
|
+
* `POST /platform/host-teams` (AGF-SD-6a) — find-or-create a
|
|
62
|
+
* team-orchestrator for an EXISTING tenant on behalf of a trusted host
|
|
63
|
+
* app. Idempotent by `(tenantId, hostRef)`: a re-provision returns the
|
|
64
|
+
* SAME `teamId`/`orchestratorAgentId`, never a duplicate orchestrator.
|
|
65
|
+
*
|
|
66
|
+
* @param input.tenantId the tenant the team belongs to (host provisions
|
|
67
|
+
* it first via `tenant()`)
|
|
68
|
+
* @param input.hostApp short host id (e.g. "scrappydoc") — recorded
|
|
69
|
+
* for parity with `tenant()`/`app()`, not part of
|
|
70
|
+
* the idempotency key here (a team already lives
|
|
71
|
+
* under one tenant, so `(tenantId, hostRef)`
|
|
72
|
+
* alone is unambiguous)
|
|
73
|
+
* @param input.hostRef host reference (e.g. the workspaceId) — the
|
|
74
|
+
* idempotency key together with `tenantId`
|
|
75
|
+
* @param input.name display name, only used on first provision
|
|
76
|
+
*/
|
|
77
|
+
team(input: {
|
|
78
|
+
tenantId: string;
|
|
79
|
+
hostApp: string;
|
|
80
|
+
hostRef: string;
|
|
81
|
+
name?: string;
|
|
82
|
+
}): Promise<ProvisionedTeam>;
|
|
52
83
|
}
|
|
@@ -51,5 +51,30 @@ class ProvisioningResource {
|
|
|
51
51
|
async app(input) {
|
|
52
52
|
return this.client.request('POST', '/platform/host-apps', { tenantId: input.tenantId, hostApp: input.hostApp, hostRef: input.hostRef }, { headers: this.headers() });
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* `POST /platform/host-teams` (AGF-SD-6a) — find-or-create a
|
|
56
|
+
* team-orchestrator for an EXISTING tenant on behalf of a trusted host
|
|
57
|
+
* app. Idempotent by `(tenantId, hostRef)`: a re-provision returns the
|
|
58
|
+
* SAME `teamId`/`orchestratorAgentId`, never a duplicate orchestrator.
|
|
59
|
+
*
|
|
60
|
+
* @param input.tenantId the tenant the team belongs to (host provisions
|
|
61
|
+
* it first via `tenant()`)
|
|
62
|
+
* @param input.hostApp short host id (e.g. "scrappydoc") — recorded
|
|
63
|
+
* for parity with `tenant()`/`app()`, not part of
|
|
64
|
+
* the idempotency key here (a team already lives
|
|
65
|
+
* under one tenant, so `(tenantId, hostRef)`
|
|
66
|
+
* alone is unambiguous)
|
|
67
|
+
* @param input.hostRef host reference (e.g. the workspaceId) — the
|
|
68
|
+
* idempotency key together with `tenantId`
|
|
69
|
+
* @param input.name display name, only used on first provision
|
|
70
|
+
*/
|
|
71
|
+
async team(input) {
|
|
72
|
+
return this.client.request('POST', '/platform/host-teams', {
|
|
73
|
+
tenantId: input.tenantId,
|
|
74
|
+
hostApp: input.hostApp,
|
|
75
|
+
hostRef: input.hostRef,
|
|
76
|
+
name: input.name,
|
|
77
|
+
}, { headers: this.headers() });
|
|
78
|
+
}
|
|
54
79
|
}
|
|
55
80
|
exports.ProvisioningResource = ProvisioningResource;
|
package/dist/types.d.ts
CHANGED
|
@@ -84,6 +84,16 @@ export interface AppSelfConnectors {
|
|
|
84
84
|
mode: 'whitelist' | 'legacy';
|
|
85
85
|
connectors: AppSelfConnector[];
|
|
86
86
|
}
|
|
87
|
+
export interface AppSelfConnectorTools {
|
|
88
|
+
connectorId: string;
|
|
89
|
+
toolNames: string[];
|
|
90
|
+
}
|
|
91
|
+
export interface AppSelfConnectorToolsResponse {
|
|
92
|
+
connectors: AppSelfConnectorTools[];
|
|
93
|
+
/** Flat, de-duplicated union of every `toolNames` entry above — this is
|
|
94
|
+
* what a whitelist consumer actually wants. */
|
|
95
|
+
toolNames: string[];
|
|
96
|
+
}
|
|
87
97
|
export interface RegisterToolInput {
|
|
88
98
|
name: string;
|
|
89
99
|
description: string;
|
|
@@ -488,4 +498,93 @@ export interface TenantSecretEntry {
|
|
|
488
498
|
* Ausente si nunca se configuró. */
|
|
489
499
|
updatedAt?: string;
|
|
490
500
|
}
|
|
501
|
+
export type InboxThreadMode = 'agent' | 'human';
|
|
502
|
+
export type InboxMessageDirection = 'inbound' | 'outbound';
|
|
503
|
+
export type InboxMessageSource = 'customer' | 'agent' | 'operator';
|
|
504
|
+
export type InboxMessageType = 'text' | 'image' | 'video' | 'audio' | 'document' | 'sticker' | 'location' | 'unsupported';
|
|
505
|
+
/** Read-through customer profile snapshot embedded on every thread — saves
|
|
506
|
+
* the UI a round-trip per thread. NULL on threads whose customerProfileId
|
|
507
|
+
* hasn't been linked yet (very brief window on first inbound). */
|
|
508
|
+
export interface InboxThreadCustomerProfileView {
|
|
509
|
+
id: string;
|
|
510
|
+
displayName?: string;
|
|
511
|
+
/** Provider handle without the leading `@`. */
|
|
512
|
+
username?: string;
|
|
513
|
+
avatarUrl?: string;
|
|
514
|
+
providerId?: string;
|
|
515
|
+
tags?: string[];
|
|
516
|
+
notes?: string;
|
|
517
|
+
}
|
|
518
|
+
export interface InboxThreadView {
|
|
519
|
+
id: string;
|
|
520
|
+
channelId: string;
|
|
521
|
+
externalId: string;
|
|
522
|
+
displayName?: string;
|
|
523
|
+
mode: InboxThreadMode;
|
|
524
|
+
unreadCount: number;
|
|
525
|
+
lastMessageAt?: string;
|
|
526
|
+
lastMessagePreview?: string;
|
|
527
|
+
/** Workspace user currently responsible for the thread. */
|
|
528
|
+
assignedHumanUserId?: string;
|
|
529
|
+
/** AGF-ASSIGN-P1-CLOSE. ISO timestamp when the human conversation was
|
|
530
|
+
* formally closed. Undefined = open / never escalated. */
|
|
531
|
+
closedAt?: string;
|
|
532
|
+
closeNotes?: string;
|
|
533
|
+
closedByUserId?: string;
|
|
534
|
+
customerProfileId?: string;
|
|
535
|
+
customerProfile?: InboxThreadCustomerProfileView;
|
|
536
|
+
createdAt: string;
|
|
537
|
+
updatedAt: string;
|
|
538
|
+
}
|
|
539
|
+
export interface InboxMessageView {
|
|
540
|
+
id: string;
|
|
541
|
+
threadId: string;
|
|
542
|
+
direction: InboxMessageDirection;
|
|
543
|
+
source: InboxMessageSource;
|
|
544
|
+
type: InboxMessageType;
|
|
545
|
+
body: string;
|
|
546
|
+
externalMessageId?: string;
|
|
547
|
+
payload?: Record<string, unknown>;
|
|
548
|
+
sentAt: string;
|
|
549
|
+
recordedAt: string;
|
|
550
|
+
}
|
|
551
|
+
export interface SupportKpiTotals {
|
|
552
|
+
receivedCount: number;
|
|
553
|
+
aiResponsesCount: number;
|
|
554
|
+
humanMessagesCount: number;
|
|
555
|
+
escalationsCount: number;
|
|
556
|
+
aiResolvedCount: number;
|
|
557
|
+
humanHandledCount: number;
|
|
558
|
+
assignmentsCount: number;
|
|
559
|
+
avgResolutionMs: number | null;
|
|
560
|
+
avgFrtMs: number | null;
|
|
561
|
+
avgTimeToAssignMs: number | null;
|
|
562
|
+
}
|
|
563
|
+
export interface SupportKpiResponse {
|
|
564
|
+
tenantId: string;
|
|
565
|
+
from: string;
|
|
566
|
+
to: string;
|
|
567
|
+
totals: SupportKpiTotals;
|
|
568
|
+
/** One entry per (dimensionType, dimensionKey) in range. */
|
|
569
|
+
byDimension: Array<SupportKpiTotals & {
|
|
570
|
+
dimensionType: 'agent' | 'operator';
|
|
571
|
+
dimensionKey: string;
|
|
572
|
+
}>;
|
|
573
|
+
}
|
|
574
|
+
export interface AgentAttentionLogRow {
|
|
575
|
+
dimensionType: 'agent' | 'operator';
|
|
576
|
+
dimensionKey: string;
|
|
577
|
+
/** YYYY-MM-DD */
|
|
578
|
+
metricDate: string;
|
|
579
|
+
receivedCount: number;
|
|
580
|
+
aiResponsesCount: number;
|
|
581
|
+
humanMessagesCount: number;
|
|
582
|
+
escalationsCount: number;
|
|
583
|
+
aiResolvedCount: number;
|
|
584
|
+
humanHandledCount: number;
|
|
585
|
+
assignmentsCount: number;
|
|
586
|
+
avgResolutionMs: number | null;
|
|
587
|
+
avgFrtMs: number | null;
|
|
588
|
+
avgTimeToAssignMs: number | null;
|
|
589
|
+
}
|
|
491
590
|
export {};
|
package/package.json
CHANGED