@tangle-network/agent-app 0.43.47 → 0.43.49

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 (57) hide show
  1. package/dist/assistant/index.d.ts +3 -2
  2. package/dist/assistant/index.js +4 -3
  3. package/dist/assistant/index.js.map +1 -1
  4. package/dist/chat-routes/index.d.ts +394 -4
  5. package/dist/chat-routes/index.js +510 -12
  6. package/dist/chat-routes/index.js.map +1 -1
  7. package/dist/chat-store/index.d.ts +3 -2
  8. package/dist/chat-store/index.js +19 -1
  9. package/dist/chat-store/index.js.map +1 -1
  10. package/dist/chunk-23LUHHHN.js +282 -0
  11. package/dist/chunk-23LUHHHN.js.map +1 -0
  12. package/dist/{chunk-UHXQ3KNX.js → chunk-54GSK2KK.js} +4 -4
  13. package/dist/{chunk-4AUQIAYU.js → chunk-5MG74GVQ.js} +2 -281
  14. package/dist/chunk-5MG74GVQ.js.map +1 -0
  15. package/dist/{chunk-5RJNEEO2.js → chunk-HRJJH3RX.js} +2 -2
  16. package/dist/{chunk-6E2XJSCT.js → chunk-JGYOYY5D.js} +65 -2
  17. package/dist/chunk-JGYOYY5D.js.map +1 -0
  18. package/dist/{chunk-E7QYOOON.js → chunk-MCJSS6SM.js} +2 -1
  19. package/dist/chunk-MCJSS6SM.js.map +1 -0
  20. package/dist/chunk-NBSBRZ6F.js +337 -0
  21. package/dist/chunk-NBSBRZ6F.js.map +1 -0
  22. package/dist/{chunk-7VMUOD3G.js → chunk-O6H2WD3I.js} +2 -2
  23. package/dist/chunk-O6H2WD3I.js.map +1 -0
  24. package/dist/{file-index-Bn6sitKb.d.ts → file-index-b26ee-_R.d.ts} +1 -1
  25. package/dist/harness/index.d.ts +1 -1
  26. package/dist/harness/index.js +1 -1
  27. package/dist/index.d.ts +3 -2
  28. package/dist/index.js +119 -103
  29. package/dist/{parts-1_3y2JmR.d.ts → parts-IB-Kbb7z.d.ts} +146 -2
  30. package/dist/preset-cloudflare/index.js +2 -2
  31. package/dist/profile/index.d.ts +13 -2
  32. package/dist/profile/index.js +25 -4
  33. package/dist/profile/index.js.map +1 -1
  34. package/dist/prompt/index.d.ts +2 -1
  35. package/dist/prompt/index.js.map +1 -1
  36. package/dist/run/index.js +1 -1
  37. package/dist/sandbox/index.d.ts +1 -1
  38. package/dist/sandbox/index.js +2 -2
  39. package/dist/skills/index.d.ts +183 -8
  40. package/dist/skills/index.js +21 -3
  41. package/dist/skills-placement/index.d.ts +52 -0
  42. package/dist/skills-placement/index.js +44 -0
  43. package/dist/skills-placement/index.js.map +1 -0
  44. package/dist/stream/index.d.ts +4 -47
  45. package/dist/stream/index.js +14 -12
  46. package/dist/stream-normalizer-DWvtmY6F.d.ts +48 -0
  47. package/dist/web-react/index.d.ts +4 -3
  48. package/dist/web-react/index.js +25 -3
  49. package/package.json +12 -2
  50. package/dist/chunk-4AUQIAYU.js.map +0 -1
  51. package/dist/chunk-6E2XJSCT.js.map +0 -1
  52. package/dist/chunk-7VMUOD3G.js.map +0 -1
  53. package/dist/chunk-E7QYOOON.js.map +0 -1
  54. package/dist/chunk-KOG473C4.js +0 -132
  55. package/dist/chunk-KOG473C4.js.map +0 -1
  56. /package/dist/{chunk-UHXQ3KNX.js.map → chunk-54GSK2KK.js.map} +0 -0
  57. /package/dist/{chunk-5RJNEEO2.js.map → chunk-HRJJH3RX.js.map} +0 -0
@@ -1,14 +1,21 @@
1
- import { A as ChatTurnRequestPayload, B as ChatTurnPartInput, e as ChatMessagePart, D as ChatTurnFilePartInput } from '../parts-1_3y2JmR.js';
2
- export { c as ChatMentionKind, E as ChatTurnInputError, G as ChatTurnTextPartInput, F as FileMention, H as FileMentionsToPartsOptions, I as INLINE_PARTS_MAX_BYTES, M as MENTION_MAX_COUNT, J as SandboxMentionPathCheck, K as assertPromptPartsWithinCap, L as buildMentionPromptBlock, N as chatTurnRequestInit, O as fileMentionsToParts, P as mediaTypeForMentionPath, Q as mentionKindForPath, R as parseChatTurnParts, T as parseFileMentions, U as promptPartsByteSize, V as validateSandboxMentionPath } from '../parts-1_3y2JmR.js';
1
+ import { L as ChatTurnRequestPayload, M as ChatTurnPartInput, g as ChatMessagePart, N as ChatTurnFilePartInput, a as ChatAttachmentPart, f as ChatMentionPart, C as ChatAttachmentKind } from '../parts-IB-Kbb7z.js';
2
+ export { O as ChatAttachmentInput, e as ChatMentionKind, P as ChatTurnInputError, Q as ChatTurnTextPartInput, R as DISPATCH_MAX_MEDIA_PARTS, T as DISPATCH_MAX_PARTS, U as DISPATCH_REQUEST_MAX_BYTES, V as DISPATCH_STRUCTURAL_RESERVE_BYTES, K as FileMention, W as FileMentionsToPartsOptions, X as INLINE_PARTS_MAX_BYTES, Y as MENTION_MAX_COUNT, Z as SandboxMentionPathCheck, _ as assertPromptPartsWithinCap, $ as base64WireLen, a0 as buildMentionPromptBlock, a1 as chatTurnRequestInit, a2 as fileMentionsToParts, a3 as formatBytes, a4 as mediaTypeForMentionPath, a5 as mentionKindForPath, a6 as parseChatTurnParts, a7 as parseFileMentions, a8 as promptPartsByteSize, a9 as validateSandboxMentionPath } from '../parts-IB-Kbb7z.js';
3
3
  import { ChatTurnIdentity, ChatTurnProducer } from '@tangle-network/agent-runtime';
4
4
  import { InteractionAnswerRoute, InteractionAnswerRouteOptions } from '../interactions/index.js';
5
5
  import { PersistedChatMessageForTurn } from '../stream/index.js';
6
6
  import { d as TurnEventStore } from '../turn-buffer-C9mEgoop.js';
7
7
  export { D as DEFAULT_STALE_TURN_LOCK_GRACE_MS, a as DEFAULT_TERMINAL_TURN_LOCK_GRACE_MS, R as ReconcileStaleTurnLockOptions, b as ReconcileStaleTurnLockResult, S as StaleTurnLockSandboxProbeResult, c as StaleTurnLockSessionProbeResult, r as reconcileStaleTurnLock } from '../stale-turn-lock-C8Na1cFZ.js';
8
- export { C as CreateSandboxFileIndexRouteOptions, F as FileIndexAuthorization, a as FileIndexCache, b as FileIndexReadyResponse, c as FileIndexResponse, d as FileIndexWarmingResponse, S as SandboxFileTreeSource, e as SandboxTreeFile, f as SandboxTreeResult, g as createSandboxFileIndexRoute } from '../file-index-Bn6sitKb.js';
8
+ import { J as JsonRecord } from '../stream-normalizer-DWvtmY6F.js';
9
+ export { C as CreateSandboxFileIndexRouteOptions, F as FileIndexAuthorization, a as FileIndexCache, b as FileIndexReadyResponse, c as FileIndexResponse, d as FileIndexWarmingResponse, S as SandboxFileTreeSource, e as SandboxTreeFile, f as SandboxTreeResult, g as createSandboxFileIndexRoute } from '../file-index-b26ee-_R.js';
10
+ import { SandboxExecChannel, PromptInputPart } from '../sandbox/index.js';
9
11
  import '@tangle-network/agent-interface';
10
12
  import '../contract-KfqJh_au.js';
11
13
  import '../plans/index.js';
14
+ import '@tangle-network/sandbox';
15
+ import '../auth-DuptSkWh.js';
16
+ import '../types-BEOvc_ue.js';
17
+ import '../harness/index.js';
18
+ import '../model-dF2h4xT9.js';
12
19
 
13
20
  /**
14
21
  * `createChatTurnRoutes` — the assembled server chat vertical (issue #188
@@ -338,6 +345,30 @@ declare function createChatTurnRoutes<TContext = void>(options: CreateChatTurnRo
338
345
  * `step-finish` parts. `createChatTurnRoutes` reads both after drain.
339
346
  */
340
347
 
348
+ /** Outcome of a `promoteFilePart` attempt. `key`, when given, becomes the
349
+ * persisted part's row key (e.g. `attachment:<path>`) so repeat promotions
350
+ * of the same underlying file fold into one segment instead of appending;
351
+ * omitted, the default `getPartKey` keying applies.
352
+ *
353
+ * On failure, `part` is an OPTIONAL substitute part to persist in place of
354
+ * the raw url-bearing one — this is how a product swaps in a transcript
355
+ * notice (gtm persists a `warning` notice part, never the transient url) for
356
+ * a failed promotion instead of baking a `data:`/sandbox-path url into the
357
+ * durable row. When `part` is present it is persisted (via the same
358
+ * `recordPersistedPart` path as a success, honoring the optional `key`);
359
+ * when absent, the existing raw-part fallback applies unchanged — so a
360
+ * caller that only returns `{ succeeded: false, reason }` keeps today's
361
+ * behavior verbatim. */
362
+ type FilePartPromotionOutcome = {
363
+ succeeded: true;
364
+ part: Record<string, unknown>;
365
+ key?: string;
366
+ } | {
367
+ succeeded: false;
368
+ reason: string;
369
+ part?: Record<string, unknown>;
370
+ key?: string;
371
+ };
341
372
  interface SandboxChatProducerOptions {
342
373
  /** The raw sandbox event stream (e.g. `streamSandboxPrompt(...)`). */
343
374
  events: AsyncIterable<unknown>;
@@ -351,6 +382,34 @@ interface SandboxChatProducerOptions {
351
382
  * session's sidecar connection). Without it, non-renderable asks are only
352
383
  * logged — the run stays blocked until the broker times out. */
353
384
  declineInteraction?: (id: string) => Promise<void>;
385
+ /** Opt-in eager promotion of harness-emitted `file` parts. Unset, a `file`
386
+ * part persists exactly as the harness sent it — a transient `url` (a
387
+ * `data:` URI or in-sandbox path) baked into the transcript, which is
388
+ * today's behavior and stays byte-identical if this is never wired. Set,
389
+ * EVERY `file` part (never `image`, never any other kind) is routed
390
+ * through this callback instead of `recordPersistedPart`'s default
391
+ * fallback — including a part with NEITHER `id` NOR `url` (gtm always
392
+ * attempts promotion; such a part simply fails "carries no url" and
393
+ * resolves through the same failure path as any other rejection, rather
394
+ * than being persisted raw and unpromoted) — so the product can durably
395
+ * write the bytes and swap in a path-bearing part before the raw url ever
396
+ * reaches the persisted transcript. Keyed per source-prefixed `id:<id>` /
397
+ * `url:<url>` (an `id` and a `url` sharing the same text must never collide
398
+ * onto one memo entry) and memoized by PROMISE (not result), so re-emitted
399
+ * snapshot events for the same part —
400
+ * the harness resends the whole part on every update, not just deltas —
401
+ * fold onto the one in-flight or settled attempt rather than promoting
402
+ * twice or racing two concurrent writes; a raw part with neither `id` nor
403
+ * `url` cannot be keyed, so it is invoked UN-memoized (once per event) —
404
+ * each occurrence is its own attempt. A rejecting promise is caught,
405
+ * logged via `log`, and treated as `succeeded: false`. On `succeeded:
406
+ * false` the outcome's optional `part` (a substitute — e.g. a warning
407
+ * notice — see {@link FilePartPromotionOutcome}) persists in its place when
408
+ * given; otherwise the raw part persists exactly as it does today — this
409
+ * seam only decides whether to call the promoter and what to do with its
410
+ * outcomes; the promotion mechanics (vault write, key derivation, notice
411
+ * construction) live in the caller's callback, not here. */
412
+ promoteFilePart?: (raw: JsonRecord) => Promise<FilePartPromotionOutcome>;
354
413
  log?: (message: string, meta?: Record<string, unknown>) => void;
355
414
  }
356
415
  declare function createSandboxChatProducer(options: SandboxChatProducerOptions): ChatTurnRouteProducer;
@@ -445,4 +504,335 @@ declare function sanitizeUploadFilename(name: string): string;
445
504
  declare function bytesToBase64(bytes: Uint8Array): string;
446
505
  declare function createUploadRoute(options: CreateUploadRouteOptions): (request: Request) => Promise<Response>;
447
506
 
448
- export { type ChatRouteDurableProjection, type ChatRouteDurableProjectionLogger, type ChatTurnAuthorization, type ChatTurnAuthorizeArgs, ChatTurnFilePartInput, type ChatTurnGateResult, type ChatTurnHeartbeat, type ChatTurnInputPatch, type ChatTurnLifecycle, type ChatTurnLifecycleComplete, type ChatTurnLifecycleError, type ChatTurnLifecycleStart, type ChatTurnLock, type ChatTurnLockResult, type ChatTurnMessageStore, ChatTurnPartInput, type ChatTurnProduceArgs, ChatTurnRequestPayload, type ChatTurnRouteProducer, type ChatTurnRoutes, type ChatTurnUsage, type CreateChatTurnRoutesOptions, type CreateUploadRouteOptions, type SandboxChatProducerOptions, type SandboxUploadSink, UPLOAD_INLINE_MAX_BYTES, UPLOAD_MAX_FILE_BYTES, type UploadAuthorization, type UploadedChatFile, bytesToBase64, createChatTurnRoutes, createSandboxChatProducer, createUploadRoute, sanitizeUploadFilename, withDurableChatProjection };
507
+ /**
508
+ * Storage seams for the chat-attachment vertical (`resolveChatAttachments`,
509
+ * `buildDispatchParts`, `promoteAgentFilePart`). Structural function ports in
510
+ * the same style as `upload.ts`'s `SandboxUploadSink`: REQUIRED injection, no
511
+ * default implementation — agent-app owns the size/budget/idempotency
512
+ * mechanism, the product owns where the bytes actually live.
513
+ *
514
+ * One reader, two callers: `resolveChatAttachments` reads only the
515
+ * authoritative `size` (never trusting the client-reported size), while
516
+ * `buildDispatchParts` reads the inline `content` (base64 or raw bytes) to
517
+ * build a `data:` URI. Both fit behind ONE `ReadAttachmentFn` so a product
518
+ * wires a single vault/object-store adapter, not two. gtm's KV vault (stores
519
+ * base64 bodies) and `/object-store`'s `ObjectStore` (hands back raw bytes)
520
+ * both satisfy this shape.
521
+ */
522
+ /**
523
+ * The result of reading one stored attachment. `ok:true` MUST carry the
524
+ * authoritative decoded byte `size` (the cap is meaningless against a
525
+ * client-controlled number) and, when the caller needs to inline the file,
526
+ * its content as `base64` and/or raw `bytes`. `mediaType` is the stored
527
+ * content type when the store knows it (used as the fallback when the wire
528
+ * part carried none). `ok:false` carries a human `reason` that SHOULD name the
529
+ * offending path — it is surfaced verbatim in the caller's typed outcome.
530
+ */
531
+ type AttachmentReadResult = {
532
+ ok: true;
533
+ /** Authoritative decoded byte length of the stored content. */
534
+ size: number;
535
+ /** Inline content as base64 — reused verbatim for a `data:` URI, so a
536
+ * store holding already-base64 bodies never decodes-and-re-encodes. */
537
+ base64?: string;
538
+ /** Inline content as raw bytes — base64-encoded by the caller when a
539
+ * `data:` URI is needed. Ignored when `base64` is present. */
540
+ bytes?: Uint8Array;
541
+ /** Stored content type, when the store tracks one. */
542
+ mediaType?: string;
543
+ } | {
544
+ ok: false;
545
+ reason: string;
546
+ };
547
+ /**
548
+ * Read one stored attachment for `scopeId` (the product's workspace/tenant
549
+ * key) at its store-relative `path`. Missing, deleted, or unreadable content
550
+ * MUST resolve to `{ ok: false, reason }`, never throw — a store failure is a
551
+ * per-attachment outcome the caller folds into its own typed result, not a
552
+ * turn-level exception.
553
+ */
554
+ type ReadAttachmentFn = (scopeId: string, path: string) => Promise<AttachmentReadResult>;
555
+ /** Outcome of persisting one attachment. Mirrors `AttachmentReadResult`'s
556
+ * `ok`/`reason` shape and `upload.ts`'s `{ ok }` convention. */
557
+ type AttachmentWriteResult = {
558
+ ok: true;
559
+ } | {
560
+ ok: false;
561
+ reason: string;
562
+ };
563
+ /**
564
+ * Persist `content` for `scopeId` at `path`. `content` is either raw `bytes`
565
+ * or a base64 `string` — a string argument is ALWAYS base64 (never utf8), so
566
+ * a store that speaks base64 (gtm's vault) writes it verbatim and one that
567
+ * speaks bytes decodes once. Like the reader, failures resolve to
568
+ * `{ ok: false, reason }` rather than throwing.
569
+ *
570
+ * `opts` mirrors the vault frontmatter gtm's `writeAttachmentVaultFile`
571
+ * persists alongside the body (promote-file-parts.ts:181-190), so a product
572
+ * reimplementing that vault writer through this seam can reproduce it
573
+ * exactly:
574
+ * - `mediaType` — the resolved MIME type; gtm's frontmatter key `mime`.
575
+ * - `name` — the sanitized (store-path-safe) display filename; gtm passes
576
+ * this only to shape its oversize message, not into frontmatter.
577
+ * - `originalName` — the filename as the harness/browser reported it, BEFORE
578
+ * sanitization (`raw.filename ?? filename` — falls back to the sanitized
579
+ * name when the source carried none); gtm's frontmatter key `originalName`.
580
+ * This is the one field with no other recovery path once sanitization has
581
+ * run, so it must ride the write, not be re-derived after the fact.
582
+ * - `size` — the authoritative decoded byte length being written; gtm's
583
+ * frontmatter key `size`.
584
+ */
585
+ type WriteAttachmentFn = (scopeId: string, path: string, content: Uint8Array | string, opts: {
586
+ mediaType?: string;
587
+ name?: string;
588
+ originalName?: string;
589
+ size?: number;
590
+ }) => Promise<AttachmentWriteResult>;
591
+
592
+ /**
593
+ * `resolveChatAttachments` — validate a turn body's `attachments` field into
594
+ * persistable {@link ChatAttachmentPart}s. Every path is re-validated (a path
595
+ * off the wire is never trusted to stay inside the store root) and every size
596
+ * is re-derived from the STORED body via the injected {@link ReadAttachmentFn},
597
+ * never the client-reported `size` — the upload path lets a caller rewrite its
598
+ * own frontmatter, so a stored size cannot bound anything and the wire size can
599
+ * be anything. Both the aggregate cap and the size carried on the returned part
600
+ * come from the authoritative read.
601
+ *
602
+ * Storage-parameterized: the frontmatter parsing / base64 sizing that derives
603
+ * the authoritative size lives BEHIND `readAttachment` (a product's vault or
604
+ * object-store adapter), so this module is a pure validator + budget gate with
605
+ * no store knowledge. Lifted from gtm-agent's `resolve-attachments.ts`
606
+ * (workspaceId → scopeId, the vault read → the injected reader) and kept
607
+ * behavior-identical for gtm-agent#618 adoption.
608
+ */
609
+
610
+ type ResolveChatAttachmentsResult = {
611
+ succeeded: true;
612
+ value: ChatAttachmentPart[];
613
+ } | {
614
+ succeeded: false;
615
+ error: string;
616
+ };
617
+ /** Verdict of a path check: OK, or a rejection naming why. Mirrors
618
+ * `SandboxMentionPathCheck` in `./wire`. */
619
+ type AttachmentPathCheck = {
620
+ succeeded: true;
621
+ } | {
622
+ succeeded: false;
623
+ error: string;
624
+ };
625
+ /** Most files a single request may carry. */
626
+ declare const ATTACHMENT_MAX_COUNT = 10;
627
+ /** Aggregate raw-byte ceiling across one message's attachments. */
628
+ declare const MAX_ATTACHMENT_TOTAL_BYTES: number;
629
+ /** Human-readable error for a message whose combined attachments exceed the
630
+ * aggregate raw-byte ceiling. Ported to match gtm's `attachmentTotalSizeErrorMessage`
631
+ * (attachment-limits.ts:93-95) verbatim, via the shared {@link formatBytes} —
632
+ * e.g. "Attachments total 25MB; each message is limited to 25MB", not raw
633
+ * byte counts. */
634
+ declare function attachmentTotalSizeErrorMessage(totalBytes: number, limitBytes: number): string;
635
+ /**
636
+ * Default path validator when a caller supplies none. Rejects the ways a path
637
+ * picked in a client can escape the store root — traversal (`..` segment),
638
+ * absolute (leading `/`), backslashes, null bytes, control characters (see
639
+ * {@link CONTROL_CHARS} — a path also feeds {@link buildAttachmentPromptBlock}'s
640
+ * `(vault: ${path})` pointer, so it is exposed to the same injection surface as
641
+ * `name`) — plus a dotfile/hidden segment (a leading `.` on any segment).
642
+ * Generalized from gtm's `validateVaultFilePath`, in the spirit of
643
+ * `validateSandboxMentionPath` (`/chat-routes`'s wire mention-path validator) —
644
+ * but the dotfile rejection here is INTENTIONALLY stricter than that sibling:
645
+ * an uploaded attachment path is sanitized store-relative storage the product
646
+ * itself assigned, whereas a mention path points at a file that already exists
647
+ * in the sandbox and may legitimately live under a dotfile segment. A caller
648
+ * that needs gtm's exact (looser) rule can supply `validatePath` to override
649
+ * this default entirely.
650
+ */
651
+ declare function defaultValidateAttachmentPath(path: string): AttachmentPathCheck;
652
+ interface ResolveChatAttachmentsOptions {
653
+ /** The product's workspace/tenant key, passed to `readAttachment`. */
654
+ scopeId: string;
655
+ /** Authoritative size + content reader — see {@link ReadAttachmentFn}. */
656
+ readAttachment: ReadAttachmentFn;
657
+ /** Most attachments one request may carry. Default {@link ATTACHMENT_MAX_COUNT}. */
658
+ maxCount?: number;
659
+ /** Aggregate raw-byte ceiling. Default {@link MAX_ATTACHMENT_TOTAL_BYTES}. */
660
+ maxTotalBytes?: number;
661
+ /** Path validator override. Default {@link defaultValidateAttachmentPath}. */
662
+ validatePath?: (path: string) => AttachmentPathCheck;
663
+ }
664
+ /**
665
+ * Validate and resolve a turn body's `attachments` field into persistable
666
+ * parts. Every path is confirmed present (and not deleted) in the caller's own
667
+ * store by `readAttachment` before it is trusted, and size is derived from the
668
+ * authoritative read for both the aggregate cap and the returned part's size.
669
+ */
670
+ declare function resolveChatAttachments(value: unknown, options: ResolveChatAttachmentsOptions): Promise<ResolveChatAttachmentsResult>;
671
+
672
+ /**
673
+ * `buildDispatchParts` — assemble the `PromptInputPart[]` a turn carrying
674
+ * attachments and/or `@`-mentions dispatches to the sandbox. `parts[0]` is
675
+ * always the full prompt text (typed text plus the attachment + mention pointer
676
+ * blocks); each attachment or mention becomes one media part. An attachment
677
+ * (read from the product store via the injected reader) draws the inline byte
678
+ * budget first; a mention (read from the LIVE box) takes what is left. A file
679
+ * inlines as a `data:` URI when it fits the remaining budget, otherwise demotes
680
+ * to an in-box path part so the whole request stays under the proxy cap. Every
681
+ * media part is deduped by its resolved absolute path. This module only
682
+ * produces the parts array; the caller decides when a turn dispatches parts
683
+ * instead of a plain string.
684
+ *
685
+ * Storage-parameterized port of gtm-agent's `dispatch-parts.ts`: the vault
686
+ * default reader is dropped (`readAttachment` is REQUIRED — the product supplies
687
+ * its store adapter), the `GTM_SANDBOX_VAULT_DIR` prefixing becomes the required
688
+ * `resolveAttachmentPath` seam, the `GTM_MULTIMODAL_FORCE_PATH` env fallback
689
+ * becomes an explicit `forcePath` flag, and every budget cap reads an overridable
690
+ * `./wire` constant. Kept behavior-identical for gtm-agent#618 adoption (the
691
+ * demotion math and emitted part shapes reproduce its dispatched prompt bytes).
692
+ */
693
+
694
+ type DispatchPartsOutcome = {
695
+ succeeded: true;
696
+ value: PromptInputPart[];
697
+ } | {
698
+ succeeded: false;
699
+ error: string;
700
+ };
701
+ /** One mention file's size (always) and inline bytes (only when the caller
702
+ * asked for them — a path-only mention never reads its bytes). */
703
+ type SandboxMentionReadOutcome = {
704
+ succeeded: true;
705
+ value: {
706
+ size: number;
707
+ base64?: string;
708
+ };
709
+ } | {
710
+ succeeded: false;
711
+ error: string;
712
+ };
713
+ type ReadSandboxMentionFn = (box: SandboxExecChannel, absolutePath: string, options: {
714
+ readBytes: boolean;
715
+ }) => Promise<SandboxMentionReadOutcome>;
716
+ interface BuildDispatchPartsInput {
717
+ text: string;
718
+ attachments: ChatAttachmentPart[];
719
+ mentions?: ChatMentionPart[];
720
+ history: Array<{
721
+ role: 'user' | 'assistant';
722
+ content: string;
723
+ }>;
724
+ systemPrompt: string;
725
+ /** Serialized size of the backend profile the SDK inlines into the same
726
+ * prompt request body — a large, non-negotiable rider that must come out of
727
+ * the inline budget or near-cap attachments 413 at the proxy instead of
728
+ * demoting to path parts. */
729
+ profileWireBytes: number;
730
+ /** The product's workspace/tenant key, passed to `readAttachment`. */
731
+ scopeId: string;
732
+ /** Maps an attachment's store-relative path to the in-box absolute path a
733
+ * path-based part references (same seam style as `fileMentionsToParts`'s
734
+ * `resolvePath`). */
735
+ resolveAttachmentPath: (path: string) => string;
736
+ /** Maps a mention's workspace-relative path to its in-box absolute path.
737
+ * Default: {@link BuildDispatchPartsInput.resolveAttachmentPath} — in gtm the
738
+ * vault mount roots both; a product that mounts them apart overrides this. */
739
+ resolveMentionPath?: (path: string) => string;
740
+ /** The turn's already-ensured box — required when `mentions` is non-empty
741
+ * (mention bytes are read from the live box, not the store). */
742
+ box?: SandboxExecChannel;
743
+ /** Force every media part to a path reference, skipping all inlining. */
744
+ forcePath?: boolean;
745
+ /** REQUIRED store reader for attachment content — no default (the product
746
+ * owns its store; see {@link ReadAttachmentFn}). */
747
+ readAttachment: ReadAttachmentFn;
748
+ readSandboxMention?: ReadSandboxMentionFn;
749
+ /** Whole-request proxy cap. Default {@link DISPATCH_REQUEST_MAX_BYTES}. */
750
+ requestMaxBytes?: number;
751
+ /** JSON-envelope reserve off the top of the request cap. Default
752
+ * {@link DISPATCH_STRUCTURAL_RESERVE_BYTES}. */
753
+ structuralReserveBytes?: number;
754
+ /** Sidecar per-request parts-array cap. Default {@link DISPATCH_MAX_PARTS}. */
755
+ maxParts?: number;
756
+ }
757
+ declare function buildDispatchParts(input: BuildDispatchPartsInput): Promise<DispatchPartsOutcome>;
758
+
759
+ /**
760
+ * `promoteAgentFilePart` — turn a harness-emitted `type:"file"` stream part
761
+ * into a store-backed {@link ChatAttachmentPart}. The harness hands back a URL
762
+ * pointing at bytes it produced (a `data:` URI, or a path inside the sandbox);
763
+ * nothing durable survives past the turn unless it is written into the
764
+ * product's store, the same way a user upload is. Typed outcomes throughout:
765
+ * every failure mode (unsupported scheme, no sandbox, oversize, store-write
766
+ * failure, malformed part) resolves to `{ succeeded: false, filename, reason }`
767
+ * rather than throwing past this boundary, so the caller folds a visible notice
768
+ * instead of losing the file silently.
769
+ *
770
+ * Storage-parameterized port of gtm-agent's `promote-file-parts.ts` with the
771
+ * refactor gtm never made: persistence goes through the injected
772
+ * {@link WriteAttachmentFn} (gtm hard-wired its vault writer), the path strategy
773
+ * is the injected `buildAttachmentPath` (neutral `uploads/agent/<date>/` default,
774
+ * no domain bucket taxonomy baked), the MIME map is an injectable hook, and the
775
+ * date segment reads an injectable clock. The idempotent `hash8(id ?? url ??
776
+ * filename)` naming is preserved so re-promoting the same source part resolves
777
+ * to the same path.
778
+ */
779
+
780
+ /** Default ceiling on a promoted file's raw (pre-encoding) byte size. */
781
+ declare const PROMOTE_MAX_FILE_BYTES: number;
782
+ interface RawAgentFilePart {
783
+ type: 'file';
784
+ id?: string;
785
+ filename?: string;
786
+ /** AI-SDK-shaped parts carry the MIME type here… */
787
+ mediaType?: string;
788
+ /** …but OpenCode's native FilePart calls the same field `mime`. */
789
+ mime?: string;
790
+ url?: string;
791
+ }
792
+ type PromoteFilePartResult = {
793
+ succeeded: true;
794
+ part: ChatAttachmentPart;
795
+ } | {
796
+ succeeded: false;
797
+ filename: string;
798
+ reason: string;
799
+ };
800
+ /** Arguments handed to a {@link PromoteAgentFilePartOptions.buildAttachmentPath}
801
+ * override — everything needed to place the file deterministically. */
802
+ interface AttachmentPathArgs {
803
+ /** Sanitized display filename (basename, safe charset). */
804
+ filename: string;
805
+ /** First 8 hex chars of the SHA-256 idempotency digest. */
806
+ hash8: string;
807
+ /** `YYYY-MM-DD` from the injected clock. */
808
+ date: string;
809
+ /** Resolved media type. */
810
+ mediaType: string;
811
+ /** `image`/`file` split of the media type. */
812
+ kind: ChatAttachmentKind;
813
+ }
814
+ /** Default MIME hook: extension → mime, or `text/plain` for the unknown. */
815
+ declare function sniffMimeFromName(filename: string): string;
816
+ interface PromoteAgentFilePartOptions {
817
+ raw: RawAgentFilePart;
818
+ /** The turn's box — required only to promote a sandbox-path part; a `data:`
819
+ * URI needs none. */
820
+ box?: SandboxExecChannel;
821
+ /** The product's workspace/tenant key, passed to `writeAttachment`. */
822
+ scopeId: string;
823
+ /** The turn's session id, used for the sandbox stat/read exec calls. */
824
+ sessionId: string;
825
+ /** REQUIRED store writer — no default (the product owns its store). */
826
+ writeAttachment: WriteAttachmentFn;
827
+ /** Store-path strategy. Default {@link defaultBuildAttachmentPath}. */
828
+ buildAttachmentPath?: (args: AttachmentPathArgs) => string;
829
+ /** Raw-byte ceiling. Default {@link PROMOTE_MAX_FILE_BYTES}. */
830
+ maxBytes?: number;
831
+ /** Last-resort media-type hook. Default {@link sniffMimeFromName}. */
832
+ sniffMime?: (filename: string) => string;
833
+ /** Clock for the date path segment. Default `() => new Date()`. */
834
+ now?: () => Date;
835
+ }
836
+ declare function promoteAgentFilePart(options: PromoteAgentFilePartOptions): Promise<PromoteFilePartResult>;
837
+
838
+ export { ATTACHMENT_MAX_COUNT, type AttachmentPathArgs, type AttachmentPathCheck, type AttachmentReadResult, type AttachmentWriteResult, type BuildDispatchPartsInput, ChatAttachmentKind, type ChatRouteDurableProjection, type ChatRouteDurableProjectionLogger, type ChatTurnAuthorization, type ChatTurnAuthorizeArgs, ChatTurnFilePartInput, type ChatTurnGateResult, type ChatTurnHeartbeat, type ChatTurnInputPatch, type ChatTurnLifecycle, type ChatTurnLifecycleComplete, type ChatTurnLifecycleError, type ChatTurnLifecycleStart, type ChatTurnLock, type ChatTurnLockResult, type ChatTurnMessageStore, ChatTurnPartInput, type ChatTurnProduceArgs, ChatTurnRequestPayload, type ChatTurnRouteProducer, type ChatTurnRoutes, type ChatTurnUsage, type CreateChatTurnRoutesOptions, type CreateUploadRouteOptions, type DispatchPartsOutcome, type FilePartPromotionOutcome, MAX_ATTACHMENT_TOTAL_BYTES, PROMOTE_MAX_FILE_BYTES, type PromoteAgentFilePartOptions, type PromoteFilePartResult, PromptInputPart, type RawAgentFilePart, type ReadAttachmentFn, type ReadSandboxMentionFn, type ResolveChatAttachmentsOptions, type ResolveChatAttachmentsResult, type SandboxChatProducerOptions, type SandboxUploadSink, UPLOAD_INLINE_MAX_BYTES, UPLOAD_MAX_FILE_BYTES, type UploadAuthorization, type UploadedChatFile, type WriteAttachmentFn, attachmentTotalSizeErrorMessage, buildDispatchParts, bytesToBase64, createChatTurnRoutes, createSandboxChatProducer, createUploadRoute, defaultValidateAttachmentPath, promoteAgentFilePart, resolveChatAttachments, sanitizeUploadFilename, sniffMimeFromName, withDurableChatProjection };