@opengeni/react 2.0.1 → 2.0.2-canary.38789554071001

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 (70) hide show
  1. package/dist/artifacts.js +4 -2
  2. package/dist/artifacts.js.map +1 -1
  3. package/dist/{browser-viewer-RZH5JVFZ.js → browser-viewer-M7BIVFTW.js} +3 -3
  4. package/dist/{chat-interactive-block-UCACTZIE.js → chat-interactive-block-BO2IWXVK.js} +3 -3
  5. package/dist/{chunk-NIIXN66Z.js → chunk-5XEXTWEM.js} +2 -2
  6. package/dist/{chunk-4JUSFDTA.js → chunk-6JFN3OWG.js} +28 -225
  7. package/dist/chunk-6JFN3OWG.js.map +1 -0
  8. package/dist/{chunk-BSIADJ4U.js → chunk-6SNDCUPB.js} +2 -2
  9. package/dist/{chunk-RRYCD3QD.js → chunk-AMVCNAGC.js} +992 -924
  10. package/dist/chunk-AMVCNAGC.js.map +1 -0
  11. package/dist/{chunk-ERLG2X3U.js → chunk-CORUP6JB.js} +3 -2
  12. package/dist/chunk-CORUP6JB.js.map +1 -0
  13. package/dist/{chunk-6JUSXDF4.js → chunk-HBXL6HWG.js} +2 -2
  14. package/dist/{chunk-HQN5AZFY.js → chunk-HGKELH6Z.js} +12 -3
  15. package/dist/{chunk-HQN5AZFY.js.map → chunk-HGKELH6Z.js.map} +1 -1
  16. package/dist/{chunk-QWA4BHC6.js → chunk-ISN726VG.js} +2 -2
  17. package/dist/{chunk-QQ5UGGGE.js → chunk-KZENYIA2.js} +16 -2
  18. package/dist/{chunk-QQ5UGGGE.js.map → chunk-KZENYIA2.js.map} +1 -1
  19. package/dist/{chunk-25YZS7TK.js → chunk-O5GPRG76.js} +4 -4
  20. package/dist/{chunk-UPP6YD2R.js → chunk-PWCBMEV2.js} +4 -4
  21. package/dist/{chunk-X6KAA43Z.js → chunk-Q26UAIXI.js} +2 -2
  22. package/dist/{chunk-U7A22SY4.js → chunk-TIHSXNBC.js} +6 -2
  23. package/dist/{chunk-U7A22SY4.js.map → chunk-TIHSXNBC.js.map} +1 -1
  24. package/dist/{chunk-2U54CHR5.js → chunk-VIUEOHXY.js} +3 -2
  25. package/dist/chunk-VIUEOHXY.js.map +1 -0
  26. package/dist/components/artifacts/artifact-sandbox.d.ts +3 -0
  27. package/dist/components/artifacts/published-html-artifact-frame.d.ts +15 -51
  28. package/dist/components/artifacts/site-view.d.ts +4 -1
  29. package/dist/components/linkified-text.d.ts +18 -0
  30. package/dist/composer-messages.js +2 -2
  31. package/dist/composer.js +4 -4
  32. package/dist/connect.js +2 -2
  33. package/dist/index.js +12 -12
  34. package/dist/interaction.js +2 -2
  35. package/dist/{latest-question-6WZQV23L.js → latest-question-CHE7E753.js} +3 -3
  36. package/dist/lib/format.d.ts +7 -0
  37. package/dist/machines.js +2 -2
  38. package/dist/{platform-activity-row-UQDQDX4C.js → platform-activity-row-5OCKOQWZ.js} +2 -2
  39. package/dist/session-ui.js +10 -10
  40. package/dist/session.js +4 -4
  41. package/dist/sites.js +1 -1
  42. package/dist/timeline/types.d.ts +1 -1
  43. package/dist/timeline-model.js +3 -3
  44. package/package.json +3 -3
  45. package/src/components/artifacts/artifact-sandbox.tsx +4 -0
  46. package/src/components/artifacts/published-html-artifact-frame.tsx +48 -321
  47. package/src/components/artifacts/site-view.tsx +5 -0
  48. package/src/components/human-input-form.tsx +19 -13
  49. package/src/components/linkified-text.tsx +79 -0
  50. package/src/components/message-timeline.tsx +4 -3
  51. package/src/hooks/use-machines.ts +4 -0
  52. package/src/lib/format.ts +25 -1
  53. package/src/timeline/platform-activity-presentation.ts +1 -0
  54. package/src/timeline/projection.ts +18 -1
  55. package/src/timeline/types.ts +1 -0
  56. package/dist/chunk-2U54CHR5.js.map +0 -1
  57. package/dist/chunk-4JUSFDTA.js.map +0 -1
  58. package/dist/chunk-ERLG2X3U.js.map +0 -1
  59. package/dist/chunk-RRYCD3QD.js.map +0 -1
  60. /package/dist/{browser-viewer-RZH5JVFZ.js.map → browser-viewer-M7BIVFTW.js.map} +0 -0
  61. /package/dist/{chat-interactive-block-UCACTZIE.js.map → chat-interactive-block-BO2IWXVK.js.map} +0 -0
  62. /package/dist/{chunk-NIIXN66Z.js.map → chunk-5XEXTWEM.js.map} +0 -0
  63. /package/dist/{chunk-BSIADJ4U.js.map → chunk-6SNDCUPB.js.map} +0 -0
  64. /package/dist/{chunk-6JUSXDF4.js.map → chunk-HBXL6HWG.js.map} +0 -0
  65. /package/dist/{chunk-QWA4BHC6.js.map → chunk-ISN726VG.js.map} +0 -0
  66. /package/dist/{chunk-25YZS7TK.js.map → chunk-O5GPRG76.js.map} +0 -0
  67. /package/dist/{chunk-UPP6YD2R.js.map → chunk-PWCBMEV2.js.map} +0 -0
  68. /package/dist/{chunk-X6KAA43Z.js.map → chunk-Q26UAIXI.js.map} +0 -0
  69. /package/dist/{latest-question-6WZQV23L.js.map → latest-question-CHE7E753.js.map} +0 -0
  70. /package/dist/{platform-activity-row-UQDQDX4C.js.map → platform-activity-row-5OCKOQWZ.js.map} +0 -0
@@ -22,7 +22,7 @@ import {
22
22
  } from "./chunk-G76LSA76.js";
23
23
  import {
24
24
  formatBytes
25
- } from "./chunk-QQ5UGGGE.js";
25
+ } from "./chunk-KZENYIA2.js";
26
26
  import {
27
27
  STREAM_CLOSE_REASON_NORMAL,
28
28
  STREAM_KIND_BROWSER,
@@ -4720,4 +4720,4 @@ export {
4720
4720
  staleBrowserEndRetryDelayMs,
4721
4721
  BrowserViewer
4722
4722
  };
4723
- //# sourceMappingURL=chunk-QWA4BHC6.js.map
4723
+ //# sourceMappingURL=chunk-ISN726VG.js.map
@@ -249,6 +249,17 @@ function isModelUnavailableSubmissionError(error) {
249
249
  }
250
250
  return error.message === COMPOSER_MODEL_UNAVAILABLE_MESSAGE || /^(?:Opengeni|OpenGeni) API 422: model is not available: /.test(error.message);
251
251
  }
252
+ var COMPOSER_SITE_REFUSAL_MESSAGES = Object.freeze({
253
+ not_available_for_viewer: "This Site's assistant can't do that for you. Your message is saved.",
254
+ site_budget_exhausted: "This Site's assistant has reached its usage limit for now. Your message is saved.",
255
+ site_budget_busy: "This Site's assistant is busy. Try again in a moment. Your message is saved.",
256
+ site_platform_brake_engaged: "This Site's assistant is paused for visitors right now. Your message is saved."
257
+ });
258
+ function siteRefusalCode(error) {
259
+ if (!(error instanceof OpenGeniApiError)) return null;
260
+ const code = error.details?.code;
261
+ return typeof code === "string" && code in COMPOSER_SITE_REFUSAL_MESSAGES ? code : null;
262
+ }
252
263
  function composerSubmissionErrorMessage(error) {
253
264
  if (error instanceof ComposerReconciliationRequiredError) {
254
265
  return "This client cannot safely retry this uncertain request after remount; reconcile the session before sending again.";
@@ -260,6 +271,8 @@ function composerSubmissionErrorMessage(error) {
260
271
  if (error instanceof OpenGeniApiError && error.outcomeUnknown) return formatErrorMessage(error);
261
272
  if (isModelUnavailableSubmissionError(error)) return COMPOSER_MODEL_UNAVAILABLE_MESSAGE;
262
273
  if (isSessionUsageLimitSubmissionError(error)) return COMPOSER_SESSION_USAGE_LIMIT_MESSAGE;
274
+ const siteRefusal = siteRefusalCode(error);
275
+ if (siteRefusal) return COMPOSER_SITE_REFUSAL_MESSAGES[siteRefusal];
263
276
  if (error instanceof OpenGeniApiError && error.code === "allowance_exhausted") {
264
277
  const message = error.scope === "workspace" ? COMPOSER_WORKSPACE_ALLOWANCE_MESSAGE : COMPOSER_MEMBER_ALLOWANCE_MESSAGE;
265
278
  return composerErrorReference(error, message);
@@ -270,7 +283,8 @@ function composerErrorReference(error, message) {
270
283
  return error instanceof OpenGeniApiError && error.correlationId ? `${message} Reference: ${error.correlationId}.` : message;
271
284
  }
272
285
  function composerSubmissionCanRetry(error) {
273
- return !(isComposerCreditRefusal(error) || isModelUnavailableSubmissionError(error) || isSessionUsageLimitSubmissionError(error) || error instanceof OpenGeniApiError && error.code === "allowance_exhausted");
286
+ return !(isComposerCreditRefusal(error) || isModelUnavailableSubmissionError(error) || isSessionUsageLimitSubmissionError(error) || error instanceof OpenGeniApiError && error.code === "allowance_exhausted" || // Only a busy Site assistant is worth an unchanged retry.
287
+ siteRefusalCode(error) !== null && siteRefusalCode(error) !== "site_budget_busy");
274
288
  }
275
289
  function isComposerCreditRefusal(error) {
276
290
  if (isSessionUsageLimitSubmissionError(error)) return false;
@@ -365,4 +379,4 @@ export {
365
379
  humanizeFailureReason,
366
380
  presentFailure
367
381
  };
368
- //# sourceMappingURL=chunk-QQ5UGGGE.js.map
382
+ //# sourceMappingURL=chunk-KZENYIA2.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/provider-recovery.ts","../src/lib/format.ts"],"sourcesContent":["import type { SessionEvent, SessionStatus } from \"@opengeni/sdk\";\n\n/**\n * Finite same-turn provider recovery, projected for people. Presentation only:\n * the worker owns retry authority, pacing and the recovery budget. The worker\n * (`apps/worker/src/activities/agent-turn/provider-recovery-copy.ts`) writes\n * the same exhausted sentence into `turn.failed.error`; keep the two in step.\n */\nexport type ProviderRecoveryCondition =\n | \"overloaded\"\n | \"unavailable\"\n | \"unresponsive\"\n | \"rate_limited\";\n\nexport type ProviderRecoveryFacts = {\n /** Recorded worker failure code (`provider_unavailable`, `mcp_transport_timeout`, ...). */\n code: string;\n condition: ProviderRecoveryCondition | null;\n /** Display label of the affected model, when the route was recorded. */\n modelLabel: string | null;\n /** Display label of the serving provider, when the route was recorded. */\n providerLabel: string | null;\n /** Automatic retries scheduled (live) or spent (exhausted). */\n attempt: number | null;\n /** Finite automatic retry budget. */\n maxAttempts: number | null;\n /** True when the model route itself is affected, so another model may help. */\n modelRoute: boolean;\n /** True while the turn waits for its sandbox to be saved and replaced. It\n * has no retry budget: it resumes as soon as the successor box is ready. */\n sandboxWait?: boolean;\n /** Recorded lifecycle fence of a sandbox wait (`capture_in_progress`,\n * `rotation_in_progress`, `provider_recovery_in_progress`), when known. */\n sandboxTransition?: string | null;\n};\n\nconst MODEL_CODES: ReadonlySet<string> = new Set([\n \"provider_unavailable\",\n \"provider_rate_limited\",\n \"provider_unknown_finish_reason\",\n \"post_compaction_continuation_empty\",\n]);\n\n/** A recovering turn parked behind a sandbox lifecycle transition (worker\n * `failure-settlement.ts`). Before, this showed only \"Recovering\" with no\n * reason. A superseded lease\n * counts only when the worker recorded the pending transition it waits for. */\nconst SANDBOX_WAIT_CODES: ReadonlySet<string> = new Set([\n \"sandbox_deadline_rotation\",\n \"sandbox_lifecycle_transition\",\n \"sandbox_lease_superseded\",\n]);\n\nconst RECOVERY_CODES: ReadonlySet<string> = new Set([\n ...MODEL_CODES,\n ...SANDBOX_WAIT_CODES,\n \"upstream_connectivity_unavailable\",\n \"mcp_transport_timeout\",\n \"mcp_transport_unavailable\",\n \"sandbox_command_start_unavailable\",\n \"turn_execution_policy_definition_mismatch\",\n]);\n\n/** Matches the worker's default budget for legacy events that omit it. */\nconst DEFAULT_MAX_ATTEMPTS = 5;\n\nfunction text(value: unknown, max = 120): string | null {\n if (typeof value !== \"string\") return null;\n const normalized = value.replace(/\\s+/g, \" \").trim();\n return normalized ? normalized.slice(0, max) : null;\n}\n\nfunction count(value: unknown): number | null {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value > 0 ? value : null;\n}\n\nfunction condition(\n payload: Record<string, unknown>,\n code: string,\n): ProviderRecoveryCondition | null {\n const recorded = payload.providerCondition;\n if (\n recorded === \"overloaded\" ||\n recorded === \"unavailable\" ||\n recorded === \"unresponsive\" ||\n recorded === \"rate_limited\"\n )\n return recorded;\n if (code === \"provider_rate_limited\") return \"rate_limited\";\n if (code !== \"provider_unavailable\") return null;\n // Older events predate the typed condition; their provider text still says so.\n return [payload.lastRetryableError, payload.detail, payload.error].some(\n (value) => typeof value === \"string\" && /\\boverload(?:ed)?(?:_error)?\\b/i.test(value),\n )\n ? \"overloaded\"\n : null;\n}\n\n/**\n * Read a retryable `turn.recovery.requested` payload or an exhausted\n * `turn.failed` payload. Returns null for every other recovery reason (human\n * Retry, worker shutdown, credential rotation, capacity waits, ...).\n */\nexport function parseProviderRecovery(payload: unknown): ProviderRecoveryFacts | null {\n if (!payload || typeof payload !== \"object\" || Array.isArray(payload)) return null;\n const record = payload as Record<string, unknown>;\n const code = text(record.code) ?? text(record.reason);\n if (!code || !RECOVERY_CODES.has(code)) return null;\n const rotation = text(record.rotationReason);\n const transition = text(record.transitionReason);\n if (code === \"sandbox_lease_superseded\" && !rotation && !transition) return null;\n // A live recovery request is retryable; a spent budget is explicitly marked.\n if (record.recoveryExhausted !== true && record.retryable === false) return null;\n const attempt = count(record.providerRecoveryCount);\n return {\n code,\n condition: condition(record, code),\n modelLabel: text(record.modelLabel),\n providerLabel: text(record.providerLabel),\n attempt,\n maxAttempts: count(record.maxProviderRecoveryCount) ?? DEFAULT_MAX_ATTEMPTS,\n modelRoute: MODEL_CODES.has(code),\n ...(SANDBOX_WAIT_CODES.has(code)\n ? {\n sandboxWait: true,\n sandboxTransition: transition ?? (rotation ? \"rotation_in_progress\" : null),\n }\n : {}),\n };\n}\n\n/** One present-tense clause naming what is unavailable, without a trailing period. */\nexport function providerRecoverySubject(facts: ProviderRecoveryFacts): string {\n const model = facts.modelLabel ?? \"The model\";\n const at = facts.providerLabel ? ` at the provider (${facts.providerLabel})` : \" at the provider\";\n switch (facts.code) {\n case \"provider_rate_limited\":\n return `${model} is rate limited${at}`;\n case \"provider_unavailable\":\n return facts.condition === \"overloaded\"\n ? `${model} is overloaded${at}`\n : facts.condition === \"unresponsive\"\n ? `${model} stopped responding${at}`\n : `${model} is temporarily unavailable${at}`;\n case \"provider_unknown_finish_reason\":\n return `${model} ended its response unexpectedly`;\n case \"post_compaction_continuation_empty\":\n return `${model} stopped right after compacting the conversation`;\n case \"upstream_connectivity_unavailable\":\n return \"Opengeni can't reach an upstream service\";\n case \"mcp_transport_timeout\":\n return \"A required MCP server isn't responding\";\n case \"mcp_transport_unavailable\":\n return \"A required MCP server is unreachable\";\n case \"sandbox_command_start_unavailable\":\n return \"The sandbox isn't ready yet\";\n case \"turn_execution_policy_definition_mismatch\":\n return \"Opengeni is applying a configuration update\";\n case \"sandbox_deadline_rotation\":\n return \"The sandbox reached its maximum lifetime, so Opengeni is moving the workspace to a fresh sandbox\";\n case \"sandbox_lifecycle_transition\":\n case \"sandbox_lease_superseded\":\n return facts.sandboxTransition === \"capture_in_progress\"\n ? \"Opengeni is saving the sandbox workspace\"\n : facts.sandboxTransition === \"provider_recovery_in_progress\"\n ? \"Opengeni is recovering the sandbox\"\n : facts.sandboxTransition === \"rotation_in_progress\"\n ? \"Opengeni is moving the workspace to a fresh sandbox\"\n : \"Opengeni is preparing the sandbox\";\n default:\n return \"A service this turn depends on is temporarily unavailable\";\n }\n}\n\n/** Live status while the same turn waits for its next automatic retry. */\nexport function providerRecoveryRetryingText(facts: ProviderRecoveryFacts): string {\n if (facts.sandboxWait) return `${providerRecoverySubject(facts)}…`;\n const progress =\n facts.attempt !== null && facts.maxAttempts !== null\n ? ` (attempt ${Math.min(facts.attempt, facts.maxAttempts)} of ${facts.maxAttempts})`\n : \" automatically\";\n return `${providerRecoverySubject(facts)} — retrying${progress}…`;\n}\n\n/** Terminal sentence once the automatic budget is spent. */\nexport function providerRecoveryExhaustedText(facts: ProviderRecoveryFacts): string {\n const spent = facts.attempt ?? facts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n const retried = `Opengeni retried ${spent} ${spent === 1 ? \"time\" : \"times\"} without success.`;\n const remedy = facts.modelRoute\n ? \"Try again in a few minutes, or switch to another model.\"\n : \"Try again in a few minutes.\";\n return `${providerRecoverySubject(facts)}. ${retried} ${remedy}`;\n}\n\nconst BOUNDARY_TYPES: ReadonlySet<string> = new Set([\n \"turn.recovery.requested\",\n \"turn.started\",\n \"turn.completed\",\n \"turn.failed\",\n \"turn.cancelled\",\n \"turn.superseded\",\n]);\n\n/**\n * The active turn's current automatic provider retry, or null. Only a\n * `recovering`, unpaused session qualifies, and only the newest boundary of its\n * exact active turn counts, so merged or replayed pages never borrow another\n * turn's diagnosis.\n */\nexport function currentProviderRecovery(\n session: {\n id: string;\n status: SessionStatus | null | undefined;\n activeTurnId: string | null | undefined;\n effectiveControl?: { state: string } | null | undefined;\n },\n events: readonly SessionEvent[],\n): ProviderRecoveryFacts | null {\n if (\n session.status !== \"recovering\" ||\n (session.effectiveControl && session.effectiveControl.state !== \"active\") ||\n !session.activeTurnId\n )\n return null;\n let latest: SessionEvent | undefined;\n for (const event of events) {\n if (\n event.sessionId !== session.id ||\n event.turnId !== session.activeTurnId ||\n event.duplicateOfEventId ||\n (event.turnAssociation && event.turnAssociation !== \"current\") ||\n !BOUNDARY_TYPES.has(event.type)\n )\n continue;\n if (!latest || event.sequence > latest.sequence) latest = event;\n }\n if (latest?.type !== \"turn.recovery.requested\") return null;\n const payload = latest.payload as Record<string, unknown> | null | undefined;\n return payload?.recoveryExhausted === true ? null : parseProviderRecovery(payload);\n}\n","import { formatErrorMessage, OpenGeniApiError } from \"@opengeni/sdk\";\nimport { parseProviderRecovery, providerRecoveryExhaustedText } from \"./provider-recovery\";\n\nconst clockTimeFormatter = new Intl.DateTimeFormat(undefined, {\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n});\n\n/** Local finished-at stamp for message footers: \"Aug 2, 3:42 PM\" / locale-equivalent. */\nexport function formatClockTime(iso: string): string {\n const then = new Date(iso);\n if (Number.isNaN(then.getTime())) {\n return \"\";\n }\n return clockTimeFormatter.format(then);\n}\n\n/** Compact relative time: \"now\", \"42s\", \"7m\", \"3h\", \"2d\", then a date. */\nexport function formatRelativeTime(iso: string, now: Date = new Date()): string {\n const then = new Date(iso).getTime();\n if (Number.isNaN(then)) {\n return \"\";\n }\n const seconds = Math.max(0, Math.floor((now.getTime() - then) / 1000));\n if (seconds < 10) {\n return \"now\";\n }\n if (seconds < 60) {\n return `${seconds}s`;\n }\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) {\n return `${minutes}m`;\n }\n const hours = Math.floor(minutes / 60);\n if (hours < 24) {\n return `${hours}h`;\n }\n const days = Math.floor(hours / 24);\n if (days < 14) {\n return `${days}d`;\n }\n return new Date(iso).toLocaleDateString();\n}\n\n/** Human-readable byte size: \"512 B\", \"8.0 KB\", \"1.4 MB\", \"3 GB\". */\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n const units = [\"KB\", \"MB\", \"GB\"] as const;\n let value = bytes / 1024;\n for (const unit of units) {\n if (value < 1024 || unit === \"GB\") {\n return `${value.toFixed(value < 10 ? 1 : 0)} ${unit}`;\n }\n value /= 1024;\n }\n return `${bytes} B`;\n}\n\n/** Single-line preview of arbitrary text, for tiles and collapsed rows. */\nexport function truncate(text: string, maxLength: number): string {\n const collapsed = text.replace(/\\s+/g, \" \").trim();\n if (collapsed.length <= maxLength) {\n return collapsed;\n }\n return `${collapsed.slice(0, Math.max(0, maxLength - 1)).trimEnd()}…`;\n}\n\n/** Render an unknown payload as readable text (pretty JSON when possible). */\nexport function stringifyPayload(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n if (typeof value === \"string\") {\n const parsed = tryParseJson(value);\n if (parsed !== undefined && typeof parsed === \"object\") {\n return stringifyPayload(parsed);\n }\n return value;\n }\n try {\n return JSON.stringify(value, null, 2) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/** JSON.parse that returns `undefined` instead of throwing. */\nexport function tryParseJson(text: string): unknown {\n const trimmed = text.trim();\n if (!trimmed.startsWith(\"{\") && !trimmed.startsWith(\"[\") && !trimmed.startsWith('\"')) {\n return undefined;\n }\n try {\n return JSON.parse(trimmed) as unknown;\n } catch {\n return undefined;\n }\n}\n\n/**\n * The canonical credit-death sentence. Credit exhaustion is the one failure a\n * user can fix themselves — the copy must say what happened (empty balance),\n * what to do (add credits), and what is safe (nothing was lost). Crucially it\n * must NOT say \"send a message to revive\": a revive turn burns credits the\n * workspace no longer has.\n */\nexport const CREDIT_EXHAUSTION_MESSAGE =\n \"Out of credits — this workspace's balance is empty. Add credits to continue; the conversation is preserved.\";\n\n/** A usage ceiling refused the send; the default allowance wording, plus what is safe. */\nexport const COMPOSER_MEMBER_ALLOWANCE_MESSAGE =\n \"Usage limit reached. A workspace admin can raise this limit. Your draft is preserved.\";\nexport const COMPOSER_WORKSPACE_ALLOWANCE_MESSAGE =\n \"Workspace usage limit reached. An organization admin can raise the workspace budget. Your draft is preserved.\";\n\n/**\n * Actionable composer copy for an edge rejection before a turn is accepted.\n * Unlike an in-flight credit exhaustion, this path has not consumed the\n * actor-private draft or any finalized attachment.\n */\nexport const COMPOSER_PAYMENT_REQUIRED_MESSAGE =\n \"Your organization doesn't have enough credits to send this message. Add credits or choose a model with another payment source. Your message and attachments are saved.\";\n\n/** Trusted, composer-owned guidance; unlike remote diagnostic prose, this is UI copy. */\nexport class ComposerStateError extends Error {}\n\n/** A restored request has omitted credentials and must be reconciled, not replayed. */\nexport class ComposerReconciliationRequiredError extends ComposerStateError {\n constructor() {\n super(\n \"Opengeni cannot safely retry this uncertain request after remount; reconcile the session before sending again.\",\n );\n }\n}\n\nexport class ComposerWorkspaceControlUnavailableError extends Error {\n constructor() {\n super(\"@opengeni/react: workspace-scoped resume requires setWorkspaceInferenceState.\");\n }\n}\n\n/**\n * The send named a model that is no longer in the live catalog (retired or\n * removed). Retrying the same send cannot succeed; the person must choose\n * another model, and the typed message stays recoverable via Edit message.\n */\nexport const COMPOSER_MODEL_UNAVAILABLE_MESSAGE =\n \"This chat's model is no longer available. Choose another model to continue. Your message is saved.\";\n\n/** `details.code` the API sets on a 422 for a model missing from the live catalog. */\nexport const MODEL_UNAVAILABLE_DETAIL_CODE = \"model_unavailable\";\n\n/**\n * A fresh Send or Steer refused because the task's own usage limit is reached.\n * The draft is kept and an unchanged retry is never offered. The one current\n * recovery action (raise or remove the limit, resume a goal) belongs to the\n * composer's `SessionUsageLimitNotice`, so this line only says what happened.\n */\nexport const COMPOSER_SESSION_USAGE_LIMIT_MESSAGE =\n \"This task's usage limit is reached. Your message is saved.\";\n\n/** The earlier wording, still recognized in refusals restored from storage. */\nconst LEGACY_COMPOSER_SESSION_USAGE_LIMIT_MESSAGE =\n \"This task's usage limit is reached. Raise or remove the limit to continue. Your message is saved.\";\n\n/**\n * Is this send refusal the task's usage limit? Reads the typed SDK error code\n * (`OpenGeniSessionUsageLimitReachedError`), and also the composer's own\n * sentence so a refusal restored from storage after a reload is recognized.\n */\nexport function isSessionUsageLimitSubmissionError(error: Error): boolean {\n return (\n (error instanceof OpenGeniApiError && error.code === \"session_usage_limit_reached\") ||\n error.message === COMPOSER_SESSION_USAGE_LIMIT_MESSAGE ||\n error.message === LEGACY_COMPOSER_SESSION_USAGE_LIMIT_MESSAGE\n );\n}\n\n/**\n * Is this send refusal \"the model is no longer available\"? Reads the typed\n * `details.code`, and also the historical message so a refusal persisted\n * before a reload (only its text survives) or from an older API is recognized.\n */\nexport function isModelUnavailableSubmissionError(error: Error): boolean {\n if (error instanceof OpenGeniApiError && error.details?.code === MODEL_UNAVAILABLE_DETAIL_CODE) {\n return true;\n }\n return (\n error.message === COMPOSER_MODEL_UNAVAILABLE_MESSAGE ||\n /^(?:Opengeni|OpenGeni) API 422: model is not available: /.test(error.message)\n );\n}\n\nexport function composerSubmissionErrorMessage(error: Error): string {\n if (error instanceof ComposerReconciliationRequiredError) {\n return \"This client cannot safely retry this uncertain request after remount; reconcile the session before sending again.\";\n }\n if (error instanceof ComposerWorkspaceControlUnavailableError) {\n return \"This client cannot resume the workspace. Ask your administrator for a control-capable client.\";\n }\n if (error instanceof ComposerStateError) return error.message;\n if (error instanceof OpenGeniApiError && error.outcomeUnknown) return formatErrorMessage(error);\n if (isModelUnavailableSubmissionError(error)) return COMPOSER_MODEL_UNAVAILABLE_MESSAGE;\n if (isSessionUsageLimitSubmissionError(error)) return COMPOSER_SESSION_USAGE_LIMIT_MESSAGE;\n if (error instanceof OpenGeniApiError && error.code === \"allowance_exhausted\") {\n // OpenGeniAllowanceExhaustedError carries the scope; read it structurally\n // so this startup-path helper adds no SDK or wording imports.\n const message =\n (error as { scope?: unknown }).scope === \"workspace\"\n ? COMPOSER_WORKSPACE_ALLOWANCE_MESSAGE\n : COMPOSER_MEMBER_ALLOWANCE_MESSAGE;\n return composerErrorReference(error, message);\n }\n return isComposerCreditRefusal(error)\n ? composerErrorReference(error, COMPOSER_PAYMENT_REQUIRED_MESSAGE)\n : formatErrorMessage(error);\n}\n\nfunction composerErrorReference(error: Error, message: string): string {\n return error instanceof OpenGeniApiError && error.correlationId\n ? `${message} Reference: ${error.correlationId}.`\n : message;\n}\n\n/** These definitive refusals need a payment, allowance or model change, not an unchanged retry. */\nexport function composerSubmissionCanRetry(error: Error): boolean {\n return !(\n isComposerCreditRefusal(error) ||\n isModelUnavailableSubmissionError(error) ||\n isSessionUsageLimitSubmissionError(error) ||\n (error instanceof OpenGeniApiError && error.code === \"allowance_exhausted\")\n );\n}\n\nfunction isComposerCreditRefusal(error: Error): boolean {\n // A 402 for the task's own usage limit is not a credit or payment problem.\n if (isSessionUsageLimitSubmissionError(error)) return false;\n return (\n (error instanceof OpenGeniApiError &&\n error.status === 402 &&\n (error.code === \"payment_required\" || error.code === \"insufficient_credits\")) ||\n isCreditExhaustion(error.message)\n );\n}\n\n/**\n * Does this failure/completion payload (or raw error string) mean the\n * workspace ran out of Opengeni credits? Matches the engine's\n * \"insufficient Opengeni credits\" text (case-insensitive, substring — it\n * arrives both bare and wrapped in \"Activity task failed: …\") and the\n * budget-exhausted segment limit the engine stamps on a turn it ended early.\n */\nexport function isCreditExhaustion(\n input: { error?: string | null; detail?: string | null; segmentLimit?: string | null } | string,\n): boolean {\n if (typeof input === \"string\") {\n return input.toLowerCase().includes(\"insufficient opengeni credits\");\n }\n if (input.segmentLimit === \"budget_exhausted\") {\n return true;\n }\n for (const text of [input.error, input.detail]) {\n if (typeof text === \"string\" && text.toLowerCase().includes(\"insufficient opengeni credits\")) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Humanize engine/provider failure text before it reaches the timeline or a\n * failure banner. Raw provider errors leak the wrong audience's instructions —\n * \"Incorrect API key … find your API key at platform.openai.com\" tells a\n * managed-deployment USER to fix credentials only an OPERATOR controls (and is\n * flatly wrong for Azure or subscription-backed engines). Auth, quota, and\n * credit-exhaustion failures collapse to one neutral, honest sentence; every\n * other reason passes through untouched. Raw payloads stay available in the\n * debug surfaces.\n */\nexport function humanizeFailureReason(reason: string | null): string | null {\n if (!reason) {\n return reason;\n }\n if (isCreditExhaustion(reason)) {\n return CREDIT_EXHAUSTION_MESSAGE;\n }\n const normalized = reason.toLowerCase();\n const authFailure =\n normalized.includes(\"incorrect api key\") ||\n normalized.includes(\"invalid api key\") ||\n normalized.includes(\"invalid_api_key\") ||\n normalized.includes(\"platform.openai.com/account/api-keys\") ||\n (normalized.includes(\"401\") &&\n (normalized.includes(\"api key\") || normalized.includes(\"unauthorized\")));\n if (authFailure) {\n return \"The model provider rejected this deployment's engine credentials. Sending messages won't help until the deployment's engine configuration is fixed.\";\n }\n const quotaFailure =\n normalized.includes(\"insufficient_quota\") || normalized.includes(\"exceeded your current quota\");\n if (quotaFailure) {\n return \"The model provider refused the request: this deployment's provider quota is exhausted.\";\n }\n return reason;\n}\n\n/** Project failure diagnostics without changing the stored event, including legacy retry wrappers. */\nexport function presentFailure(payload: Record<string, unknown>): {\n reason: string | null;\n safetyRefusal: boolean;\n} {\n const databaseFailure =\n payload.code === \"db_deadlock\" ||\n payload.code === \"db_serialization_failure\" ||\n payload.code === \"db_failure\" ||\n (typeof payload.sqlState === \"string\" &&\n /^[0-9A-Z]{5}$/.test(payload.sqlState) &&\n payload.database !== null &&\n typeof payload.database === \"object\" &&\n !Array.isArray(payload.database));\n if (databaseFailure) {\n return { reason: \"The service encountered a database error.\", safetyRefusal: false };\n }\n const text = (key: string): string | null => {\n const value = payload[key];\n return typeof value === \"string\" && value.trim() ? value : null;\n };\n const message = text(\"error\") ?? text(\"message\");\n const detail = text(\"lastRetryableError\") ?? text(\"detail\");\n const safetyRefusal =\n payload.code === \"provider_safety_refusal\" ||\n [message, detail].some(\n (value) =>\n value !== null && /\\bthis request was blocked by our safety systems\\b/i.test(value),\n );\n if (safetyRefusal) {\n return {\n reason: `The model provider blocked this request.${detail || message ? ` ${detail ?? message}` : \"\"}`,\n safetyRefusal: true,\n };\n }\n // Spent automatic retries: name the model and the remedy instead of the\n // recorded wrapper plus raw provider text (still in the stored event).\n const recovery = parseProviderRecovery(payload);\n if (recovery && payload.recoveryExhausted === true) {\n return { reason: providerRecoveryExhaustedText(recovery), safetyRefusal: false };\n }\n return {\n reason:\n detail && detail !== message\n ? [humanizeFailureReason(message), humanizeFailureReason(detail)].filter(Boolean).join(\" \")\n : humanizeFailureReason(message),\n safetyRefusal: false,\n };\n}\n"],"mappings":"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","names":["text"]}
1
+ {"version":3,"sources":["../src/lib/provider-recovery.ts","../src/lib/format.ts"],"sourcesContent":["import type { SessionEvent, SessionStatus } from \"@opengeni/sdk\";\n\n/**\n * Finite same-turn provider recovery, projected for people. Presentation only:\n * the worker owns retry authority, pacing and the recovery budget. The worker\n * (`apps/worker/src/activities/agent-turn/provider-recovery-copy.ts`) writes\n * the same exhausted sentence into `turn.failed.error`; keep the two in step.\n */\nexport type ProviderRecoveryCondition =\n | \"overloaded\"\n | \"unavailable\"\n | \"unresponsive\"\n | \"rate_limited\";\n\nexport type ProviderRecoveryFacts = {\n /** Recorded worker failure code (`provider_unavailable`, `mcp_transport_timeout`, ...). */\n code: string;\n condition: ProviderRecoveryCondition | null;\n /** Display label of the affected model, when the route was recorded. */\n modelLabel: string | null;\n /** Display label of the serving provider, when the route was recorded. */\n providerLabel: string | null;\n /** Automatic retries scheduled (live) or spent (exhausted). */\n attempt: number | null;\n /** Finite automatic retry budget. */\n maxAttempts: number | null;\n /** True when the model route itself is affected, so another model may help. */\n modelRoute: boolean;\n /** True while the turn waits for its sandbox to be saved and replaced. It\n * has no retry budget: it resumes as soon as the successor box is ready. */\n sandboxWait?: boolean;\n /** Recorded lifecycle fence of a sandbox wait (`capture_in_progress`,\n * `rotation_in_progress`, `provider_recovery_in_progress`), when known. */\n sandboxTransition?: string | null;\n};\n\nconst MODEL_CODES: ReadonlySet<string> = new Set([\n \"provider_unavailable\",\n \"provider_rate_limited\",\n \"provider_unknown_finish_reason\",\n \"post_compaction_continuation_empty\",\n]);\n\n/** A recovering turn parked behind a sandbox lifecycle transition (worker\n * `failure-settlement.ts`). Before, this showed only \"Recovering\" with no\n * reason. A superseded lease\n * counts only when the worker recorded the pending transition it waits for. */\nconst SANDBOX_WAIT_CODES: ReadonlySet<string> = new Set([\n \"sandbox_deadline_rotation\",\n \"sandbox_lifecycle_transition\",\n \"sandbox_lease_superseded\",\n]);\n\nconst RECOVERY_CODES: ReadonlySet<string> = new Set([\n ...MODEL_CODES,\n ...SANDBOX_WAIT_CODES,\n \"upstream_connectivity_unavailable\",\n \"mcp_transport_timeout\",\n \"mcp_transport_unavailable\",\n \"sandbox_command_start_unavailable\",\n \"turn_execution_policy_definition_mismatch\",\n]);\n\n/** Matches the worker's default budget for legacy events that omit it. */\nconst DEFAULT_MAX_ATTEMPTS = 5;\n\nfunction text(value: unknown, max = 120): string | null {\n if (typeof value !== \"string\") return null;\n const normalized = value.replace(/\\s+/g, \" \").trim();\n return normalized ? normalized.slice(0, max) : null;\n}\n\nfunction count(value: unknown): number | null {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value > 0 ? value : null;\n}\n\nfunction condition(\n payload: Record<string, unknown>,\n code: string,\n): ProviderRecoveryCondition | null {\n const recorded = payload.providerCondition;\n if (\n recorded === \"overloaded\" ||\n recorded === \"unavailable\" ||\n recorded === \"unresponsive\" ||\n recorded === \"rate_limited\"\n )\n return recorded;\n if (code === \"provider_rate_limited\") return \"rate_limited\";\n if (code !== \"provider_unavailable\") return null;\n // Older events predate the typed condition; their provider text still says so.\n return [payload.lastRetryableError, payload.detail, payload.error].some(\n (value) => typeof value === \"string\" && /\\boverload(?:ed)?(?:_error)?\\b/i.test(value),\n )\n ? \"overloaded\"\n : null;\n}\n\n/**\n * Read a retryable `turn.recovery.requested` payload or an exhausted\n * `turn.failed` payload. Returns null for every other recovery reason (human\n * Retry, worker shutdown, credential rotation, capacity waits, ...).\n */\nexport function parseProviderRecovery(payload: unknown): ProviderRecoveryFacts | null {\n if (!payload || typeof payload !== \"object\" || Array.isArray(payload)) return null;\n const record = payload as Record<string, unknown>;\n const code = text(record.code) ?? text(record.reason);\n if (!code || !RECOVERY_CODES.has(code)) return null;\n const rotation = text(record.rotationReason);\n const transition = text(record.transitionReason);\n if (code === \"sandbox_lease_superseded\" && !rotation && !transition) return null;\n // A live recovery request is retryable; a spent budget is explicitly marked.\n if (record.recoveryExhausted !== true && record.retryable === false) return null;\n const attempt = count(record.providerRecoveryCount);\n return {\n code,\n condition: condition(record, code),\n modelLabel: text(record.modelLabel),\n providerLabel: text(record.providerLabel),\n attempt,\n maxAttempts: count(record.maxProviderRecoveryCount) ?? DEFAULT_MAX_ATTEMPTS,\n modelRoute: MODEL_CODES.has(code),\n ...(SANDBOX_WAIT_CODES.has(code)\n ? {\n sandboxWait: true,\n sandboxTransition: transition ?? (rotation ? \"rotation_in_progress\" : null),\n }\n : {}),\n };\n}\n\n/** One present-tense clause naming what is unavailable, without a trailing period. */\nexport function providerRecoverySubject(facts: ProviderRecoveryFacts): string {\n const model = facts.modelLabel ?? \"The model\";\n const at = facts.providerLabel ? ` at the provider (${facts.providerLabel})` : \" at the provider\";\n switch (facts.code) {\n case \"provider_rate_limited\":\n return `${model} is rate limited${at}`;\n case \"provider_unavailable\":\n return facts.condition === \"overloaded\"\n ? `${model} is overloaded${at}`\n : facts.condition === \"unresponsive\"\n ? `${model} stopped responding${at}`\n : `${model} is temporarily unavailable${at}`;\n case \"provider_unknown_finish_reason\":\n return `${model} ended its response unexpectedly`;\n case \"post_compaction_continuation_empty\":\n return `${model} stopped right after compacting the conversation`;\n case \"upstream_connectivity_unavailable\":\n return \"Opengeni can't reach an upstream service\";\n case \"mcp_transport_timeout\":\n return \"A required MCP server isn't responding\";\n case \"mcp_transport_unavailable\":\n return \"A required MCP server is unreachable\";\n case \"sandbox_command_start_unavailable\":\n return \"The sandbox isn't ready yet\";\n case \"turn_execution_policy_definition_mismatch\":\n return \"Opengeni is applying a configuration update\";\n case \"sandbox_deadline_rotation\":\n return \"The sandbox reached its maximum lifetime, so Opengeni is moving the workspace to a fresh sandbox\";\n case \"sandbox_lifecycle_transition\":\n case \"sandbox_lease_superseded\":\n return facts.sandboxTransition === \"capture_in_progress\"\n ? \"Opengeni is saving the sandbox workspace\"\n : facts.sandboxTransition === \"provider_recovery_in_progress\"\n ? \"Opengeni is recovering the sandbox\"\n : facts.sandboxTransition === \"rotation_in_progress\"\n ? \"Opengeni is moving the workspace to a fresh sandbox\"\n : \"Opengeni is preparing the sandbox\";\n default:\n return \"A service this turn depends on is temporarily unavailable\";\n }\n}\n\n/** Live status while the same turn waits for its next automatic retry. */\nexport function providerRecoveryRetryingText(facts: ProviderRecoveryFacts): string {\n if (facts.sandboxWait) return `${providerRecoverySubject(facts)}…`;\n const progress =\n facts.attempt !== null && facts.maxAttempts !== null\n ? ` (attempt ${Math.min(facts.attempt, facts.maxAttempts)} of ${facts.maxAttempts})`\n : \" automatically\";\n return `${providerRecoverySubject(facts)} — retrying${progress}…`;\n}\n\n/** Terminal sentence once the automatic budget is spent. */\nexport function providerRecoveryExhaustedText(facts: ProviderRecoveryFacts): string {\n const spent = facts.attempt ?? facts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n const retried = `Opengeni retried ${spent} ${spent === 1 ? \"time\" : \"times\"} without success.`;\n const remedy = facts.modelRoute\n ? \"Try again in a few minutes, or switch to another model.\"\n : \"Try again in a few minutes.\";\n return `${providerRecoverySubject(facts)}. ${retried} ${remedy}`;\n}\n\nconst BOUNDARY_TYPES: ReadonlySet<string> = new Set([\n \"turn.recovery.requested\",\n \"turn.started\",\n \"turn.completed\",\n \"turn.failed\",\n \"turn.cancelled\",\n \"turn.superseded\",\n]);\n\n/**\n * The active turn's current automatic provider retry, or null. Only a\n * `recovering`, unpaused session qualifies, and only the newest boundary of its\n * exact active turn counts, so merged or replayed pages never borrow another\n * turn's diagnosis.\n */\nexport function currentProviderRecovery(\n session: {\n id: string;\n status: SessionStatus | null | undefined;\n activeTurnId: string | null | undefined;\n effectiveControl?: { state: string } | null | undefined;\n },\n events: readonly SessionEvent[],\n): ProviderRecoveryFacts | null {\n if (\n session.status !== \"recovering\" ||\n (session.effectiveControl && session.effectiveControl.state !== \"active\") ||\n !session.activeTurnId\n )\n return null;\n let latest: SessionEvent | undefined;\n for (const event of events) {\n if (\n event.sessionId !== session.id ||\n event.turnId !== session.activeTurnId ||\n event.duplicateOfEventId ||\n (event.turnAssociation && event.turnAssociation !== \"current\") ||\n !BOUNDARY_TYPES.has(event.type)\n )\n continue;\n if (!latest || event.sequence > latest.sequence) latest = event;\n }\n if (latest?.type !== \"turn.recovery.requested\") return null;\n const payload = latest.payload as Record<string, unknown> | null | undefined;\n return payload?.recoveryExhausted === true ? null : parseProviderRecovery(payload);\n}\n","import { formatErrorMessage, OpenGeniApiError } from \"@opengeni/sdk\";\nimport { parseProviderRecovery, providerRecoveryExhaustedText } from \"./provider-recovery\";\n\nconst clockTimeFormatter = new Intl.DateTimeFormat(undefined, {\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n});\n\n/** Local finished-at stamp for message footers: \"Aug 2, 3:42 PM\" / locale-equivalent. */\nexport function formatClockTime(iso: string): string {\n const then = new Date(iso);\n if (Number.isNaN(then.getTime())) {\n return \"\";\n }\n return clockTimeFormatter.format(then);\n}\n\n/** Compact relative time: \"now\", \"42s\", \"7m\", \"3h\", \"2d\", then a date. */\nexport function formatRelativeTime(iso: string, now: Date = new Date()): string {\n const then = new Date(iso).getTime();\n if (Number.isNaN(then)) {\n return \"\";\n }\n const seconds = Math.max(0, Math.floor((now.getTime() - then) / 1000));\n if (seconds < 10) {\n return \"now\";\n }\n if (seconds < 60) {\n return `${seconds}s`;\n }\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) {\n return `${minutes}m`;\n }\n const hours = Math.floor(minutes / 60);\n if (hours < 24) {\n return `${hours}h`;\n }\n const days = Math.floor(hours / 24);\n if (days < 14) {\n return `${days}d`;\n }\n return new Date(iso).toLocaleDateString();\n}\n\n/** Human-readable byte size: \"512 B\", \"8.0 KB\", \"1.4 MB\", \"3 GB\". */\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n const units = [\"KB\", \"MB\", \"GB\"] as const;\n let value = bytes / 1024;\n for (const unit of units) {\n if (value < 1024 || unit === \"GB\") {\n return `${value.toFixed(value < 10 ? 1 : 0)} ${unit}`;\n }\n value /= 1024;\n }\n return `${bytes} B`;\n}\n\n/** Single-line preview of arbitrary text, for tiles and collapsed rows. */\nexport function truncate(text: string, maxLength: number): string {\n const collapsed = text.replace(/\\s+/g, \" \").trim();\n if (collapsed.length <= maxLength) {\n return collapsed;\n }\n return `${collapsed.slice(0, Math.max(0, maxLength - 1)).trimEnd()}…`;\n}\n\n/** Render an unknown payload as readable text (pretty JSON when possible). */\nexport function stringifyPayload(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n if (typeof value === \"string\") {\n const parsed = tryParseJson(value);\n if (parsed !== undefined && typeof parsed === \"object\") {\n return stringifyPayload(parsed);\n }\n return value;\n }\n try {\n return JSON.stringify(value, null, 2) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/** JSON.parse that returns `undefined` instead of throwing. */\nexport function tryParseJson(text: string): unknown {\n const trimmed = text.trim();\n if (!trimmed.startsWith(\"{\") && !trimmed.startsWith(\"[\") && !trimmed.startsWith('\"')) {\n return undefined;\n }\n try {\n return JSON.parse(trimmed) as unknown;\n } catch {\n return undefined;\n }\n}\n\n/**\n * The canonical credit-death sentence. Credit exhaustion is the one failure a\n * user can fix themselves — the copy must say what happened (empty balance),\n * what to do (add credits), and what is safe (nothing was lost). Crucially it\n * must NOT say \"send a message to revive\": a revive turn burns credits the\n * workspace no longer has.\n */\nexport const CREDIT_EXHAUSTION_MESSAGE =\n \"Out of credits — this workspace's balance is empty. Add credits to continue; the conversation is preserved.\";\n\n/** A usage ceiling refused the send; the default allowance wording, plus what is safe. */\nexport const COMPOSER_MEMBER_ALLOWANCE_MESSAGE =\n \"Usage limit reached. A workspace admin can raise this limit. Your draft is preserved.\";\nexport const COMPOSER_WORKSPACE_ALLOWANCE_MESSAGE =\n \"Workspace usage limit reached. An organization admin can raise the workspace budget. Your draft is preserved.\";\n\n/**\n * Actionable composer copy for an edge rejection before a turn is accepted.\n * Unlike an in-flight credit exhaustion, this path has not consumed the\n * actor-private draft or any finalized attachment.\n */\nexport const COMPOSER_PAYMENT_REQUIRED_MESSAGE =\n \"Your organization doesn't have enough credits to send this message. Add credits or choose a model with another payment source. Your message and attachments are saved.\";\n\n/** Trusted, composer-owned guidance; unlike remote diagnostic prose, this is UI copy. */\nexport class ComposerStateError extends Error {}\n\n/** A restored request has omitted credentials and must be reconciled, not replayed. */\nexport class ComposerReconciliationRequiredError extends ComposerStateError {\n constructor() {\n super(\n \"Opengeni cannot safely retry this uncertain request after remount; reconcile the session before sending again.\",\n );\n }\n}\n\nexport class ComposerWorkspaceControlUnavailableError extends Error {\n constructor() {\n super(\"@opengeni/react: workspace-scoped resume requires setWorkspaceInferenceState.\");\n }\n}\n\n/**\n * The send named a model that is no longer in the live catalog (retired or\n * removed). Retrying the same send cannot succeed; the person must choose\n * another model, and the typed message stays recoverable via Edit message.\n */\nexport const COMPOSER_MODEL_UNAVAILABLE_MESSAGE =\n \"This chat's model is no longer available. Choose another model to continue. Your message is saved.\";\n\n/** `details.code` the API sets on a 422 for a model missing from the live catalog. */\nexport const MODEL_UNAVAILABLE_DETAIL_CODE = \"model_unavailable\";\n\n/**\n * A fresh Send or Steer refused because the task's own usage limit is reached.\n * The draft is kept and an unchanged retry is never offered. The one current\n * recovery action (raise or remove the limit, resume a goal) belongs to the\n * composer's `SessionUsageLimitNotice`, so this line only says what happened.\n */\nexport const COMPOSER_SESSION_USAGE_LIMIT_MESSAGE =\n \"This task's usage limit is reached. Your message is saved.\";\n\n/** The earlier wording, still recognized in refusals restored from storage. */\nconst LEGACY_COMPOSER_SESSION_USAGE_LIMIT_MESSAGE =\n \"This task's usage limit is reached. Raise or remove the limit to continue. Your message is saved.\";\n\n/**\n * Is this send refusal the task's usage limit? Reads the typed SDK error code\n * (`OpenGeniSessionUsageLimitReachedError`), and also the composer's own\n * sentence so a refusal restored from storage after a reload is recognized.\n */\nexport function isSessionUsageLimitSubmissionError(error: Error): boolean {\n return (\n (error instanceof OpenGeniApiError && error.code === \"session_usage_limit_reached\") ||\n error.message === COMPOSER_SESSION_USAGE_LIMIT_MESSAGE ||\n error.message === LEGACY_COMPOSER_SESSION_USAGE_LIMIT_MESSAGE\n );\n}\n\n/**\n * Is this send refusal \"the model is no longer available\"? Reads the typed\n * `details.code`, and also the historical message so a refusal persisted\n * before a reload (only its text survives) or from an older API is recognized.\n */\nexport function isModelUnavailableSubmissionError(error: Error): boolean {\n if (error instanceof OpenGeniApiError && error.details?.code === MODEL_UNAVAILABLE_DETAIL_CODE) {\n return true;\n }\n return (\n error.message === COMPOSER_MODEL_UNAVAILABLE_MESSAGE ||\n /^(?:Opengeni|OpenGeni) API 422: model is not available: /.test(error.message)\n );\n}\n\n/**\n * What a published Site's assistant tells a viewer it refused, by the\n * refusal's `details.code`. The draft is kept in every case.\n */\nexport const COMPOSER_SITE_REFUSAL_MESSAGES: Readonly<Record<string, string>> = Object.freeze({\n not_available_for_viewer: \"This Site's assistant can't do that for you. Your message is saved.\",\n site_budget_exhausted:\n \"This Site's assistant has reached its usage limit for now. Your message is saved.\",\n site_budget_busy: \"This Site's assistant is busy. Try again in a moment. Your message is saved.\",\n site_platform_brake_engaged:\n \"This Site's assistant is paused for visitors right now. Your message is saved.\",\n});\n\n/** The Site refusal code of a send refusal, if it is one. */\nexport function siteRefusalCode(error: Error): string | null {\n if (!(error instanceof OpenGeniApiError)) return null;\n const code = error.details?.code;\n return typeof code === \"string\" && code in COMPOSER_SITE_REFUSAL_MESSAGES ? code : null;\n}\n\nexport function composerSubmissionErrorMessage(error: Error): string {\n if (error instanceof ComposerReconciliationRequiredError) {\n return \"This client cannot safely retry this uncertain request after remount; reconcile the session before sending again.\";\n }\n if (error instanceof ComposerWorkspaceControlUnavailableError) {\n return \"This client cannot resume the workspace. Ask your administrator for a control-capable client.\";\n }\n if (error instanceof ComposerStateError) return error.message;\n if (error instanceof OpenGeniApiError && error.outcomeUnknown) return formatErrorMessage(error);\n if (isModelUnavailableSubmissionError(error)) return COMPOSER_MODEL_UNAVAILABLE_MESSAGE;\n if (isSessionUsageLimitSubmissionError(error)) return COMPOSER_SESSION_USAGE_LIMIT_MESSAGE;\n const siteRefusal = siteRefusalCode(error);\n if (siteRefusal) return COMPOSER_SITE_REFUSAL_MESSAGES[siteRefusal]!;\n if (error instanceof OpenGeniApiError && error.code === \"allowance_exhausted\") {\n // OpenGeniAllowanceExhaustedError carries the scope; read it structurally\n // so this startup-path helper adds no SDK or wording imports.\n const message =\n (error as { scope?: unknown }).scope === \"workspace\"\n ? COMPOSER_WORKSPACE_ALLOWANCE_MESSAGE\n : COMPOSER_MEMBER_ALLOWANCE_MESSAGE;\n return composerErrorReference(error, message);\n }\n return isComposerCreditRefusal(error)\n ? composerErrorReference(error, COMPOSER_PAYMENT_REQUIRED_MESSAGE)\n : formatErrorMessage(error);\n}\n\nfunction composerErrorReference(error: Error, message: string): string {\n return error instanceof OpenGeniApiError && error.correlationId\n ? `${message} Reference: ${error.correlationId}.`\n : message;\n}\n\n/** These definitive refusals need a payment, allowance or model change, not an unchanged retry. */\nexport function composerSubmissionCanRetry(error: Error): boolean {\n return !(\n isComposerCreditRefusal(error) ||\n isModelUnavailableSubmissionError(error) ||\n isSessionUsageLimitSubmissionError(error) ||\n (error instanceof OpenGeniApiError && error.code === \"allowance_exhausted\") ||\n // Only a busy Site assistant is worth an unchanged retry.\n (siteRefusalCode(error) !== null && siteRefusalCode(error) !== \"site_budget_busy\")\n );\n}\n\nfunction isComposerCreditRefusal(error: Error): boolean {\n // A 402 for the task's own usage limit is not a credit or payment problem.\n if (isSessionUsageLimitSubmissionError(error)) return false;\n return (\n (error instanceof OpenGeniApiError &&\n error.status === 402 &&\n (error.code === \"payment_required\" || error.code === \"insufficient_credits\")) ||\n isCreditExhaustion(error.message)\n );\n}\n\n/**\n * Does this failure/completion payload (or raw error string) mean the\n * workspace ran out of Opengeni credits? Matches the engine's\n * \"insufficient Opengeni credits\" text (case-insensitive, substring — it\n * arrives both bare and wrapped in \"Activity task failed: …\") and the\n * budget-exhausted segment limit the engine stamps on a turn it ended early.\n */\nexport function isCreditExhaustion(\n input: { error?: string | null; detail?: string | null; segmentLimit?: string | null } | string,\n): boolean {\n if (typeof input === \"string\") {\n return input.toLowerCase().includes(\"insufficient opengeni credits\");\n }\n if (input.segmentLimit === \"budget_exhausted\") {\n return true;\n }\n for (const text of [input.error, input.detail]) {\n if (typeof text === \"string\" && text.toLowerCase().includes(\"insufficient opengeni credits\")) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Humanize engine/provider failure text before it reaches the timeline or a\n * failure banner. Raw provider errors leak the wrong audience's instructions —\n * \"Incorrect API key … find your API key at platform.openai.com\" tells a\n * managed-deployment USER to fix credentials only an OPERATOR controls (and is\n * flatly wrong for Azure or subscription-backed engines). Auth, quota, and\n * credit-exhaustion failures collapse to one neutral, honest sentence; every\n * other reason passes through untouched. Raw payloads stay available in the\n * debug surfaces.\n */\nexport function humanizeFailureReason(reason: string | null): string | null {\n if (!reason) {\n return reason;\n }\n if (isCreditExhaustion(reason)) {\n return CREDIT_EXHAUSTION_MESSAGE;\n }\n const normalized = reason.toLowerCase();\n const authFailure =\n normalized.includes(\"incorrect api key\") ||\n normalized.includes(\"invalid api key\") ||\n normalized.includes(\"invalid_api_key\") ||\n normalized.includes(\"platform.openai.com/account/api-keys\") ||\n (normalized.includes(\"401\") &&\n (normalized.includes(\"api key\") || normalized.includes(\"unauthorized\")));\n if (authFailure) {\n return \"The model provider rejected this deployment's engine credentials. Sending messages won't help until the deployment's engine configuration is fixed.\";\n }\n const quotaFailure =\n normalized.includes(\"insufficient_quota\") || normalized.includes(\"exceeded your current quota\");\n if (quotaFailure) {\n return \"The model provider refused the request: this deployment's provider quota is exhausted.\";\n }\n return reason;\n}\n\n/** Project failure diagnostics without changing the stored event, including legacy retry wrappers. */\nexport function presentFailure(payload: Record<string, unknown>): {\n reason: string | null;\n safetyRefusal: boolean;\n} {\n const databaseFailure =\n payload.code === \"db_deadlock\" ||\n payload.code === \"db_serialization_failure\" ||\n payload.code === \"db_failure\" ||\n (typeof payload.sqlState === \"string\" &&\n /^[0-9A-Z]{5}$/.test(payload.sqlState) &&\n payload.database !== null &&\n typeof payload.database === \"object\" &&\n !Array.isArray(payload.database));\n if (databaseFailure) {\n return { reason: \"The service encountered a database error.\", safetyRefusal: false };\n }\n const text = (key: string): string | null => {\n const value = payload[key];\n return typeof value === \"string\" && value.trim() ? value : null;\n };\n const message = text(\"error\") ?? text(\"message\");\n const detail = text(\"lastRetryableError\") ?? text(\"detail\");\n const safetyRefusal =\n payload.code === \"provider_safety_refusal\" ||\n [message, detail].some(\n (value) =>\n value !== null && /\\bthis request was blocked by our safety systems\\b/i.test(value),\n );\n if (safetyRefusal) {\n return {\n reason: `The model provider blocked this request.${detail || message ? ` ${detail ?? message}` : \"\"}`,\n safetyRefusal: true,\n };\n }\n // Spent automatic retries: name the model and the remedy instead of the\n // recorded wrapper plus raw provider text (still in the stored event).\n const recovery = parseProviderRecovery(payload);\n if (recovery && payload.recoveryExhausted === true) {\n return { reason: providerRecoveryExhaustedText(recovery), safetyRefusal: false };\n }\n return {\n reason:\n detail && detail !== message\n ? [humanizeFailureReason(message), humanizeFailureReason(detail)].filter(Boolean).join(\" \")\n : humanizeFailureReason(message),\n safetyRefusal: false,\n };\n}\n"],"mappings":"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","names":["text"]}
@@ -3,7 +3,7 @@ import {
3
3
  buildTimeline,
4
4
  groupTimeline,
5
5
  sessionStatusFromEvents
6
- } from "./chunk-HQN5AZFY.js";
6
+ } from "./chunk-HGKELH6Z.js";
7
7
  import {
8
8
  isActionableHumanInputRequest
9
9
  } from "./chunk-IZV5FTJC.js";
@@ -11,7 +11,7 @@ import {
11
11
  FILE_ONLY_MESSAGE_TEXT,
12
12
  notifyObserver,
13
13
  useComposer
14
- } from "./chunk-X6KAA43Z.js";
14
+ } from "./chunk-Q26UAIXI.js";
15
15
  import {
16
16
  coerceReasoningEffortForModel,
17
17
  defaultEffortForModel,
@@ -1554,7 +1554,7 @@ function useSessionEvents(sessionId, options = {}) {
1554
1554
  let generation = navigationGenerationRef.current;
1555
1555
  const current = () => ownsNavigation() && generation === navigationGenerationRef.current;
1556
1556
  try {
1557
- const { resolveLatestQuestion } = await import("./latest-question-6WZQV23L.js");
1557
+ const { resolveLatestQuestion } = await import("./latest-question-CHE7E753.js");
1558
1558
  if (!current()) return null;
1559
1559
  const destination = await resolveLatestQuestion({
1560
1560
  client,
@@ -3003,4 +3003,4 @@ export {
3003
3003
  useGoal,
3004
3004
  useNewConversation
3005
3005
  };
3006
- //# sourceMappingURL=chunk-25YZS7TK.js.map
3006
+ //# sourceMappingURL=chunk-O5GPRG76.js.map
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  defaultChatComposerMessages
4
- } from "./chunk-BSIADJ4U.js";
4
+ } from "./chunk-6SNDCUPB.js";
5
5
  import {
6
6
  COMPOSER_VOICE_INPUT_START_EVENT,
7
7
  composerVoiceEventScope
@@ -9,7 +9,7 @@ import {
9
9
  import {
10
10
  shouldSteerOnKey,
11
11
  shouldSubmitOnKey
12
- } from "./chunk-X6KAA43Z.js";
12
+ } from "./chunk-Q26UAIXI.js";
13
13
  import {
14
14
  Tooltip,
15
15
  TooltipContent,
@@ -28,7 +28,7 @@ import {
28
28
  } from "./chunk-CM7LVUKC.js";
29
29
  import {
30
30
  composerSubmissionErrorMessage
31
- } from "./chunk-QQ5UGGGE.js";
31
+ } from "./chunk-KZENYIA2.js";
32
32
  import {
33
33
  cn
34
34
  } from "./chunk-TXS65BB2.js";
@@ -4899,4 +4899,4 @@ export {
4899
4899
  useVoiceInput,
4900
4900
  ComposerTranscriptionControl
4901
4901
  };
4902
- //# sourceMappingURL=chunk-UPP6YD2R.js.map
4902
+ //# sourceMappingURL=chunk-PWCBMEV2.js.map
@@ -16,7 +16,7 @@ import {
16
16
  ComposerWorkspaceControlUnavailableError,
17
17
  composerSubmissionCanRetry,
18
18
  composerSubmissionErrorMessage
19
- } from "./chunk-QQ5UGGGE.js";
19
+ } from "./chunk-KZENYIA2.js";
20
20
 
21
21
  // src/hooks/use-composer.ts
22
22
  import {
@@ -2206,4 +2206,4 @@ export {
2206
2206
  shouldSubmitOnKey,
2207
2207
  shouldSteerOnKey
2208
2208
  };
2209
- //# sourceMappingURL=chunk-X6KAA43Z.js.map
2209
+ //# sourceMappingURL=chunk-Q26UAIXI.js.map
@@ -12,7 +12,7 @@ import {
12
12
  import {
13
13
  formatBytes,
14
14
  formatRelativeTime
15
- } from "./chunk-QQ5UGGGE.js";
15
+ } from "./chunk-KZENYIA2.js";
16
16
  import {
17
17
  cn
18
18
  } from "./chunk-TXS65BB2.js";
@@ -2593,6 +2593,10 @@ function swapFailureMessage(result) {
2593
2593
  return "The selected machine is offline.";
2594
2594
  case "concurrent_swap":
2595
2595
  return "The session route changed concurrently. Refresh and try again.";
2596
+ case "personal_machine_permission_required":
2597
+ return "The machine's owner has not allowed this chat to use it.";
2598
+ case "personal_machine_not_permitted":
2599
+ return "Only the machine's owner can use it in this chat.";
2596
2600
  default:
2597
2601
  return "The session stayed on its current sandbox.";
2598
2602
  }
@@ -2770,4 +2774,4 @@ export {
2770
2774
  EnrollmentDeviceFlow,
2771
2775
  EnrollmentConsent
2772
2776
  };
2773
- //# sourceMappingURL=chunk-U7A22SY4.js.map
2777
+ //# sourceMappingURL=chunk-TIHSXNBC.js.map