@tangle-network/agent-app 0.44.10 → 0.44.12

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.
Files changed (31) hide show
  1. package/dist/assistant/index.d.ts +4 -4
  2. package/dist/assistant/index.js +6 -6
  3. package/dist/{attachment-validation-yJ6Id4pR.d.ts → attachment-validation-Zw8eslhN.d.ts} +1 -1
  4. package/dist/chat-routes/index.d.ts +4 -4
  5. package/dist/chat-routes/index.js +3 -3
  6. package/dist/chat-store/index.d.ts +3 -3
  7. package/dist/chat-store/index.js +2 -2
  8. package/dist/{chunk-J6TNPRQN.js → chunk-7SMPAAIT.js} +4 -4
  9. package/dist/{chunk-FEUW4G2L.js → chunk-DV2FA2PW.js} +2 -2
  10. package/dist/{chunk-ZRSUCTST.js → chunk-GEYACSFW.js} +2 -2
  11. package/dist/{chunk-5GA3MKOC.js → chunk-VM6VLJH6.js} +2 -2
  12. package/dist/{chunk-72TPRENZ.js → chunk-YTMKRL3L.js} +3 -3
  13. package/dist/{chunk-V3HO43PG.js → chunk-ZVEEWGDK.js} +14 -1
  14. package/dist/chunk-ZVEEWGDK.js.map +1 -0
  15. package/dist/{parts-DIKcC1p6.d.ts → parts-S1OINlRP.d.ts} +1 -1
  16. package/dist/{queue-DBkulxW1.d.ts → queue-vRI0Qx3X.d.ts} +1 -1
  17. package/dist/{types-DeEOhQbv.d.ts → types-DB82fktc.d.ts} +12 -2
  18. package/dist/web-react/index.d.ts +6 -6
  19. package/dist/web-react/index.js +6 -6
  20. package/dist/work-product/index.d.ts +51 -4
  21. package/dist/work-product/index.js +93 -6
  22. package/dist/work-product/index.js.map +1 -1
  23. package/dist/work-product-react/index.d.ts +1 -1
  24. package/dist/work-product-react/index.js +3 -3
  25. package/package.json +1 -1
  26. package/dist/chunk-V3HO43PG.js.map +0 -1
  27. /package/dist/{chunk-J6TNPRQN.js.map → chunk-7SMPAAIT.js.map} +0 -0
  28. /package/dist/{chunk-FEUW4G2L.js.map → chunk-DV2FA2PW.js.map} +0 -0
  29. /package/dist/{chunk-ZRSUCTST.js.map → chunk-GEYACSFW.js.map} +0 -0
  30. /package/dist/{chunk-5GA3MKOC.js.map → chunk-VM6VLJH6.js.map} +0 -0
  31. /package/dist/{chunk-72TPRENZ.js.map → chunk-YTMKRL3L.js.map} +0 -0
@@ -4,15 +4,15 @@ import { ToolDetailRenderers, ChatUiMessage } from '../web-react/index.js';
4
4
  import '../contract-CEewO6DI.js';
5
5
  import '@tangle-network/agent-interface';
6
6
  import '../plans/index.js';
7
- import '../parts-DIKcC1p6.js';
8
- import '../types-DeEOhQbv.js';
7
+ import '../parts-S1OINlRP.js';
8
+ import '../types-DB82fktc.js';
9
9
  import '../agent-activity-C8ZG0F0M.js';
10
10
  import '../flow-types-CJxEmaRy.js';
11
- import '../queue-DBkulxW1.js';
11
+ import '../queue-vRI0Qx3X.js';
12
12
  import '../sandbox-terminal-ChNEdHF8.js';
13
13
  import '../catalog/index.js';
14
14
  import '../harness/index.js';
15
- import '../attachment-validation-yJ6Id4pR.js';
15
+ import '../attachment-validation-Zw8eslhN.js';
16
16
  import '../stream-normalizer-DnuqkZvw.js';
17
17
 
18
18
  /**
@@ -3,14 +3,14 @@ import {
3
3
  ChatMessages,
4
4
  ModelPicker,
5
5
  ProviderLogo
6
- } from "../chunk-J6TNPRQN.js";
6
+ } from "../chunk-7SMPAAIT.js";
7
7
  import "../chunk-FBVLEGEG.js";
8
- import "../chunk-72TPRENZ.js";
9
- import "../chunk-ZRSUCTST.js";
8
+ import "../chunk-YTMKRL3L.js";
9
+ import "../chunk-GEYACSFW.js";
10
10
  import "../chunk-HCOROIRT.js";
11
- import "../chunk-5GA3MKOC.js";
12
- import "../chunk-FEUW4G2L.js";
13
- import "../chunk-V3HO43PG.js";
11
+ import "../chunk-VM6VLJH6.js";
12
+ import "../chunk-DV2FA2PW.js";
13
+ import "../chunk-ZVEEWGDK.js";
14
14
  import "../chunk-5EPIPT4V.js";
15
15
  import "../chunk-3ZK5IJSW.js";
16
16
  import "../chunk-YJMCRXQQ.js";
@@ -1,4 +1,4 @@
1
- import { M as FileMention } from './parts-DIKcC1p6.js';
1
+ import { M as FileMention } from './parts-S1OINlRP.js';
2
2
 
3
3
  /**
4
4
  * `createSandboxFileIndexRoute` — server side of `@`-file-mentions
@@ -1,6 +1,6 @@
1
- import { C as ChatMessagePart, N as ChatTurnRequestPayload, O as ChatTurnPartInput, P as ChatTurnFilePartInput, b as ChatAttachmentPart, a as ChatAttachmentKind, g as ChatMentionPart } from '../parts-DIKcC1p6.js';
2
- export { Q as ChatAttachmentInput, f as ChatMentionKind, R as ChatTurnInputError, T as ChatTurnTextPartInput, U as DISPATCH_MAX_MEDIA_PARTS, V as DISPATCH_MAX_PARTS, W as DISPATCH_REQUEST_MAX_BYTES, X as DISPATCH_STRUCTURAL_RESERVE_BYTES, M as FileMention, Y as FileMentionsToPartsOptions, Z as INLINE_PARTS_MAX_BYTES, _ as MENTION_MAX_COUNT, $ as ProducerErrorEvent, a0 as ProducerNoticeEvent, a1 as ProducerPassthroughEvent, a2 as ProducerPassthroughEventType, a3 as ProducerReasoningEvent, a4 as ProducerTextEvent, a5 as ProducerToolCallEvent, a6 as ProducerToolResultEvent, a7 as ProducerUsageEvent, a8 as ProducerWireEvent, a9 as SandboxMentionPathCheck, aa as assertPromptPartsWithinCap, ab as base64WireLen, ac as buildMentionPromptBlock, ad as chatTurnRequestInit, ae as fileMentionsToParts, af as formatBytes, ag as mediaTypeForMentionPath, ah as mentionKindForPath, ai as parseChatTurnParts, aj as parseFileMentions, ak as promptPartsByteSize, al as validateSandboxMentionPath } from '../parts-DIKcC1p6.js';
3
- export { A as ALLOWED_ATTACHMENT_SNIFFED_MIMES, a as ATTACHMENT_ACCEPT, b as ATTACHMENT_MAX_COUNT, c as AttachmentTypeCheckResult, C as CreateSandboxFileIndexRouteOptions, F as FileIndexAuthorization, d as FileIndexCache, e as FileIndexReadyResponse, f as FileIndexResponse, g as FileIndexWarmingResponse, M as MAX_ATTACHMENT_TOTAL_BYTES, h as MAX_BINARY_ATTACHMENT_BYTES, i as MAX_TEXT_ATTACHMENT_BYTES, S as SandboxFileTreeSource, j as SandboxTreeFile, k as SandboxTreeResult, l as SniffResult, m as attachmentSizeErrorMessage, n as attachmentTotalSizeErrorMessage, o as checkAttachmentType, p as createSandboxFileIndexRoute, s as sanitizeAttachmentFileName, q as sniffBinary } from '../attachment-validation-yJ6Id4pR.js';
1
+ import { C as ChatMessagePart, N as ChatTurnRequestPayload, O as ChatTurnPartInput, P as ChatTurnFilePartInput, b as ChatAttachmentPart, a as ChatAttachmentKind, g as ChatMentionPart } from '../parts-S1OINlRP.js';
2
+ export { Q as ChatAttachmentInput, f as ChatMentionKind, R as ChatTurnInputError, T as ChatTurnTextPartInput, U as DISPATCH_MAX_MEDIA_PARTS, V as DISPATCH_MAX_PARTS, W as DISPATCH_REQUEST_MAX_BYTES, X as DISPATCH_STRUCTURAL_RESERVE_BYTES, M as FileMention, Y as FileMentionsToPartsOptions, Z as INLINE_PARTS_MAX_BYTES, _ as MENTION_MAX_COUNT, $ as ProducerErrorEvent, a0 as ProducerNoticeEvent, a1 as ProducerPassthroughEvent, a2 as ProducerPassthroughEventType, a3 as ProducerReasoningEvent, a4 as ProducerTextEvent, a5 as ProducerToolCallEvent, a6 as ProducerToolResultEvent, a7 as ProducerUsageEvent, a8 as ProducerWireEvent, a9 as SandboxMentionPathCheck, aa as assertPromptPartsWithinCap, ab as base64WireLen, ac as buildMentionPromptBlock, ad as chatTurnRequestInit, ae as fileMentionsToParts, af as formatBytes, ag as mediaTypeForMentionPath, ah as mentionKindForPath, ai as parseChatTurnParts, aj as parseFileMentions, ak as promptPartsByteSize, al as validateSandboxMentionPath } from '../parts-S1OINlRP.js';
3
+ export { A as ALLOWED_ATTACHMENT_SNIFFED_MIMES, a as ATTACHMENT_ACCEPT, b as ATTACHMENT_MAX_COUNT, c as AttachmentTypeCheckResult, C as CreateSandboxFileIndexRouteOptions, F as FileIndexAuthorization, d as FileIndexCache, e as FileIndexReadyResponse, f as FileIndexResponse, g as FileIndexWarmingResponse, M as MAX_ATTACHMENT_TOTAL_BYTES, h as MAX_BINARY_ATTACHMENT_BYTES, i as MAX_TEXT_ATTACHMENT_BYTES, S as SandboxFileTreeSource, j as SandboxTreeFile, k as SandboxTreeResult, l as SniffResult, m as attachmentSizeErrorMessage, n as attachmentTotalSizeErrorMessage, o as checkAttachmentType, p as createSandboxFileIndexRoute, s as sanitizeAttachmentFileName, q as sniffBinary } from '../attachment-validation-Zw8eslhN.js';
4
4
  import { ChatTurnIdentity, ChatTurnProducer } from '@tangle-network/agent-runtime';
5
5
  import { InteractionAnswerRoute, InteractionAnswerRouteOptions } from '../interactions/index.js';
6
6
  import { PersistedChatMessageForTurn } from '../stream/index.js';
@@ -11,7 +11,7 @@ import { J as JsonRecord } from '../stream-normalizer-DnuqkZvw.js';
11
11
  import { SandboxExecChannel, PromptInputPart } from '../sandbox/index.js';
12
12
  import '@tangle-network/agent-interface';
13
13
  import '../contract-CEewO6DI.js';
14
- import '../types-DeEOhQbv.js';
14
+ import '../types-DB82fktc.js';
15
15
  import '../plans/index.js';
16
16
  import '@tangle-network/sandbox';
17
17
  import '../auth-anc7mv2W.js';
@@ -11,7 +11,7 @@ import {
11
11
  createSandboxFileIndexRoute,
12
12
  sanitizeAttachmentFileName,
13
13
  sniffBinary
14
- } from "../chunk-5GA3MKOC.js";
14
+ } from "../chunk-VM6VLJH6.js";
15
15
  import {
16
16
  coalesceDeltas,
17
17
  createBufferedTurnTap,
@@ -55,8 +55,8 @@ import {
55
55
  promptPartsByteSize,
56
56
  toChatMessageParts,
57
57
  validateSandboxMentionPath
58
- } from "../chunk-FEUW4G2L.js";
59
- import "../chunk-V3HO43PG.js";
58
+ } from "../chunk-DV2FA2PW.js";
59
+ import "../chunk-ZVEEWGDK.js";
60
60
  import {
61
61
  asRecord,
62
62
  asString,
@@ -1,12 +1,12 @@
1
- import { C as ChatMessagePart } from '../parts-DIKcC1p6.js';
2
- export { a as ChatAttachmentKind, b as ChatAttachmentPart, c as ChatFilePart, d as ChatImagePart, e as ChatInteractionPart, f as ChatMentionKind, g as ChatMentionPart, h as ChatNoticePart, i as ChatPartTime, j as ChatPlanPart, k as ChatReasoningPart, l as ChatStepFinishPart, m as ChatStepStartPart, n as ChatSubtaskPart, o as ChatTextPart, p as ChatToolPart, q as ChatToolState, r as ChatToolStatus, s as ChatUsageTokens, t as ChatWorkProductPart, D as DEFAULT_ATTACHMENT_PROMPT_HEADER, S as StorableHarnessPartKind, u as attachmentInputToPart, v as attachmentKindForMime, w as attachmentPartsFromMessageParts, x as buildAttachmentPromptBlock, y as historyContentWithAttachments, z as isChatAttachmentPart, A as isChatInteractionPart, B as isChatMentionPart, E as isChatPlanPart, F as isChatStepFinishPart, G as isChatTextPart, H as isChatToolPart, I as isChatWorkProductPart, J as mentionInputToPart, K as mentionPartsFromMessageParts, L as toChatMessageParts } from '../parts-DIKcC1p6.js';
1
+ import { C as ChatMessagePart } from '../parts-S1OINlRP.js';
2
+ export { a as ChatAttachmentKind, b as ChatAttachmentPart, c as ChatFilePart, d as ChatImagePart, e as ChatInteractionPart, f as ChatMentionKind, g as ChatMentionPart, h as ChatNoticePart, i as ChatPartTime, j as ChatPlanPart, k as ChatReasoningPart, l as ChatStepFinishPart, m as ChatStepStartPart, n as ChatSubtaskPart, o as ChatTextPart, p as ChatToolPart, q as ChatToolState, r as ChatToolStatus, s as ChatUsageTokens, t as ChatWorkProductPart, D as DEFAULT_ATTACHMENT_PROMPT_HEADER, S as StorableHarnessPartKind, u as attachmentInputToPart, v as attachmentKindForMime, w as attachmentPartsFromMessageParts, x as buildAttachmentPromptBlock, y as historyContentWithAttachments, z as isChatAttachmentPart, A as isChatInteractionPart, B as isChatMentionPart, E as isChatPlanPart, F as isChatStepFinishPart, G as isChatTextPart, H as isChatToolPart, I as isChatWorkProductPart, J as mentionInputToPart, K as mentionPartsFromMessageParts, L as toChatMessageParts } from '../parts-S1OINlRP.js';
3
3
  import * as drizzle_orm from 'drizzle-orm';
4
4
  import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
5
5
  import { SQLiteColumnBuilderBase, AnySQLiteTable, AnySQLiteColumn, BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core';
6
6
  export { a as attachmentPartKey } from '../stream-normalizer-DnuqkZvw.js';
7
7
  import '@tangle-network/agent-interface';
8
8
  import '../contract-CEewO6DI.js';
9
- import '../types-DeEOhQbv.js';
9
+ import '../types-DB82fktc.js';
10
10
  import '../plans/index.js';
11
11
 
12
12
  /**
@@ -16,8 +16,8 @@ import {
16
16
  mentionInputToPart,
17
17
  mentionPartsFromMessageParts,
18
18
  toChatMessageParts
19
- } from "../chunk-FEUW4G2L.js";
20
- import "../chunk-V3HO43PG.js";
19
+ } from "../chunk-DV2FA2PW.js";
20
+ import "../chunk-ZVEEWGDK.js";
21
21
  import {
22
22
  attachmentPartKey
23
23
  } from "../chunk-5EPIPT4V.js";
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  WorkProductCard,
6
6
  workProductPartsFromMessageParts
7
- } from "./chunk-72TPRENZ.js";
7
+ } from "./chunk-YTMKRL3L.js";
8
8
  import {
9
9
  ATTACHMENT_ACCEPT,
10
10
  ATTACHMENT_MAX_COUNT,
@@ -16,11 +16,11 @@ import {
16
16
  checkAttachmentType,
17
17
  sanitizeAttachmentFileName,
18
18
  sniffBinary
19
- } from "./chunk-5GA3MKOC.js";
19
+ } from "./chunk-VM6VLJH6.js";
20
20
  import {
21
21
  attachmentPartsFromMessageParts,
22
22
  formatBytes
23
- } from "./chunk-FEUW4G2L.js";
23
+ } from "./chunk-DV2FA2PW.js";
24
24
  import {
25
25
  cancelStatusFor,
26
26
  fieldAcceptsFreeText,
@@ -3956,4 +3956,4 @@ export {
3956
3956
  useThinkingSeconds,
3957
3957
  ChatMessages
3958
3958
  };
3959
- //# sourceMappingURL=chunk-J6TNPRQN.js.map
3959
+ //# sourceMappingURL=chunk-7SMPAAIT.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  persistedPartToWorkProduct
3
- } from "./chunk-V3HO43PG.js";
3
+ } from "./chunk-ZVEEWGDK.js";
4
4
  import {
5
5
  persistedPartToInteraction
6
6
  } from "./chunk-3ZK5IJSW.js";
@@ -367,4 +367,4 @@ export {
367
367
  buildAttachmentPromptBlock,
368
368
  historyContentWithAttachments
369
369
  };
370
- //# sourceMappingURL=chunk-FEUW4G2L.js.map
370
+ //# sourceMappingURL=chunk-DV2FA2PW.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  unresolvedBlockingExceptions
3
- } from "./chunk-V3HO43PG.js";
3
+ } from "./chunk-ZVEEWGDK.js";
4
4
 
5
5
  // src/work-product/queue.ts
6
6
  var OPEN_STATUSES = /* @__PURE__ */ new Set(["draft", "blocked", "ready", "changes_requested"]);
@@ -138,4 +138,4 @@ export {
138
138
  projectReviewQueue,
139
139
  parseReviewQueueItem
140
140
  };
141
- //# sourceMappingURL=chunk-ZRSUCTST.js.map
141
+ //# sourceMappingURL=chunk-GEYACSFW.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  formatBytes
3
- } from "./chunk-FEUW4G2L.js";
3
+ } from "./chunk-DV2FA2PW.js";
4
4
 
5
5
  // src/chat-routes/binary-sniff.ts
6
6
  function bytesStartWith(bytes, offset, signature) {
@@ -236,4 +236,4 @@ export {
236
236
  attachmentTotalSizeErrorMessage,
237
237
  createSandboxFileIndexRoute
238
238
  };
239
- //# sourceMappingURL=chunk-5GA3MKOC.js.map
239
+ //# sourceMappingURL=chunk-VM6VLJH6.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  parseReviewQueueItem
3
- } from "./chunk-ZRSUCTST.js";
3
+ } from "./chunk-GEYACSFW.js";
4
4
  import {
5
5
  persistedPartToWorkProduct
6
- } from "./chunk-V3HO43PG.js";
6
+ } from "./chunk-ZVEEWGDK.js";
7
7
 
8
8
  // src/web-react/work-product.tsx
9
9
  import { useCallback, useEffect, useState } from "react";
@@ -341,4 +341,4 @@ export {
341
341
  QualityCheckList,
342
342
  ProvenanceStamp
343
343
  };
344
- //# sourceMappingURL=chunk-72TPRENZ.js.map
344
+ //# sourceMappingURL=chunk-YTMKRL3L.js.map
@@ -46,6 +46,19 @@ function parseEvidenceInput(raw, path = "entry") {
46
46
  if (typeof locatorRaw.quote !== "string") return fail(`${path}.locator.quote`, "must be a string when present");
47
47
  locator.quote = locatorRaw.quote;
48
48
  }
49
+ if (locatorRaw.find !== void 0) {
50
+ if (typeof locatorRaw.find !== "string" || locatorRaw.find.trim().length === 0) {
51
+ return fail(`${path}.locator.find`, "must be a non-empty string \u2014 the value or text to locate in the source");
52
+ }
53
+ locator.find = locatorRaw.find;
54
+ }
55
+ if (locatorRaw.findOccurrence !== void 0) {
56
+ const value = locatorRaw.findOccurrence;
57
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1) {
58
+ return fail(`${path}.locator.findOccurrence`, "must be a positive integer (1 = the first occurrence)");
59
+ }
60
+ locator.findOccurrence = value;
61
+ }
49
62
  if (locatorRaw.span !== void 0) {
50
63
  const spanRaw = asRecord(locatorRaw.span);
51
64
  if (!spanRaw) return fail(`${path}.locator.span`, "must be an object { start, end } when present");
@@ -204,4 +217,4 @@ export {
204
217
  workProductToPersistedPart,
205
218
  persistedPartToWorkProduct
206
219
  };
207
- //# sourceMappingURL=chunk-V3HO43PG.js.map
220
+ //# sourceMappingURL=chunk-ZVEEWGDK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/work-product/types.ts"],"sourcesContent":["/**\n * The reviewable work-product contract — the one durable object every Tangle\n * agent product converges on: an artifact plus its evidence map (source→field\n * lineage), exceptions, quality checks, version history, and run provenance,\n * produced by an agent and signed off by a professional.\n *\n * Import-free and client-safe by construction: the queue projection and the\n * React surfaces re-validate these shapes at JSON boundaries, so every type\n * and codec here must load in a browser bundle. Every domain word — artifact\n * `kind`, evidence `target`, exception `kind`, check `name`, `scopeKey`\n * format — is a STRING PARAMETER validated against product-supplied\n * vocabularies in the tool layer; nothing domain-specific is baked here.\n */\n\n// ── identity / status ────────────────────────────────────────────────────────\n\n/** Stable pointer at one version of one work product. */\nexport interface WorkProductRef {\n id: string\n version: number\n}\n\nexport type WorkProductStatus =\n | 'draft' // agent is emitting incrementally (queue: working)\n | 'blocked' // unresolved blocking exception (queue: blocked / missing-info)\n | 'ready' // submit_work_product accepted (queue: ready-for-review)\n | 'changes_requested' // reviewer verdict; the correction re-enters chat as a turn\n | 'approved' // reviewer sign-off on THIS version\n | 'superseded' // a newer version replaced this one\n\nconst WORK_PRODUCT_STATUSES: readonly WorkProductStatus[] = [\n 'draft',\n 'blocked',\n 'ready',\n 'changes_requested',\n 'approved',\n 'superseded',\n]\n\n/** Runtime guard for re-validating a status read off a JSON boundary. */\nexport function isWorkProductStatus(value: unknown): value is WorkProductStatus {\n return typeof value === 'string' && (WORK_PRODUCT_STATUSES as readonly string[]).includes(value)\n}\n\n// ── artifact ─────────────────────────────────────────────────────────────────\n\n/** Define the reviewable artifact body with its kind, sources, and structured field map */\nexport interface WorkProductArtifact {\n /** PARAMETER: 'return_package' | 'redline' | 'outreach_campaign' — validated\n * against the product's `artifactKinds` vocabulary at submit. */\n kind: string\n title: string\n /** Vault/object-store ref for the rendered document (large bodies). */\n path?: string\n /** Inline body when small (markdown/JSON). */\n content?: string\n mediaType?: string\n /** Diff-first products (legal): the source document the artifact redlines. */\n baseline?: { path?: string; content?: string }\n /** The structured field map lineage targets anchor to (tax: form-line ids). */\n fields?: Record<string, unknown>\n}\n\n// ── evidence / lineage: source doc + locator → field/claim ───────────────────\n\n/** A half-open `[start, end)` character range into the source document's text.\n * Offsets index exactly the string the product's `readSourceText` seam\n * returns for the same `sourceRef` — which is the string its document-reading\n * tool pages with an `offset`. The PLATFORM slices `locator.quote` out of it,\n * so a span citation cannot name text the document does not contain. */\nexport interface EvidenceSpan {\n start: number\n end: number\n}\n\n/** How `locator.quote` got there. Server-set on every path — never read from\n * model args, because the whole value of the distinction is that a reviewer\n * can trust it:\n * - `span` the platform sliced it out of the source bytes (unfalsifiable)\n * - `model` the model supplied the text and the platform PROVED it occurs */\nexport type QuoteBasis = 'span' | 'model'\n\n/** Point into a source document: page, free-form range, span, verbatim quote */\nexport interface EvidenceLocator {\n page?: number\n /** 'L120-L134' | 'B7' | '¶4' — free-form, non-empty when present. */\n range?: string\n /** Verbatim supporting quote from the source. Model-supplied and verified,\n * or platform-sliced from {@link EvidenceLocator.span} — read `quoteBasis`\n * to tell which. */\n quote?: string\n /** Character range the quote is sliced from. Correct when the offsets are\n * computed by a tool; see {@link EvidenceLocator.find} for the form a model\n * should use, because models do not count characters reliably. */\n span?: EvidenceSpan\n /** The value or distinctive text to LOCATE in the source. The platform finds\n * the line containing it and derives both `span` and `quote` from that —\n * so the model neither retypes the quote nor computes an offset, and a\n * citation that lands on the wrong line becomes unrepresentable rather than\n * merely wrong. The preferred citation form for an agent. */\n find?: string\n /** Which occurrence of `find` to cite when the value appears more than once\n * (1-based, default 1). */\n findOccurrence?: number\n /** Server-set provenance for `quote`; a model-supplied value is discarded. */\n quoteBasis?: QuoteBasis\n}\n\n/** One lineage row: a source document location supporting one artifact claim */\nexport interface EvidenceEntry {\n /** Agent-supplied stable id — the same id re-emitted is an upsert/replace. */\n id: string\n /** Vault path / attachment id / object-store key of the SOURCE document. */\n sourceRef: string\n locator: EvidenceLocator\n /** Artifact field/claim the evidence supports: '1040.line_9' |\n * 'clause:indemnification' | 'icp.employee_count' — product vocabulary. */\n target: string\n /** The value/assertion at the target. */\n claim: string\n /** 0..1; absent = unstated (never defaulted). */\n confidence?: number\n}\n\n// ── exceptions ───────────────────────────────────────────────────────────────\n\nexport type ExceptionSeverity = 'blocking' | 'material' | 'advisory'\n\n/** One flagged problem with the work product, resolvable by agent or reviewer */\nexport interface ExceptionEntry {\n id: string\n severity: ExceptionSeverity\n /** PARAMETER: 'missing_document' | 'inconsistent_source' | … — validated\n * against the product's `exceptionKinds` vocabulary. */\n kind: string\n message: string\n /** Affected artifact targets. */\n targets?: string[]\n resolved: boolean\n resolvedBy?: 'agent' | 'reviewer'\n resolutionNote?: string\n}\n\n/** Unresolved blocking exceptions are what park a work product in `blocked`. */\nexport function unresolvedBlockingExceptions(exceptions: readonly ExceptionEntry[]): ExceptionEntry[] {\n return exceptions.filter((entry) => entry.severity === 'blocking' && !entry.resolved)\n}\n\n// ── quality checks ───────────────────────────────────────────────────────────\n\n/** One named quality verdict on the work product, tagged with who computed it */\nexport interface QualityCheck {\n id: string\n /** Product vocabulary: 'totals_reconcile', 'evidence_coverage', … */\n name: string\n passed: boolean\n detail?: string\n /** agent self-report | shell-computed | eval-ensemble verdict. */\n source: 'agent' | 'platform' | 'judge'\n}\n\n// ── provenance (the backtest spine) ──────────────────────────────────────────\n\n/** The audit triple binding a work product to the exact configuration and run\n * that produced it. `profileHash` is agent-eval's `agentProfileHash()` of the\n * EXACT shipped profile — the same hash that keys scorecard cells, so a\n * reviewer can see the measured backtest history of the configuration that\n * produced the document. */\nexport interface WorkProductProvenance {\n profileHash: string\n /** Chat turnId or mission-step run id. */\n runId: string\n /** Back-filled from the usage receipt / serving-model header at turn\n * completion — only the completed turn knows what actually served. */\n servingModels: string[]\n sessionId?: string\n missionRef?: { missionId: string; stepId: string }\n costUsd?: number\n producedAt: number\n}\n\n/** The product-resolved backtest summary for one profile hash (from its own\n * eval artifacts via agent-eval's `loadScorecard`) — the shell defines only\n * this TYPE and the `ProvenanceStamp` slot that renders it. */\nexport interface ProfileBacktestSummary {\n profileHash: string\n /** Backtest cases behind the composite. */\n cases: number\n composite: number\n /** The eval-campaign trust gate's verdict on whether the composite is\n * allowed to be believed; 'fail' renders as \"quality: unverified\". */\n trust: 'pass' | 'fail'\n trustReasons: string[]\n}\n\n// ── version history ──────────────────────────────────────────────────────────\n\n/** Frozen milestone row for one version of the work product */\nexport interface WorkProductVersionEntry {\n version: number\n status: WorkProductStatus\n provenance: WorkProductProvenance\n /** Frozen snapshot ref of this version's body (object-store key) — the\n * DiffView input for vN-1 vs vN. */\n artifactPath?: string\n reviewedBy?: string\n reviewNote?: string\n at: number\n}\n\n// ── the durable row ──────────────────────────────────────────────────────────\n\n/** Define the durable work product row accumulating artifact, lineage, exceptions, checks, and history */\nexport interface WorkProductRecord {\n /** Minted server-side; the model NEVER supplies ids — it addresses work by\n * `scopeKey`. */\n id: string\n workspaceId: string\n /** The chat thread that drives it (chat stays first). */\n threadId: string | null\n /** Product engagement key: 'return:acme:2025' | 'contract:acme-msa' |\n * 'campaign:cpa-pilots'. */\n scopeKey: string\n status: WorkProductStatus\n version: number\n /** `null` while the draft accumulates (evidence streams in before the\n * artifact arrives); non-null from the submit transition onward. Typed\n * honestly rather than forcing a placeholder artifact on every draft. */\n artifact: WorkProductArtifact | null\n evidence: EvidenceEntry[]\n exceptions: ExceptionEntry[]\n checks: QualityCheck[]\n provenance: WorkProductProvenance\n history: WorkProductVersionEntry[]\n createdAt: number\n updatedAt: number\n}\n\n// ── store port — the /missions MissionStorePort pattern ──────────────────────\n\n/** Fields a guarded write compares against the values the caller read. An\n * absent field is unguarded. A SQL implementation compares like-for-like\n * scalar columns; the in-memory store does the same. */\nexport interface WorkProductUpdateGuard {\n status?: WorkProductStatus\n version?: number\n}\n\n/** Fields a guarded write sets when the guard holds. */\nexport interface WorkProductPatch {\n status?: WorkProductStatus\n version?: number\n artifact?: WorkProductArtifact\n evidence?: EvidenceEntry[]\n exceptions?: ExceptionEntry[]\n checks?: QualityCheck[]\n provenance?: WorkProductProvenance\n history?: WorkProductVersionEntry[]\n updatedAt?: number\n}\n\n/** One audit-trail row, appended after every committed state change. */\nexport interface WorkProductAuditEvent {\n workProductId: string\n workspaceId: string\n /** Machine-readable transition name ('wp.created' | 'wp.evidence' |\n * 'wp.ready' | 'wp.verdict' | …). */\n step: string\n message: string\n metadata: Record<string, unknown>\n at: number\n}\n\n/**\n * Persistence seam — the product implements this over its own tables. The\n * invariant the implementation MUST keep: `update` applies `patch` ONLY when\n * every guard field still equals the stored value, and returns `null` when\n * the guard misses — a typed conflict, never a clobber.\n */\nexport interface WorkProductStorePort {\n load(id: string): Promise<WorkProductRecord | null>\n /** The scope's single OPEN accumulator row — status `draft` or `blocked` —\n * or null when the scope has only reviewed/terminal rows (or none). The\n * `changes_requested` row is found via {@link listByWorkspace}; reopening\n * it is the service's job. */\n findDraft(workspaceId: string, scopeKey: string): Promise<WorkProductRecord | null>\n listByWorkspace(workspaceId: string, opts?: { status?: WorkProductStatus[] }): Promise<WorkProductRecord[]>\n /** `extras` are opaque product-column values written in the SAME statement\n * as the record (single-write creation), or ignored when the table has no\n * extra columns. */\n insert(record: WorkProductRecord, extras?: Record<string, unknown>): Promise<WorkProductRecord>\n /** CAS: apply `patch` ONLY when guard fields equal stored values; null on a\n * miss — typed conflict, never a clobber. */\n update(id: string, guard: WorkProductUpdateGuard, patch: WorkProductPatch): Promise<WorkProductRecord | null>\n appendEvent(event: WorkProductAuditEvent): Promise<void>\n}\n\n// ── input codecs (strict, named-field errors) ────────────────────────────────\n\n/** Validation result whose failure names the exact field, so a tool layer can\n * hand the model a correctable error it can act on. */\nexport type WorkProductParseResult<T> =\n | { ok: true; value: T }\n | { ok: false; field: string; error: string }\n\nfunction fail<T>(field: string, error: string): WorkProductParseResult<T> {\n return { ok: false, field, error }\n}\n\nfunction nonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : null\n}\n\n/** Validate one raw evidence entry field-by-field. `path` prefixes the failure\n * field name (e.g. `entries[3]`) so batched calls name the exact offender. */\nexport function parseEvidenceInput(raw: unknown, path = 'entry'): WorkProductParseResult<EvidenceEntry> {\n const record = asRecord(raw)\n if (!record) return fail(path, 'must be an object')\n if (!nonEmptyString(record.id)) return fail(`${path}.id`, 'must be a non-empty string (stable per entry; re-emitting the same id replaces it)')\n if (!nonEmptyString(record.sourceRef)) return fail(`${path}.sourceRef`, 'must be a non-empty source document ref')\n if (!nonEmptyString(record.target)) return fail(`${path}.target`, 'must name the artifact field/claim this evidence supports')\n if (!nonEmptyString(record.claim)) return fail(`${path}.claim`, 'must state the value/assertion at the target')\n const locatorRaw = record.locator === undefined ? {} : asRecord(record.locator)\n if (!locatorRaw) return fail(`${path}.locator`, 'must be an object when present')\n const locator: EvidenceLocator = {}\n if (locatorRaw.page !== undefined) {\n if (typeof locatorRaw.page !== 'number' || !Number.isFinite(locatorRaw.page)) {\n return fail(`${path}.locator.page`, 'must be a finite number when present')\n }\n locator.page = locatorRaw.page\n }\n if (locatorRaw.range !== undefined) {\n if (!nonEmptyString(locatorRaw.range)) return fail(`${path}.locator.range`, 'must be a non-empty string when present')\n locator.range = locatorRaw.range\n }\n if (locatorRaw.quote !== undefined) {\n if (typeof locatorRaw.quote !== 'string') return fail(`${path}.locator.quote`, 'must be a string when present')\n locator.quote = locatorRaw.quote\n }\n if (locatorRaw.find !== undefined) {\n if (typeof locatorRaw.find !== 'string' || locatorRaw.find.trim().length === 0) {\n return fail(`${path}.locator.find`, 'must be a non-empty string — the value or text to locate in the source')\n }\n locator.find = locatorRaw.find\n }\n if (locatorRaw.findOccurrence !== undefined) {\n const value = locatorRaw.findOccurrence\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 1) {\n return fail(`${path}.locator.findOccurrence`, 'must be a positive integer (1 = the first occurrence)')\n }\n locator.findOccurrence = value\n }\n if (locatorRaw.span !== undefined) {\n const spanRaw = asRecord(locatorRaw.span)\n if (!spanRaw) return fail(`${path}.locator.span`, 'must be an object { start, end } when present')\n for (const field of ['start', 'end'] as const) {\n const value = spanRaw[field]\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {\n return fail(`${path}.locator.span.${field}`, 'must be a non-negative integer character offset')\n }\n }\n if ((spanRaw.end as number) <= (spanRaw.start as number)) {\n return fail(`${path}.locator.span`, `end (${String(spanRaw.end)}) must be greater than start (${String(spanRaw.start)}) — the range is half-open [start, end)`)\n }\n locator.span = { start: spanRaw.start as number, end: spanRaw.end as number }\n }\n // `quoteBasis` is server-set. A model-supplied value is DROPPED rather than\n // rejected: it is not a correctable mistake the model should burn a turn on,\n // and silently honouring it would let a model label an unverified quote\n // 'span'. The tool layer stamps the real basis after resolution.\n const entry: EvidenceEntry = {\n id: (record.id as string).trim(),\n sourceRef: (record.sourceRef as string).trim(),\n locator,\n target: (record.target as string).trim(),\n claim: record.claim as string,\n }\n if (record.confidence !== undefined) {\n if (typeof record.confidence !== 'number' || !(record.confidence >= 0 && record.confidence <= 1)) {\n return fail(`${path}.confidence`, 'must be a number in 0..1 when present')\n }\n entry.confidence = record.confidence\n }\n return { ok: true, value: entry }\n}\n\nconst EXCEPTION_SEVERITIES: readonly ExceptionSeverity[] = ['blocking', 'material', 'advisory']\n\n/** Validate one raw exception entry field-by-field. Kind MEMBERSHIP in the\n * product vocabulary is the tool layer's check (it owns the config). */\nexport function parseExceptionInput(raw: unknown, path = 'exception'): WorkProductParseResult<ExceptionEntry> {\n const record = asRecord(raw)\n if (!record) return fail(path, 'must be an object')\n if (!nonEmptyString(record.id)) return fail(`${path}.id`, 'must be a non-empty string (stable per entry; re-emitting the same id replaces it)')\n if (!EXCEPTION_SEVERITIES.includes(record.severity as ExceptionSeverity)) {\n return fail(`${path}.severity`, `must be one of: ${EXCEPTION_SEVERITIES.join(', ')}`)\n }\n if (!nonEmptyString(record.kind)) return fail(`${path}.kind`, 'must be a non-empty exception kind')\n if (!nonEmptyString(record.message)) return fail(`${path}.message`, 'must describe the problem')\n const entry: ExceptionEntry = {\n id: (record.id as string).trim(),\n severity: record.severity as ExceptionSeverity,\n kind: (record.kind as string).trim(),\n message: record.message as string,\n resolved: record.resolved === true,\n }\n if (record.targets !== undefined) {\n if (!Array.isArray(record.targets) || !record.targets.every(nonEmptyString)) {\n return fail(`${path}.targets`, 'must be an array of non-empty strings when present')\n }\n entry.targets = record.targets as string[]\n }\n if (record.resolvedBy !== undefined) {\n if (record.resolvedBy !== 'agent' && record.resolvedBy !== 'reviewer') {\n return fail(`${path}.resolvedBy`, \"must be 'agent' or 'reviewer' when present\")\n }\n entry.resolvedBy = record.resolvedBy\n }\n if (record.resolutionNote !== undefined) {\n if (typeof record.resolutionNote !== 'string') return fail(`${path}.resolutionNote`, 'must be a string when present')\n entry.resolutionNote = record.resolutionNote\n }\n return { ok: true, value: entry }\n}\n\n/** Validate a raw artifact. Kind MEMBERSHIP in `artifactKinds` is the tool\n * layer's check. An artifact must carry a body: at least one of `path`,\n * `content`, or `fields`. */\nexport function parseArtifactInput(raw: unknown, path = 'artifact'): WorkProductParseResult<WorkProductArtifact> {\n const record = asRecord(raw)\n if (!record) return fail(path, 'must be an object')\n if (!nonEmptyString(record.kind)) return fail(`${path}.kind`, 'must be a non-empty artifact kind')\n if (!nonEmptyString(record.title)) return fail(`${path}.title`, 'must be a non-empty title')\n for (const key of ['path', 'content', 'mediaType'] as const) {\n if (record[key] !== undefined && !nonEmptyString(record[key])) {\n return fail(`${path}.${key}`, 'must be a non-empty string when present')\n }\n }\n let baseline: WorkProductArtifact['baseline']\n if (record.baseline !== undefined) {\n const baselineRecord = asRecord(record.baseline)\n if (!baselineRecord) return fail(`${path}.baseline`, 'must be an object when present')\n baseline = {}\n if (baselineRecord.path !== undefined) {\n if (!nonEmptyString(baselineRecord.path)) return fail(`${path}.baseline.path`, 'must be a non-empty string when present')\n baseline.path = (baselineRecord.path as string).trim()\n }\n if (baselineRecord.content !== undefined) {\n if (typeof baselineRecord.content !== 'string') return fail(`${path}.baseline.content`, 'must be a string when present')\n baseline.content = baselineRecord.content\n }\n }\n let fields: Record<string, unknown> | undefined\n if (record.fields !== undefined) {\n const fieldsRecord = asRecord(record.fields)\n if (!fieldsRecord) return fail(`${path}.fields`, 'must be an object when present')\n fields = fieldsRecord\n }\n if (record.path === undefined && record.content === undefined && fields === undefined) {\n return fail(path, 'must carry a body: at least one of path, content, or fields')\n }\n const artifact: WorkProductArtifact = {\n kind: (record.kind as string).trim(),\n title: (record.title as string).trim(),\n }\n if (record.path !== undefined) artifact.path = (record.path as string).trim()\n if (record.content !== undefined) artifact.content = record.content as string\n if (record.mediaType !== undefined) artifact.mediaType = (record.mediaType as string).trim()\n if (baseline !== undefined) artifact.baseline = baseline\n if (fields !== undefined) artifact.fields = fields\n return { ok: true, value: artifact }\n}\n\n/** Agent self-reported check input for `submit_work_product` (persisted with\n * `source: 'agent'`; `platform`/`judge` sources are never model-suppliable). */\nexport interface AgentCheckInput {\n id: string\n name: string\n passed: boolean\n detail?: string\n}\n\n/** Validate one agent self-check ensuring identifiers, verdict flag, and optional detail are well formed */\nexport function parseAgentCheckInput(raw: unknown, path = 'check'): WorkProductParseResult<AgentCheckInput> {\n const record = asRecord(raw)\n if (!record) return fail(path, 'must be an object')\n if (!nonEmptyString(record.id)) return fail(`${path}.id`, 'must be a non-empty string')\n if (!nonEmptyString(record.name)) return fail(`${path}.name`, 'must be a non-empty check name')\n if (typeof record.passed !== 'boolean') return fail(`${path}.passed`, 'must be a boolean')\n const check: AgentCheckInput = {\n id: (record.id as string).trim(),\n name: (record.name as string).trim(),\n passed: record.passed,\n }\n if (record.detail !== undefined) {\n if (typeof record.detail !== 'string') return fail(`${path}.detail`, 'must be a string when present')\n check.detail = record.detail\n }\n return { ok: true, value: check }\n}\n\n// ── chat transcript anchor (system-authored) ─────────────────────────────────\n\n/**\n * The persisted `type:'work_product'` transcript anchor — the chat card that\n * keeps chat the driver surface for review. The PLATFORM writes it on the\n * ready transition (and updates it on a verdict); no prompt ever teaches an\n * agent to author one. `/chat-store` aliases this as `ChatWorkProductPart` in\n * its stored-part union, exactly like the `interaction`/`plan` members.\n */\nexport interface WorkProductPersistedPart {\n type: 'work_product'\n ref: WorkProductRef\n kind: string\n title: string\n status: WorkProductStatus\n}\n\n/** Project the transcript anchor part from a record. Requires the submitted\n * artifact (the anchor is written on the ready transition, after which\n * `artifact` is always non-null); falls back to the scopeKey label for\n * defensive callers on an accumulating draft. */\nexport function workProductToPersistedPart(record: WorkProductRecord): WorkProductPersistedPart {\n return {\n type: 'work_product',\n ref: { id: record.id, version: record.version },\n kind: record.artifact?.kind ?? '',\n title: record.artifact?.title ?? record.scopeKey,\n status: record.status,\n }\n}\n\n/** Re-validate a stored/wire part into the typed anchor; null for junk. */\nexport function persistedPartToWorkProduct(part: Record<string, unknown>): WorkProductPersistedPart | null {\n if (!part || part.type !== 'work_product') return null\n const ref = asRecord(part.ref)\n if (!ref || !nonEmptyString(ref.id) || typeof ref.version !== 'number' || !Number.isFinite(ref.version)) return null\n if (typeof part.kind !== 'string' || !nonEmptyString(part.title) || !isWorkProductStatus(part.status)) return null\n return {\n type: 'work_product',\n ref: { id: ref.id as string, version: ref.version },\n kind: part.kind,\n title: part.title as string,\n status: part.status,\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import { Part } from '@tangle-network/agent-interface';
2
2
  import { a as ChatInteractionField, C as ChatInteractionStatus, I as InteractionAnswers, N as NoticeKind } from './contract-CEewO6DI.js';
3
- import { c as WorkProductPersistedPart } from './types-DeEOhQbv.js';
3
+ import { c as WorkProductPersistedPart } from './types-DB82fktc.js';
4
4
  import { ChatPlanPersistedPart } from './plans/index.js';
5
5
 
6
6
  /**
@@ -1,4 +1,4 @@
1
- import { W as WorkProductRef, a as WorkProductProvenance, b as WorkProductRecord } from './types-DeEOhQbv.js';
1
+ import { W as WorkProductRef, a as WorkProductProvenance, b as WorkProductRecord } from './types-DB82fktc.js';
2
2
 
3
3
  /**
4
4
  * The review queue is a PROJECTION, not a store — a client-safe pure fold of
@@ -62,9 +62,19 @@ interface EvidenceLocator {
62
62
  * or platform-sliced from {@link EvidenceLocator.span} — read `quoteBasis`
63
63
  * to tell which. */
64
64
  quote?: string;
65
- /** Character range the quote is sliced from. The preferred citation form:
66
- * two integers cannot be a fabricated quote. */
65
+ /** Character range the quote is sliced from. Correct when the offsets are
66
+ * computed by a tool; see {@link EvidenceLocator.find} for the form a model
67
+ * should use, because models do not count characters reliably. */
67
68
  span?: EvidenceSpan;
69
+ /** The value or distinctive text to LOCATE in the source. The platform finds
70
+ * the line containing it and derives both `span` and `quote` from that —
71
+ * so the model neither retypes the quote nor computes an offset, and a
72
+ * citation that lands on the wrong line becomes unrepresentable rather than
73
+ * merely wrong. The preferred citation form for an agent. */
74
+ find?: string;
75
+ /** Which occurrence of `find` to cite when the value appears more than once
76
+ * (1-based, default 1). */
77
+ findOccurrence?: number;
68
78
  /** Server-set provenance for `quote`; a model-supplied value is discarded. */
69
79
  quoteBasis?: QuoteBasis;
70
80
  }
@@ -5,17 +5,17 @@ export { f as ChatFreeTextField, g as ComposerAnswerDelivery, h as INTERACTION_C
5
5
  import { ChatPlan } from '../plans/index.js';
6
6
  import { InteractionData } from '@tangle-network/agent-interface';
7
7
  export { InteractionData, InteractionOutcome, InteractionRequest } from '@tangle-network/agent-interface';
8
- import { M as FileMention, g as ChatMentionPart, b as ChatAttachmentPart, a as ChatAttachmentKind, Q as ChatAttachmentInput } from '../parts-DIKcC1p6.js';
9
- export { f as ChatMentionKind, P as ChatTurnFilePartInput, O as ChatTurnPartInput, N as ChatTurnRequestPayload, U as DISPATCH_MAX_MEDIA_PARTS, V as DISPATCH_MAX_PARTS, W as DISPATCH_REQUEST_MAX_BYTES, X as DISPATCH_STRUCTURAL_RESERVE_BYTES, $ as ProducerErrorEvent, a0 as ProducerNoticeEvent, a1 as ProducerPassthroughEvent, a2 as ProducerPassthroughEventType, a3 as ProducerReasoningEvent, a4 as ProducerTextEvent, a5 as ProducerToolCallEvent, a6 as ProducerToolResultEvent, a7 as ProducerUsageEvent, a8 as ProducerWireEvent, u as attachmentInputToPart, v as attachmentKindForMime, w as attachmentPartsFromMessageParts, ab as base64WireLen, ac as buildMentionPromptBlock, ad as chatTurnRequestInit, ae as fileMentionsToParts, z as isChatAttachmentPart, ag as mediaTypeForMentionPath, J as mentionInputToPart, ah as mentionKindForPath, K as mentionPartsFromMessageParts } from '../parts-DIKcC1p6.js';
10
- import { E as EvidenceEntry, g as ExceptionEntry, a as WorkProductProvenance, P as ProfileBacktestSummary, Q as QualityCheck, c as WorkProductPersistedPart, h as WorkProductStatus } from '../types-DeEOhQbv.js';
8
+ import { M as FileMention, g as ChatMentionPart, b as ChatAttachmentPart, a as ChatAttachmentKind, Q as ChatAttachmentInput } from '../parts-S1OINlRP.js';
9
+ export { f as ChatMentionKind, P as ChatTurnFilePartInput, O as ChatTurnPartInput, N as ChatTurnRequestPayload, U as DISPATCH_MAX_MEDIA_PARTS, V as DISPATCH_MAX_PARTS, W as DISPATCH_REQUEST_MAX_BYTES, X as DISPATCH_STRUCTURAL_RESERVE_BYTES, $ as ProducerErrorEvent, a0 as ProducerNoticeEvent, a1 as ProducerPassthroughEvent, a2 as ProducerPassthroughEventType, a3 as ProducerReasoningEvent, a4 as ProducerTextEvent, a5 as ProducerToolCallEvent, a6 as ProducerToolResultEvent, a7 as ProducerUsageEvent, a8 as ProducerWireEvent, u as attachmentInputToPart, v as attachmentKindForMime, w as attachmentPartsFromMessageParts, ab as base64WireLen, ac as buildMentionPromptBlock, ad as chatTurnRequestInit, ae as fileMentionsToParts, z as isChatAttachmentPart, ag as mediaTypeForMentionPath, J as mentionInputToPart, ah as mentionKindForPath, K as mentionPartsFromMessageParts } from '../parts-S1OINlRP.js';
10
+ import { E as EvidenceEntry, g as ExceptionEntry, a as WorkProductProvenance, P as ProfileBacktestSummary, Q as QualityCheck, c as WorkProductPersistedPart, h as WorkProductStatus } from '../types-DB82fktc.js';
11
11
  import { S as StepAgentActivity } from '../agent-activity-C8ZG0F0M.js';
12
12
  import { F as FlowTrace } from '../flow-types-CJxEmaRy.js';
13
- import { a as ReviewQueueItem, c as ReviewQueueState } from '../queue-DBkulxW1.js';
14
- export { p as parseReviewQueueItem } from '../queue-DBkulxW1.js';
13
+ import { a as ReviewQueueItem, c as ReviewQueueState } from '../queue-vRI0Qx3X.js';
14
+ export { p as parseReviewQueueItem } from '../queue-vRI0Qx3X.js';
15
15
  export { S as SandboxTerminalConnection, a as SandboxTerminalConnectionResponse, U as UseSandboxTerminalConnectionOptions, b as UseSandboxTerminalConnectionResult, t as tabTerminalConnectionId, u as useSandboxTerminalConnection } from '../sandbox-terminal-ChNEdHF8.js';
16
16
  import { CatalogModel } from '../catalog/index.js';
17
17
  import { Harness } from '../harness/index.js';
18
- export { a as ATTACHMENT_ACCEPT, e as FileIndexReadyResponse, f as FileIndexResponse, g as FileIndexWarmingResponse } from '../attachment-validation-yJ6Id4pR.js';
18
+ export { a as ATTACHMENT_ACCEPT, e as FileIndexReadyResponse, f as FileIndexResponse, g as FileIndexWarmingResponse } from '../attachment-validation-Zw8eslhN.js';
19
19
  export { a as attachmentPartKey } from '../stream-normalizer-DnuqkZvw.js';
20
20
 
21
21
  /** Represent durable plan decisions as either approved or rejected */
@@ -74,7 +74,7 @@ import {
74
74
  useSmoothText,
75
75
  useThinkingSeconds,
76
76
  waterfallLayout
77
- } from "../chunk-J6TNPRQN.js";
77
+ } from "../chunk-7SMPAAIT.js";
78
78
  import "../chunk-FBVLEGEG.js";
79
79
  import {
80
80
  EvidenceLineageTable,
@@ -87,17 +87,17 @@ import {
87
87
  reviewQueueStateLabel,
88
88
  workProductPartsFromMessageParts,
89
89
  workProductStatusLabel
90
- } from "../chunk-72TPRENZ.js";
90
+ } from "../chunk-YTMKRL3L.js";
91
91
  import {
92
92
  parseReviewQueueItem
93
- } from "../chunk-ZRSUCTST.js";
93
+ } from "../chunk-GEYACSFW.js";
94
94
  import {
95
95
  tabTerminalConnectionId,
96
96
  useSandboxTerminalConnection
97
97
  } from "../chunk-HCOROIRT.js";
98
98
  import {
99
99
  ATTACHMENT_ACCEPT
100
- } from "../chunk-5GA3MKOC.js";
100
+ } from "../chunk-VM6VLJH6.js";
101
101
  import {
102
102
  DISPATCH_MAX_MEDIA_PARTS,
103
103
  DISPATCH_MAX_PARTS,
@@ -115,8 +115,8 @@ import {
115
115
  mentionInputToPart,
116
116
  mentionKindForPath,
117
117
  mentionPartsFromMessageParts
118
- } from "../chunk-FEUW4G2L.js";
119
- import "../chunk-V3HO43PG.js";
118
+ } from "../chunk-DV2FA2PW.js";
119
+ import "../chunk-ZVEEWGDK.js";
120
120
  import {
121
121
  attachmentPartKey
122
122
  } from "../chunk-5EPIPT4V.js";
@@ -1,9 +1,9 @@
1
- import { a as WorkProductProvenance, d as WorkProductStorePort, e as WorkProductAuditEvent, b as WorkProductRecord, f as WorkProductArtifact, Q as QualityCheck, E as EvidenceEntry, g as ExceptionEntry, h as WorkProductStatus, c as WorkProductPersistedPart } from '../types-DeEOhQbv.js';
2
- export { A as AgentCheckInput, i as EvidenceLocator, j as EvidenceSpan, k as ExceptionSeverity, P as ProfileBacktestSummary, l as QuoteBasis, m as WorkProductParseResult, n as WorkProductPatch, W as WorkProductRef, o as WorkProductUpdateGuard, p as WorkProductVersionEntry, q as isWorkProductStatus, r as parseAgentCheckInput, s as parseArtifactInput, t as parseEvidenceInput, u as parseExceptionInput, v as persistedPartToWorkProduct, w as unresolvedBlockingExceptions, x as workProductToPersistedPart } from '../types-DeEOhQbv.js';
1
+ import { a as WorkProductProvenance, d as WorkProductStorePort, e as WorkProductAuditEvent, b as WorkProductRecord, f as WorkProductArtifact, Q as QualityCheck, E as EvidenceEntry, g as ExceptionEntry, h as WorkProductStatus, c as WorkProductPersistedPart } from '../types-DB82fktc.js';
2
+ export { A as AgentCheckInput, i as EvidenceLocator, j as EvidenceSpan, k as ExceptionSeverity, P as ProfileBacktestSummary, l as QuoteBasis, m as WorkProductParseResult, n as WorkProductPatch, W as WorkProductRef, o as WorkProductUpdateGuard, p as WorkProductVersionEntry, q as isWorkProductStatus, r as parseAgentCheckInput, s as parseArtifactInput, t as parseEvidenceInput, u as parseExceptionInput, v as persistedPartToWorkProduct, w as unresolvedBlockingExceptions, x as workProductToPersistedPart } from '../types-DB82fktc.js';
3
3
  import { a as AppToolContext, c as AppToolDefinition } from '../types-BCxK0wyS.js';
4
4
  import { JudgeVerdict } from '@tangle-network/agent-eval';
5
5
  import { T as TrustItem } from '../trust-gate-Dcm5xSva.js';
6
- export { R as ReviewQueueInputs, a as ReviewQueueItem, b as ReviewQueuePendingAsk, c as ReviewQueueState, d as ReviewQueueThread, p as parseReviewQueueItem, e as projectReviewQueue } from '../queue-DBkulxW1.js';
6
+ export { R as ReviewQueueInputs, a as ReviewQueueItem, b as ReviewQueuePendingAsk, c as ReviewQueueState, d as ReviewQueueThread, p as parseReviewQueueItem, e as projectReviewQueue } from '../queue-vRI0Qx3X.js';
7
7
 
8
8
  /**
9
9
  * The guarded work-product status machine — the `/missions` service PATTERN
@@ -353,6 +353,53 @@ type SourceSpanResult = {
353
353
  ok: false;
354
354
  failure: SourceSpanFailure;
355
355
  };
356
+ /**
357
+ * Locate the line containing `value` and return it as a span — the citation
358
+ * form for a model that cannot count characters.
359
+ *
360
+ * Measured on production (tax session 135b7cc3, gpt-4.1-mini): given the
361
+ * document text and told exactly which line to cite, the model produced
362
+ * offsets that landed on the WRONG line four times out of four, then missed
363
+ * again on a second attempt after being shown the text its offsets had
364
+ * selected. Character arithmetic is not something this model class does.
365
+ *
366
+ * What it DOES do reliably is read the value: all four `claim` fields in that
367
+ * same run were correct to the cent. So the model names the value it read and
368
+ * the PLATFORM finds it. Both failure modes close at once —
369
+ *
370
+ * - the quote cannot be invented, because the platform slices it;
371
+ * - the span cannot be mis-addressed, because the platform computed it from
372
+ * a needle it PROVED occurs in the text.
373
+ *
374
+ * A needle that is not in the document is refused, which is the same fail-loud
375
+ * posture as a quote that does not occur — and correctly so: the model is
376
+ * asserting the document says something it does not.
377
+ *
378
+ * The cited span is the whole LINE, not the needle: "128,450.00" alone is not
379
+ * a click target a reviewer can judge, whereas the line it sits on says what
380
+ * the number IS. Number-only needles are common and deliberately supported.
381
+ */
382
+ type SourceFindFailure = {
383
+ reason: 'blank_needle';
384
+ } | {
385
+ reason: 'not_found';
386
+ } | {
387
+ reason: 'occurrence_out_of_range';
388
+ found: number;
389
+ };
390
+ type SourceFindResult = {
391
+ ok: true;
392
+ span: {
393
+ start: number;
394
+ end: number;
395
+ };
396
+ quote: string;
397
+ occurrences: number;
398
+ } | {
399
+ ok: false;
400
+ failure: SourceFindFailure;
401
+ };
402
+ declare function findSourceLine(sourceText: string, needle: string, occurrence?: number): SourceFindResult;
356
403
  /** Resolve `[start, end)` against `sourceText`. Every rejection is a caller
357
404
  * mistake the model can correct from the paged read it already has, so each
358
405
  * carries the discriminator a tool layer turns into a specific message. */
@@ -450,4 +497,4 @@ interface WorkProductRoutes {
450
497
  /** Create the work-product review endpoints over the store port and product seams */
451
498
  declare function createWorkProductRoutes(options: WorkProductRoutesOptions): WorkProductRoutes;
452
499
 
453
- export { type CreateWorkProductInput, EVIDENCE_COVERAGE_CHECK, EvidenceEntry, ExceptionEntry, type FinalizeWorkProductProvenanceInput, type InMemoryWorkProductStore, MAX_WORK_PRODUCT_BATCH, QUOTE_VERIFICATION_CHECK, QualityCheck, type SourceSpanFailure, type SourceSpanResult, type SubmitWorkProductInput, TrustItem, WorkProductArtifact, WorkProductAuditEvent, type WorkProductAuthorizeArgs, type WorkProductOutcome, WorkProductPersistedPart, WorkProductProvenance, type WorkProductProvenanceBase, WorkProductRecord, type WorkProductRouteAuthorization, type WorkProductRoutes, type WorkProductRoutesOptions, type WorkProductService, type WorkProductServiceOptions, WorkProductStatus, WorkProductStorePort, type WorkProductToolConfig, type WorkProductVerdictBody, type WorkProductVerdictInput, buildWorkProductTools, canTransitionWorkProduct, createInMemoryWorkProductStore, createWorkProductRoutes, createWorkProductService, finalizeWorkProductProvenance, isWorkProductTerminal, normalizeQuoteText, sliceSourceSpan, sourceContainsQuote, stampProvenance, validateWorkProductVerdictBody, workProductTrustInputs };
500
+ export { type CreateWorkProductInput, EVIDENCE_COVERAGE_CHECK, EvidenceEntry, ExceptionEntry, type FinalizeWorkProductProvenanceInput, type InMemoryWorkProductStore, MAX_WORK_PRODUCT_BATCH, QUOTE_VERIFICATION_CHECK, QualityCheck, type SourceFindFailure, type SourceFindResult, type SourceSpanFailure, type SourceSpanResult, type SubmitWorkProductInput, TrustItem, WorkProductArtifact, WorkProductAuditEvent, type WorkProductAuthorizeArgs, type WorkProductOutcome, WorkProductPersistedPart, WorkProductProvenance, type WorkProductProvenanceBase, WorkProductRecord, type WorkProductRouteAuthorization, type WorkProductRoutes, type WorkProductRoutesOptions, type WorkProductService, type WorkProductServiceOptions, WorkProductStatus, WorkProductStorePort, type WorkProductToolConfig, type WorkProductVerdictBody, type WorkProductVerdictInput, buildWorkProductTools, canTransitionWorkProduct, createInMemoryWorkProductStore, createWorkProductRoutes, createWorkProductService, finalizeWorkProductProvenance, findSourceLine, isWorkProductTerminal, normalizeQuoteText, sliceSourceSpan, sourceContainsQuote, stampProvenance, validateWorkProductVerdictBody, workProductTrustInputs };