@productbrain/mcp 0.0.1-beta.46 → 0.0.1-beta.48
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/{chunk-5ZCY6NLZ.js → chunk-4ZJEIAA6.js} +455 -127
- package/dist/chunk-4ZJEIAA6.js.map +1 -0
- package/dist/{chunk-6O4EVIVI.js → chunk-RPESSNTC.js} +1372 -811
- package/dist/chunk-RPESSNTC.js.map +1 -0
- package/dist/http.js +2 -2
- package/dist/index.js +2 -2
- package/dist/{smart-capture-QDF6MKRP.js → smart-capture-YIBXUP2H.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-5ZCY6NLZ.js.map +0 -1
- package/dist/chunk-6O4EVIVI.js.map +0 -1
- /package/dist/{smart-capture-QDF6MKRP.js.map → smart-capture-YIBXUP2H.js.map} +0 -0
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-MRIO53BY.js";
|
|
9
9
|
|
|
10
10
|
// src/tools/smart-capture.ts
|
|
11
|
-
import { z } from "zod";
|
|
11
|
+
import { z as z2 } from "zod";
|
|
12
12
|
|
|
13
13
|
// src/client.ts
|
|
14
14
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
@@ -666,6 +666,214 @@ function isClassificationAmbiguous(result) {
|
|
|
666
666
|
return result.scoreMargin < CLASSIFIER_AMBIGUITY_MARGIN;
|
|
667
667
|
}
|
|
668
668
|
|
|
669
|
+
// src/envelope.ts
|
|
670
|
+
import { z } from "zod";
|
|
671
|
+
|
|
672
|
+
// src/errors.ts
|
|
673
|
+
var GateError = class extends Error {
|
|
674
|
+
constructor(message) {
|
|
675
|
+
super(message);
|
|
676
|
+
this.name = "GateError";
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
var BackendError = class extends Error {
|
|
680
|
+
constructor(message) {
|
|
681
|
+
super(message);
|
|
682
|
+
this.name = "BackendError";
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
var ValidationError = class extends Error {
|
|
686
|
+
constructor(message) {
|
|
687
|
+
super(message);
|
|
688
|
+
this.name = "ValidationError";
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
var GATE_PATTERNS = [
|
|
692
|
+
{
|
|
693
|
+
pattern: /session required|no active.*session|call.*session.*start/i,
|
|
694
|
+
code: "SESSION_REQUIRED",
|
|
695
|
+
recovery: "Start an agent session first.",
|
|
696
|
+
action: { tool: "session", description: "Start session", parameters: { action: "start" } }
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
pattern: /session.*closed/i,
|
|
700
|
+
code: "SESSION_CLOSED",
|
|
701
|
+
recovery: "Start a new session.",
|
|
702
|
+
action: { tool: "session", description: "Start new session", parameters: { action: "start" } }
|
|
703
|
+
},
|
|
704
|
+
{
|
|
705
|
+
pattern: /orientation required|call.*orient/i,
|
|
706
|
+
code: "ORIENTATION_REQUIRED",
|
|
707
|
+
recovery: "Orient before writing.",
|
|
708
|
+
action: { tool: "orient", description: "Orient session", parameters: {} }
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
pattern: /read.?only.*scope/i,
|
|
712
|
+
code: "READONLY_SCOPE",
|
|
713
|
+
recovery: "This API key cannot write. Use a readwrite key.",
|
|
714
|
+
action: { tool: "health", description: "Check key scope", parameters: { action: "whoami" } }
|
|
715
|
+
}
|
|
716
|
+
];
|
|
717
|
+
function classifyError(err) {
|
|
718
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
719
|
+
if (err instanceof GateError) {
|
|
720
|
+
return {
|
|
721
|
+
code: "PERMISSION_DENIED",
|
|
722
|
+
message,
|
|
723
|
+
recovery: "Check permissions or use a readwrite API key.",
|
|
724
|
+
availableActions: [{ tool: "health", description: "Check key scope", parameters: { action: "whoami" } }]
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
if (err instanceof BackendError) {
|
|
728
|
+
return { code: "BACKEND_ERROR", message, recovery: "Retry the operation or check backend health." };
|
|
729
|
+
}
|
|
730
|
+
if (err instanceof ValidationError) {
|
|
731
|
+
return { code: "VALIDATION_ERROR", message };
|
|
732
|
+
}
|
|
733
|
+
for (const { pattern, code, recovery, action } of GATE_PATTERNS) {
|
|
734
|
+
if (pattern.test(message)) {
|
|
735
|
+
return { code, message, recovery, availableActions: [action] };
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
if (/network error|fetch failed|ECONNREFUSED|ETIMEDOUT/i.test(message)) {
|
|
739
|
+
return { code: "BACKEND_UNAVAILABLE", message, recovery: "Retry in a few seconds." };
|
|
740
|
+
}
|
|
741
|
+
if (/not found/i.test(message)) {
|
|
742
|
+
return {
|
|
743
|
+
code: "NOT_FOUND",
|
|
744
|
+
message,
|
|
745
|
+
recovery: "Use entries action=search to find the correct ID.",
|
|
746
|
+
availableActions: [{ tool: "entries", description: "Search entries", parameters: { action: "search" } }]
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
if (/duplicate|already exists/i.test(message)) {
|
|
750
|
+
return {
|
|
751
|
+
code: "DUPLICATE",
|
|
752
|
+
message,
|
|
753
|
+
recovery: "Use entries action=get to inspect the existing entry.",
|
|
754
|
+
availableActions: [{ tool: "entries", description: "Get entry", parameters: { action: "get" } }]
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
if (/invalid|validation|required field/i.test(message)) {
|
|
758
|
+
return { code: "VALIDATION_ERROR", message };
|
|
759
|
+
}
|
|
760
|
+
return { code: "INTERNAL_ERROR", message: message || "An unexpected error occurred." };
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// src/envelope.ts
|
|
764
|
+
function success(summary, data, next) {
|
|
765
|
+
return {
|
|
766
|
+
ok: true,
|
|
767
|
+
summary: summary || "Operation completed.",
|
|
768
|
+
data,
|
|
769
|
+
...next?.length ? { next } : {}
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
function failure(code, message, recovery, availableActions, diagnostics) {
|
|
773
|
+
return {
|
|
774
|
+
ok: false,
|
|
775
|
+
code,
|
|
776
|
+
message,
|
|
777
|
+
...recovery ? { recovery } : {},
|
|
778
|
+
...availableActions?.length ? { availableActions } : {},
|
|
779
|
+
...diagnostics ? { diagnostics } : {}
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
function notFound(id, hint) {
|
|
783
|
+
return failure(
|
|
784
|
+
"NOT_FOUND",
|
|
785
|
+
`Entry '${id}' not found.`,
|
|
786
|
+
hint ?? "Use entries action=search to find the correct ID.",
|
|
787
|
+
[{ tool: "entries", description: "Search entries", parameters: { action: "search", query: id } }]
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
function validationError(message) {
|
|
791
|
+
return failure("VALIDATION_ERROR", message);
|
|
792
|
+
}
|
|
793
|
+
function textContent(text) {
|
|
794
|
+
return [{ type: "text", text }];
|
|
795
|
+
}
|
|
796
|
+
function parseOrFail(schema, args) {
|
|
797
|
+
const parsed = schema.safeParse(args);
|
|
798
|
+
if (parsed.success) return { ok: true, data: parsed.data };
|
|
799
|
+
const issues = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
|
|
800
|
+
const msg = `Invalid arguments: ${issues}`;
|
|
801
|
+
return {
|
|
802
|
+
ok: false,
|
|
803
|
+
result: { content: textContent(msg), structuredContent: validationError(msg) }
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
function unknownAction(action, valid) {
|
|
807
|
+
const msg = `Unknown action '${action}'. Valid actions: ${valid.join(", ")}.`;
|
|
808
|
+
return { content: textContent(msg), structuredContent: validationError(msg) };
|
|
809
|
+
}
|
|
810
|
+
function successResult(text, summary, data, next) {
|
|
811
|
+
return { content: textContent(text), structuredContent: success(summary, data, next) };
|
|
812
|
+
}
|
|
813
|
+
function failureResult(text, code, message, recovery, availableActions, diagnostics) {
|
|
814
|
+
return { content: textContent(text), structuredContent: failure(code, message, recovery, availableActions, diagnostics) };
|
|
815
|
+
}
|
|
816
|
+
function notFoundResult(id, text, hint) {
|
|
817
|
+
return { content: textContent(text ?? `Entry '${id}' not found.`), structuredContent: notFound(id, hint) };
|
|
818
|
+
}
|
|
819
|
+
function validationResult(message) {
|
|
820
|
+
return { content: textContent(message), structuredContent: validationError(message) };
|
|
821
|
+
}
|
|
822
|
+
var nextActionSchema = z.object({
|
|
823
|
+
tool: z.string(),
|
|
824
|
+
description: z.string(),
|
|
825
|
+
parameters: z.record(z.unknown())
|
|
826
|
+
});
|
|
827
|
+
var metaSchema = z.object({
|
|
828
|
+
durationMs: z.number().optional()
|
|
829
|
+
}).optional();
|
|
830
|
+
function withEnvelope(handler) {
|
|
831
|
+
return async (args) => {
|
|
832
|
+
const start = Date.now();
|
|
833
|
+
try {
|
|
834
|
+
const result = await handler(args);
|
|
835
|
+
const durationMs = Date.now() - start;
|
|
836
|
+
const sc = result.structuredContent;
|
|
837
|
+
if (sc && typeof sc === "object" && "ok" in sc) {
|
|
838
|
+
sc._meta = { ...sc._meta, durationMs };
|
|
839
|
+
return {
|
|
840
|
+
content: result.content ?? [],
|
|
841
|
+
structuredContent: sc,
|
|
842
|
+
...sc.ok === false ? { isError: true } : {}
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
console.warn(`[withEnvelope] Handler returned without envelope shape. Wrapping automatically. Content preview: "${result.content?.[0]?.text?.slice(0, 60) ?? "(empty)"}"`);
|
|
846
|
+
return {
|
|
847
|
+
content: result.content ?? [],
|
|
848
|
+
structuredContent: {
|
|
849
|
+
...success(
|
|
850
|
+
result.content?.[0]?.text?.slice(0, 100) ?? "",
|
|
851
|
+
sc ?? {}
|
|
852
|
+
),
|
|
853
|
+
_meta: { durationMs }
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
} catch (err) {
|
|
857
|
+
const durationMs = Date.now() - start;
|
|
858
|
+
const classified = classifyError(err);
|
|
859
|
+
const envelope = {
|
|
860
|
+
...failure(
|
|
861
|
+
classified.code,
|
|
862
|
+
classified.message,
|
|
863
|
+
classified.recovery,
|
|
864
|
+
classified.availableActions
|
|
865
|
+
),
|
|
866
|
+
_meta: { durationMs }
|
|
867
|
+
};
|
|
868
|
+
return {
|
|
869
|
+
content: [{ type: "text", text: classified.message }],
|
|
870
|
+
structuredContent: envelope,
|
|
871
|
+
isError: true
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
|
|
669
877
|
// src/tools/smart-capture.ts
|
|
670
878
|
var AREA_KEYWORDS = {
|
|
671
879
|
"Architecture": ["convex", "schema", "database", "migration", "api", "backend", "infrastructure", "scaling", "performance"],
|
|
@@ -1264,43 +1472,46 @@ var AUTO_LINK_CONFIDENCE_THRESHOLD = 35;
|
|
|
1264
1472
|
var MAX_AUTO_LINKS = 5;
|
|
1265
1473
|
var MAX_SUGGESTIONS = 5;
|
|
1266
1474
|
var CAPTURE_WITHOUT_THINKING_FLAG = "capture-without-thinking";
|
|
1267
|
-
var captureSchema =
|
|
1268
|
-
collection:
|
|
1269
|
-
name:
|
|
1270
|
-
description:
|
|
1271
|
-
context:
|
|
1272
|
-
entryId:
|
|
1273
|
-
canonicalKey:
|
|
1274
|
-
data:
|
|
1275
|
-
links:
|
|
1276
|
-
to:
|
|
1277
|
-
type:
|
|
1475
|
+
var captureSchema = z2.object({
|
|
1476
|
+
collection: z2.string().optional().describe("Collection slug, e.g. 'tensions', 'business-rules', 'glossary', 'decisions'. Optional when `capture-without-thinking` is enabled."),
|
|
1477
|
+
name: z2.string().describe("Display name \u2014 be specific (e.g. 'Convex adjacency list won't scale for graph traversal')"),
|
|
1478
|
+
description: z2.string().describe("Full context \u2014 what's happening, why it matters, what you observed"),
|
|
1479
|
+
context: z2.string().optional().describe("Optional additional context (e.g. 'Observed during context gather calls taking 700ms+')"),
|
|
1480
|
+
entryId: z2.string().optional().describe("Optional custom entry ID (e.g. 'TEN-my-id'). Auto-generated if omitted."),
|
|
1481
|
+
canonicalKey: z2.string().optional().describe("Semantic type (e.g. 'decision', 'tension', 'vision'). Auto-assigned from collection if omitted."),
|
|
1482
|
+
data: z2.record(z2.unknown()).optional().describe("Explicit field values when you know the schema (e.g. canonical_key, cardinality_rule, required_fields). Merged with inferred values; user-provided wins."),
|
|
1483
|
+
links: z2.array(z2.object({
|
|
1484
|
+
to: z2.string().describe("Target entry ID (e.g. 'BR-64', 'ARCH-8')"),
|
|
1485
|
+
type: z2.string().describe("Relation type (e.g. 'governs', 'related_to', 'informs')")
|
|
1278
1486
|
})).optional().describe("Relations to create after capture. Skips auto-link discovery when provided."),
|
|
1279
|
-
autoCommit:
|
|
1487
|
+
autoCommit: z2.boolean().optional().describe("If true, commits the entry immediately after capture + linking. Use for ungoverned collections or when you're certain.")
|
|
1280
1488
|
});
|
|
1281
|
-
var batchCaptureSchema =
|
|
1282
|
-
entries:
|
|
1283
|
-
collection:
|
|
1284
|
-
name:
|
|
1285
|
-
description:
|
|
1286
|
-
entryId:
|
|
1489
|
+
var batchCaptureSchema = z2.object({
|
|
1490
|
+
entries: z2.array(z2.object({
|
|
1491
|
+
collection: z2.string().describe("Collection slug"),
|
|
1492
|
+
name: z2.string().describe("Display name"),
|
|
1493
|
+
description: z2.string().describe("Full context / definition"),
|
|
1494
|
+
entryId: z2.string().optional().describe("Optional custom entry ID")
|
|
1287
1495
|
})).min(1).max(50).describe("Array of entries to capture")
|
|
1288
1496
|
});
|
|
1289
|
-
var captureClassifierSchema =
|
|
1290
|
-
enabled:
|
|
1291
|
-
autoRouted:
|
|
1292
|
-
|
|
1497
|
+
var captureClassifierSchema = z2.object({
|
|
1498
|
+
enabled: z2.boolean(),
|
|
1499
|
+
autoRouted: z2.boolean(),
|
|
1500
|
+
agrees: z2.boolean(),
|
|
1501
|
+
topConfidence: z2.number(),
|
|
1293
1502
|
// Backward-compatible alias for topConfidence.
|
|
1294
|
-
confidence:
|
|
1295
|
-
reasons:
|
|
1296
|
-
candidates:
|
|
1297
|
-
|
|
1298
|
-
collection:
|
|
1299
|
-
signalScore:
|
|
1503
|
+
confidence: z2.number(),
|
|
1504
|
+
reasons: z2.array(z2.string()),
|
|
1505
|
+
candidates: z2.array(
|
|
1506
|
+
z2.object({
|
|
1507
|
+
collection: z2.enum(STARTER_COLLECTIONS),
|
|
1508
|
+
signalScore: z2.number(),
|
|
1300
1509
|
// Backward-compatible alias for signalScore.
|
|
1301
|
-
confidence:
|
|
1510
|
+
confidence: z2.number()
|
|
1302
1511
|
})
|
|
1303
|
-
)
|
|
1512
|
+
),
|
|
1513
|
+
agentProvidedCollection: z2.string().optional(),
|
|
1514
|
+
overrideCommand: z2.string().optional()
|
|
1304
1515
|
});
|
|
1305
1516
|
function trackClassifierTelemetry(params) {
|
|
1306
1517
|
const telemetry = {
|
|
@@ -1322,7 +1533,13 @@ function buildCollectionRequiredResult() {
|
|
|
1322
1533
|
content: [{
|
|
1323
1534
|
type: "text",
|
|
1324
1535
|
text: "Collection is required unless `capture-without-thinking` is enabled.\n\nProvide `collection` explicitly, or enable the feature flag for this workspace."
|
|
1325
|
-
}]
|
|
1536
|
+
}],
|
|
1537
|
+
structuredContent: failure(
|
|
1538
|
+
"VALIDATION_ERROR",
|
|
1539
|
+
"Collection is required unless capture-without-thinking is enabled.",
|
|
1540
|
+
"Provide collection explicitly, or enable the feature flag.",
|
|
1541
|
+
[{ tool: "collections", description: "List available collections", parameters: { action: "list" } }]
|
|
1542
|
+
)
|
|
1326
1543
|
};
|
|
1327
1544
|
}
|
|
1328
1545
|
function buildClassifierUnknownResult() {
|
|
@@ -1331,16 +1548,13 @@ function buildClassifierUnknownResult() {
|
|
|
1331
1548
|
type: "text",
|
|
1332
1549
|
text: "I could not infer a collection confidently from this input.\n\nPlease provide `collection`, or rewrite with clearer intent (decision/problem/definition/insight/bet)."
|
|
1333
1550
|
}],
|
|
1334
|
-
structuredContent:
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
candidates: []
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1551
|
+
structuredContent: failure(
|
|
1552
|
+
"VALIDATION_ERROR",
|
|
1553
|
+
"Could not infer collection from input.",
|
|
1554
|
+
"Provide collection explicitly, or rewrite with clearer intent.",
|
|
1555
|
+
[{ tool: "collections", description: "List available collections", parameters: { action: "list" } }],
|
|
1556
|
+
{ classifier: { enabled: true, autoRouted: false, agrees: true, topConfidence: 0, confidence: 0, reasons: [], candidates: [] } }
|
|
1557
|
+
)
|
|
1344
1558
|
};
|
|
1345
1559
|
}
|
|
1346
1560
|
function buildProvisionedCollectionSuggestions(candidates) {
|
|
@@ -1348,10 +1562,7 @@ function buildProvisionedCollectionSuggestions(candidates) {
|
|
|
1348
1562
|
}
|
|
1349
1563
|
function buildUnsupportedProvisioningResult(classified, provisionedCandidates) {
|
|
1350
1564
|
const suggestions = buildProvisionedCollectionSuggestions(provisionedCandidates);
|
|
1351
|
-
|
|
1352
|
-
content: [{
|
|
1353
|
-
type: "text",
|
|
1354
|
-
text: `Collection inference is not safe to auto-route yet.
|
|
1565
|
+
const textBody = `Collection inference is not safe to auto-route yet.
|
|
1355
1566
|
|
|
1356
1567
|
Predicted collection \`${classified.collection}\` is not provisioned/supported for auto-routing in this workspace.
|
|
1357
1568
|
Reason: ${classified.reasons.join("; ") || "low signal"}
|
|
@@ -1359,36 +1570,50 @@ Reason: ${classified.reasons.join("; ") || "low signal"}
|
|
|
1359
1570
|
Choose one of these provisioned starter collections and retry with \`collection\`:
|
|
1360
1571
|
${suggestions}
|
|
1361
1572
|
|
|
1362
|
-
Correction path: rerun with explicit \`collection
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1573
|
+
Correction path: rerun with explicit \`collection\`.`;
|
|
1574
|
+
return {
|
|
1575
|
+
content: [{ type: "text", text: textBody }],
|
|
1576
|
+
structuredContent: failure(
|
|
1577
|
+
"VALIDATION_ERROR",
|
|
1578
|
+
`Collection '${classified.collection}' is not provisioned for auto-routing.`,
|
|
1579
|
+
"Rerun with explicit collection.",
|
|
1580
|
+
[{ tool: "collections", description: "List available collections", parameters: { action: "list" } }],
|
|
1581
|
+
{
|
|
1582
|
+
classifier: {
|
|
1583
|
+
enabled: true,
|
|
1584
|
+
autoRouted: false,
|
|
1585
|
+
agrees: false,
|
|
1586
|
+
topConfidence: classified.topConfidence,
|
|
1587
|
+
confidence: classified.confidence,
|
|
1588
|
+
reasons: classified.reasons,
|
|
1589
|
+
candidates: provisionedCandidates.map((c) => ({ collection: c.collection, signalScore: c.signalScore, confidence: c.confidence }))
|
|
1590
|
+
}
|
|
1372
1591
|
}
|
|
1373
|
-
|
|
1592
|
+
)
|
|
1374
1593
|
};
|
|
1375
1594
|
}
|
|
1376
1595
|
function buildAmbiguousRouteResult(classified, classifierMeta, ambiguousRoute) {
|
|
1377
1596
|
const suggestions = buildProvisionedCollectionSuggestions(classifierMeta.candidates);
|
|
1378
|
-
|
|
1379
|
-
content: [{
|
|
1380
|
-
type: "text",
|
|
1381
|
-
text: "Collection inference is not safe to auto-route yet.\n\n" + (ambiguousRoute ? "Routing held because intent is ambiguous across top candidates.\n\n" : "") + `Predicted: \`${classified.collection}\` (${classified.topConfidence}% top confidence)
|
|
1597
|
+
const textBody = "Collection inference is not safe to auto-route yet.\n\n" + (ambiguousRoute ? "Routing held because intent is ambiguous across top candidates.\n\n" : "") + `Predicted: \`${classified.collection}\` (${classified.topConfidence}% top confidence)
|
|
1382
1598
|
Reason: ${classified.reasons.join("; ") || "low signal"}
|
|
1383
1599
|
|
|
1384
1600
|
Choose one of these and retry with \`collection\`:
|
|
1385
1601
|
${suggestions}
|
|
1386
1602
|
|
|
1387
|
-
Correction path: if this was close, rerun with your chosen \`collection
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1603
|
+
Correction path: if this was close, rerun with your chosen \`collection\`.`;
|
|
1604
|
+
return {
|
|
1605
|
+
content: [{ type: "text", text: textBody }],
|
|
1606
|
+
structuredContent: failure(
|
|
1607
|
+
"VALIDATION_ERROR",
|
|
1608
|
+
ambiguousRoute ? `Ambiguous routing \u2014 top candidates too close (${classified.topConfidence}% confidence).` : `Low confidence routing to '${classified.collection}' (${classified.topConfidence}%).`,
|
|
1609
|
+
"Rerun with explicit collection.",
|
|
1610
|
+
classifierMeta.candidates.map((c) => ({
|
|
1611
|
+
tool: "capture",
|
|
1612
|
+
description: `Capture to ${c.collection}`,
|
|
1613
|
+
parameters: { collection: c.collection }
|
|
1614
|
+
})),
|
|
1615
|
+
{ classifier: classifierMeta }
|
|
1616
|
+
)
|
|
1392
1617
|
};
|
|
1393
1618
|
}
|
|
1394
1619
|
async function getProvisionedStarterCollectionCandidates(classified, supportedStarterCollections) {
|
|
@@ -1414,7 +1639,48 @@ async function resolveCaptureCollection(params) {
|
|
|
1414
1639
|
explicitCollectionProvided
|
|
1415
1640
|
} = params;
|
|
1416
1641
|
if (collection) {
|
|
1417
|
-
|
|
1642
|
+
const classified2 = classifyStarterCollection(name, description);
|
|
1643
|
+
if (classified2) {
|
|
1644
|
+
const agrees = classified2.collection === collection;
|
|
1645
|
+
const classifierMeta2 = {
|
|
1646
|
+
enabled: true,
|
|
1647
|
+
autoRouted: false,
|
|
1648
|
+
agrees,
|
|
1649
|
+
topConfidence: classified2.topConfidence,
|
|
1650
|
+
confidence: classified2.confidence,
|
|
1651
|
+
reasons: classified2.reasons,
|
|
1652
|
+
candidates: classified2.candidates.slice(0, 3),
|
|
1653
|
+
agentProvidedCollection: collection,
|
|
1654
|
+
...!agrees && {
|
|
1655
|
+
overrideCommand: `capture collection="${classified2.collection}"`
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
if (!agrees) {
|
|
1659
|
+
trackClassifierTelemetry({
|
|
1660
|
+
workspaceId,
|
|
1661
|
+
predictedCollection: classified2.collection,
|
|
1662
|
+
confidence: classified2.confidence,
|
|
1663
|
+
autoRouted: false,
|
|
1664
|
+
reasonCategory: "low-confidence",
|
|
1665
|
+
explicitCollectionProvided: true,
|
|
1666
|
+
outcome: "fallback"
|
|
1667
|
+
});
|
|
1668
|
+
}
|
|
1669
|
+
return { resolvedCollection: collection, classifierMeta: classifierMeta2 };
|
|
1670
|
+
}
|
|
1671
|
+
return {
|
|
1672
|
+
resolvedCollection: collection,
|
|
1673
|
+
classifierMeta: {
|
|
1674
|
+
enabled: true,
|
|
1675
|
+
autoRouted: false,
|
|
1676
|
+
agrees: true,
|
|
1677
|
+
topConfidence: 0,
|
|
1678
|
+
confidence: 0,
|
|
1679
|
+
reasons: [],
|
|
1680
|
+
candidates: [],
|
|
1681
|
+
agentProvidedCollection: collection
|
|
1682
|
+
}
|
|
1683
|
+
};
|
|
1418
1684
|
}
|
|
1419
1685
|
if (!classifierFlagOn) {
|
|
1420
1686
|
return { earlyResult: buildCollectionRequiredResult() };
|
|
@@ -1452,6 +1718,7 @@ async function resolveCaptureCollection(params) {
|
|
|
1452
1718
|
const classifierMeta = {
|
|
1453
1719
|
enabled: true,
|
|
1454
1720
|
autoRouted: autoRoute,
|
|
1721
|
+
agrees: true,
|
|
1455
1722
|
topConfidence: classified.topConfidence,
|
|
1456
1723
|
confidence: classified.confidence,
|
|
1457
1724
|
reasons: classified.reasons,
|
|
@@ -1486,36 +1753,36 @@ async function resolveCaptureCollection(params) {
|
|
|
1486
1753
|
classifierMeta
|
|
1487
1754
|
};
|
|
1488
1755
|
}
|
|
1489
|
-
var captureSuccessOutputSchema =
|
|
1490
|
-
entryId:
|
|
1491
|
-
collection:
|
|
1492
|
-
name:
|
|
1493
|
-
status:
|
|
1494
|
-
qualityScore:
|
|
1495
|
-
qualityVerdict:
|
|
1756
|
+
var captureSuccessOutputSchema = z2.object({
|
|
1757
|
+
entryId: z2.string(),
|
|
1758
|
+
collection: z2.string(),
|
|
1759
|
+
name: z2.string(),
|
|
1760
|
+
status: z2.enum(["draft", "committed"]),
|
|
1761
|
+
qualityScore: z2.number(),
|
|
1762
|
+
qualityVerdict: z2.record(z2.unknown()).optional(),
|
|
1496
1763
|
classifier: captureClassifierSchema.optional(),
|
|
1497
|
-
studioUrl:
|
|
1764
|
+
studioUrl: z2.string().optional()
|
|
1498
1765
|
}).strict();
|
|
1499
|
-
var captureClassifierOnlyOutputSchema =
|
|
1766
|
+
var captureClassifierOnlyOutputSchema = z2.object({
|
|
1500
1767
|
classifier: captureClassifierSchema
|
|
1501
1768
|
}).strict();
|
|
1502
|
-
var captureOutputSchema =
|
|
1769
|
+
var captureOutputSchema = z2.union([
|
|
1503
1770
|
captureSuccessOutputSchema,
|
|
1504
1771
|
captureClassifierOnlyOutputSchema
|
|
1505
1772
|
]);
|
|
1506
|
-
var batchCaptureOutputSchema =
|
|
1507
|
-
captured:
|
|
1508
|
-
entryId:
|
|
1509
|
-
collection:
|
|
1510
|
-
name:
|
|
1773
|
+
var batchCaptureOutputSchema = z2.object({
|
|
1774
|
+
captured: z2.array(z2.object({
|
|
1775
|
+
entryId: z2.string(),
|
|
1776
|
+
collection: z2.string(),
|
|
1777
|
+
name: z2.string()
|
|
1511
1778
|
})),
|
|
1512
|
-
total:
|
|
1513
|
-
failed:
|
|
1514
|
-
failedEntries:
|
|
1515
|
-
index:
|
|
1516
|
-
collection:
|
|
1517
|
-
name:
|
|
1518
|
-
error:
|
|
1779
|
+
total: z2.number(),
|
|
1780
|
+
failed: z2.number(),
|
|
1781
|
+
failedEntries: z2.array(z2.object({
|
|
1782
|
+
index: z2.number(),
|
|
1783
|
+
collection: z2.string(),
|
|
1784
|
+
name: z2.string(),
|
|
1785
|
+
error: z2.string()
|
|
1519
1786
|
})).optional()
|
|
1520
1787
|
});
|
|
1521
1788
|
function registerSmartCaptureTools(server) {
|
|
@@ -1530,7 +1797,7 @@ function registerSmartCaptureTools(server) {
|
|
|
1530
1797
|
inputSchema: captureSchema.shape,
|
|
1531
1798
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
1532
1799
|
},
|
|
1533
|
-
async ({ collection, name, description, context, entryId, canonicalKey, data: userData, links, autoCommit }) => {
|
|
1800
|
+
withEnvelope(async ({ collection, name, description, context, entryId, canonicalKey, data: userData, links, autoCommit }) => {
|
|
1534
1801
|
requireWriteAccess();
|
|
1535
1802
|
const wsCtx = await getWorkspaceContext();
|
|
1536
1803
|
const explicitCollectionProvided = typeof collection === "string" && collection.trim().length > 0;
|
|
@@ -1571,7 +1838,16 @@ collections action=create slug="${resolvedCollection}" name="${displayName}" des
|
|
|
1571
1838
|
\`\`\`
|
|
1572
1839
|
|
|
1573
1840
|
Or use \`collections action=list\` to see available collections.`
|
|
1574
|
-
}]
|
|
1841
|
+
}],
|
|
1842
|
+
structuredContent: failure(
|
|
1843
|
+
"NOT_FOUND",
|
|
1844
|
+
`Collection '${resolvedCollection}' not found.`,
|
|
1845
|
+
"Create the collection first, or use collections action=list to see available ones.",
|
|
1846
|
+
[
|
|
1847
|
+
{ tool: "collections", description: "Create collection", parameters: { action: "create", slug: resolvedCollection, name: displayName } },
|
|
1848
|
+
{ tool: "collections", description: "List collections", parameters: { action: "list" } }
|
|
1849
|
+
]
|
|
1850
|
+
)
|
|
1575
1851
|
};
|
|
1576
1852
|
}
|
|
1577
1853
|
const data = {};
|
|
@@ -1647,7 +1923,16 @@ Or use \`collections action=list\` to see available collections.`
|
|
|
1647
1923
|
${msg}
|
|
1648
1924
|
|
|
1649
1925
|
Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to modify it.`
|
|
1650
|
-
}]
|
|
1926
|
+
}],
|
|
1927
|
+
structuredContent: failure(
|
|
1928
|
+
"DUPLICATE",
|
|
1929
|
+
msg,
|
|
1930
|
+
"Use entries action=get to inspect the existing entry.",
|
|
1931
|
+
[
|
|
1932
|
+
{ tool: "entries", description: "Get existing entry", parameters: { action: "get", entryId: entryId ?? name } },
|
|
1933
|
+
{ tool: "update-entry", description: "Update existing entry", parameters: { entryId: entryId ?? "" } }
|
|
1934
|
+
]
|
|
1935
|
+
)
|
|
1651
1936
|
};
|
|
1652
1937
|
}
|
|
1653
1938
|
throw error;
|
|
@@ -1809,14 +2094,27 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
1809
2094
|
`**${name}** added to \`${resolvedCollection}\` as \`${finalStatus}\``,
|
|
1810
2095
|
`**Workspace:** ${wsCtx.workspaceSlug} (${wsCtx.workspaceId})`
|
|
1811
2096
|
];
|
|
1812
|
-
if (classifierMeta
|
|
2097
|
+
if (classifierMeta && classifierMeta.topConfidence > 0) {
|
|
1813
2098
|
lines.push("");
|
|
1814
|
-
lines.push("##
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
2099
|
+
lines.push("## Classification");
|
|
2100
|
+
if (classifierMeta.autoRouted) {
|
|
2101
|
+
lines.push(`Auto-routed to \`${resolvedCollection}\` (${classifierMeta.topConfidence}% confidence).`);
|
|
2102
|
+
if (classifierMeta.reasons.length > 0) {
|
|
2103
|
+
lines.push(`Reason: ${classifierMeta.reasons.join("; ")}.`);
|
|
2104
|
+
}
|
|
2105
|
+
lines.push(`Override: rerun with explicit \`collection\` if wrong.`);
|
|
2106
|
+
} else if (classifierMeta.agrees) {
|
|
2107
|
+
lines.push(`Classifier confirms \`${resolvedCollection}\` (${classifierMeta.topConfidence}% confidence).`);
|
|
2108
|
+
} else {
|
|
2109
|
+
const suggested = classifierMeta.candidates[0]?.collection ?? "unknown";
|
|
2110
|
+
lines.push(`Agent chose \`${resolvedCollection}\`, classifier suggests \`${suggested}\` (${classifierMeta.topConfidence}% confidence).`);
|
|
2111
|
+
if (classifierMeta.reasons.length > 0) {
|
|
2112
|
+
lines.push(`Reason: ${classifierMeta.reasons.join("; ")}.`);
|
|
2113
|
+
}
|
|
2114
|
+
if (classifierMeta.overrideCommand) {
|
|
2115
|
+
lines.push(`Override: \`${classifierMeta.overrideCommand}\``);
|
|
2116
|
+
}
|
|
1818
2117
|
}
|
|
1819
|
-
lines.push("Correction path: rerun capture with explicit `collection` if this routing is wrong.");
|
|
1820
2118
|
}
|
|
1821
2119
|
const appUrl = process.env.PRODUCTBRAIN_APP_URL ?? "https://productbrain.io";
|
|
1822
2120
|
const studioUrl = resolvedCollection === "bets" ? `${appUrl.replace(/\/$/, "")}/w/${wsCtx.workspaceSlug}/studio/${internalId}` : void 0;
|
|
@@ -1924,21 +2222,35 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
1924
2222
|
}
|
|
1925
2223
|
} catch {
|
|
1926
2224
|
}
|
|
2225
|
+
const next = [];
|
|
2226
|
+
if (finalStatus === "committed") {
|
|
2227
|
+
next.push({ tool: "graph", description: "Discover connections", parameters: { action: "suggest", entryId: finalEntryId } });
|
|
2228
|
+
} else {
|
|
2229
|
+
if (userLinkResults.length === 0) {
|
|
2230
|
+
next.push({ tool: "graph", description: "Discover links", parameters: { action: "suggest", entryId: finalEntryId } });
|
|
2231
|
+
}
|
|
2232
|
+
next.push({ tool: "commit-entry", description: "Commit to Chain", parameters: { entryId: finalEntryId } });
|
|
2233
|
+
}
|
|
2234
|
+
const summary = finalStatus === "committed" ? `Captured and committed ${finalEntryId} (${name}) to ${resolvedCollection}. Quality ${quality.score}/10.` : `Captured ${finalEntryId} (${name}) as draft in ${resolvedCollection}. Quality ${quality.score}/10.`;
|
|
1927
2235
|
const toolResult = {
|
|
1928
2236
|
content: [{ type: "text", text: lines.join("\n") }],
|
|
1929
|
-
structuredContent:
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
2237
|
+
structuredContent: success(
|
|
2238
|
+
summary,
|
|
2239
|
+
{
|
|
2240
|
+
entryId: finalEntryId,
|
|
2241
|
+
collection: resolvedCollection,
|
|
2242
|
+
name,
|
|
2243
|
+
status: finalStatus,
|
|
2244
|
+
qualityScore: quality.score,
|
|
2245
|
+
qualityVerdict: verdictResult?.verdict ? { ...verdictResult.verdict, source: verdictResult.source ?? "heuristic" } : void 0,
|
|
2246
|
+
...classifierMeta && { classifier: classifierMeta },
|
|
2247
|
+
...studioUrl && { studioUrl }
|
|
2248
|
+
},
|
|
2249
|
+
next
|
|
2250
|
+
)
|
|
1939
2251
|
};
|
|
1940
2252
|
return toolResult;
|
|
1941
|
-
}
|
|
2253
|
+
})
|
|
1942
2254
|
);
|
|
1943
2255
|
trackWriteTool(captureTool);
|
|
1944
2256
|
const batchCaptureTool = server.registerTool(
|
|
@@ -1949,7 +2261,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
1949
2261
|
inputSchema: batchCaptureSchema.shape,
|
|
1950
2262
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
1951
2263
|
},
|
|
1952
|
-
async ({ entries }) => {
|
|
2264
|
+
withEnvelope(async ({ entries }) => {
|
|
1953
2265
|
requireWriteAccess();
|
|
1954
2266
|
const agentId = getAgentSessionId();
|
|
1955
2267
|
const createdBy = agentId ? `agent:${agentId}` : "capture";
|
|
@@ -2113,25 +2425,32 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2113
2425
|
lines.push(`- **Commit:** Use \`commit-entry\` to promote drafts to SSOT`);
|
|
2114
2426
|
lines.push(`- **Quality:** Run \`quality action=check\` on individual entries to assess completeness`);
|
|
2115
2427
|
}
|
|
2428
|
+
const summary = failed.length > 0 ? `Batch captured ${created.length}/${entries.length} entries (${failed.length} failed).` : `Batch captured ${created.length} entries successfully.`;
|
|
2429
|
+
const next = created.length > 0 ? [
|
|
2430
|
+
{ tool: "graph", description: "Discover connections", parameters: { action: "suggest", entryId: created[0].entryId } },
|
|
2431
|
+
{ tool: "commit-entry", description: "Commit first entry", parameters: { entryId: created[0].entryId } }
|
|
2432
|
+
] : [];
|
|
2116
2433
|
return {
|
|
2117
2434
|
content: [{ type: "text", text: lines.join("\n") }],
|
|
2118
|
-
structuredContent:
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2435
|
+
structuredContent: success(
|
|
2436
|
+
summary,
|
|
2437
|
+
{
|
|
2438
|
+
captured: created.map((r) => ({ entryId: r.entryId, collection: r.collection, name: r.name })),
|
|
2439
|
+
total: created.length,
|
|
2440
|
+
failed: failed.length,
|
|
2441
|
+
...failed.length > 0 && {
|
|
2442
|
+
failedEntries: failed.map((r) => ({
|
|
2443
|
+
index: results.indexOf(r),
|
|
2444
|
+
collection: r.collection,
|
|
2445
|
+
name: r.name,
|
|
2446
|
+
error: r.error ?? "unknown error"
|
|
2447
|
+
}))
|
|
2448
|
+
}
|
|
2449
|
+
},
|
|
2450
|
+
next
|
|
2451
|
+
)
|
|
2133
2452
|
};
|
|
2134
|
-
}
|
|
2453
|
+
})
|
|
2135
2454
|
);
|
|
2136
2455
|
trackWriteTool(batchCaptureTool);
|
|
2137
2456
|
}
|
|
@@ -2362,6 +2681,15 @@ export {
|
|
|
2362
2681
|
STARTER_COLLECTIONS,
|
|
2363
2682
|
classifyStarterCollection,
|
|
2364
2683
|
isClassificationAmbiguous,
|
|
2684
|
+
success,
|
|
2685
|
+
failure,
|
|
2686
|
+
parseOrFail,
|
|
2687
|
+
unknownAction,
|
|
2688
|
+
successResult,
|
|
2689
|
+
failureResult,
|
|
2690
|
+
notFoundResult,
|
|
2691
|
+
validationResult,
|
|
2692
|
+
withEnvelope,
|
|
2365
2693
|
formatQualityReport,
|
|
2366
2694
|
checkEntryQuality,
|
|
2367
2695
|
captureSchema,
|
|
@@ -2374,4 +2702,4 @@ export {
|
|
|
2374
2702
|
formatRubricCoaching,
|
|
2375
2703
|
formatRubricVerdictSection
|
|
2376
2704
|
};
|
|
2377
|
-
//# sourceMappingURL=chunk-
|
|
2705
|
+
//# sourceMappingURL=chunk-4ZJEIAA6.js.map
|