@moda-ai/cli 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +80 -2
- package/dist/schemas.d.ts +23 -0
- package/dist/schemas.js +14 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { validateConfig, VERSION, resolveApiKey } from './config.js';
|
|
4
4
|
import { callDataAPI, ApiError, getApiRequestCount, resetApiRequestCount, } from './api-client.js';
|
|
5
|
-
import { OverviewSchema, ClustersSchema, ClusterConversationsSchema, ConversationsSchema, ContextSchema, FrustrationsSchema, ToolFailuresSchema, ToolFailureDetailSchema, WorkflowsSchema, RunsSchema, RunDetailSchema, LoopsSchema, LoopDetailSchema, } from './schemas.js';
|
|
5
|
+
import { OverviewSchema, ClustersSchema, ClusterConversationsSchema, ConversationsSchema, WorldStateSchema, ContextSchema, FrustrationsSchema, ToolFailuresSchema, ToolFailureDetailSchema, WorkflowsSchema, RunsSchema, RunDetailSchema, LoopsSchema, LoopDetailSchema, } from './schemas.js';
|
|
6
6
|
import { withFrustrationAnchors, withToolFailureAnchors, embeddedWindowSize, asRecord, asString, asNumber } from './transforms.js';
|
|
7
7
|
import { runPromptsCommand } from './prompts.js';
|
|
8
8
|
// Coding-agent capture (shadow workspace / Shadow Spark / trace hooks) is temporarily
|
|
@@ -137,6 +137,7 @@ Commands:
|
|
|
137
137
|
clusters Browse topic cluster hierarchy
|
|
138
138
|
cluster-conversations <node_id> List conversations in a cluster
|
|
139
139
|
conversations Search and filter conversations
|
|
140
|
+
world-state <conversation_id> Get a conversation's world state (slots/threads/events)
|
|
140
141
|
context <conversation_id> Get windowed conversation context
|
|
141
142
|
frustrations Get user frustration detections
|
|
142
143
|
tool-failures Get tool failure overview
|
|
@@ -183,6 +184,18 @@ Common flags:
|
|
|
183
184
|
--no-tui Show raw analyst stream instead of dashboard
|
|
184
185
|
--no-update-check Skip the daily new-version check (or MODA_CLI_UPDATE_CHECK=0)
|
|
185
186
|
|
|
187
|
+
Conversations flags:
|
|
188
|
+
--search=TEXT Substring match on the conversation summary
|
|
189
|
+
--world-state=KEYWORDS Match world-state content (slots + durable profile); comma = AND
|
|
190
|
+
--outcome=any|positive|negative Filter by conversation outcome (trajectory + frustration)
|
|
191
|
+
--include-world-state Attach each result's world-state summary
|
|
192
|
+
--user-id=ID Filter to a single user
|
|
193
|
+
--environment=ENV Filter by environment (all|development|staging|production)
|
|
194
|
+
|
|
195
|
+
World-state flags:
|
|
196
|
+
--summary-only Return segment summaries only (omit the event stream)
|
|
197
|
+
--event-limit=N Max world-state events to return (1-5000, default 2000)
|
|
198
|
+
|
|
186
199
|
Runs flags:
|
|
187
200
|
--outcome=OUTCOME Filter by outcome (running|succeeded|partial|failed|loop|abandoned|unknown)
|
|
188
201
|
--class-id=ID Filter to a single workflow class (e.g. cron:helpscout-triage-hourly)
|
|
@@ -234,6 +247,9 @@ Examples:
|
|
|
234
247
|
moda overview --days-back=30
|
|
235
248
|
moda clusters --time-range=7d
|
|
236
249
|
moda conversations --search="error" --limit=5
|
|
250
|
+
moda conversations --world-state="enterprise" --outcome=positive
|
|
251
|
+
moda conversations --world-state="refund,billing" --include-world-state
|
|
252
|
+
moda world-state <conversation_id> --summary-only
|
|
237
253
|
moda frustrations --days-back=14 --limit=20
|
|
238
254
|
moda context <conversation_id> --window=3
|
|
239
255
|
moda workflows --time-range=7d
|
|
@@ -292,6 +308,25 @@ async function printWithOptionalWindows(enriched, listKey, includeWindow, window
|
|
|
292
308
|
const withWindows = await attachWindows(list, windowSize);
|
|
293
309
|
output.writeData({ ...enriched, [listKey]: withWindows });
|
|
294
310
|
}
|
|
311
|
+
// Hydrate each conversation row with its world-state summary (slots + segment
|
|
312
|
+
// summaries, no event stream) via the drill-in endpoint. Mirrors attachWindows:
|
|
313
|
+
// best-effort per row, never throws.
|
|
314
|
+
async function attachWorldState(rows) {
|
|
315
|
+
return Promise.all(rows.map(async (row) => {
|
|
316
|
+
const conv_id = asString(row.conversation_id) ?? '';
|
|
317
|
+
if (!conv_id) {
|
|
318
|
+
return { ...row, world_state: null };
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
const data = await callDataAPI(`/conversations/${conv_id}/world-state?summary_only=1`);
|
|
322
|
+
return { ...row, world_state: data };
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
326
|
+
return { ...row, world_state: { error: message } };
|
|
327
|
+
}
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
295
330
|
export async function runCommand(command, positional, flags, positionals = positional ? [positional] : [], context = createCommandContext({ command, positional, positionals, flags })) {
|
|
296
331
|
switch (command) {
|
|
297
332
|
case 'prompts': {
|
|
@@ -357,12 +392,42 @@ export async function runCommand(command, positional, flags, positionals = posit
|
|
|
357
392
|
query.set('time_range', params.time_range);
|
|
358
393
|
if (params.environment)
|
|
359
394
|
query.set('environment', params.environment);
|
|
395
|
+
if (params.world_state)
|
|
396
|
+
query.set('world_state', params.world_state);
|
|
397
|
+
if (params.outcome && params.outcome !== 'any')
|
|
398
|
+
query.set('outcome', params.outcome);
|
|
360
399
|
if (params.limit)
|
|
361
400
|
query.set('limit', params.limit.toString());
|
|
362
401
|
if (params.offset !== undefined)
|
|
363
402
|
query.set('offset', params.offset.toString());
|
|
364
403
|
const queryString = query.toString() ? `?${query.toString()}` : '';
|
|
365
404
|
const data = await callDataAPI(`/conversations${queryString}`);
|
|
405
|
+
if (params.include_world_state === true) {
|
|
406
|
+
const enriched = asRecord(data) ?? {};
|
|
407
|
+
const list = Array.isArray(enriched.conversations)
|
|
408
|
+
? enriched.conversations
|
|
409
|
+
: [];
|
|
410
|
+
const withState = await attachWorldState(list);
|
|
411
|
+
context.output.writeData({ ...enriched, conversations: withState });
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
context.output.writeData(data);
|
|
415
|
+
}
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
case 'world-state': {
|
|
419
|
+
if (!positional) {
|
|
420
|
+
throw new CliInputError('<conversation_id> is required', 'Usage: moda world-state <conversation_id> [--summary-only] [--event-limit=N]');
|
|
421
|
+
}
|
|
422
|
+
const args = flagsToArgs(flags, 'conversation_id', positional);
|
|
423
|
+
const params = WorldStateSchema.parse(args);
|
|
424
|
+
const query = new URLSearchParams();
|
|
425
|
+
if (params.summary_only === true)
|
|
426
|
+
query.set('summary_only', '1');
|
|
427
|
+
if (params.event_limit)
|
|
428
|
+
query.set('event_limit', params.event_limit.toString());
|
|
429
|
+
const queryString = query.toString() ? `?${query.toString()}` : '';
|
|
430
|
+
const data = await callDataAPI(`/conversations/${params.conversation_id}/world-state${queryString}`);
|
|
366
431
|
context.output.writeData(data);
|
|
367
432
|
break;
|
|
368
433
|
}
|
|
@@ -784,7 +849,20 @@ export const commandRegistry = createCommandRegistry([
|
|
|
784
849
|
legacyCommand({
|
|
785
850
|
name: 'conversations',
|
|
786
851
|
description: 'Search and filter conversations',
|
|
787
|
-
examples: [
|
|
852
|
+
examples: [
|
|
853
|
+
'moda conversations --search="error" --limit=5',
|
|
854
|
+
'moda conversations --world-state="enterprise" --outcome=positive',
|
|
855
|
+
'moda conversations --world-state="refund,enterprise" --include-world-state',
|
|
856
|
+
],
|
|
857
|
+
...dataApiDefaults,
|
|
858
|
+
}),
|
|
859
|
+
legacyCommand({
|
|
860
|
+
name: 'world-state',
|
|
861
|
+
description: "Get a conversation's world state (slots, threads, events)",
|
|
862
|
+
examples: [
|
|
863
|
+
'moda world-state <conversation_id>',
|
|
864
|
+
'moda world-state <conversation_id> --summary-only',
|
|
865
|
+
],
|
|
788
866
|
...dataApiDefaults,
|
|
789
867
|
}),
|
|
790
868
|
legacyCommand({
|
package/dist/schemas.d.ts
CHANGED
|
@@ -35,6 +35,9 @@ export declare const ConversationsSchema: z.ZodObject<{
|
|
|
35
35
|
user_id: z.ZodOptional<z.ZodString>;
|
|
36
36
|
time_range: z.ZodOptional<z.ZodDefault<z.ZodEnum<["all", "1h", "3d", "24h", "7d", "30d", "90d"]>>>;
|
|
37
37
|
environment: z.ZodOptional<z.ZodDefault<z.ZodEnum<["all", "development", "staging", "production"]>>>;
|
|
38
|
+
world_state: z.ZodOptional<z.ZodString>;
|
|
39
|
+
outcome: z.ZodOptional<z.ZodDefault<z.ZodEnum<["any", "positive", "negative"]>>>;
|
|
40
|
+
include_world_state: z.ZodOptional<z.ZodEffects<z.ZodBoolean, boolean, unknown>>;
|
|
38
41
|
limit: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
39
42
|
offset: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
40
43
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -45,6 +48,9 @@ export declare const ConversationsSchema: z.ZodObject<{
|
|
|
45
48
|
offset?: number | undefined;
|
|
46
49
|
cluster_id?: string | undefined;
|
|
47
50
|
user_id?: string | undefined;
|
|
51
|
+
world_state?: string | undefined;
|
|
52
|
+
outcome?: "any" | "positive" | "negative" | undefined;
|
|
53
|
+
include_world_state?: boolean | undefined;
|
|
48
54
|
}, {
|
|
49
55
|
search?: string | undefined;
|
|
50
56
|
environment?: "staging" | "all" | "development" | "production" | undefined;
|
|
@@ -53,6 +59,23 @@ export declare const ConversationsSchema: z.ZodObject<{
|
|
|
53
59
|
offset?: number | undefined;
|
|
54
60
|
cluster_id?: string | undefined;
|
|
55
61
|
user_id?: string | undefined;
|
|
62
|
+
world_state?: string | undefined;
|
|
63
|
+
outcome?: "any" | "positive" | "negative" | undefined;
|
|
64
|
+
include_world_state?: unknown;
|
|
65
|
+
}>;
|
|
66
|
+
/** moda world-state <conversationId> — per-conversation world-state drill-in. */
|
|
67
|
+
export declare const WorldStateSchema: z.ZodObject<{
|
|
68
|
+
conversation_id: z.ZodString;
|
|
69
|
+
summary_only: z.ZodOptional<z.ZodEffects<z.ZodBoolean, boolean, unknown>>;
|
|
70
|
+
event_limit: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
71
|
+
}, "strip", z.ZodTypeAny, {
|
|
72
|
+
conversation_id: string;
|
|
73
|
+
summary_only?: boolean | undefined;
|
|
74
|
+
event_limit?: number | undefined;
|
|
75
|
+
}, {
|
|
76
|
+
conversation_id: string;
|
|
77
|
+
summary_only?: unknown;
|
|
78
|
+
event_limit?: number | undefined;
|
|
56
79
|
}>;
|
|
57
80
|
export declare const ContextSchema: z.ZodObject<{
|
|
58
81
|
conversation_id: z.ZodString;
|
package/dist/schemas.js
CHANGED
|
@@ -25,9 +25,23 @@ export const ConversationsSchema = z.object({
|
|
|
25
25
|
user_id: z.string().optional(),
|
|
26
26
|
time_range: z.enum(['all', '1h', '3d', '24h', '7d', '30d', '90d']).default('all').optional(),
|
|
27
27
|
environment: z.enum(['all', 'development', 'staging', 'production']).default('all').optional(),
|
|
28
|
+
// Keyword(s) matched against conversation world-state content (segment slots
|
|
29
|
+
// + carried-in durable profile slots). Comma-separated terms are ANDed.
|
|
30
|
+
// max(200) mirrors the backend ConversationsQueryDto @MaxLength(200) so an
|
|
31
|
+
// over-long value fails locally instead of round-tripping a 400.
|
|
32
|
+
world_state: z.string().max(200).optional(),
|
|
33
|
+
// Filter by conversation outcome (trajectory + frustration).
|
|
34
|
+
outcome: z.enum(['any', 'positive', 'negative']).default('any').optional(),
|
|
35
|
+
include_world_state: boolFlag(),
|
|
28
36
|
limit: z.number().min(1).max(100).default(20).optional(),
|
|
29
37
|
offset: z.number().min(0).default(0).optional(),
|
|
30
38
|
});
|
|
39
|
+
/** moda world-state <conversationId> — per-conversation world-state drill-in. */
|
|
40
|
+
export const WorldStateSchema = z.object({
|
|
41
|
+
conversation_id: z.string(),
|
|
42
|
+
summary_only: boolFlag(),
|
|
43
|
+
event_limit: z.number().min(1).max(5000).default(2000).optional(),
|
|
44
|
+
});
|
|
31
45
|
export const ContextSchema = z.object({
|
|
32
46
|
conversation_id: z.string(),
|
|
33
47
|
msg_index: z.number().min(0).optional(),
|