@tangle-network/agent-app 0.44.49 → 0.44.51

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.
@@ -3,9 +3,9 @@ import {
3
3
  ChatMessages,
4
4
  ModelPicker,
5
5
  ProviderLogo
6
- } from "../chunk-D3GK2IPA.js";
6
+ } from "../chunk-WXWU2FEB.js";
7
7
  import "../chunk-FBVLEGEG.js";
8
- import "../chunk-YOSSGDIG.js";
8
+ import "../chunk-GINKOZFD.js";
9
9
  import "../chunk-YTMKRL3L.js";
10
10
  import "../chunk-GEYACSFW.js";
11
11
  import "../chunk-6MUJROBT.js";
@@ -68,6 +68,11 @@ interface DraftStoredMessage {
68
68
  role: 'user' | 'assistant' | 'system' | 'tool';
69
69
  content: string;
70
70
  parts?: ChatMessagePart[] | null;
71
+ model?: string | null;
72
+ requestedModel?: string | null;
73
+ servedModel?: string | null;
74
+ servedProvider?: string | null;
75
+ servedSource?: string | null;
71
76
  }
72
77
  /** Values written to the assistant row — the intersection of the append and
73
78
  * patch shapes, so one snapshot serves both. */
@@ -75,6 +80,10 @@ interface AssistantRowValues {
75
80
  content: string;
76
81
  parts?: ChatMessagePart[];
77
82
  model?: string | null;
83
+ requestedModel?: string | null;
84
+ servedModel?: string | null;
85
+ servedProvider?: string | null;
86
+ servedSource?: string | null;
78
87
  inputTokens?: number | null;
79
88
  outputTokens?: number | null;
80
89
  reasoningTokens?: number | null;
@@ -281,6 +290,10 @@ interface ChatTurnMessageStore {
281
290
  content: string;
282
291
  parts?: ChatMessagePart[];
283
292
  model?: string | null;
293
+ requestedModel?: string | null;
294
+ servedModel?: string | null;
295
+ servedProvider?: string | null;
296
+ servedSource?: string | null;
284
297
  inputTokens?: number | null;
285
298
  outputTokens?: number | null;
286
299
  reasoningTokens?: number | null;
@@ -295,6 +308,10 @@ interface ChatTurnMessageStore {
295
308
  content?: string;
296
309
  parts?: ChatMessagePart[];
297
310
  model?: string | null;
311
+ requestedModel?: string | null;
312
+ servedModel?: string | null;
313
+ servedProvider?: string | null;
314
+ servedSource?: string | null;
298
315
  inputTokens?: number | null;
299
316
  outputTokens?: number | null;
300
317
  reasoningTokens?: number | null;
@@ -325,6 +342,9 @@ interface ChatTurnRouteProducer extends ChatTurnProducer {
325
342
  /** Model-failover attribution, when the producer supports it. Reported onto
326
343
  * the usage/billing receipt so a downgrade is never silent. */
327
344
  modelFailover?(): ChatTurnModelFailover;
345
+ /** Requested-versus-served attribution reported by the sandbox sidecar.
346
+ * `echoReceived` distinguishes a missing echo from a partial echo. */
347
+ modelAttribution?(): ChatTurnModelAttribution;
328
348
  }
329
349
  /** Which model served, and what it took to get there. */
330
350
  interface ChatTurnModelFailover {
@@ -335,6 +355,19 @@ interface ChatTurnModelFailover {
335
355
  /** True when the preferred model did not serve. */
336
356
  usedFallback: boolean;
337
357
  }
358
+ /** Requested and effective model attribution for one sandbox turn. */
359
+ interface ChatTurnModelAttribution {
360
+ /** The model explicitly requested by the caller, before shell failover. */
361
+ requestedModel?: string;
362
+ /** The model the downstream sandbox reports actually served the turn. */
363
+ servedModel?: string;
364
+ /** The provider that served the turn, when echoed by the sandbox. */
365
+ servedProvider?: string;
366
+ /** How the sandbox selected the served model. */
367
+ servedSource?: 'request' | 'environment' | 'profile';
368
+ /** True when a structurally valid effective-backend echo was observed. */
369
+ echoReceived: boolean;
370
+ }
338
371
  /** Resolve authorization status and context for a chat turn including tenant and user identification */
339
372
  type ChatTurnAuthorization<TContext> = {
340
373
  ok: true;
@@ -475,6 +508,12 @@ interface ChatTurnLifecycleComplete<TContext> extends ChatTurnLifecycleBase<TCon
475
508
  * `usage` is that model's, so telemetry that splits cost or quality by model
476
509
  * must key on this and not on the requested one. */
477
510
  model?: string;
511
+ /** Requested-versus-served attribution. A difference is detectable from
512
+ * this receipt and from the persisted assistant row independently. */
513
+ requestedModel?: string;
514
+ servedModel?: string;
515
+ servedProvider?: string;
516
+ servedSource?: 'request' | 'environment' | 'profile';
478
517
  /** Attribution for a downgrade: which models were tried and why each failed.
479
518
  * `undefined` when the producer reports no failover support. */
480
519
  modelFailover?: ChatTurnModelFailover;
@@ -520,6 +559,12 @@ interface ChatTurnCompleteInput<TContext> {
520
559
  * the requested one, so a product that bills or scores per model MUST read
521
560
  * it here rather than assuming the model it asked for. */
522
561
  model?: string;
562
+ /** Requested-versus-served attribution. A difference is detectable from
563
+ * this receipt and from the persisted assistant row independently. */
564
+ requestedModel?: string;
565
+ servedModel?: string;
566
+ servedProvider?: string;
567
+ servedSource?: 'request' | 'environment' | 'profile';
523
568
  /** Present when the producer supports failover: the full attempt trail, and
524
569
  * `usedFallback` — the flag that makes a silent downgrade impossible. */
525
570
  modelFailover?: ChatTurnModelFailover;
@@ -1162,6 +1207,14 @@ interface DetachedTurnResult {
1162
1207
  * A caller that bills or scores per model must read this, not the model it
1163
1208
  * requested. */
1164
1209
  model?: string;
1210
+ /** The caller's explicit model request, before shell failover. */
1211
+ requestedModel?: string;
1212
+ /** The effective model echoed by the downstream sandbox. */
1213
+ servedModel?: string;
1214
+ /** The effective provider echoed by the downstream sandbox. */
1215
+ servedProvider?: string;
1216
+ /** How the downstream sandbox selected the effective model. */
1217
+ servedSource?: 'request' | 'environment' | 'profile';
1165
1218
  /** True when the preferred model did not serve. Makes an autonomous
1166
1219
  * downgrade — which no human watched happen — attributable after the fact. */
1167
1220
  usedModelFallback?: boolean;
@@ -1702,4 +1755,4 @@ interface PromoteAgentFilePartOptions {
1702
1755
  /** Promote a part of an agent file with optional byte limits and MIME type detection */
1703
1756
  declare function promoteAgentFilePart(options: PromoteAgentFilePartOptions): Promise<PromoteFilePartResult>;
1704
1757
 
1705
- export { type AssistantDraftSnapshot, type AssistantDraftStore, type AssistantDraftWriter, type AssistantDraftWriterOptions, type AssistantRowValues, type AttachmentPathArgs, type AttachmentPathCheck, type AttachmentReadResult, type AttachmentUploadAuthorization, type AttachmentWriteResult, type BuildDispatchPartsInput, ChatAttachmentKind, type ChatRouteDurableProjection, type ChatRouteDurableProjectionLogger, type ChatRouteEvent, type ChatTurnAuthorization, type ChatTurnAuthorizeArgs, type ChatTurnCompleteInput, ChatTurnFilePartInput, type ChatTurnGateResult, type ChatTurnHeartbeat, type ChatTurnInputPatch, type ChatTurnLifecycle, type ChatTurnLifecycleComplete, type ChatTurnLifecycleError, type ChatTurnLifecycleStart, type ChatTurnLock, type ChatTurnLockResult, type ChatTurnMessageStore, type ChatTurnModelFailover, ChatTurnPartInput, type ChatTurnProduceArgs, ChatTurnRequestPayload, type ChatTurnRouteProducer, type ChatTurnRoutes, type ChatTurnUsage, type CreateAttachmentUploadRouteOptions, type CreateChatTurnRoutesOptions, type CreateUploadRouteOptions, type DetachedTurnFinal, type DetachedTurnOptions, type DetachedTurnParts, type DetachedTurnResult, type DispatchPartsOutcome, type DraftPersistenceTuning, type DraftStoredMessage, type EmptyTurnRetryInfo, type FilePartPromotionOutcome, MAX_EMPTY_TURN_RETRIES, type ModelFailoverStreamHandle, type ModelFailoverStreamOptions, type ModelFallbackInfo, type OpenModelStream, 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, assistantRowIdForTurn, buildDispatchParts, bytesToBase64, classifyTerminalFailure, createAssistantDraftWriter, createAttachmentUploadRoute, createChatTurnRoutes, createSandboxChatProducer, createUploadRoute, defaultValidateAttachmentPath, isCommittingSandboxEvent, isDraftContentEvent, normalizeChatPromptForSandbox, promoteAgentFilePart, resolveChatAttachments, resolveEmptyTurnRetries, rowIdOf, runDetachedTurn, sanitizeUploadFilename, sniffMimeFromName, storeSupportsDraftPersistence, streamWithModelFailover, summarizeFailoverReason, withDurableChatProjection };
1758
+ export { type AssistantDraftSnapshot, type AssistantDraftStore, type AssistantDraftWriter, type AssistantDraftWriterOptions, type AssistantRowValues, type AttachmentPathArgs, type AttachmentPathCheck, type AttachmentReadResult, type AttachmentUploadAuthorization, type AttachmentWriteResult, type BuildDispatchPartsInput, ChatAttachmentKind, type ChatRouteDurableProjection, type ChatRouteDurableProjectionLogger, type ChatRouteEvent, type ChatTurnAuthorization, type ChatTurnAuthorizeArgs, type ChatTurnCompleteInput, ChatTurnFilePartInput, type ChatTurnGateResult, type ChatTurnHeartbeat, type ChatTurnInputPatch, type ChatTurnLifecycle, type ChatTurnLifecycleComplete, type ChatTurnLifecycleError, type ChatTurnLifecycleStart, type ChatTurnLock, type ChatTurnLockResult, type ChatTurnMessageStore, type ChatTurnModelAttribution, type ChatTurnModelFailover, ChatTurnPartInput, type ChatTurnProduceArgs, ChatTurnRequestPayload, type ChatTurnRouteProducer, type ChatTurnRoutes, type ChatTurnUsage, type CreateAttachmentUploadRouteOptions, type CreateChatTurnRoutesOptions, type CreateUploadRouteOptions, type DetachedTurnFinal, type DetachedTurnOptions, type DetachedTurnParts, type DetachedTurnResult, type DispatchPartsOutcome, type DraftPersistenceTuning, type DraftStoredMessage, type EmptyTurnRetryInfo, type FilePartPromotionOutcome, MAX_EMPTY_TURN_RETRIES, type ModelFailoverStreamHandle, type ModelFailoverStreamOptions, type ModelFallbackInfo, type OpenModelStream, 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, assistantRowIdForTurn, buildDispatchParts, bytesToBase64, classifyTerminalFailure, createAssistantDraftWriter, createAttachmentUploadRoute, createChatTurnRoutes, createSandboxChatProducer, createUploadRoute, defaultValidateAttachmentPath, isCommittingSandboxEvent, isDraftContentEvent, normalizeChatPromptForSandbox, promoteAgentFilePart, resolveChatAttachments, resolveEmptyTurnRetries, rowIdOf, runDetachedTurn, sanitizeUploadFilename, sniffMimeFromName, storeSupportsDraftPersistence, streamWithModelFailover, summarizeFailoverReason, withDurableChatProjection };
@@ -504,6 +504,7 @@ function createChatTurnRoutes(options) {
504
504
  });
505
505
  } else {
506
506
  const failoverInfo = producer?.modelFailover?.();
507
+ const attribution = producer?.modelAttribution?.();
507
508
  await lifecycle.onTurnComplete?.({
508
509
  identity,
509
510
  executionId,
@@ -515,6 +516,10 @@ function createChatTurnRoutes(options) {
515
516
  assistantMessageId: assistantRowId(),
516
517
  ...gatedTurn ? { gated: true } : {},
517
518
  ...producer?.model ? { model: producer.model } : {},
519
+ ...attribution?.requestedModel ? { requestedModel: attribution.requestedModel } : {},
520
+ ...attribution?.servedModel ? { servedModel: attribution.servedModel } : {},
521
+ ...attribution?.servedProvider ? { servedProvider: attribution.servedProvider } : {},
522
+ ...attribution?.servedSource ? { servedSource: attribution.servedSource } : {},
518
523
  ...failoverInfo ? { modelFailover: failoverInfo } : {}
519
524
  });
520
525
  }
@@ -659,10 +664,15 @@ function createChatTurnRoutes(options) {
659
664
  return;
660
665
  }
661
666
  const usage = producer?.usage?.() ?? {};
667
+ const attribution = producer?.modelAttribution?.();
662
668
  const values = {
663
669
  content: finalText,
664
670
  ...parts && parts.length > 0 ? { parts } : {},
665
671
  ...producer?.model ? { model: producer.model } : {},
672
+ ...attribution?.requestedModel ? { requestedModel: attribution.requestedModel } : {},
673
+ ...attribution?.servedModel ? { servedModel: attribution.servedModel } : {},
674
+ ...attribution?.servedProvider ? { servedProvider: attribution.servedProvider } : {},
675
+ ...attribution?.servedSource ? { servedSource: attribution.servedSource } : {},
666
676
  ...usage.inputTokens !== void 0 ? { inputTokens: usage.inputTokens } : {},
667
677
  ...usage.outputTokens !== void 0 ? { outputTokens: usage.outputTokens } : {},
668
678
  ...usage.reasoningTokens !== void 0 ? { reasoningTokens: usage.reasoningTokens } : {},
@@ -691,6 +701,7 @@ function createChatTurnRoutes(options) {
691
701
  // complete with empty text.
692
702
  onTurnComplete: ({ identity: turnIdentity, finalText }) => {
693
703
  const failoverInfo = producer?.modelFailover?.();
704
+ const attribution = producer?.modelAttribution?.();
694
705
  return options.onTurnComplete({
695
706
  identity: turnIdentity,
696
707
  finalText,
@@ -699,6 +710,10 @@ function createChatTurnRoutes(options) {
699
710
  assistantMessageId: assistantRowId(),
700
711
  ...runFailed ? { failureReason: failureReasonOf(lastFailureData) } : {},
701
712
  ...producer?.model ? { model: producer.model } : {},
713
+ ...attribution?.requestedModel ? { requestedModel: attribution.requestedModel } : {},
714
+ ...attribution?.servedModel ? { servedModel: attribution.servedModel } : {},
715
+ ...attribution?.servedProvider ? { servedProvider: attribution.servedProvider } : {},
716
+ ...attribution?.servedSource ? { servedSource: attribution.servedSource } : {},
702
717
  ...failoverInfo ? { modelFailover: failoverInfo } : {}
703
718
  });
704
719
  }
@@ -1029,6 +1044,20 @@ function textDelta(tracker, key, part, rawDelta) {
1029
1044
  tracker.seen.set(key, snapshot);
1030
1045
  return snapshot;
1031
1046
  }
1047
+ function parseEffectiveBackend(data) {
1048
+ const backend = asRecord(data.effectiveBackend);
1049
+ if (!backend) return void 0;
1050
+ const provider = asString(backend.provider);
1051
+ const model = asString(backend.model);
1052
+ const rawSource = asString(backend.source);
1053
+ const source = rawSource === "request" || rawSource === "environment" || rawSource === "profile" ? rawSource : void 0;
1054
+ if (!provider && !model && !source) return void 0;
1055
+ return {
1056
+ ...model ? { servedModel: model } : {},
1057
+ ...provider ? { servedProvider: provider } : {},
1058
+ ...source ? { servedSource: source } : {}
1059
+ };
1060
+ }
1032
1061
  function usageFromStepFinish(part, usage) {
1033
1062
  const tokens = asRecord(part.tokens);
1034
1063
  if (tokens) {
@@ -1163,6 +1192,22 @@ function createSandboxChatProducer(options) {
1163
1192
  source = options.events;
1164
1193
  }
1165
1194
  const servingModel = () => failover?.servingModel() ?? options.model;
1195
+ let effectiveBackend;
1196
+ let substitutionNoticeQueued = false;
1197
+ const servedModel = () => effectiveBackend?.servedModel ?? servingModel();
1198
+ const captureEffectiveBackend = (data) => {
1199
+ if (!data) return;
1200
+ const parsed = parseEffectiveBackend(data);
1201
+ if (!parsed) return;
1202
+ effectiveBackend = parsed;
1203
+ const sentModel = servingModel();
1204
+ if (substitutionNoticeQueued || !options.model || !sentModel || !parsed.servedModel || parsed.servedModel === sentModel) return;
1205
+ substitutionNoticeQueued = true;
1206
+ pendingModelNotices.push({
1207
+ id: "model-substitution-1",
1208
+ text: `Requested ${sentModel} \u2014 the sandbox answered with ${parsed.servedModel} instead.`
1209
+ });
1210
+ };
1166
1211
  let fullText = "";
1167
1212
  const partOrder = [];
1168
1213
  const partMap = /* @__PURE__ */ new Map();
@@ -1220,8 +1265,9 @@ function createSandboxChatProducer(options) {
1220
1265
  async function* stream() {
1221
1266
  try {
1222
1267
  for await (const raw of source) {
1223
- yield* drainModelNotices();
1224
1268
  const record = asRecord(raw);
1269
+ captureEffectiveBackend(asRecord(record?.data));
1270
+ yield* drainModelNotices();
1225
1271
  if (!record || typeof record.type !== "string") continue;
1226
1272
  const normalized = normalizeToolEvent({ type: record.type, data: asRecord(record.data) });
1227
1273
  const event = normalized.type === "message.part.updated" ? normalized : { type: record.type, data: asRecord(record.data) };
@@ -1487,12 +1533,17 @@ ${diagnostic.userMessage}` : diagnostic.userMessage;
1487
1533
  // model into the row and make a downgrade unattributable — the exact
1488
1534
  // failure mode this work exists to prevent.
1489
1535
  get model() {
1490
- return servingModel();
1536
+ return servedModel();
1491
1537
  },
1492
1538
  modelFailover: () => ({
1493
1539
  model: servingModel(),
1494
1540
  attempts: failover?.attempts() ?? [],
1495
1541
  usedFallback: failover?.usedFallback() ?? false
1542
+ }),
1543
+ modelAttribution: () => ({
1544
+ ...options.model ? { requestedModel: options.model } : {},
1545
+ ...effectiveBackend ?? {},
1546
+ echoReceived: effectiveBackend !== void 0
1496
1547
  })
1497
1548
  };
1498
1549
  }
@@ -1544,10 +1595,23 @@ async function runDetachedTurn(opts) {
1544
1595
  });
1545
1596
  }
1546
1597
  const settleRow = async (base) => {
1598
+ const persisted = !producer && opts.persist ? (await opts.persist.store.listMessages(opts.persist.threadId)).find(
1599
+ (message) => message.id === (opts.persist?.messageId ?? assistantRowIdForTurn(turnId))
1600
+ ) : void 0;
1547
1601
  const info = producer?.modelFailover?.();
1602
+ const attribution = producer?.modelAttribution?.();
1603
+ const model = producer?.model ?? persisted?.model ?? opts.model;
1604
+ const requestedModel = attribution?.requestedModel ?? persisted?.requestedModel ?? opts.model;
1605
+ const servedModel = attribution?.servedModel ?? persisted?.servedModel;
1606
+ const servedProvider = attribution?.servedProvider ?? persisted?.servedProvider;
1607
+ const servedSource = attribution?.servedSource ?? (persisted?.servedSource === "request" || persisted?.servedSource === "environment" || persisted?.servedSource === "profile" ? persisted.servedSource : void 0);
1548
1608
  const result = {
1549
1609
  ...base,
1550
- ...servingModel() ? { model: servingModel() } : {},
1610
+ ...model ? { model } : {},
1611
+ ...requestedModel ? { requestedModel } : {},
1612
+ ...servedModel ? { servedModel } : {},
1613
+ ...servedProvider ? { servedProvider } : {},
1614
+ ...servedSource ? { servedSource } : {},
1551
1615
  ...info ? { usedModelFallback: info.usedFallback, modelAttempts: info.attempts } : {}
1552
1616
  };
1553
1617
  if (!draft) return result;
@@ -1567,6 +1631,10 @@ async function runDetachedTurn(opts) {
1567
1631
  content,
1568
1632
  ...parts2.length > 0 ? { parts: parts2 } : {},
1569
1633
  ...result.model ? { model: result.model } : {},
1634
+ ...result.requestedModel ? { requestedModel: result.requestedModel } : {},
1635
+ ...result.servedModel ? { servedModel: result.servedModel } : {},
1636
+ ...result.servedProvider ? { servedProvider: result.servedProvider } : {},
1637
+ ...result.servedSource ? { servedSource: result.servedSource } : {},
1570
1638
  ...result.usage.inputTokens !== void 0 ? { inputTokens: result.usage.inputTokens } : {},
1571
1639
  ...result.usage.outputTokens !== void 0 ? { outputTokens: result.usage.outputTokens } : {},
1572
1640
  ...result.usage.reasoningTokens !== void 0 ? { reasoningTokens: result.usage.reasoningTokens } : {},