struere 0.12.1 → 0.12.2
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/bin/struere.js +277 -11
- package/dist/cli/commands/add.d.ts.map +1 -1
- package/dist/cli/commands/chat.d.ts.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/pull.d.ts.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/sync.d.ts.map +1 -1
- package/dist/cli/index.js +277 -11
- package/dist/cli/templates/index.d.ts +1 -0
- package/dist/cli/templates/index.d.ts.map +1 -1
- package/dist/cli/utils/convex.d.ts +78 -0
- package/dist/cli/utils/convex.d.ts.map +1 -1
- package/dist/cli/utils/extractor.d.ts +27 -0
- package/dist/cli/utils/extractor.d.ts.map +1 -1
- package/dist/cli/utils/generator.d.ts +3 -2
- package/dist/cli/utils/generator.d.ts.map +1 -1
- package/dist/cli/utils/loader.d.ts +3 -1
- package/dist/cli/utils/loader.d.ts.map +1 -1
- package/dist/cli/utils/scaffold.d.ts +1 -0
- package/dist/cli/utils/scaffold.d.ts.map +1 -1
- package/dist/define/index.d.ts +1 -0
- package/dist/define/index.d.ts.map +1 -1
- package/dist/define/router.d.ts +3 -0
- package/dist/define/router.d.ts.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -0
- package/dist/types.d.ts +31 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/bin/struere.js
CHANGED
|
@@ -35,6 +35,7 @@ __export(exports_convex, {
|
|
|
35
35
|
getPullState: () => getPullState,
|
|
36
36
|
createOrganization: () => createOrganization,
|
|
37
37
|
compilePrompt: () => compilePrompt,
|
|
38
|
+
chatWithRouter: () => chatWithRouter,
|
|
38
39
|
chatWithAgent: () => chatWithAgent
|
|
39
40
|
});
|
|
40
41
|
async function refreshToken() {
|
|
@@ -184,6 +185,7 @@ async function syncViaHttp(apiKey, payload) {
|
|
|
184
185
|
roles: payload.roles,
|
|
185
186
|
evalSuites: payload.evalSuites,
|
|
186
187
|
triggers: payload.triggers,
|
|
188
|
+
routers: payload.routers,
|
|
187
189
|
fixtures: payload.fixtures
|
|
188
190
|
}),
|
|
189
191
|
signal: AbortSignal.timeout(30000)
|
|
@@ -635,6 +637,65 @@ async function chatWithAgent(options) {
|
|
|
635
637
|
return { error: `Network error: ${err instanceof Error ? err.message : String(err)}` };
|
|
636
638
|
}
|
|
637
639
|
}
|
|
640
|
+
async function chatWithRouter(options) {
|
|
641
|
+
const credentials = loadCredentials();
|
|
642
|
+
const apiKey = getApiKey();
|
|
643
|
+
if (credentials?.sessionId) {
|
|
644
|
+
await refreshToken();
|
|
645
|
+
}
|
|
646
|
+
const freshCredentials = loadCredentials();
|
|
647
|
+
const token = apiKey || freshCredentials?.token;
|
|
648
|
+
if (!token) {
|
|
649
|
+
return { error: "Not authenticated" };
|
|
650
|
+
}
|
|
651
|
+
try {
|
|
652
|
+
const response = await fetch(`${CONVEX_URL}/api/action`, {
|
|
653
|
+
method: "POST",
|
|
654
|
+
headers: {
|
|
655
|
+
"Content-Type": "application/json",
|
|
656
|
+
Authorization: `Bearer ${token}`
|
|
657
|
+
},
|
|
658
|
+
body: JSON.stringify({
|
|
659
|
+
path: "chat:sendByRouterSlug",
|
|
660
|
+
args: {
|
|
661
|
+
routerSlug: options.routerSlug,
|
|
662
|
+
message: options.message,
|
|
663
|
+
threadId: options.threadId,
|
|
664
|
+
phoneNumber: options.phoneNumber,
|
|
665
|
+
environment: options.environment,
|
|
666
|
+
channel: options.channel || "api"
|
|
667
|
+
}
|
|
668
|
+
}),
|
|
669
|
+
signal: options.signal || AbortSignal.timeout(120000)
|
|
670
|
+
});
|
|
671
|
+
const text = await response.text();
|
|
672
|
+
let json;
|
|
673
|
+
try {
|
|
674
|
+
json = JSON.parse(text);
|
|
675
|
+
} catch {
|
|
676
|
+
return { error: text || `HTTP ${response.status}` };
|
|
677
|
+
}
|
|
678
|
+
if (!response.ok) {
|
|
679
|
+
const msg = json.errorData?.message || json.errorMessage || text;
|
|
680
|
+
return { error: msg };
|
|
681
|
+
}
|
|
682
|
+
if (json.status === "success" && json.value) {
|
|
683
|
+
return { result: json.value };
|
|
684
|
+
}
|
|
685
|
+
if (json.status === "success" && json.value === null) {
|
|
686
|
+
return { error: `Router not found or no config for environment: ${options.environment}` };
|
|
687
|
+
}
|
|
688
|
+
if (json.status === "error") {
|
|
689
|
+
return { error: json.errorData?.message || json.errorMessage || "Unknown error from Convex" };
|
|
690
|
+
}
|
|
691
|
+
return { error: `Unexpected response: ${text}` };
|
|
692
|
+
} catch (err) {
|
|
693
|
+
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
694
|
+
return { error: "Request timed out after 120s" };
|
|
695
|
+
}
|
|
696
|
+
return { error: `Network error: ${err instanceof Error ? err.message : String(err)}` };
|
|
697
|
+
}
|
|
698
|
+
}
|
|
638
699
|
async function getPullState(organizationId, environment = "development") {
|
|
639
700
|
const credentials = loadCredentials();
|
|
640
701
|
const apiKey = getApiKey();
|
|
@@ -1343,6 +1404,26 @@ export default defineTrigger({
|
|
|
1343
1404
|
})
|
|
1344
1405
|
`;
|
|
1345
1406
|
}
|
|
1407
|
+
function getRouterTs(name, slug) {
|
|
1408
|
+
return `import { defineRouter } from 'struere'
|
|
1409
|
+
|
|
1410
|
+
export default defineRouter({
|
|
1411
|
+
name: "${name}",
|
|
1412
|
+
slug: "${slug}",
|
|
1413
|
+
mode: "rules",
|
|
1414
|
+
agents: [
|
|
1415
|
+
{ slug: "agent-one", description: "Handles ..." },
|
|
1416
|
+
],
|
|
1417
|
+
rules: [
|
|
1418
|
+
{
|
|
1419
|
+
conditions: [{ field: "channel", operator: "eq", value: "whatsapp" }],
|
|
1420
|
+
route: "agent-one",
|
|
1421
|
+
},
|
|
1422
|
+
],
|
|
1423
|
+
fallback: "agent-one",
|
|
1424
|
+
})
|
|
1425
|
+
`;
|
|
1426
|
+
}
|
|
1346
1427
|
|
|
1347
1428
|
// src/cli/utils/scaffold.ts
|
|
1348
1429
|
function ensureDir(filePath) {
|
|
@@ -1368,6 +1449,7 @@ function scaffoldProject(cwd, options) {
|
|
|
1368
1449
|
"tools",
|
|
1369
1450
|
"evals",
|
|
1370
1451
|
"triggers",
|
|
1452
|
+
"routers",
|
|
1371
1453
|
"fixtures",
|
|
1372
1454
|
".struere"
|
|
1373
1455
|
];
|
|
@@ -1487,6 +1569,24 @@ function scaffoldTrigger(cwd, name, slug) {
|
|
|
1487
1569
|
result.createdFiles.push(`triggers/${fileName}`);
|
|
1488
1570
|
return result;
|
|
1489
1571
|
}
|
|
1572
|
+
function scaffoldRouter(cwd, name, slug) {
|
|
1573
|
+
const result = {
|
|
1574
|
+
createdFiles: [],
|
|
1575
|
+
updatedFiles: []
|
|
1576
|
+
};
|
|
1577
|
+
const routersDir = join3(cwd, "routers");
|
|
1578
|
+
if (!existsSync3(routersDir)) {
|
|
1579
|
+
mkdirSync2(routersDir, { recursive: true });
|
|
1580
|
+
}
|
|
1581
|
+
const fileName = `${slug}.ts`;
|
|
1582
|
+
const filePath = join3(routersDir, fileName);
|
|
1583
|
+
if (existsSync3(filePath)) {
|
|
1584
|
+
return result;
|
|
1585
|
+
}
|
|
1586
|
+
writeFileSync2(filePath, getRouterTs(name, slug));
|
|
1587
|
+
result.createdFiles.push(`routers/${fileName}`);
|
|
1588
|
+
return result;
|
|
1589
|
+
}
|
|
1490
1590
|
function scaffoldFixture(cwd, name, slug) {
|
|
1491
1591
|
const result = {
|
|
1492
1592
|
createdFiles: [],
|
|
@@ -1916,9 +2016,10 @@ async function loadAllResources(cwd) {
|
|
|
1916
2016
|
const { suites: evalSuites, errors: evalErrors } = loadEvalSuites(join5(cwd, "evals"));
|
|
1917
2017
|
errors.push(...evalErrors);
|
|
1918
2018
|
const triggers = await loadTsDirectory(join5(cwd, "triggers"));
|
|
2019
|
+
const routers = await loadTsDirectory(join5(cwd, "routers"));
|
|
1919
2020
|
const { fixtures, errors: fixtureErrors } = loadFixtures(join5(cwd, "fixtures"));
|
|
1920
2021
|
errors.push(...fixtureErrors);
|
|
1921
|
-
return { agents, entityTypes, roles, customTools, evalSuites, triggers, fixtures, errors };
|
|
2022
|
+
return { agents, entityTypes, roles, customTools, evalSuites, triggers, routers, fixtures, errors };
|
|
1922
2023
|
}
|
|
1923
2024
|
async function loadTsDirectory(dir) {
|
|
1924
2025
|
if (!existsSync5(dir)) {
|
|
@@ -2005,6 +2106,7 @@ function getResourceDirectories(cwd) {
|
|
|
2005
2106
|
tools: join5(cwd, "tools"),
|
|
2006
2107
|
evals: join5(cwd, "evals"),
|
|
2007
2108
|
triggers: join5(cwd, "triggers"),
|
|
2109
|
+
routers: join5(cwd, "routers"),
|
|
2008
2110
|
fixtures: join5(cwd, "fixtures")
|
|
2009
2111
|
};
|
|
2010
2112
|
}
|
|
@@ -2143,6 +2245,7 @@ async function generateDocs(cwd, targets) {
|
|
|
2143
2245
|
customTools: [],
|
|
2144
2246
|
evalSuites: [],
|
|
2145
2247
|
triggers: [],
|
|
2248
|
+
routers: [],
|
|
2146
2249
|
fixtures: [],
|
|
2147
2250
|
errors: []
|
|
2148
2251
|
});
|
|
@@ -2687,6 +2790,29 @@ function extractSyncPayload(resources) {
|
|
|
2687
2790
|
schedule: t.schedule,
|
|
2688
2791
|
retry: t.retry
|
|
2689
2792
|
})) : undefined;
|
|
2793
|
+
const routers = resources.routers.length > 0 ? resources.routers.map((r) => ({
|
|
2794
|
+
name: r.name,
|
|
2795
|
+
slug: r.slug,
|
|
2796
|
+
description: r.description,
|
|
2797
|
+
mode: r.mode,
|
|
2798
|
+
agents: r.agents.map((a) => ({
|
|
2799
|
+
slug: a.slug,
|
|
2800
|
+
description: a.description
|
|
2801
|
+
})),
|
|
2802
|
+
rules: r.rules?.map((rule) => ({
|
|
2803
|
+
conditions: rule.conditions.map((c) => ({
|
|
2804
|
+
field: c.field,
|
|
2805
|
+
operator: c.operator,
|
|
2806
|
+
value: c.value
|
|
2807
|
+
})),
|
|
2808
|
+
route: rule.route
|
|
2809
|
+
})),
|
|
2810
|
+
fallback: r.fallback,
|
|
2811
|
+
classifyModel: r.classifyModel,
|
|
2812
|
+
contextMessages: r.contextMessages,
|
|
2813
|
+
maxTransfers: r.maxTransfers,
|
|
2814
|
+
inactivityResetMs: r.inactivityResetMs
|
|
2815
|
+
})) : undefined;
|
|
2690
2816
|
const fixtures = resources.fixtures.length > 0 ? resources.fixtures.map((f) => ({
|
|
2691
2817
|
name: f.name,
|
|
2692
2818
|
slug: f.slug,
|
|
@@ -2703,7 +2829,7 @@ function extractSyncPayload(resources) {
|
|
|
2703
2829
|
metadata: r.metadata
|
|
2704
2830
|
}))
|
|
2705
2831
|
})) : undefined;
|
|
2706
|
-
return { agents, entityTypes, roles, evalSuites, triggers, fixtures };
|
|
2832
|
+
return { agents, entityTypes, roles, evalSuites, triggers, routers, fixtures };
|
|
2707
2833
|
}
|
|
2708
2834
|
function extractAgentPayload(agent, customToolsMap) {
|
|
2709
2835
|
let systemPrompt;
|
|
@@ -3132,6 +3258,7 @@ ${resources.errors.join(`
|
|
|
3132
3258
|
entityTypes: payload.entityTypes,
|
|
3133
3259
|
roles: payload.roles,
|
|
3134
3260
|
triggers: payload.triggers,
|
|
3261
|
+
routers: payload.routers,
|
|
3135
3262
|
organizationId,
|
|
3136
3263
|
environment: "development"
|
|
3137
3264
|
});
|
|
@@ -3165,7 +3292,8 @@ async function checkForDeletions(resources, organizationId, environment) {
|
|
|
3165
3292
|
entityTypes: new Set(payload.entityTypes.map((et) => et.slug)),
|
|
3166
3293
|
roles: new Set(payload.roles.map((r) => r.name)),
|
|
3167
3294
|
evalSuites: new Set((payload.evalSuites || []).map((es) => es.slug)),
|
|
3168
|
-
triggers: new Set((payload.triggers || []).map((t) => t.slug))
|
|
3295
|
+
triggers: new Set((payload.triggers || []).map((t) => t.slug)),
|
|
3296
|
+
routers: new Set((payload.routers || []).map((r) => r.slug))
|
|
3169
3297
|
};
|
|
3170
3298
|
const deletions = [];
|
|
3171
3299
|
const deletedAgents = remoteState.agents.filter((a) => !localSlugs.agents.has(a.slug)).map((a) => a.name);
|
|
@@ -3185,6 +3313,10 @@ async function checkForDeletions(resources, organizationId, environment) {
|
|
|
3185
3313
|
const deletedTriggers = remoteTriggers.filter((t) => !localSlugs.triggers.has(t.slug)).map((t) => t.name);
|
|
3186
3314
|
if (deletedTriggers.length > 0)
|
|
3187
3315
|
deletions.push({ type: "Triggers", remote: remoteTriggers.length, local: (payload.triggers || []).length, deleted: deletedTriggers });
|
|
3316
|
+
const remoteRouters = remoteState.routers || [];
|
|
3317
|
+
const deletedRouters = remoteRouters.filter((r) => !localSlugs.routers.has(r.slug)).map((r) => r.name);
|
|
3318
|
+
if (deletedRouters.length > 0)
|
|
3319
|
+
deletions.push({ type: "Routers", remote: remoteRouters.length, local: (payload.routers || []).length, deleted: deletedRouters });
|
|
3188
3320
|
return deletions;
|
|
3189
3321
|
}
|
|
3190
3322
|
async function syncToEnvironment(cwd, organizationId, environment) {
|
|
@@ -3304,6 +3436,7 @@ var syncCommand = new Command5("sync").description("Sync resources to Convex and
|
|
|
3304
3436
|
entityTypes: payload.entityTypes.map((et) => et.slug),
|
|
3305
3437
|
roles: payload.roles.map((r) => r.name),
|
|
3306
3438
|
triggers: (payload.triggers || []).map((t) => t.slug),
|
|
3439
|
+
routers: (payload.routers || []).map((r) => r.slug),
|
|
3307
3440
|
deletions: deletions.map((d) => ({ type: d.type, names: d.deleted }))
|
|
3308
3441
|
}));
|
|
3309
3442
|
} else {
|
|
@@ -3313,6 +3446,7 @@ var syncCommand = new Command5("sync").description("Sync resources to Convex and
|
|
|
3313
3446
|
console.log(chalk6.gray(" Data types:"), payload.entityTypes.map((et) => et.slug).join(", ") || "none");
|
|
3314
3447
|
console.log(chalk6.gray(" Roles:"), payload.roles.map((r) => r.name).join(", ") || "none");
|
|
3315
3448
|
console.log(chalk6.gray(" Triggers:"), (payload.triggers || []).map((t) => t.slug).join(", ") || "none");
|
|
3449
|
+
console.log(chalk6.gray(" Routers:"), (payload.routers || []).map((r) => r.slug).join(", ") || "none");
|
|
3316
3450
|
if (deletions.length > 0) {
|
|
3317
3451
|
console.log();
|
|
3318
3452
|
console.log(chalk6.yellow.bold(" Would delete:"));
|
|
@@ -3477,7 +3611,7 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
|
|
|
3477
3611
|
spinner.start("Loading resources");
|
|
3478
3612
|
try {
|
|
3479
3613
|
loadedResources = await loadAllResources(cwd);
|
|
3480
|
-
spinner.succeed(`Loaded ${loadedResources.agents.length} agents, ${loadedResources.entityTypes.length} data types, ${loadedResources.roles.length} roles, ${loadedResources.customTools.length} custom tools, ${loadedResources.evalSuites.length} eval suites, ${loadedResources.triggers.length} triggers, ${loadedResources.fixtures.length} fixtures`);
|
|
3614
|
+
spinner.succeed(`Loaded ${loadedResources.agents.length} agents, ${loadedResources.entityTypes.length} data types, ${loadedResources.roles.length} roles, ${loadedResources.customTools.length} custom tools, ${loadedResources.evalSuites.length} eval suites, ${loadedResources.triggers.length} triggers, ${loadedResources.routers.length} routers, ${loadedResources.fixtures.length} fixtures`);
|
|
3481
3615
|
for (const err of loadedResources.errors) {
|
|
3482
3616
|
console.log(chalk7.red(" \u2716"), err);
|
|
3483
3617
|
}
|
|
@@ -3572,6 +3706,7 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
|
|
|
3572
3706
|
dirs.tools,
|
|
3573
3707
|
dirs.evals,
|
|
3574
3708
|
dirs.triggers,
|
|
3709
|
+
dirs.routers,
|
|
3575
3710
|
dirs.fixtures
|
|
3576
3711
|
].filter((p) => existsSync8(p));
|
|
3577
3712
|
const watcher = chokidar.watch(watchPaths, {
|
|
@@ -4069,7 +4204,7 @@ var whoamiCommand = new Command9("whoami").description("Show current logged in u
|
|
|
4069
4204
|
// src/cli/commands/add.ts
|
|
4070
4205
|
import { Command as Command10 } from "commander";
|
|
4071
4206
|
import chalk11 from "chalk";
|
|
4072
|
-
var addCommand = new Command10("add").description("Scaffold a new resource").argument("<type>", "Resource type: agent, data-type, role, eval, trigger, or fixture").argument("<name>", "Resource name").action(async (type, name) => {
|
|
4207
|
+
var addCommand = new Command10("add").description("Scaffold a new resource").argument("<type>", "Resource type: agent, data-type, role, eval, trigger, router, or fixture").argument("<name>", "Resource name").action(async (type, name) => {
|
|
4073
4208
|
const cwd = process.cwd();
|
|
4074
4209
|
console.log();
|
|
4075
4210
|
if (!hasProject(cwd)) {
|
|
@@ -4147,6 +4282,17 @@ var addCommand = new Command10("add").description("Scaffold a new resource").arg
|
|
|
4147
4282
|
console.log(chalk11.yellow("Trigger already exists:"), `triggers/${slug}.ts`);
|
|
4148
4283
|
}
|
|
4149
4284
|
break;
|
|
4285
|
+
case "router":
|
|
4286
|
+
result = scaffoldRouter(cwd, displayName, slug);
|
|
4287
|
+
if (result.createdFiles.length > 0) {
|
|
4288
|
+
console.log(chalk11.green("\u2713"), `Created router "${displayName}"`);
|
|
4289
|
+
for (const file of result.createdFiles) {
|
|
4290
|
+
console.log(chalk11.gray(" \u2192"), file);
|
|
4291
|
+
}
|
|
4292
|
+
} else {
|
|
4293
|
+
console.log(chalk11.yellow("Router already exists:"), `routers/${slug}.ts`);
|
|
4294
|
+
}
|
|
4295
|
+
break;
|
|
4150
4296
|
case "fixture":
|
|
4151
4297
|
result = scaffoldFixture(cwd, displayName, slug);
|
|
4152
4298
|
if (result.createdFiles.length > 0) {
|
|
@@ -4169,6 +4315,7 @@ var addCommand = new Command10("add").description("Scaffold a new resource").arg
|
|
|
4169
4315
|
console.log(chalk11.gray(" -"), chalk11.cyan("role"), "- Create a role with permissions");
|
|
4170
4316
|
console.log(chalk11.gray(" -"), chalk11.cyan("eval"), "- Create an eval suite (YAML)");
|
|
4171
4317
|
console.log(chalk11.gray(" -"), chalk11.cyan("trigger"), "- Create a data trigger");
|
|
4318
|
+
console.log(chalk11.gray(" -"), chalk11.cyan("router"), "- Create a message router");
|
|
4172
4319
|
console.log(chalk11.gray(" -"), chalk11.cyan("fixture"), "- Create a test data fixture (YAML)");
|
|
4173
4320
|
console.log();
|
|
4174
4321
|
process.exit(1);
|
|
@@ -4298,6 +4445,8 @@ var statusCommand = new Command11("status").description("Compare local vs remote
|
|
|
4298
4445
|
const devEntityTypeSlugs = new Set(devState.entityTypes.map((et) => et.slug));
|
|
4299
4446
|
const localRoleNames = new Set(localResources.roles.map((r) => r.name));
|
|
4300
4447
|
const devRoleNames = new Set(devState.roles.map((r) => r.name));
|
|
4448
|
+
const localRouterSlugs = new Set(localResources.routers.map((r) => r.slug));
|
|
4449
|
+
const devRouterSlugs = new Set((devState.routers || []).map((r) => r.slug));
|
|
4301
4450
|
if (opts.json) {
|
|
4302
4451
|
const classify = (localItems, remoteItems, useSlug) => {
|
|
4303
4452
|
const localKeys = new Set(localItems.map((i) => useSlug ? i.slug : i.name));
|
|
@@ -4311,7 +4460,8 @@ var statusCommand = new Command11("status").description("Compare local vs remote
|
|
|
4311
4460
|
console.log(JSON.stringify({
|
|
4312
4461
|
agents: classify(localResources.agents, devState.agents, true),
|
|
4313
4462
|
entityTypes: classify(localResources.entityTypes, devState.entityTypes, true),
|
|
4314
|
-
roles: classify(localResources.roles, devState.roles, false)
|
|
4463
|
+
roles: classify(localResources.roles, devState.roles, false),
|
|
4464
|
+
routers: classify(localResources.routers, devState.routers || [], true)
|
|
4315
4465
|
}));
|
|
4316
4466
|
return;
|
|
4317
4467
|
}
|
|
@@ -4381,6 +4531,26 @@ var statusCommand = new Command11("status").description("Compare local vs remote
|
|
|
4381
4531
|
}
|
|
4382
4532
|
}
|
|
4383
4533
|
console.log();
|
|
4534
|
+
console.log(chalk12.bold("Routers"));
|
|
4535
|
+
console.log(chalk12.gray("\u2500".repeat(60)));
|
|
4536
|
+
if (localResources.routers.length === 0 && (devState.routers || []).length === 0) {
|
|
4537
|
+
console.log(chalk12.gray(" No routers"));
|
|
4538
|
+
} else {
|
|
4539
|
+
for (const router of localResources.routers) {
|
|
4540
|
+
const remote = (devState.routers || []).find((r) => r.slug === router.slug);
|
|
4541
|
+
if (remote) {
|
|
4542
|
+
console.log(` ${chalk12.green("\u25CF")} ${chalk12.cyan(router.name)} (${router.slug}) - ${router.mode}`);
|
|
4543
|
+
} else {
|
|
4544
|
+
console.log(` ${chalk12.blue("+")} ${chalk12.cyan(router.name)} (${router.slug}) - ${chalk12.blue("new")}`);
|
|
4545
|
+
}
|
|
4546
|
+
}
|
|
4547
|
+
for (const remote of devState.routers || []) {
|
|
4548
|
+
if (!localRouterSlugs.has(remote.slug)) {
|
|
4549
|
+
console.log(` ${chalk12.red("-")} ${remote.name} (${remote.slug}) - ${chalk12.red("will be deleted")}`);
|
|
4550
|
+
}
|
|
4551
|
+
}
|
|
4552
|
+
}
|
|
4553
|
+
console.log();
|
|
4384
4554
|
console.log(chalk12.gray("Legend:"));
|
|
4385
4555
|
console.log(chalk12.gray(" "), chalk12.green("\u25CF"), "Synced", chalk12.yellow("\u25CB"), "Not in production", chalk12.blue("+"), "New", chalk12.red("-"), "Will be deleted");
|
|
4386
4556
|
console.log();
|
|
@@ -4655,6 +4825,53 @@ ${parts.join(`,
|
|
|
4655
4825
|
})
|
|
4656
4826
|
`;
|
|
4657
4827
|
}
|
|
4828
|
+
function generateRouterFile(router) {
|
|
4829
|
+
const agentLines = router.agents.map((a) => {
|
|
4830
|
+
const aParts = [
|
|
4831
|
+
` slug: "${a.slug}"`,
|
|
4832
|
+
` description: "${a.description}"`
|
|
4833
|
+
];
|
|
4834
|
+
return ` {
|
|
4835
|
+
${aParts.join(`,
|
|
4836
|
+
`)},
|
|
4837
|
+
}`;
|
|
4838
|
+
});
|
|
4839
|
+
const parts = [
|
|
4840
|
+
` name: "${router.name}"`,
|
|
4841
|
+
` slug: "${router.slug}"`
|
|
4842
|
+
];
|
|
4843
|
+
if (router.description) {
|
|
4844
|
+
parts.push(` description: "${router.description}"`);
|
|
4845
|
+
}
|
|
4846
|
+
parts.push(` mode: "${router.mode}"`);
|
|
4847
|
+
parts.push(` agents: [
|
|
4848
|
+
${agentLines.join(`,
|
|
4849
|
+
`)},
|
|
4850
|
+
]`);
|
|
4851
|
+
if (router.rules && router.rules.length > 0) {
|
|
4852
|
+
parts.push(` rules: ${stringifyValue(router.rules, 2)}`);
|
|
4853
|
+
}
|
|
4854
|
+
parts.push(` fallback: "${router.fallback}"`);
|
|
4855
|
+
if (router.classifyModel) {
|
|
4856
|
+
parts.push(` classifyModel: ${stringifyValue(router.classifyModel, 2)}`);
|
|
4857
|
+
}
|
|
4858
|
+
if (router.contextMessages !== undefined) {
|
|
4859
|
+
parts.push(` contextMessages: ${router.contextMessages}`);
|
|
4860
|
+
}
|
|
4861
|
+
if (router.maxTransfers !== undefined) {
|
|
4862
|
+
parts.push(` maxTransfers: ${router.maxTransfers}`);
|
|
4863
|
+
}
|
|
4864
|
+
if (router.inactivityResetMs !== undefined) {
|
|
4865
|
+
parts.push(` inactivityResetMs: ${router.inactivityResetMs}`);
|
|
4866
|
+
}
|
|
4867
|
+
return `import { defineRouter } from 'struere'
|
|
4868
|
+
|
|
4869
|
+
export default defineRouter({
|
|
4870
|
+
${parts.join(`,
|
|
4871
|
+
`)},
|
|
4872
|
+
})
|
|
4873
|
+
`;
|
|
4874
|
+
}
|
|
4658
4875
|
function generateIndexFile(type, slugs) {
|
|
4659
4876
|
if (slugs.length === 0) {
|
|
4660
4877
|
return "";
|
|
@@ -4789,6 +5006,7 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
|
|
|
4789
5006
|
ensureDir2(join9(cwd, "entity-types"));
|
|
4790
5007
|
ensureDir2(join9(cwd, "roles"));
|
|
4791
5008
|
ensureDir2(join9(cwd, "triggers"));
|
|
5009
|
+
ensureDir2(join9(cwd, "routers"));
|
|
4792
5010
|
ensureDir2(join9(cwd, "tools"));
|
|
4793
5011
|
const agentSlugs = [];
|
|
4794
5012
|
for (const agent of state.agents) {
|
|
@@ -4816,6 +5034,12 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
|
|
|
4816
5034
|
const content = generateTriggerFile(trigger);
|
|
4817
5035
|
writeOrSkip(`triggers/${trigger.slug}.ts`, content);
|
|
4818
5036
|
}
|
|
5037
|
+
const routerSlugs = [];
|
|
5038
|
+
for (const router of state.routers || []) {
|
|
5039
|
+
routerSlugs.push(router.slug);
|
|
5040
|
+
const content = generateRouterFile(router);
|
|
5041
|
+
writeOrSkip(`routers/${router.slug}.ts`, content);
|
|
5042
|
+
}
|
|
4819
5043
|
const customTools = collectCustomTools(state.agents);
|
|
4820
5044
|
if (customTools.length > 0) {
|
|
4821
5045
|
const content = generateToolsFile(customTools);
|
|
@@ -4841,6 +5065,11 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
|
|
|
4841
5065
|
if (content)
|
|
4842
5066
|
writeOrSkip("triggers/index.ts", content);
|
|
4843
5067
|
}
|
|
5068
|
+
if (routerSlugs.length > 0) {
|
|
5069
|
+
const content = generateIndexFile("routers", routerSlugs);
|
|
5070
|
+
if (content)
|
|
5071
|
+
writeOrSkip("routers/index.ts", content);
|
|
5072
|
+
}
|
|
4844
5073
|
await installSkill(cwd);
|
|
4845
5074
|
if (options.json) {
|
|
4846
5075
|
console.log(JSON.stringify({
|
|
@@ -8281,7 +8510,7 @@ import chalk23 from "chalk";
|
|
|
8281
8510
|
import ora17 from "ora";
|
|
8282
8511
|
import readline from "readline";
|
|
8283
8512
|
init_convex();
|
|
8284
|
-
var chatCommand = new Command21("chat").description("Chat with an agent").argument("<
|
|
8513
|
+
var chatCommand = new Command21("chat").description("Chat with an agent or via a router").argument("<slug>", "Agent slug (or router slug when --router is used)").option("--env <environment>", "Environment: development | production | eval", "development").option("--thread <id>", "Continue an existing thread").option("--message <msg>", "Single message mode (send and exit)").option("--json", "Output JSON").option("--channel <channel>", "Channel identifier", "api").option("-v, --verbose", "Show detailed response info").option("--confirm", "Skip production warning prompt").option("--router", "Chat via a router instead of directly with an agent").option("--phone <number>", "Sender phone number for routing rules").action(async (slug, options) => {
|
|
8285
8514
|
const spinner = ora17();
|
|
8286
8515
|
const cwd = process.cwd();
|
|
8287
8516
|
const nonInteractive = !isInteractive();
|
|
@@ -8333,6 +8562,15 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
|
|
|
8333
8562
|
console.log();
|
|
8334
8563
|
}
|
|
8335
8564
|
const environment = options.env;
|
|
8565
|
+
const isRouterMode = !!options.router;
|
|
8566
|
+
if (isRouterMode && !options.phone) {
|
|
8567
|
+
if (jsonMode) {
|
|
8568
|
+
console.log(JSON.stringify({ success: false, error: "--phone is required when using --router" }));
|
|
8569
|
+
} else {
|
|
8570
|
+
console.log(chalk23.red("--phone is required when using --router"));
|
|
8571
|
+
}
|
|
8572
|
+
process.exit(1);
|
|
8573
|
+
}
|
|
8336
8574
|
if (environment === "production" && !nonInteractive && !options.confirm) {
|
|
8337
8575
|
const confirmRl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
8338
8576
|
await new Promise((resolve) => {
|
|
@@ -8342,8 +8580,20 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
|
|
|
8342
8580
|
confirmRl.close();
|
|
8343
8581
|
}
|
|
8344
8582
|
const doChat = async (message, threadId2, signal) => {
|
|
8583
|
+
if (isRouterMode) {
|
|
8584
|
+
return chatWithRouter({
|
|
8585
|
+
routerSlug: slug,
|
|
8586
|
+
message,
|
|
8587
|
+
threadId: threadId2,
|
|
8588
|
+
phoneNumber: options.phone,
|
|
8589
|
+
environment,
|
|
8590
|
+
organizationId: project?.organization.id,
|
|
8591
|
+
channel: options.channel,
|
|
8592
|
+
signal
|
|
8593
|
+
});
|
|
8594
|
+
}
|
|
8345
8595
|
return chatWithAgent({
|
|
8346
|
-
slug
|
|
8596
|
+
slug,
|
|
8347
8597
|
message,
|
|
8348
8598
|
threadId: threadId2,
|
|
8349
8599
|
environment,
|
|
@@ -8395,12 +8645,22 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
|
|
|
8395
8645
|
}
|
|
8396
8646
|
if (!jsonMode)
|
|
8397
8647
|
spinner.succeed("Message sent");
|
|
8648
|
+
const routerResult = result;
|
|
8398
8649
|
if (jsonMode) {
|
|
8399
|
-
|
|
8650
|
+
const output = { message: result.message, threadId: result.threadId, usage: result.usage };
|
|
8651
|
+
if (routerResult.routedToAgent) {
|
|
8652
|
+
output.routedToAgent = routerResult.routedToAgent;
|
|
8653
|
+
output.routedToAgentSlug = routerResult.routedToAgentSlug;
|
|
8654
|
+
}
|
|
8655
|
+
console.log(JSON.stringify(output, null, 2));
|
|
8400
8656
|
} else {
|
|
8401
8657
|
console.log();
|
|
8402
8658
|
console.log("\u2500".repeat(60));
|
|
8403
8659
|
console.log();
|
|
8660
|
+
if (routerResult.routedToAgent) {
|
|
8661
|
+
console.log(chalk23.magenta(`Routed to: ${routerResult.routedToAgent} (${routerResult.routedToAgentSlug})`));
|
|
8662
|
+
console.log();
|
|
8663
|
+
}
|
|
8404
8664
|
console.log(chalk23.green("Agent:"));
|
|
8405
8665
|
console.log(result.message);
|
|
8406
8666
|
console.log();
|
|
@@ -8416,7 +8676,8 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
|
|
|
8416
8676
|
}
|
|
8417
8677
|
return;
|
|
8418
8678
|
}
|
|
8419
|
-
|
|
8679
|
+
const headerLabel = isRouterMode ? `router ${chalk23.cyan(slug)}` : chalk23.cyan(slug);
|
|
8680
|
+
console.log(chalk23.bold(`Chat with ${headerLabel} (${environment})`));
|
|
8420
8681
|
console.log(chalk23.dim("Type 'exit' to quit"));
|
|
8421
8682
|
console.log();
|
|
8422
8683
|
let threadId = options.thread;
|
|
@@ -8505,7 +8766,12 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
|
|
|
8505
8766
|
}
|
|
8506
8767
|
spinner.stop();
|
|
8507
8768
|
threadId = result.threadId;
|
|
8769
|
+
const interactiveRouterResult = result;
|
|
8508
8770
|
console.log();
|
|
8771
|
+
if (interactiveRouterResult.routedToAgent) {
|
|
8772
|
+
console.log(chalk23.magenta(`Routed to: ${interactiveRouterResult.routedToAgent} (${interactiveRouterResult.routedToAgentSlug})`));
|
|
8773
|
+
console.log();
|
|
8774
|
+
}
|
|
8509
8775
|
console.log(chalk23.green("Agent:"));
|
|
8510
8776
|
console.log(result.message);
|
|
8511
8777
|
console.log();
|
|
@@ -8531,7 +8797,7 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
|
|
|
8531
8797
|
// package.json
|
|
8532
8798
|
var package_default = {
|
|
8533
8799
|
name: "struere",
|
|
8534
|
-
version: "0.12.
|
|
8800
|
+
version: "0.12.2",
|
|
8535
8801
|
description: "Build, test, and deploy AI agents",
|
|
8536
8802
|
keywords: [
|
|
8537
8803
|
"ai",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAMnC,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAMnC,eAAO,MAAM,UAAU,SA2InB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAWnC,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAWnC,eAAO,MAAM,WAAW,SAmUpB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAiBnC,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAiBnC,eAAO,MAAM,UAAU,SA2PnB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAuBnC,eAAO,MAAM,WAAW,SA0OpB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAWnC,eAAO,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAWnC,eAAO,MAAM,aAAa,SAgQtB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKnC,OAAO,EAAkC,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAA;AACnG,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAMxE,KAAK,WAAW,GAAG,WAAW,CAAC,aAAa,CAAC,CAAA;AAE7C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKnC,OAAO,EAAkC,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAA;AACnG,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAMxE,KAAK,WAAW,GAAG,WAAW,CAAC,aAAa,CAAC,CAAA;AAE7C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAwC7F;AAED,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,eAAe,EAC1B,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC,eAAe,EAAE,CAAC,CAsC5B;AAwCD,eAAO,MAAM,WAAW,SA2MpB,CAAA"}
|