@axiom-lattice/protocols 4.11.0 → 6.0.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/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +115 -0
- package/dist/index.d.mts +605 -44
- package/dist/index.d.ts +605 -44
- package/dist/index.js +179 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +162 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/AgentInterruptProtocol.ts +15 -0
- package/src/AgentLatticeProtocol.ts +0 -49
- package/src/AgentWebAppRuntimeProtocol.ts +2 -0
- package/src/ChannelAdapterProtocol.ts +10 -0
- package/src/ChannelReplyJobProtocol.ts +184 -0
- package/src/CheckpointStorageProtocol.ts +98 -0
- package/src/EvalStoreProtocol.ts +4 -0
- package/src/McpUiProtocol.ts +22 -2
- package/src/MenuProtocol.ts +2 -0
- package/src/MessageProtocol.ts +8 -0
- package/src/ObservabilityDashboardProtocol.ts +167 -0
- package/src/RunCancelProtocol.ts +76 -0
- package/src/ScheduleLatticeProtocol.ts +7 -0
- package/src/StoreProtocol.ts +181 -0
- package/src/TaskStoreProtocol.ts +8 -0
- package/src/ThreadStoreProtocol.ts +24 -0
- package/src/__tests__/McpUiProtocol.test.ts +48 -0
- package/src/__tests__/MenuProtocol.test.ts +4 -0
- package/src/__tests__/ObservabilityDashboardProtocol.test.ts +17 -0
- package/src/__tests__/RunCancelProtocol.test.ts +148 -0
- package/src/__tests__/agent-web-app-types.test.ts +4 -0
- package/src/index.ts +6 -0
package/package.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalized human-in-the-loop interrupt exposed by the Agent Server surface.
|
|
3
|
+
*/
|
|
4
|
+
export interface AgentInterrupt {
|
|
5
|
+
/** Stable id derived from the LangGraph interrupt id or task/index. */
|
|
6
|
+
interruptId: string;
|
|
7
|
+
/** Normalized interrupt kind. */
|
|
8
|
+
type: "clarify" | "task_review" | "custom";
|
|
9
|
+
/** Thread whose graph is interrupted. */
|
|
10
|
+
threadId: string;
|
|
11
|
+
/** Task id that owns the interrupt, when available. */
|
|
12
|
+
taskId?: string;
|
|
13
|
+
/** Raw or normalized interrupt payload. */
|
|
14
|
+
payload: unknown;
|
|
15
|
+
}
|
|
@@ -14,7 +14,6 @@ import { BaseLatticeProtocol } from "./BaseLatticeProtocol";
|
|
|
14
14
|
export enum AgentType {
|
|
15
15
|
REACT = "react",
|
|
16
16
|
DEEP_AGENT = "deep_agent",
|
|
17
|
-
TEAM = "team",
|
|
18
17
|
PROCESSING = "processing",
|
|
19
18
|
/** Remote A2A agent — delegates to an external A2A-compatible server */
|
|
20
19
|
A2A_REMOTE = "a2a_remote",
|
|
@@ -203,52 +202,6 @@ export interface ProcessingAgentConfig extends BaseAgentConfig {
|
|
|
203
202
|
internalSubAgents?: AgentConfig[];
|
|
204
203
|
}
|
|
205
204
|
|
|
206
|
-
/**
|
|
207
|
-
* Team teammate configuration -- describes an available teammate.
|
|
208
|
-
*/
|
|
209
|
-
export interface TeamTeammateConfig {
|
|
210
|
-
/** Unique name for this teammate (used as agent ID) */
|
|
211
|
-
name: string;
|
|
212
|
-
/** Role category (e.g. "research", "writing", "review") */
|
|
213
|
-
role: string;
|
|
214
|
-
/** Human-readable description of what this teammate does */
|
|
215
|
-
description: string;
|
|
216
|
-
/** Tool keys this teammate has access to */
|
|
217
|
-
tools?: string[];
|
|
218
|
-
/** Custom system prompt for this teammate */
|
|
219
|
-
prompt?: string;
|
|
220
|
-
/** Model key override for this teammate */
|
|
221
|
-
modelKey?: string;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* TEAM agent configuration -- a team lead that dynamically creates teammates.
|
|
226
|
-
* Teammates are created on-the-fly from create_team tool input (name, role, description).
|
|
227
|
-
*/
|
|
228
|
-
export interface TeamAgentConfig extends BaseAgentConfig {
|
|
229
|
-
type: AgentType.TEAM;
|
|
230
|
-
/** Tool keys available to the team lead */
|
|
231
|
-
tools?: string[];
|
|
232
|
-
/** Maximum number of teammates running concurrently */
|
|
233
|
-
maxConcurrency?: number;
|
|
234
|
-
/**
|
|
235
|
-
* Schedule lattice key for polling task list / mailbox.
|
|
236
|
-
* When set, teammates use ScheduleLattice for periodic polling instead of event-driven wait.
|
|
237
|
-
*/
|
|
238
|
-
scheduleLatticeKey?: string;
|
|
239
|
-
/** Poll interval in ms when using schedule lattice (default: 5000) */
|
|
240
|
-
pollIntervalMs?: number;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Type guard to check if config is TeamAgentConfig
|
|
245
|
-
*/
|
|
246
|
-
export function isTeamAgentConfig(
|
|
247
|
-
config: AgentConfig
|
|
248
|
-
): config is TeamAgentConfig {
|
|
249
|
-
return config.type === AgentType.TEAM;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
205
|
// ─── A2A_REMOTE Agent ──────────────────────────────────────────────────────
|
|
253
206
|
|
|
254
207
|
export interface LocalRuntimeConfig {
|
|
@@ -361,7 +314,6 @@ export function isWorkflowAgentConfig(
|
|
|
361
314
|
export type AgentConfig =
|
|
362
315
|
| ReactAgentConfig
|
|
363
316
|
| DeepAgentConfig
|
|
364
|
-
| TeamAgentConfig
|
|
365
317
|
| ProcessingAgentConfig
|
|
366
318
|
| A2ARemoteAgentConfig
|
|
367
319
|
| WorkflowAgentConfig
|
|
@@ -372,7 +324,6 @@ export type AgentConfig =
|
|
|
372
324
|
export type AgentConfigWithTools =
|
|
373
325
|
| ReactAgentConfig
|
|
374
326
|
| DeepAgentConfig
|
|
375
|
-
| TeamAgentConfig
|
|
376
327
|
| ProcessingAgentConfig
|
|
377
328
|
| A2ARemoteAgentConfig
|
|
378
329
|
| WorkflowAgentConfig
|
|
@@ -87,6 +87,16 @@ export type MessageMiddleware = (
|
|
|
87
87
|
export interface ChannelAdapter<TConfig = unknown> {
|
|
88
88
|
readonly channel: string;
|
|
89
89
|
readonly configSchema: z.ZodSchema<TConfig>;
|
|
90
|
+
/**
|
|
91
|
+
* Whether `sendReply` is safe to call from any Gateway replica.
|
|
92
|
+
*
|
|
93
|
+
* @remarks
|
|
94
|
+
* Only adapters whose reply transport is stateless/HTTP (for example Lark)
|
|
95
|
+
* may set this. Connection-bound adapters (WeCom/WeChat/Room) leave it
|
|
96
|
+
* undefined: their replies depend on process-local sockets or context tokens,
|
|
97
|
+
* so the durable cross-replica reply path must not claim their jobs.
|
|
98
|
+
*/
|
|
99
|
+
readonly durableReply?: boolean;
|
|
90
100
|
receive(
|
|
91
101
|
rawPayload: unknown,
|
|
92
102
|
installation: ChannelInstallation,
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/** Lifecycle of one durable channel reply delivery attempt. */
|
|
2
|
+
export type ChannelReplyJobStatus = "pending" | "delivered" | "failed";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A durable, cross-replica channel reply job.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* The row is keyed by `runId` but always read/written inside a tenant scope.
|
|
9
|
+
* Claiming is a lease-based CAS: only a pending, due row with no live lease can
|
|
10
|
+
* be claimed, and terminal writes must present the current lease owner.
|
|
11
|
+
*/
|
|
12
|
+
export interface ChannelReplyJob {
|
|
13
|
+
runId: string;
|
|
14
|
+
tenantId: string;
|
|
15
|
+
assistantId: string;
|
|
16
|
+
threadId: string;
|
|
17
|
+
adapterChannel: string;
|
|
18
|
+
channelInstallationId: string;
|
|
19
|
+
replyTarget: Record<string, unknown>;
|
|
20
|
+
inputMessageId: string;
|
|
21
|
+
/**
|
|
22
|
+
* Legacy chunk-buffer cursor captured before the run was created.
|
|
23
|
+
*
|
|
24
|
+
* @remarks Retained for schema compatibility. The durable dispatcher now
|
|
25
|
+
* reads final text from the thread checkpoint and does not use this field.
|
|
26
|
+
*/
|
|
27
|
+
streamCursor?: string | null;
|
|
28
|
+
status: ChannelReplyJobStatus;
|
|
29
|
+
attempts: number;
|
|
30
|
+
/** Epoch milliseconds. */
|
|
31
|
+
availableAt: number;
|
|
32
|
+
leaseOwner: string | null;
|
|
33
|
+
/** Epoch milliseconds. */
|
|
34
|
+
leaseExpiresAt: number | null;
|
|
35
|
+
lastError: string | null;
|
|
36
|
+
outputMessageId: string | null;
|
|
37
|
+
/** Epoch milliseconds. */
|
|
38
|
+
createdAt: number;
|
|
39
|
+
/** Epoch milliseconds. */
|
|
40
|
+
updatedAt: number;
|
|
41
|
+
/** Epoch milliseconds. */
|
|
42
|
+
deliveredAt: number | null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Fields accepted when enqueuing a reply job. Status/lease/output fields are assigned by the store. */
|
|
46
|
+
export interface CreateChannelReplyJobInput {
|
|
47
|
+
runId: string;
|
|
48
|
+
tenantId: string;
|
|
49
|
+
assistantId: string;
|
|
50
|
+
threadId: string;
|
|
51
|
+
adapterChannel: string;
|
|
52
|
+
channelInstallationId: string;
|
|
53
|
+
replyTarget: Record<string, unknown>;
|
|
54
|
+
inputMessageId: string;
|
|
55
|
+
/**
|
|
56
|
+
* Legacy chunk-buffer cursor captured before the run was created.
|
|
57
|
+
*
|
|
58
|
+
* @remarks Retained for schema compatibility. The durable dispatcher now
|
|
59
|
+
* reads final text from the thread checkpoint and does not use this field.
|
|
60
|
+
*/
|
|
61
|
+
streamCursor?: string | null;
|
|
62
|
+
/** Earliest epoch-ms time the job may be claimed. */
|
|
63
|
+
availableAt: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Persistence boundary for durable channel reply jobs. */
|
|
67
|
+
export interface ChannelReplyJobStore {
|
|
68
|
+
/** Creates a pending job. */
|
|
69
|
+
create(input: CreateChannelReplyJobInput): Promise<ChannelReplyJob>;
|
|
70
|
+
/** Reads one job within a tenant scope. */
|
|
71
|
+
get(tenantId: string, runId: string): Promise<ChannelReplyJob | null>;
|
|
72
|
+
/** Lists claimable pending jobs that are due at `now`, oldest first. */
|
|
73
|
+
listPending(now: number, limit?: number): Promise<ChannelReplyJob[]>;
|
|
74
|
+
/**
|
|
75
|
+
* Atomically leases a pending, due job that is unleased or has an expired
|
|
76
|
+
* lease. Returns the claimed job, or `null` when another owner won.
|
|
77
|
+
*/
|
|
78
|
+
claim(
|
|
79
|
+
tenantId: string,
|
|
80
|
+
runId: string,
|
|
81
|
+
owner: string,
|
|
82
|
+
leaseMs: number,
|
|
83
|
+
now?: number,
|
|
84
|
+
): Promise<ChannelReplyJob | null>;
|
|
85
|
+
/** Marks a job delivered when `owner` still holds the lease. */
|
|
86
|
+
markDelivered(
|
|
87
|
+
tenantId: string,
|
|
88
|
+
runId: string,
|
|
89
|
+
owner: string,
|
|
90
|
+
outputMessageId?: string | null,
|
|
91
|
+
now?: number,
|
|
92
|
+
): Promise<ChannelReplyJob | null>;
|
|
93
|
+
/** Returns a job to pending with an incremented attempt count. */
|
|
94
|
+
reschedule(
|
|
95
|
+
tenantId: string,
|
|
96
|
+
runId: string,
|
|
97
|
+
owner: string,
|
|
98
|
+
error: string,
|
|
99
|
+
availableAt: number,
|
|
100
|
+
now?: number,
|
|
101
|
+
): Promise<ChannelReplyJob | null>;
|
|
102
|
+
/** Marks a job terminally failed. */
|
|
103
|
+
markFailed(
|
|
104
|
+
tenantId: string,
|
|
105
|
+
runId: string,
|
|
106
|
+
owner: string,
|
|
107
|
+
error: string,
|
|
108
|
+
now?: number,
|
|
109
|
+
): Promise<ChannelReplyJob | null>;
|
|
110
|
+
/** Deletes one job. Returns whether a row was removed. */
|
|
111
|
+
delete(tenantId: string, runId: string): Promise<boolean>;
|
|
112
|
+
/**
|
|
113
|
+
* Deletes up to `limit` terminal (`delivered`/`failed`) jobs whose last update
|
|
114
|
+
* is strictly older than `before`.
|
|
115
|
+
*
|
|
116
|
+
* @param before Epoch milliseconds retention cutoff.
|
|
117
|
+
* @param limit Maximum rows to prune in this batch (normalized 1..200).
|
|
118
|
+
* @returns Number of rows removed.
|
|
119
|
+
*/
|
|
120
|
+
deleteTerminalBefore(before: number, limit?: number): Promise<number>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Smallest accepted page size for {@link ChannelReplyJobStore.listPending}. */
|
|
124
|
+
export const CHANNEL_REPLY_JOB_LIST_LIMIT_MIN = 1;
|
|
125
|
+
/** Largest accepted page size for {@link ChannelReplyJobStore.listPending}. */
|
|
126
|
+
export const CHANNEL_REPLY_JOB_LIST_LIMIT_MAX = 200;
|
|
127
|
+
/** Default page size for {@link ChannelReplyJobStore.listPending}. */
|
|
128
|
+
export const CHANNEL_REPLY_JOB_LIST_LIMIT_DEFAULT = 100;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Normalizes a caller-supplied page size into the shared 1..200 range.
|
|
132
|
+
*
|
|
133
|
+
* @remarks Zero and negative values clamp to 1; non-finite values fall back to
|
|
134
|
+
* the default. Stores must use this helper so InMemory and PostgreSQL agree.
|
|
135
|
+
*/
|
|
136
|
+
export function normalizeChannelReplyJobListLimit(limit?: number): number {
|
|
137
|
+
if (limit === undefined || !Number.isFinite(limit)) {
|
|
138
|
+
return CHANNEL_REPLY_JOB_LIST_LIMIT_DEFAULT;
|
|
139
|
+
}
|
|
140
|
+
return Math.min(
|
|
141
|
+
CHANNEL_REPLY_JOB_LIST_LIMIT_MAX,
|
|
142
|
+
Math.max(CHANNEL_REPLY_JOB_LIST_LIMIT_MIN, Math.trunc(limit)),
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Rejects missing/blank required fields and malformed create payloads at runtime. */
|
|
147
|
+
export function assertValidCreateChannelReplyJobInput(
|
|
148
|
+
input: CreateChannelReplyJobInput,
|
|
149
|
+
): void {
|
|
150
|
+
if (input === null || typeof input !== "object") {
|
|
151
|
+
throw new Error("ChannelReplyJob create input is required");
|
|
152
|
+
}
|
|
153
|
+
const required: Array<[string, unknown]> = [
|
|
154
|
+
["runId", input.runId],
|
|
155
|
+
["tenantId", input.tenantId],
|
|
156
|
+
["assistantId", input.assistantId],
|
|
157
|
+
["threadId", input.threadId],
|
|
158
|
+
["adapterChannel", input.adapterChannel],
|
|
159
|
+
["channelInstallationId", input.channelInstallationId],
|
|
160
|
+
["inputMessageId", input.inputMessageId],
|
|
161
|
+
];
|
|
162
|
+
for (const [field, value] of required) {
|
|
163
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
164
|
+
throw new Error(`ChannelReplyJob requires a non-empty ${field}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (
|
|
168
|
+
typeof input.replyTarget !== "object" ||
|
|
169
|
+
input.replyTarget === null ||
|
|
170
|
+
Array.isArray(input.replyTarget)
|
|
171
|
+
) {
|
|
172
|
+
throw new Error("ChannelReplyJob requires a replyTarget object");
|
|
173
|
+
}
|
|
174
|
+
if (typeof input.availableAt !== "number" || !Number.isFinite(input.availableAt)) {
|
|
175
|
+
throw new Error("ChannelReplyJob requires a finite availableAt");
|
|
176
|
+
}
|
|
177
|
+
if (
|
|
178
|
+
input.streamCursor !== undefined &&
|
|
179
|
+
input.streamCursor !== null &&
|
|
180
|
+
typeof input.streamCursor !== "string"
|
|
181
|
+
) {
|
|
182
|
+
throw new Error("ChannelReplyJob streamCursor must be a string");
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkpoint storage usage for a single thread.
|
|
3
|
+
*
|
|
4
|
+
* This is a read-only accounting view over the checkpointer's persisted rows.
|
|
5
|
+
*/
|
|
6
|
+
export interface ThreadCheckpointStorage {
|
|
7
|
+
/** Thread whose checkpoint rows were measured. */
|
|
8
|
+
threadId: string;
|
|
9
|
+
/** Sum of checkpoint, channel-value, and pending-write bytes. */
|
|
10
|
+
totalBytes: number;
|
|
11
|
+
/** Persisted checkpoint rows (`checkpoints` table). */
|
|
12
|
+
checkpoints: { count: number; bytes: number };
|
|
13
|
+
/** Persisted channel values (`checkpoint_blobs` table). */
|
|
14
|
+
channelValues: { count: number; bytes: number };
|
|
15
|
+
/** Persisted pending writes (`checkpoint_writes` table). */
|
|
16
|
+
pendingWrites: { count: number; bytes: number };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Read-only checkpoint storage accounting.
|
|
21
|
+
*
|
|
22
|
+
* Implementations must not create, copy, prune, or mutate checkpoint rows.
|
|
23
|
+
*/
|
|
24
|
+
export interface CheckpointStorage {
|
|
25
|
+
/**
|
|
26
|
+
* Measure the checkpoint storage used by one thread.
|
|
27
|
+
*
|
|
28
|
+
* @param threadId - Thread id whose checkpoint rows should be measured.
|
|
29
|
+
* @returns Counts and byte sizes grouped by checkpoint storage category.
|
|
30
|
+
*/
|
|
31
|
+
get(threadId: string): Promise<ThreadCheckpointStorage>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Checkpoint maintenance operations over persisted thread checkpoints.
|
|
36
|
+
*
|
|
37
|
+
* Implementations copy, delete, and prune raw checkpoint rows for a thread.
|
|
38
|
+
* Callers must verify thread ownership and refuse to run while the thread is
|
|
39
|
+
* active.
|
|
40
|
+
*/
|
|
41
|
+
export interface CheckpointMaintenance {
|
|
42
|
+
/**
|
|
43
|
+
* Copy every checkpoint row from a source thread to an empty target thread.
|
|
44
|
+
*
|
|
45
|
+
* @param sourceThreadId - Thread whose rows are copied.
|
|
46
|
+
* @param targetThreadId - Empty thread that receives the rows.
|
|
47
|
+
* @returns Resolves when the copy commits; an empty source is a no-op.
|
|
48
|
+
* @throws When the target already has checkpoint rows.
|
|
49
|
+
*/
|
|
50
|
+
copyThread(sourceThreadId: string, targetThreadId: string): Promise<void>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Delete every checkpoint row for a thread.
|
|
54
|
+
*
|
|
55
|
+
* @param threadId - Thread whose checkpoint rows are deleted.
|
|
56
|
+
* @returns Resolves when the deletion commits.
|
|
57
|
+
*/
|
|
58
|
+
deleteThread(threadId: string): Promise<void>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Delete the checkpoints that descend from a base checkpoint.
|
|
62
|
+
*
|
|
63
|
+
* Preserves the base checkpoint and every checkpoint that is not descended
|
|
64
|
+
* from it. Descendants are discovered by following both same-namespace
|
|
65
|
+
* `parent_checkpoint_id` edges and cross-namespace `metadata.parents` edges
|
|
66
|
+
* (the `{ "<parent checkpoint_ns>": "<parent checkpoint id>" }` map that
|
|
67
|
+
* LangGraph writes for subgraph checkpoints), recursively across all
|
|
68
|
+
* namespaces. Checkpoint-id ordering is not used. LangGraph keys the first
|
|
69
|
+
* superstep's writes of a resumed execution to the parent/base checkpoint, so
|
|
70
|
+
* writes keyed to the base itself belong to the rolled-back run and are
|
|
71
|
+
* deleted with descendant writes. Channel blobs are removed only when no
|
|
72
|
+
* retained checkpoint references them.
|
|
73
|
+
*
|
|
74
|
+
* @param threadId - Thread whose later checkpoint history is deleted.
|
|
75
|
+
* @param baseCheckpointId - Checkpoint to retain as the new tip, or `null` to
|
|
76
|
+
* delete every checkpoint for the thread. An empty string is invalid and must
|
|
77
|
+
* never be treated as the `null` wildcard.
|
|
78
|
+
* @returns Resolves when the deletion commits; no descendants is a no-op.
|
|
79
|
+
* @throws When the base checkpoint does not exist on the thread. Callers must
|
|
80
|
+
* fail closed rather than deleting an unknown range.
|
|
81
|
+
* @remarks The operation is transactional and idempotent so rollback recovery
|
|
82
|
+
* can retry it.
|
|
83
|
+
*/
|
|
84
|
+
deleteAfter(threadId: string, baseCheckpointId: string | null): Promise<void>;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Retain only the latest N checkpoints per checkpoint namespace.
|
|
88
|
+
*
|
|
89
|
+
* @param threadId - Thread whose checkpoint history is pruned.
|
|
90
|
+
* @param options - Retention options.
|
|
91
|
+
* @param options.keepLatest - Number of latest checkpoints to retain per namespace.
|
|
92
|
+
* @returns Counts of deleted checkpoint, blob, and write rows.
|
|
93
|
+
*/
|
|
94
|
+
pruneThread(
|
|
95
|
+
threadId: string,
|
|
96
|
+
options: { keepLatest: number },
|
|
97
|
+
): Promise<{ checkpoints: number; blobs: number; writes: number }>;
|
|
98
|
+
}
|
package/src/EvalStoreProtocol.ts
CHANGED
|
@@ -104,6 +104,8 @@ export interface EvalRun {
|
|
|
104
104
|
interruptedCases?: number;
|
|
105
105
|
avgScore: number;
|
|
106
106
|
error?: string;
|
|
107
|
+
/** A client requested cancellation; the executing worker polls this flag. */
|
|
108
|
+
cancelRequested?: boolean;
|
|
107
109
|
/**
|
|
108
110
|
* When true, this run executed ONLY the hold-out validation suite.
|
|
109
111
|
* Per-case results of holdout runs are withheld from agents (aggregate
|
|
@@ -179,6 +181,8 @@ export interface EvalStore {
|
|
|
179
181
|
getRunById(tenantId: string, id: string): Promise<EvalRun | null>;
|
|
180
182
|
createRun(tenantId: string, projectId: string, id: string, data: CreateEvalRunRequest): Promise<EvalRun>;
|
|
181
183
|
updateRunStatus(tenantId: string, id: string, updates: { status?: EvalRun['status']; passedCases?: number; failedCases?: number; interruptedCases?: number; avgScore?: number; error?: string; completedAt?: Date }): Promise<EvalRun | null>;
|
|
184
|
+
/** Request cooperative cancellation for a running evaluation. */
|
|
185
|
+
requestCancel?(tenantId: string, id: string): Promise<boolean>;
|
|
182
186
|
deleteRun(tenantId: string, id: string): Promise<boolean>;
|
|
183
187
|
|
|
184
188
|
getResultsByRun(tenantId: string, runId: string): Promise<EvalRunResult[]>;
|
package/src/McpUiProtocol.ts
CHANGED
|
@@ -32,7 +32,15 @@ export type McpUiRef =
|
|
|
32
32
|
*/
|
|
33
33
|
structuredContent?: unknown;
|
|
34
34
|
}
|
|
35
|
-
| {
|
|
35
|
+
| {
|
|
36
|
+
kind: "plugin";
|
|
37
|
+
pluginType: string;
|
|
38
|
+
resource: string;
|
|
39
|
+
displayMode: McpUiDisplayMode;
|
|
40
|
+
title?: string;
|
|
41
|
+
/** Opaque HMAC-signed run/connection scope (1..4096 chars); never contains secrets. */
|
|
42
|
+
scope?: string;
|
|
43
|
+
};
|
|
36
44
|
|
|
37
45
|
/** Resolved UI resource body returned by the gateway. */
|
|
38
46
|
export interface McpUiResourcePayload {
|
|
@@ -45,6 +53,7 @@ export interface McpUiResourcePayload {
|
|
|
45
53
|
}
|
|
46
54
|
|
|
47
55
|
const MODES: McpUiDisplayMode[] = ["inline", "fullscreen", "pip"];
|
|
56
|
+
const MAX_MCP_UI_SCOPE_LENGTH = 4096;
|
|
48
57
|
const isObj = (v: unknown): v is Record<string, unknown> => typeof v === "object" && v !== null;
|
|
49
58
|
|
|
50
59
|
/** Type guard for a parsed `McpUiRef`. */
|
|
@@ -70,7 +79,18 @@ export function parseMcpUiRef(value: unknown): McpUiRef | null {
|
|
|
70
79
|
};
|
|
71
80
|
}
|
|
72
81
|
if (value.kind === "plugin" && typeof value.pluginType === "string" && typeof value.resource === "string") {
|
|
73
|
-
|
|
82
|
+
const scope =
|
|
83
|
+
typeof value.scope === "string" && value.scope.length > 0 && value.scope.length <= MAX_MCP_UI_SCOPE_LENGTH
|
|
84
|
+
? value.scope
|
|
85
|
+
: undefined;
|
|
86
|
+
return {
|
|
87
|
+
kind: "plugin",
|
|
88
|
+
pluginType: value.pluginType,
|
|
89
|
+
resource: value.resource,
|
|
90
|
+
displayMode,
|
|
91
|
+
...(title ? { title } : {}),
|
|
92
|
+
...(scope ? { scope } : {}),
|
|
93
|
+
};
|
|
74
94
|
}
|
|
75
95
|
return null;
|
|
76
96
|
}
|
package/src/MenuProtocol.ts
CHANGED
|
@@ -54,6 +54,8 @@ export type McpAppMenuConfig =
|
|
|
54
54
|
resource: string;
|
|
55
55
|
displayMode?: McpUiDisplayMode;
|
|
56
56
|
title?: string;
|
|
57
|
+
/** Signed scope copied from the ref so a pinned App can keep calling. */
|
|
58
|
+
scope?: string;
|
|
57
59
|
toolInput?: Record<string, unknown>;
|
|
58
60
|
toolResult?: unknown;
|
|
59
61
|
ui?: ToolCallUi;
|
package/src/MessageProtocol.ts
CHANGED
|
@@ -114,6 +114,14 @@ export type MessageChunkType = typeof MessageChunkTypes[keyof typeof MessageChun
|
|
|
114
114
|
|
|
115
115
|
export interface MessageChunk {
|
|
116
116
|
type: MessageChunkType;
|
|
117
|
+
/**
|
|
118
|
+
* Shared append-log cursor for this chunk.
|
|
119
|
+
*
|
|
120
|
+
* Set by streaming transports when the chunk is read from a cursor-addressable
|
|
121
|
+
* log (for example Redis Streams) so reconnects can resume via SSE
|
|
122
|
+
* `Last-Event-ID`. Omitted by in-memory buffers configured without a log.
|
|
123
|
+
*/
|
|
124
|
+
cursor?: string;
|
|
117
125
|
data: {
|
|
118
126
|
id: string;
|
|
119
127
|
content?: string;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time range accepted by an observability dashboard.
|
|
3
|
+
*/
|
|
4
|
+
export type ObservabilityDashboardRange = "1h" | "24h" | "7d" | "30d";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Input passed by the gateway to the selected observability provider.
|
|
8
|
+
*/
|
|
9
|
+
export interface ObservabilityDashboardInput {
|
|
10
|
+
/** Time window to aggregate. */
|
|
11
|
+
range: ObservabilityDashboardRange;
|
|
12
|
+
/** Tenant resolved from the authenticated request, never from the client. */
|
|
13
|
+
tenantId: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Provider-owned dashboard result.
|
|
18
|
+
*
|
|
19
|
+
* The `payload` shape belongs to the provider; consumers must check `version`
|
|
20
|
+
* before rendering it.
|
|
21
|
+
*/
|
|
22
|
+
export interface ObservabilityDashboardResult {
|
|
23
|
+
/** Provider payload version. */
|
|
24
|
+
version: number;
|
|
25
|
+
/** Section keys that could not be loaded. */
|
|
26
|
+
warnings?: string[];
|
|
27
|
+
/** Provider-specific dashboard data. */
|
|
28
|
+
payload: unknown;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Cross-provider response envelope returned by the gateway.
|
|
33
|
+
*/
|
|
34
|
+
export interface ObservabilityDashboardEnvelope {
|
|
35
|
+
/** Provider type, also used as the UI element key suffix. */
|
|
36
|
+
provider: string;
|
|
37
|
+
/** Requested time window. */
|
|
38
|
+
range: ObservabilityDashboardRange;
|
|
39
|
+
/** Server generation timestamp. */
|
|
40
|
+
generatedAt: string;
|
|
41
|
+
/** Provider payload version. */
|
|
42
|
+
version: number;
|
|
43
|
+
/** Section keys that could not be loaded. */
|
|
44
|
+
warnings?: string[];
|
|
45
|
+
/** Provider-specific dashboard data. */
|
|
46
|
+
payload: unknown;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Prefix used to register a dashboard renderer in the GenUI element registry. */
|
|
50
|
+
export const OBSERVABILITY_DASHBOARD_ELEMENT_KEY_PREFIX =
|
|
51
|
+
"observability_dashboard_";
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Returns the GenUI element key for a provider dashboard.
|
|
55
|
+
*
|
|
56
|
+
* @param provider - Provider type such as `"langfuse"`.
|
|
57
|
+
* @returns The registry key used by both the provider renderer and the panel.
|
|
58
|
+
*/
|
|
59
|
+
export function observabilityDashboardElementKey(provider: string): string {
|
|
60
|
+
return `${OBSERVABILITY_DASHBOARD_ELEMENT_KEY_PREFIX}${provider}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Version of the built-in Langfuse dashboard payload. */
|
|
64
|
+
export const LANGFUSE_OBSERVABILITY_DASHBOARD_VERSION = 3;
|
|
65
|
+
|
|
66
|
+
/** One point in a Langfuse dashboard time series. */
|
|
67
|
+
export interface LangfuseObservabilitySeriesPoint {
|
|
68
|
+
/** ISO timestamp of the bucket start. */
|
|
69
|
+
bucket: string;
|
|
70
|
+
/** Aggregated value, or `null` when the bucket has no value. */
|
|
71
|
+
value: number | null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Agent breakdown row, derived from the `assistant:<id>` trace tag. */
|
|
75
|
+
export interface LangfuseAgentBreakdownRow {
|
|
76
|
+
/** Assistant id from the trace tag. */
|
|
77
|
+
assistantId: string;
|
|
78
|
+
/** Display name from the trace name, when Langfuse captured one. */
|
|
79
|
+
name?: string;
|
|
80
|
+
/** Root-observation count, i.e. invocations started by this agent. */
|
|
81
|
+
calls: number;
|
|
82
|
+
/** All observations emitted by this agent. */
|
|
83
|
+
observations: number;
|
|
84
|
+
/** Total cost in USD. */
|
|
85
|
+
costUsd: number;
|
|
86
|
+
/** Input tokens consumed. */
|
|
87
|
+
inputTokens: number;
|
|
88
|
+
/** Output tokens produced. */
|
|
89
|
+
outputTokens: number;
|
|
90
|
+
/** Error-level observation count. */
|
|
91
|
+
errorCount: number;
|
|
92
|
+
/** Error ratio in `[0, 1]` over observations. */
|
|
93
|
+
errorRate: number;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** One model's cost over time. */
|
|
97
|
+
export interface LangfuseModelCostSeries {
|
|
98
|
+
/** Model name. */
|
|
99
|
+
model: string;
|
|
100
|
+
/** Cost points for this model. */
|
|
101
|
+
points: LangfuseObservabilitySeriesPoint[];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Model breakdown row. */
|
|
105
|
+
export interface LangfuseModelBreakdownRow {
|
|
106
|
+
/** Model name reported by Langfuse. */
|
|
107
|
+
model: string;
|
|
108
|
+
/** Observation count. */
|
|
109
|
+
count: number;
|
|
110
|
+
/** Total cost in USD. */
|
|
111
|
+
costUsd: number;
|
|
112
|
+
/** Input tokens consumed. */
|
|
113
|
+
inputTokens: number;
|
|
114
|
+
/** Output tokens produced. */
|
|
115
|
+
outputTokens: number;
|
|
116
|
+
/** p95 generation latency in milliseconds, or `null` when unknown. */
|
|
117
|
+
p95LatencyMs: number | null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Tool breakdown row. */
|
|
121
|
+
export interface LangfuseToolBreakdownRow {
|
|
122
|
+
/** Tool observation name. */
|
|
123
|
+
tool: string;
|
|
124
|
+
/** Observation count. */
|
|
125
|
+
count: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Built-in Langfuse dashboard payload.
|
|
130
|
+
*
|
|
131
|
+
* Aggregated for one tenant and time range; it never contains prompts,
|
|
132
|
+
* completions, user text, or credentials.
|
|
133
|
+
*/
|
|
134
|
+
export interface LangfuseObservabilityDashboardPayload {
|
|
135
|
+
/** Provider sample rate; values below 1 mean the numbers are sampled. */
|
|
136
|
+
samplingRate: number;
|
|
137
|
+
/** Tracing environment used for the query, when configured. */
|
|
138
|
+
environment?: string;
|
|
139
|
+
kpis: {
|
|
140
|
+
traces: number;
|
|
141
|
+
costUsd: number;
|
|
142
|
+
inputTokens: number;
|
|
143
|
+
outputTokens: number;
|
|
144
|
+
/** Error observation ratio in `[0, 1]`. */
|
|
145
|
+
errorRate: number;
|
|
146
|
+
};
|
|
147
|
+
series: {
|
|
148
|
+
traces: LangfuseObservabilitySeriesPoint[];
|
|
149
|
+
cost: LangfuseObservabilitySeriesPoint[];
|
|
150
|
+
tokens: {
|
|
151
|
+
input: LangfuseObservabilitySeriesPoint[];
|
|
152
|
+
output: LangfuseObservabilitySeriesPoint[];
|
|
153
|
+
};
|
|
154
|
+
latency: {
|
|
155
|
+
p50: LangfuseObservabilitySeriesPoint[];
|
|
156
|
+
p95: LangfuseObservabilitySeriesPoint[];
|
|
157
|
+
p99: LangfuseObservabilitySeriesPoint[];
|
|
158
|
+
};
|
|
159
|
+
errorRate: LangfuseObservabilitySeriesPoint[];
|
|
160
|
+
toolCalls: LangfuseObservabilitySeriesPoint[];
|
|
161
|
+
/** Per-model cost trend. Optional so older payloads keep working. */
|
|
162
|
+
costByModel?: LangfuseModelCostSeries[];
|
|
163
|
+
};
|
|
164
|
+
agents: LangfuseAgentBreakdownRow[];
|
|
165
|
+
models: LangfuseModelBreakdownRow[];
|
|
166
|
+
tools: LangfuseToolBreakdownRow[];
|
|
167
|
+
}
|