@tangle-network/agent-app 0.44.7 → 0.44.9
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/assistant/index.d.ts +4 -4
- package/dist/assistant/index.js +6 -6
- package/dist/{attachment-validation-DRuLEjAE.d.ts → attachment-validation-yJ6Id4pR.d.ts} +1 -1
- package/dist/chat-routes/index.d.ts +4 -4
- package/dist/chat-routes/index.js +3 -3
- package/dist/chat-store/index.d.ts +3 -3
- package/dist/chat-store/index.js +2 -2
- package/dist/{chunk-V55WJSR4.js → chunk-5GA3MKOC.js} +2 -2
- package/dist/{chunk-UDSY2F6N.js → chunk-72TPRENZ.js} +21 -8
- package/dist/chunk-72TPRENZ.js.map +1 -0
- package/dist/{chunk-AFNTRJQ7.js → chunk-FEUW4G2L.js} +2 -2
- package/dist/{chunk-TKRI463Z.js → chunk-J6TNPRQN.js} +4 -4
- package/dist/{chunk-F2CBC4DY.js → chunk-V3HO43PG.js} +15 -1
- package/dist/chunk-V3HO43PG.js.map +1 -0
- package/dist/{chunk-UP33Z633.js → chunk-ZRSUCTST.js} +2 -2
- package/dist/{parts-Co_lFgLI.d.ts → parts-DIKcC1p6.d.ts} +1 -1
- package/dist/{queue-CD5-_VTX.d.ts → queue-DBkulxW1.d.ts} +1 -1
- package/dist/turn-health/index.d.ts +57 -1
- package/dist/turn-health/index.js +14 -4
- package/dist/turn-health/index.js.map +1 -1
- package/dist/{types-XIZqIdX1.d.ts → types-DeEOhQbv.d.ts} +25 -3
- package/dist/web-react/index.d.ts +6 -6
- package/dist/web-react/index.js +6 -6
- package/dist/work-product/index.d.ts +73 -5
- package/dist/work-product/index.js +131 -17
- package/dist/work-product/index.js.map +1 -1
- package/dist/work-product-react/index.d.ts +1 -1
- package/dist/work-product-react/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-F2CBC4DY.js.map +0 -1
- package/dist/chunk-UDSY2F6N.js.map +0 -1
- /package/dist/{chunk-V55WJSR4.js.map → chunk-5GA3MKOC.js.map} +0 -0
- /package/dist/{chunk-AFNTRJQ7.js.map → chunk-FEUW4G2L.js.map} +0 -0
- /package/dist/{chunk-TKRI463Z.js.map → chunk-J6TNPRQN.js.map} +0 -0
- /package/dist/{chunk-UP33Z633.js.map → chunk-ZRSUCTST.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parseReviewQueueItem,
|
|
3
3
|
projectReviewQueue
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-ZRSUCTST.js";
|
|
5
5
|
import {
|
|
6
6
|
isWorkProductStatus,
|
|
7
7
|
parseAgentCheckInput,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
persistedPartToWorkProduct,
|
|
12
12
|
unresolvedBlockingExceptions,
|
|
13
13
|
workProductToPersistedPart
|
|
14
|
-
} from "../chunk-
|
|
14
|
+
} from "../chunk-V3HO43PG.js";
|
|
15
15
|
import {
|
|
16
16
|
ToolInputError,
|
|
17
17
|
defineAppTool
|
|
@@ -403,6 +403,20 @@ function sourceContainsQuote(sourceText, quote) {
|
|
|
403
403
|
if (normalizedQuote.length === 0) return false;
|
|
404
404
|
return normalizeQuoteText(sourceText).includes(normalizedQuote);
|
|
405
405
|
}
|
|
406
|
+
function sliceSourceSpan(sourceText, span) {
|
|
407
|
+
for (const field of ["start", "end"]) {
|
|
408
|
+
const value = span[field];
|
|
409
|
+
if (!Number.isInteger(value)) return { ok: false, failure: { reason: "not_integer", field } };
|
|
410
|
+
if (value < 0) return { ok: false, failure: { reason: "negative", field } };
|
|
411
|
+
}
|
|
412
|
+
if (span.end <= span.start) return { ok: false, failure: { reason: "inverted" } };
|
|
413
|
+
if (span.end > sourceText.length) {
|
|
414
|
+
return { ok: false, failure: { reason: "out_of_range", totalChars: sourceText.length } };
|
|
415
|
+
}
|
|
416
|
+
const quote = sourceText.slice(span.start, span.end);
|
|
417
|
+
if (quote.trim().length === 0) return { ok: false, failure: { reason: "blank" } };
|
|
418
|
+
return { ok: true, quote };
|
|
419
|
+
}
|
|
406
420
|
|
|
407
421
|
// src/work-product/tools.ts
|
|
408
422
|
var MAX_WORK_PRODUCT_BATCH = 50;
|
|
@@ -452,17 +466,61 @@ async function resolveDraft(service, config, scopeKey, ctx) {
|
|
|
452
466
|
provenance: stampProvenance(config.provenance(ctx), config.now)
|
|
453
467
|
});
|
|
454
468
|
}
|
|
455
|
-
|
|
469
|
+
function spanErrorDetail(failure) {
|
|
470
|
+
switch (failure.reason) {
|
|
471
|
+
case "not_integer":
|
|
472
|
+
return `${failure.field} must be a whole character offset.`;
|
|
473
|
+
case "negative":
|
|
474
|
+
return `${failure.field} must not be negative.`;
|
|
475
|
+
case "inverted":
|
|
476
|
+
return "end must be greater than start \u2014 the range is half-open [start, end).";
|
|
477
|
+
case "out_of_range":
|
|
478
|
+
return `end is past the end of the document, which is ${failure.totalChars} characters. Offsets are absolute in the whole document: when you read with an offset, add that offset to the position within the returned text.`;
|
|
479
|
+
case "blank":
|
|
480
|
+
return "that range is only whitespace. Widen it to the characters that carry the value.";
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
async function resolveEvidenceQuotes(config, entries, ctx) {
|
|
456
484
|
const readSourceText = config.readSourceText;
|
|
457
|
-
if (!readSourceText) return;
|
|
458
485
|
const texts = /* @__PURE__ */ new Map();
|
|
486
|
+
const readText = async (ref) => {
|
|
487
|
+
if (!texts.has(ref)) texts.set(ref, await readSourceText(ref, ctx));
|
|
488
|
+
return texts.get(ref) ?? null;
|
|
489
|
+
};
|
|
459
490
|
for (let index = 0; index < entries.length; index += 1) {
|
|
460
491
|
const entry = entries[index];
|
|
492
|
+
const span = entry.locator.span;
|
|
461
493
|
const quote = entry.locator.quote;
|
|
494
|
+
if (span) {
|
|
495
|
+
if (!readSourceText) {
|
|
496
|
+
throw new ToolInputError(
|
|
497
|
+
"span_unsupported",
|
|
498
|
+
`entries[${index}].locator.span: this deployment cannot read source text, so a span cannot be resolved into a quote. Record the entry without locator.span.`,
|
|
499
|
+
500
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
const text2 = await readText(entry.sourceRef);
|
|
503
|
+
if (text2 === null) {
|
|
504
|
+
throw new ToolInputError(
|
|
505
|
+
"unverifiable_quote",
|
|
506
|
+
`entries[${index}].locator.span: "${entry.sourceRef}" has no readable text, so the span cannot be resolved. Record the entry without locator.span or locator.quote and state the basis in claim.`
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
const sliced = sliceSourceSpan(text2, span);
|
|
510
|
+
if (!sliced.ok) {
|
|
511
|
+
throw new ToolInputError(
|
|
512
|
+
"invalid_span",
|
|
513
|
+
`entries[${index}].locator.span [${span.start}, ${span.end}) into "${entry.sourceRef}": ${spanErrorDetail(sliced.failure)}`
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
entry.locator.quote = sliced.quote;
|
|
517
|
+
entry.locator.quoteBasis = "span";
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
462
520
|
if (quote === void 0 || quote.trim().length === 0) continue;
|
|
463
|
-
if (!
|
|
464
|
-
const text =
|
|
465
|
-
if (text === null
|
|
521
|
+
if (!readSourceText) continue;
|
|
522
|
+
const text = await readText(entry.sourceRef);
|
|
523
|
+
if (text === null) {
|
|
466
524
|
throw new ToolInputError(
|
|
467
525
|
"unverifiable_quote",
|
|
468
526
|
`entries[${index}].locator.quote: "${entry.sourceRef}" has no readable text, so the quote cannot be verified. Record the entry without locator.quote and state the basis in claim.`
|
|
@@ -471,9 +529,10 @@ async function assertQuotesOccurInSources(config, entries, ctx) {
|
|
|
471
529
|
if (!sourceContainsQuote(text, quote)) {
|
|
472
530
|
throw new ToolInputError(
|
|
473
531
|
"quote_not_found",
|
|
474
|
-
`entries[${index}].locator.quote: ${JSON.stringify(quote)} does not occur in "${entry.sourceRef}".
|
|
532
|
+
`entries[${index}].locator.quote: ${JSON.stringify(quote)} does not occur in "${entry.sourceRef}". Cite locator.span {start, end} instead \u2014 the character range you read it at, which this platform slices out of the document itself so the text is right by construction. If the value is COMPUTED rather than read, omit both and state the computation in claim.`
|
|
475
533
|
);
|
|
476
534
|
}
|
|
535
|
+
entry.locator.quoteBasis = "model";
|
|
477
536
|
}
|
|
478
537
|
}
|
|
479
538
|
async function summarizeQuoteVerification(config, evidence, ctx) {
|
|
@@ -481,6 +540,7 @@ async function summarizeQuoteVerification(config, evidence, ctx) {
|
|
|
481
540
|
if (!readSourceText) return void 0;
|
|
482
541
|
const texts = /* @__PURE__ */ new Map();
|
|
483
542
|
let verified = 0;
|
|
543
|
+
let spanAnchored = 0;
|
|
484
544
|
let withoutQuote = 0;
|
|
485
545
|
const failed = [];
|
|
486
546
|
for (const entry of evidence) {
|
|
@@ -491,10 +551,23 @@ async function summarizeQuoteVerification(config, evidence, ctx) {
|
|
|
491
551
|
}
|
|
492
552
|
if (!texts.has(entry.sourceRef)) texts.set(entry.sourceRef, await readSourceText(entry.sourceRef, ctx));
|
|
493
553
|
const text = texts.get(entry.sourceRef);
|
|
494
|
-
if (typeof text
|
|
554
|
+
if (typeof text !== "string") {
|
|
555
|
+
failed.push(entry.id);
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
const span = entry.locator.span;
|
|
559
|
+
if (span) {
|
|
560
|
+
const sliced = sliceSourceSpan(text, span);
|
|
561
|
+
if (sliced.ok && sliced.quote === quote) {
|
|
562
|
+
verified += 1;
|
|
563
|
+
spanAnchored += 1;
|
|
564
|
+
} else failed.push(entry.id);
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
if (sourceContainsQuote(text, quote)) verified += 1;
|
|
495
568
|
else failed.push(entry.id);
|
|
496
569
|
}
|
|
497
|
-
return { verified, withoutQuote, failed };
|
|
570
|
+
return { verified, spanAnchored, withoutQuote, failed };
|
|
498
571
|
}
|
|
499
572
|
function buildWorkProductTools(config) {
|
|
500
573
|
const service = createWorkProductService({
|
|
@@ -504,7 +577,7 @@ function buildWorkProductTools(config) {
|
|
|
504
577
|
});
|
|
505
578
|
const upsertEvidence = defineAppTool({
|
|
506
579
|
name: "upsert_evidence",
|
|
507
|
-
description: "Record source\u2192field lineage for the current work product, incrementally as you find it. Each entry links a source document (sourceRef + locator) to one artifact target and states the claim it supports. Re-emitting an entry id replaces that entry. Address the work product by scopeKey; the first call creates the draft.",
|
|
580
|
+
description: "Record source\u2192field lineage for the current work product, incrementally as you find it. Each entry links a source document (sourceRef + locator) to one artifact target and states the claim it supports. Cite by locator.span {start, end} \u2014 the character range you read the value at \u2014 and the platform slices the supporting quote out of the document for you. Re-emitting an entry id replaces that entry. Address the work product by scopeKey; the first call creates the draft.",
|
|
508
581
|
parameters: {
|
|
509
582
|
type: "object",
|
|
510
583
|
properties: {
|
|
@@ -523,9 +596,18 @@ function buildWorkProductTools(config) {
|
|
|
523
596
|
properties: {
|
|
524
597
|
page: { type: "number" },
|
|
525
598
|
range: { type: "string", description: "Free-form location: 'L120-L134' | 'B7' | '\xB64'." },
|
|
599
|
+
span: {
|
|
600
|
+
type: "object",
|
|
601
|
+
description: "PREFERRED. The character range you read the value at, as absolute offsets into the whole document: start is the first character, end is one past the last. If you read with an offset, add that offset to the position within the text you got back. The platform slices the quote out of the document itself and stores it, and returns it to you \u2014 you never retype source text, so the citation cannot be wrong. Use this whenever the value was READ from a document.",
|
|
602
|
+
properties: {
|
|
603
|
+
start: { type: "integer", minimum: 0 },
|
|
604
|
+
end: { type: "integer", minimum: 1 }
|
|
605
|
+
},
|
|
606
|
+
required: ["start", "end"]
|
|
607
|
+
},
|
|
526
608
|
quote: {
|
|
527
609
|
type: "string",
|
|
528
|
-
description: "
|
|
610
|
+
description: "Fallback for sources that cannot give you character offsets: the supporting text copied character-for-character. The platform checks it occurs in the document and REFUSES the entry if it does not. Prefer span. For a value you COMPUTED rather than read, omit both and state the computation in claim."
|
|
529
611
|
}
|
|
530
612
|
}
|
|
531
613
|
},
|
|
@@ -557,10 +639,24 @@ function buildWorkProductTools(config) {
|
|
|
557
639
|
);
|
|
558
640
|
}
|
|
559
641
|
}
|
|
560
|
-
await
|
|
642
|
+
await resolveEvidenceQuotes(config, entries, ctx);
|
|
561
643
|
const draft = await resolveDraft(service, config, scopeKey, ctx);
|
|
562
644
|
const record = await unwrap(() => service.upsertEvidence(draft.id, entries), "evidence_rejected");
|
|
563
|
-
return {
|
|
645
|
+
return {
|
|
646
|
+
workProductId: record.id,
|
|
647
|
+
version: record.version,
|
|
648
|
+
evidenceCount: record.evidence.length,
|
|
649
|
+
// Echo what was actually STORED for the entries in this call. A span
|
|
650
|
+
// citation's quote is produced here, not sent here, so the model must
|
|
651
|
+
// be able to see the text its offsets selected — that is how it
|
|
652
|
+
// notices an off-by-a-line span without a second read.
|
|
653
|
+
entries: entries.map((entry) => ({
|
|
654
|
+
id: entry.id,
|
|
655
|
+
target: entry.target,
|
|
656
|
+
...entry.locator.quote === void 0 ? {} : { quote: entry.locator.quote },
|
|
657
|
+
...entry.locator.quoteBasis === void 0 ? {} : { quoteBasis: entry.locator.quoteBasis }
|
|
658
|
+
}))
|
|
659
|
+
};
|
|
564
660
|
}
|
|
565
661
|
});
|
|
566
662
|
const flagException = defineAppTool({
|
|
@@ -692,7 +788,7 @@ function buildWorkProductTools(config) {
|
|
|
692
788
|
id: QUOTE_VERIFICATION_CHECK,
|
|
693
789
|
name: QUOTE_VERIFICATION_CHECK,
|
|
694
790
|
passed: quotes.failed.length === 0,
|
|
695
|
-
detail: quotes.failed.length === 0 ? `${quotes.verified}/${quoted} quoted evidence entries verified against their source; ${quotes.withoutQuote} recorded without a quote` : `Unverifiable quotes on: ${quotes.failed.join(", ")}`,
|
|
791
|
+
detail: quotes.failed.length === 0 ? `${quotes.verified}/${quoted} quoted evidence entries verified against their source (${quotes.spanAnchored} platform-sliced from a source span, ${quotes.verified - quotes.spanAnchored} model-quoted and proved to occur); ${quotes.withoutQuote} recorded without a quote` : `Unverifiable quotes on: ${quotes.failed.join(", ")}`,
|
|
696
792
|
source: "platform"
|
|
697
793
|
});
|
|
698
794
|
if (quotes.failed.length > 0) {
|
|
@@ -707,11 +803,21 @@ function buildWorkProductTools(config) {
|
|
|
707
803
|
const targets = config.materialTargets(artifact);
|
|
708
804
|
const covered = new Set(draft.evidence.map((entry) => entry.target));
|
|
709
805
|
const missing = targets.filter((target) => !covered.has(target));
|
|
806
|
+
const anchoredTargets = new Set(
|
|
807
|
+
draft.evidence.filter((entry) => entry.locator.quoteBasis !== void 0).map((entry) => entry.target)
|
|
808
|
+
);
|
|
809
|
+
const spanTargets = new Set(
|
|
810
|
+
draft.evidence.filter((entry) => entry.locator.quoteBasis === "span").map((entry) => entry.target)
|
|
811
|
+
);
|
|
812
|
+
const present = targets.filter((target) => covered.has(target));
|
|
813
|
+
const unanchored = present.filter((target) => !anchoredTargets.has(target));
|
|
814
|
+
const spanCount = present.filter((target) => spanTargets.has(target)).length;
|
|
815
|
+
const breakdown = `${spanCount} span-anchored, ${present.length - spanCount - unanchored.length} quote-verified, ${unanchored.length} claim-only`;
|
|
710
816
|
const coverage = {
|
|
711
817
|
id: EVIDENCE_COVERAGE_CHECK,
|
|
712
818
|
name: EVIDENCE_COVERAGE_CHECK,
|
|
713
|
-
passed: missing.length === 0,
|
|
714
|
-
detail: missing.length
|
|
819
|
+
passed: missing.length === 0 && !(config.requireAnchoredEvidence && unanchored.length > 0),
|
|
820
|
+
detail: missing.length > 0 ? `Missing evidence for: ${missing.join(", ")}` : config.requireAnchoredEvidence && unanchored.length > 0 ? `No source anchor for: ${unanchored.join(", ")}` : `${targets.length}/${targets.length} material targets evidenced (${breakdown})`,
|
|
715
821
|
source: "platform"
|
|
716
822
|
};
|
|
717
823
|
checks.unshift(coverage);
|
|
@@ -722,6 +828,13 @@ function buildWorkProductTools(config) {
|
|
|
722
828
|
`Cannot submit: material targets lack evidence: ${missing.join(", ")}. Add upsert_evidence entries targeting each, then resubmit.`
|
|
723
829
|
);
|
|
724
830
|
}
|
|
831
|
+
if (config.requireAnchoredEvidence && unanchored.length > 0) {
|
|
832
|
+
await unwrap(() => service.recordChecks(draft.id, checks), "checks_rejected");
|
|
833
|
+
throw new ToolInputError(
|
|
834
|
+
"evidence_not_anchored",
|
|
835
|
+
`Cannot submit: these material targets have an evidence row but no source anchor: ${unanchored.join(", ")}. Re-emit each with locator.span {start, end} \u2014 the character range in the document you read the value at. The platform slices the quote out of the document itself, so you never retype source text.`
|
|
836
|
+
);
|
|
837
|
+
}
|
|
725
838
|
}
|
|
726
839
|
const provenance = stampProvenance(config.provenance(ctx), config.now);
|
|
727
840
|
const record = await unwrap(
|
|
@@ -851,6 +964,7 @@ export {
|
|
|
851
964
|
parseReviewQueueItem,
|
|
852
965
|
persistedPartToWorkProduct,
|
|
853
966
|
projectReviewQueue,
|
|
967
|
+
sliceSourceSpan,
|
|
854
968
|
sourceContainsQuote,
|
|
855
969
|
stampProvenance,
|
|
856
970
|
unresolvedBlockingExceptions,
|