@iota-uz/sdk 0.4.24 → 0.4.26

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.
@@ -1649,6 +1649,37 @@ function loadDebugMode(sessionId) {
1649
1649
  }
1650
1650
  }
1651
1651
 
1652
+ // ui/src/bichat/utils/reasoningEffortStorage.ts
1653
+ var STORAGE_KEY = "bichat.reasoningEffort";
1654
+ function saveReasoningEffort(effort) {
1655
+ if (typeof window === "undefined") {
1656
+ return;
1657
+ }
1658
+ try {
1659
+ window.sessionStorage.setItem(STORAGE_KEY, effort);
1660
+ } catch {
1661
+ }
1662
+ }
1663
+ function loadReasoningEffort() {
1664
+ if (typeof window === "undefined") {
1665
+ return null;
1666
+ }
1667
+ try {
1668
+ return window.sessionStorage.getItem(STORAGE_KEY);
1669
+ } catch {
1670
+ return null;
1671
+ }
1672
+ }
1673
+ function clearReasoningEffort() {
1674
+ if (typeof window === "undefined") {
1675
+ return;
1676
+ }
1677
+ try {
1678
+ window.sessionStorage.removeItem(STORAGE_KEY);
1679
+ } catch {
1680
+ }
1681
+ }
1682
+
1652
1683
  // ui/src/bichat/utils/debugTrace.ts
1653
1684
  function hasMeaningfulUsage(trace) {
1654
1685
  if (!trace) {
@@ -1791,6 +1822,16 @@ function readDebugLimitsFromGlobalContext() {
1791
1822
  completionReserveTokens
1792
1823
  };
1793
1824
  }
1825
+ function readReasoningEffortOptionsFromGlobalContext() {
1826
+ if (typeof window === "undefined") {
1827
+ return void 0;
1828
+ }
1829
+ const opts = window.__APPLET_CONTEXT__?.extensions?.llm?.reasoningEffortOptions;
1830
+ if (!Array.isArray(opts) || opts.length === 0) {
1831
+ return void 0;
1832
+ }
1833
+ return opts.filter((o) => typeof o === "string");
1834
+ }
1794
1835
 
1795
1836
  // ui/src/bichat/machine/selectors.ts
1796
1837
  function deriveDebugMode(state) {
@@ -1807,8 +1848,10 @@ function deriveSessionSnapshot(state, methods) {
1807
1848
  debugMode: deriveDebugMode(state),
1808
1849
  sessionDebugUsage: getSessionDebugUsage(state.messaging.turns),
1809
1850
  debugLimits: state.session.debugLimits,
1851
+ reasoningEffort: state.session.reasoningEffort,
1810
1852
  setError: methods.setError,
1811
- retryFetchSession: methods.retryFetchSession
1853
+ retryFetchSession: methods.retryFetchSession,
1854
+ setReasoningEffort: methods.setReasoningEffort
1812
1855
  };
1813
1856
  }
1814
1857
  function deriveMessagingSnapshot(state, methods) {
@@ -1998,6 +2041,7 @@ var ChatMachine = class {
1998
2041
  this.sendingSessionId = null;
1999
2042
  this.fetchCancelled = false;
2000
2043
  this.disposed = false;
2044
+ this.reasoningEffortOptions = null;
2001
2045
  /** Memoized sessionDebugUsage — avoids unnecessary session re-renders during streaming. */
2002
2046
  this.lastSessionDebugUsage = null;
2003
2047
  /** Interval handle for passive polling when another tab has an active stream. */
@@ -2029,7 +2073,8 @@ var ChatMachine = class {
2029
2073
  if (this.lastSessionSnapshotVersion !== this.sessionSnapshotVersion) {
2030
2074
  this.cachedSessionSnapshot = deriveSessionSnapshot(this.state, {
2031
2075
  setError: this.setError,
2032
- retryFetchSession: this.retryFetchSession
2076
+ retryFetchSession: this.retryFetchSession,
2077
+ setReasoningEffort: this.setReasoningEffort
2033
2078
  });
2034
2079
  this.lastSessionSnapshotVersion = this.sessionSnapshotVersion;
2035
2080
  }
@@ -2083,6 +2128,11 @@ var ChatMachine = class {
2083
2128
  this.dataSource = config.dataSource;
2084
2129
  this.rateLimiter = config.rateLimiter;
2085
2130
  this.onSessionCreated = config.onSessionCreated;
2131
+ this.reasoningEffortOptions = this.buildReasoningEffortOptions();
2132
+ const initialReasoningEffort = this.sanitizeReasoningEffort(loadReasoningEffort() || void 0);
2133
+ if (!initialReasoningEffort) {
2134
+ clearReasoningEffort();
2135
+ }
2086
2136
  this.state = {
2087
2137
  session: {
2088
2138
  currentSessionId: void 0,
@@ -2091,7 +2141,8 @@ var ChatMachine = class {
2091
2141
  error: null,
2092
2142
  errorRetryable: false,
2093
2143
  debugModeBySession: {},
2094
- debugLimits: readDebugLimitsFromGlobalContext()
2144
+ debugLimits: readDebugLimitsFromGlobalContext(),
2145
+ reasoningEffort: initialReasoningEffort
2095
2146
  },
2096
2147
  messaging: {
2097
2148
  turns: [],
@@ -2133,6 +2184,21 @@ var ChatMachine = class {
2133
2184
  this.enqueueMessage = this._enqueueMessage.bind(this);
2134
2185
  this.removeQueueItem = this._removeQueueItem.bind(this);
2135
2186
  this.updateQueueItem = this._updateQueueItem.bind(this);
2187
+ this.setReasoningEffort = this._setReasoningEffort.bind(this);
2188
+ }
2189
+ buildReasoningEffortOptions() {
2190
+ const options = readReasoningEffortOptionsFromGlobalContext();
2191
+ if (!options || options.length === 0) {
2192
+ return null;
2193
+ }
2194
+ return new Set(options);
2195
+ }
2196
+ // Keep outbound payloads constrained to server-declared options.
2197
+ sanitizeReasoningEffort(effort) {
2198
+ if (!effort || !this.reasoningEffortOptions || this.reasoningEffortOptions.size === 0) {
2199
+ return void 0;
2200
+ }
2201
+ return this.reasoningEffortOptions.has(effort) ? effort : void 0;
2136
2202
  }
2137
2203
  // =====================================================================
2138
2204
  // Lifecycle
@@ -2253,6 +2319,15 @@ var ChatMachine = class {
2253
2319
  }
2254
2320
  });
2255
2321
  }
2322
+ _setReasoningEffort(effort) {
2323
+ const next = this.sanitizeReasoningEffort(effort);
2324
+ this._updateSession({ reasoningEffort: next });
2325
+ if (next) {
2326
+ saveReasoningEffort(next);
2327
+ return;
2328
+ }
2329
+ clearReasoningEffort();
2330
+ }
2256
2331
  // =====================================================================
2257
2332
  // Private — session fetch
2258
2333
  // =====================================================================
@@ -2454,6 +2529,33 @@ var ChatMachine = class {
2454
2529
  });
2455
2530
  }
2456
2531
  }
2532
+ async _resumeAcceptedRunOrPoll(sessionId, runId) {
2533
+ setRunMarker(sessionId, runId);
2534
+ try {
2535
+ await this._runResumeStream(sessionId, runId);
2536
+ } catch (err) {
2537
+ if (this.disposed) {
2538
+ return;
2539
+ }
2540
+ console.warn("[ChatMachine] resumeStream failed, switching to status polling fallback:", err);
2541
+ const getStreamStatus2 = this.dataSource.getStreamStatus;
2542
+ const status = getStreamStatus2 ? await getStreamStatus2(sessionId).catch(() => null) : null;
2543
+ if (!status?.active) {
2544
+ clearRunMarker(sessionId);
2545
+ await this._syncSessionFromServer(sessionId, true).catch(() => {
2546
+ });
2547
+ this._updateMessaging({ generationInProgress: false });
2548
+ return;
2549
+ }
2550
+ setRunMarker(sessionId, status.runId ?? runId);
2551
+ this._updateMessaging({
2552
+ isStreaming: false,
2553
+ loading: false,
2554
+ generationInProgress: true
2555
+ });
2556
+ this._startPassivePolling(sessionId);
2557
+ }
2558
+ }
2457
2559
  // =====================================================================
2458
2560
  // Private — actions
2459
2561
  // =====================================================================
@@ -2572,20 +2674,28 @@ var ChatMachine = class {
2572
2674
  streamingContent: ""
2573
2675
  });
2574
2676
  try {
2575
- const compactResult = await this.dataSource.compactSessionHistory(curSessionId);
2576
- const summary = compactResult.summary || "";
2677
+ const accepted = await this.dataSource.compactSessionHistory(curSessionId);
2678
+ if (!accepted.runId) {
2679
+ throw new Error("Async compaction run metadata is missing");
2680
+ }
2577
2681
  this._updateMessaging({
2578
- turns: applyTurnLifecycleForPendingQuestion([createCompactedSystemTurn(curSessionId, summary)], null),
2682
+ turns: applyTurnLifecycleForPendingQuestion(
2683
+ [createCompactedSystemTurn(curSessionId, "Compacting conversation history...")],
2684
+ null
2685
+ ),
2579
2686
  pendingQuestion: null
2580
2687
  });
2581
- const result = await this.dataSource.fetchSession(curSessionId);
2582
- if (result) {
2583
- this._updateSession({ session: result.session });
2584
- this._setTurnsFromFetch(result.turns, result.pendingQuestion || null);
2585
- } else {
2586
- this._setTurnsFromFetch([], null);
2688
+ await this._resumeAcceptedRunOrPoll(curSessionId, accepted.runId);
2689
+ if (!this.state.messaging.generationInProgress) {
2690
+ const result = await this.dataSource.fetchSession(curSessionId);
2691
+ if (result) {
2692
+ this._updateSession({ session: result.session });
2693
+ this._setTurnsFromFetch(result.turns, result.pendingQuestion || null);
2694
+ } else {
2695
+ this._setTurnsFromFetch([], null);
2696
+ }
2697
+ this._updateMessaging({ codeOutputs: [] });
2587
2698
  }
2588
- this._updateMessaging({ codeOutputs: [] });
2589
2699
  } catch (err) {
2590
2700
  const normalized = normalizeRPCError(err, "Failed to compact session history");
2591
2701
  this._updateInput({ inputError: normalized.userMessage });
@@ -2645,6 +2755,7 @@ var ChatMachine = class {
2645
2755
  attachments,
2646
2756
  debugMode,
2647
2757
  replaceFromMessageID,
2758
+ reasoningEffort,
2648
2759
  tempTurnId
2649
2760
  } = params;
2650
2761
  let accumulatedContent = "";
@@ -2659,7 +2770,8 @@ var ChatMachine = class {
2659
2770
  this.abortController?.signal,
2660
2771
  {
2661
2772
  debugMode,
2662
- replaceFromMessageID
2773
+ replaceFromMessageID,
2774
+ reasoningEffort
2663
2775
  }
2664
2776
  )) {
2665
2777
  if (this.abortController?.signal.aborted) {
@@ -2750,8 +2862,6 @@ var ChatMachine = class {
2750
2862
  this._notifySessionsUpdated("session_created", targetSessionId);
2751
2863
  if (this.onSessionCreated) {
2752
2864
  this.onSessionCreated(targetSessionId);
2753
- } else {
2754
- this.dataSource.navigateToSession?.(targetSessionId);
2755
2865
  }
2756
2866
  }
2757
2867
  this._clearStreamError();
@@ -2858,6 +2968,7 @@ var ChatMachine = class {
2858
2968
  attachments,
2859
2969
  debugMode: curDebugMode,
2860
2970
  replaceFromMessageID,
2971
+ reasoningEffort: this.sanitizeReasoningEffort(this.state.session.reasoningEffort),
2861
2972
  tempTurnId: tempTurn.id
2862
2973
  });
2863
2974
  if (stopped) {
@@ -3037,9 +3148,24 @@ var ChatMachine = class {
3037
3148
  return;
3038
3149
  }
3039
3150
  if (result.success) {
3151
+ this._updateMessaging({
3152
+ pendingQuestion: null,
3153
+ turns: applyTurnLifecycleForPendingQuestion(this.state.messaging.turns, null)
3154
+ });
3040
3155
  if (result.data) {
3041
- this._updateSession({ session: result.data.session });
3042
- this._setTurnsFromFetch(result.data.turns, result.data.pendingQuestion || null);
3156
+ await this._resumeAcceptedRunOrPoll(curSessionId, result.data.runId);
3157
+ if (!this.state.messaging.generationInProgress) {
3158
+ const fetchResult = await this.dataSource.fetchSession(curSessionId);
3159
+ if (this.disposed) {
3160
+ return;
3161
+ }
3162
+ if (fetchResult) {
3163
+ this._updateSession({ session: fetchResult.session });
3164
+ this._setTurnsFromFetch(fetchResult.turns, fetchResult.pendingQuestion || null);
3165
+ } else {
3166
+ this._updateSession({ error: "Failed to load updated session", errorRetryable: true });
3167
+ }
3168
+ }
3043
3169
  } else if (curSessionId !== "new") {
3044
3170
  const fetchResult = await this.dataSource.fetchSession(curSessionId);
3045
3171
  if (this.disposed) {
@@ -3083,7 +3209,9 @@ var ChatMachine = class {
3083
3209
  pendingQuestion: null,
3084
3210
  turns: applyTurnLifecycleForPendingQuestion(this.state.messaging.turns, null)
3085
3211
  });
3086
- if (curSessionId !== "new") {
3212
+ if (result.data) {
3213
+ await this._resumeAcceptedRunOrPoll(curSessionId, result.data.runId);
3214
+ } else if (curSessionId !== "new") {
3087
3215
  const fetchResult = await this.dataSource.fetchSession(curSessionId);
3088
3216
  if (this.disposed) {
3089
3217
  return;
@@ -7077,6 +7205,43 @@ function CopyPill({ text }) {
7077
7205
  }
7078
7206
  );
7079
7207
  }
7208
+ function InlineCopyButton({ text }) {
7209
+ const [copied, setCopied] = React.useState(false);
7210
+ const timerRef = React.useRef(null);
7211
+ React.useEffect(() => () => {
7212
+ if (timerRef.current !== null) {
7213
+ clearTimeout(timerRef.current);
7214
+ }
7215
+ }, []);
7216
+ const handleCopy = async (e) => {
7217
+ e.stopPropagation();
7218
+ try {
7219
+ await navigator.clipboard.writeText(text);
7220
+ setCopied(true);
7221
+ if (timerRef.current !== null) {
7222
+ clearTimeout(timerRef.current);
7223
+ }
7224
+ timerRef.current = window.setTimeout(() => {
7225
+ setCopied(false);
7226
+ timerRef.current = null;
7227
+ }, 2e3);
7228
+ } catch (err) {
7229
+ console.error("Copy failed:", err);
7230
+ }
7231
+ };
7232
+ return /* @__PURE__ */ jsxRuntime.jsx(
7233
+ "button",
7234
+ {
7235
+ onClick: handleCopy,
7236
+ "aria-label": copied ? "Copied" : "Copy",
7237
+ className: [
7238
+ "flex-shrink-0 p-1 rounded transition-colors duration-150",
7239
+ copied ? "text-emerald-500 dark:text-emerald-400" : "text-gray-300 dark:text-gray-600 hover:text-gray-500 dark:hover:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700/40"
7240
+ ].join(" "),
7241
+ children: copied ? /* @__PURE__ */ jsxRuntime.jsx(react.Check, { size: 11, weight: "bold" }) : /* @__PURE__ */ jsxRuntime.jsx(react.Copy, { size: 11 })
7242
+ }
7243
+ );
7244
+ }
7080
7245
  function MetricChip({ icon, value, label }) {
7081
7246
  return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 px-2 py-1 rounded-md bg-gray-50 dark:bg-gray-800/40 text-[11px] tabular-nums", children: [
7082
7247
  icon,
@@ -7175,7 +7340,7 @@ function ToolCard({ tool }) {
7175
7340
  }
7176
7341
  );
7177
7342
  }
7178
- function DebugPanel({ trace, debugLimits = null }) {
7343
+ function DebugPanel({ trace }) {
7179
7344
  const hasData = !!trace && hasDebugTrace(trace);
7180
7345
  const traceID = trace?.traceId?.trim() || "";
7181
7346
  const traceURL = trace?.traceUrl?.trim() || "";
@@ -7194,22 +7359,6 @@ function DebugPanel({ trace, debugLimits = null }) {
7194
7359
  }
7195
7360
  })();
7196
7361
  const tokensPerSecond = calculateCompletionTokensPerSecond(trace?.usage, trace?.generationMs);
7197
- const effectiveMaxTokens = debugLimits?.effectiveMaxTokens ?? 0;
7198
- const promptTokens = trace?.usage?.promptTokens ?? 0;
7199
- const contextUsagePercent = calculateContextUsagePercent(promptTokens, effectiveMaxTokens);
7200
- const contextUsagePercentLabel = contextUsagePercent !== null ? contextUsagePercent.toFixed(1) : null;
7201
- const formatCompactTokens = (value) => {
7202
- if (!Number.isFinite(value) || value <= 0) {
7203
- return "0 tokens";
7204
- }
7205
- return `${new Intl.NumberFormat("en-US", {
7206
- notation: "compact",
7207
- maximumFractionDigits: value >= 1e5 ? 0 : 1
7208
- }).format(value)} tokens`;
7209
- };
7210
- const contextPercentValue = contextUsagePercent ?? 0;
7211
- const contextUsageToneClass = contextPercentValue > 75 ? "bg-red-100 dark:bg-red-900/30 text-red-600 dark:text-red-400" : contextPercentValue > 50 ? "bg-amber-100 dark:bg-amber-900/30 text-amber-600 dark:text-amber-400" : "bg-emerald-100 dark:bg-emerald-900/30 text-emerald-600 dark:text-emerald-400";
7212
- const contextUsageBarColor = contextPercentValue > 75 ? "#ef4444" : contextPercentValue > 50 ? "#f59e0b" : "#10b981";
7213
7362
  const metrics = [];
7214
7363
  if (hasData && trace) {
7215
7364
  if (trace.generationMs !== void 0) {
@@ -7262,34 +7411,36 @@ function DebugPanel({ trace, debugLimits = null }) {
7262
7411
  hasData && trace && /* @__PURE__ */ jsxRuntime.jsx(CopyPill, { text: JSON.stringify(trace, null, 2) })
7263
7412
  ] }),
7264
7413
  hasData && trace ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
7265
- (traceID || safeTraceURL) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-gray-200/60 dark:border-gray-700/40 bg-gray-50/50 dark:bg-gray-800/40 p-3 space-y-2", children: [
7266
- traceID && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
7267
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
7268
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] uppercase tracking-wider text-gray-500 dark:text-gray-400", children: "Trace ID" }),
7269
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-mono text-[11px] text-gray-800 dark:text-gray-200 break-all", children: traceID })
7270
- ] }),
7271
- /* @__PURE__ */ jsxRuntime.jsx(CopyPill, { text: traceID })
7414
+ (traceID || trace.sessionId) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-gray-200/60 dark:border-gray-700/40 bg-gray-50/50 dark:bg-gray-800/40 px-3 py-2 space-y-1.5", children: [
7415
+ traceID && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
7416
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-[10px] uppercase tracking-wider text-gray-400 dark:text-gray-500 w-14", children: "Trace" }),
7417
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 min-w-0 font-mono text-[11px] text-gray-700 dark:text-gray-300 truncate", title: traceID, children: traceID }),
7418
+ /* @__PURE__ */ jsxRuntime.jsx(InlineCopyButton, { text: traceID })
7272
7419
  ] }),
7273
- safeTraceURL && /* @__PURE__ */ jsxRuntime.jsxs(
7274
- "a",
7275
- {
7276
- href: safeTraceURL,
7277
- target: "_blank",
7278
- rel: "noopener noreferrer",
7279
- "aria-label": "View full trace in Langfuse (opens in new tab)",
7280
- className: "inline-flex items-center gap-1.5 text-[11px] font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300",
7281
- children: [
7282
- /* @__PURE__ */ jsxRuntime.jsx(react.ArrowSquareOut, { size: 12, weight: "bold" }),
7283
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Open in Langfuse" })
7284
- ]
7285
- }
7286
- )
7287
- ] }),
7288
- (trace.thinking || trace.observationReason || trace.sessionId) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-gray-200/60 dark:border-gray-700/40 bg-gray-50/50 dark:bg-gray-800/40 p-3 space-y-2", children: [
7289
- trace.sessionId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[10px] uppercase tracking-wider text-gray-500 dark:text-gray-400", children: [
7290
- "Session: ",
7291
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono normal-case break-all", children: trace.sessionId })
7420
+ trace.sessionId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
7421
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-[10px] uppercase tracking-wider text-gray-400 dark:text-gray-500 w-14", children: "Session" }),
7422
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 min-w-0 font-mono text-[11px] text-gray-700 dark:text-gray-300 truncate", title: trace.sessionId, children: trace.sessionId }),
7423
+ /* @__PURE__ */ jsxRuntime.jsx(InlineCopyButton, { text: trace.sessionId })
7292
7424
  ] }),
7425
+ safeTraceURL && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 min-w-0 pt-0.5", children: [
7426
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 w-14" }),
7427
+ /* @__PURE__ */ jsxRuntime.jsxs(
7428
+ "a",
7429
+ {
7430
+ href: safeTraceURL,
7431
+ target: "_blank",
7432
+ rel: "noopener noreferrer",
7433
+ "aria-label": "Open in Langfuse",
7434
+ className: "inline-flex items-center gap-1.5 text-[11px] font-medium text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 transition-colors duration-150",
7435
+ children: [
7436
+ /* @__PURE__ */ jsxRuntime.jsx(react.ArrowSquareOut, { size: 11, weight: "bold" }),
7437
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Open in Langfuse" })
7438
+ ]
7439
+ }
7440
+ )
7441
+ ] })
7442
+ ] }),
7443
+ (trace.thinking || trace.observationReason) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-gray-200/60 dark:border-gray-700/40 bg-gray-50/50 dark:bg-gray-800/40 p-3 space-y-2", children: [
7293
7444
  trace.observationReason && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[11px] text-amber-700 dark:text-amber-300", children: [
7294
7445
  "Observation: ",
7295
7446
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: trace.observationReason })
@@ -7329,30 +7480,6 @@ function DebugPanel({ trace, debugLimits = null }) {
7329
7480
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-1.5 py-0.5 rounded-full bg-gray-100 dark:bg-gray-800 text-[10px] font-mono font-medium text-gray-500 dark:text-gray-400 tabular-nums", children: trace.tools.length })
7330
7481
  ] }),
7331
7482
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: trace.tools.map((tool, idx) => /* @__PURE__ */ jsxRuntime.jsx(ToolCard, { tool }, `${tool.callId || tool.name}-${idx}`)) })
7332
- ] }),
7333
- contextUsagePercentLabel !== null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-gray-200/60 dark:border-gray-700/40 bg-gray-50/50 dark:bg-gray-800/40 p-3 space-y-2", children: [
7334
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
7335
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wider text-gray-500 dark:text-gray-400", children: "Context usage" }),
7336
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-[10px] text-gray-500 dark:text-gray-400 tabular-nums", children: [
7337
- formatCompactTokens(promptTokens),
7338
- " / ",
7339
- formatCompactTokens(effectiveMaxTokens)
7340
- ] }),
7341
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `px-1.5 py-0.5 rounded-full text-[10px] font-semibold tabular-nums ${contextUsageToneClass}`, children: [
7342
- contextUsagePercentLabel,
7343
- "%"
7344
- ] })
7345
- ] }),
7346
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1.5 rounded-full bg-gray-200/80 dark:bg-gray-700/50 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
7347
- "div",
7348
- {
7349
- className: "h-full rounded-full transition-all duration-700 ease-out",
7350
- style: {
7351
- width: `${Math.min(contextPercentValue, 100)}%`,
7352
- backgroundColor: contextUsageBarColor
7353
- }
7354
- }
7355
- ) })
7356
7483
  ] })
7357
7484
  ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-400 dark:text-gray-500 italic", children: "Debug info unavailable" })
7358
7485
  ] });
@@ -7414,8 +7541,7 @@ function AssistantMessage({
7414
7541
  hideAvatar = false,
7415
7542
  hideActions = false,
7416
7543
  hideTimestamp = false,
7417
- showDebug = false,
7418
- debugLimits = null
7544
+ showDebug = false
7419
7545
  }) {
7420
7546
  const { t } = useTranslation();
7421
7547
  const [explanationExpanded, setExplanationExpanded] = React.useState(false);
@@ -7606,7 +7732,7 @@ function AssistantMessage({
7606
7732
  explanationExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-3 text-sm text-gray-600 dark:text-gray-400", children: /* @__PURE__ */ jsxRuntime.jsx(React.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx("div", { children: t("BiChat.Common.Loading") }), children: /* @__PURE__ */ jsxRuntime.jsx(MarkdownRenderer2, { content: turn.explanation }) }) })
7607
7733
  ] })
7608
7734
  ) }),
7609
- showDebug && /* @__PURE__ */ jsxRuntime.jsx(DebugPanel, { trace: turn.debug, debugLimits })
7735
+ showDebug && /* @__PURE__ */ jsxRuntime.jsx(DebugPanel, { trace: turn.debug })
7610
7736
  ] }),
7611
7737
  turn.artifacts && turn.artifacts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: classes.artifacts, children: renderSlot(
7612
7738
  slots?.artifacts,
@@ -7798,7 +7924,7 @@ function AssistantTurnView({
7798
7924
  hideTimestamp,
7799
7925
  allowRegenerate = true
7800
7926
  }) {
7801
- const { debugMode, debugLimits } = useChatSession();
7927
+ const { debugMode } = useChatSession();
7802
7928
  const { handleCopy, handleRegenerate, pendingQuestion, sendMessage: sendMessage2, loading } = useChatMessaging();
7803
7929
  const assistantTurn = turn.assistantTurn;
7804
7930
  if (!assistantTurn) {
@@ -7833,8 +7959,7 @@ function AssistantTurnView({
7833
7959
  hideAvatar,
7834
7960
  hideActions,
7835
7961
  hideTimestamp,
7836
- showDebug: debugMode,
7837
- debugLimits
7962
+ showDebug: debugMode
7838
7963
  }
7839
7964
  );
7840
7965
  }
@@ -8979,6 +9104,36 @@ function DebugStatsPanel({ debugSessionUsage, debugLimits }) {
8979
9104
  ] })
8980
9105
  ] });
8981
9106
  }
9107
+ var EFFORT_LABEL_KEYS = {
9108
+ low: "BiChat.Input.ReasoningEffortLow",
9109
+ medium: "BiChat.Input.ReasoningEffortMedium",
9110
+ high: "BiChat.Input.ReasoningEffortHigh",
9111
+ xhigh: "BiChat.Input.ReasoningEffortXHigh"
9112
+ };
9113
+ function ReasoningEffortSelector({ options, value, onChange, disabled }) {
9114
+ const { t } = useTranslation();
9115
+ const selected = value || options[1] || options[0];
9116
+ const label = t("BiChat.Input.ReasoningEffort");
9117
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 self-center flex items-center gap-1.5", children: [
9118
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500 font-medium whitespace-nowrap select-none", children: label }),
9119
+ /* @__PURE__ */ jsxRuntime.jsx(
9120
+ "select",
9121
+ {
9122
+ value: selected,
9123
+ disabled,
9124
+ onChange: (event) => onChange(event.target.value),
9125
+ className: [
9126
+ "cursor-pointer h-8 rounded-lg border border-gray-200 dark:border-gray-600",
9127
+ "bg-gray-50 dark:bg-gray-700/50 px-2.5 text-[11px] font-medium leading-none",
9128
+ "text-gray-700 dark:text-gray-200 focus:outline-none focus:ring-2 focus:ring-primary-500/25",
9129
+ "disabled:opacity-40 disabled:cursor-not-allowed"
9130
+ ].join(" "),
9131
+ "aria-label": label,
9132
+ children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt, children: t(EFFORT_LABEL_KEYS[opt] ?? opt) }, opt))
9133
+ }
9134
+ )
9135
+ ] });
9136
+ }
8982
9137
  var MAX_FILES_DEFAULT = 10;
8983
9138
  var MAX_FILE_SIZE_DEFAULT = 20 * 1024 * 1024;
8984
9139
  var MAX_HEIGHT = 192;
@@ -9005,7 +9160,10 @@ var MessageInput = React.forwardRef(
9005
9160
  maxFiles = MAX_FILES_DEFAULT,
9006
9161
  maxFileSize = MAX_FILE_SIZE_DEFAULT,
9007
9162
  containerClassName,
9008
- formClassName
9163
+ formClassName,
9164
+ reasoningEffortOptions,
9165
+ reasoningEffort,
9166
+ onReasoningEffortChange
9009
9167
  }, ref) => {
9010
9168
  const { t } = useTranslation();
9011
9169
  const [attachments, setAttachments] = React.useState([]);
@@ -9454,16 +9612,25 @@ var MessageInput = React.forwardRef(
9454
9612
  "aria-label": t("BiChat.Input.MessageInput")
9455
9613
  }
9456
9614
  ) }),
9615
+ reasoningEffortOptions && reasoningEffortOptions.length > 0 && onReasoningEffortChange && /* @__PURE__ */ jsxRuntime.jsx(
9616
+ ReasoningEffortSelector,
9617
+ {
9618
+ options: reasoningEffortOptions,
9619
+ value: reasoningEffort,
9620
+ onChange: onReasoningEffortChange,
9621
+ disabled: disabled || loading
9622
+ }
9623
+ ),
9457
9624
  isStreaming && onCancelStreaming ? /* @__PURE__ */ jsxRuntime.jsx(
9458
9625
  "button",
9459
9626
  {
9460
9627
  type: "button",
9461
9628
  onClick: onCancelStreaming,
9462
9629
  disabled: disabled || fetching,
9463
- className: "cursor-pointer flex-shrink-0 self-center p-2 rounded-lg bg-red-600 hover:bg-red-700 active:bg-red-800 active:scale-95 text-white shadow-sm transition-all disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-red-600",
9630
+ className: "cursor-pointer flex-shrink-0 self-center p-2 rounded-lg bg-gray-900 hover:bg-gray-800 active:bg-black active:scale-95 text-white shadow-sm transition-all dark:bg-gray-100 dark:hover:bg-gray-200 dark:active:bg-white dark:text-gray-900 disabled:opacity-40 disabled:cursor-not-allowed",
9464
9631
  "aria-label": t("BiChat.Common.Cancel"),
9465
9632
  title: t("BiChat.Common.Cancel"),
9466
- children: /* @__PURE__ */ jsxRuntime.jsx(react.X, { size: 18, weight: "bold" })
9633
+ children: /* @__PURE__ */ jsxRuntime.jsx(react.Stop, { size: 18, weight: "fill" })
9467
9634
  }
9468
9635
  ) : /* @__PURE__ */ jsxRuntime.jsx(
9469
9636
  "button",
@@ -11653,7 +11820,9 @@ function ChatSessionCore({
11653
11820
  debugLimits,
11654
11821
  currentSessionId,
11655
11822
  setError,
11656
- retryFetchSession
11823
+ retryFetchSession,
11824
+ reasoningEffort,
11825
+ setReasoningEffort
11657
11826
  } = useChatSession();
11658
11827
  const {
11659
11828
  turns,
@@ -11681,6 +11850,7 @@ function ChatSessionCore({
11681
11850
  const accessReadOnly = session?.access ? !session.access.canWrite : false;
11682
11851
  const effectiveReadOnly = Boolean(readOnly ?? isReadOnly) || isArchived || accessReadOnly;
11683
11852
  const [restoring, setRestoring] = React.useState(false);
11853
+ const [reasoningEffortOptions] = React.useState(() => readReasoningEffortOptionsFromGlobalContext());
11684
11854
  const handleRestore = React.useCallback(async () => {
11685
11855
  if (!session?.id) {
11686
11856
  return;
@@ -11948,7 +12118,10 @@ function ChatSessionCore({
11948
12118
  onUpdateQueueItem: updateQueueItem,
11949
12119
  onCancelStreaming: cancel,
11950
12120
  containerClassName: "pt-6 px-6",
11951
- formClassName: "mx-auto"
12121
+ formClassName: "mx-auto",
12122
+ reasoningEffortOptions,
12123
+ reasoningEffort,
12124
+ onReasoningEffortChange: setReasoningEffort
11952
12125
  }
11953
12126
  ),
11954
12127
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-4 pb-1 text-center text-xs text-gray-500 dark:text-gray-400", children: t("BiChat.Welcome.Disclaimer") })
@@ -12004,7 +12177,10 @@ function ChatSessionCore({
12004
12177
  onUnqueue: handleUnqueue,
12005
12178
  onRemoveQueueItem: removeQueueItem,
12006
12179
  onUpdateQueueItem: updateQueueItem,
12007
- onCancelStreaming: cancel
12180
+ onCancelStreaming: cancel,
12181
+ reasoningEffortOptions,
12182
+ reasoningEffort,
12183
+ onReasoningEffortChange: setReasoningEffort
12008
12184
  }
12009
12185
  )
12010
12186
  ] }) }),
@@ -16892,9 +17068,10 @@ function useHttpDataSourceConfigFromApplet(options) {
16892
17068
  rpcEndpoint,
16893
17069
  streamEndpoint,
16894
17070
  csrfToken,
16895
- timeout: options?.timeout ?? 12e4
17071
+ rpcTimeoutMs: options?.rpcTimeoutMs ?? 12e4,
17072
+ streamConnectTimeoutMs: options?.streamConnectTimeoutMs ?? 3e4
16896
17073
  };
16897
- }, [options?.timeout]);
17074
+ }, [options?.rpcTimeoutMs, options?.streamConnectTimeoutMs]);
16898
17075
  }
16899
17076
  var SESSION_PATH_REGEX = /\/session\/([^/]+)/;
16900
17077
  function useBichatRouter({
@@ -18060,7 +18237,23 @@ async function clearSessionHistory(callRPC, sessionId) {
18060
18237
  return callRPC("bichat.session.clear", { id: sessionId });
18061
18238
  }
18062
18239
  async function compactSessionHistory(callRPC, sessionId) {
18063
- return callRPC("bichat.session.compact", { id: sessionId });
18240
+ const result = await callRPC("bichat.session.compact", { id: sessionId });
18241
+ if (!result.accepted) {
18242
+ throw new Error("Session compact request was not accepted");
18243
+ }
18244
+ if (result.operation !== "session_compact") {
18245
+ throw new Error(`Unexpected async operation: ${result.operation}`);
18246
+ }
18247
+ if (!result.sessionId || !result.runId) {
18248
+ throw new Error("Missing async run metadata");
18249
+ }
18250
+ return {
18251
+ accepted: true,
18252
+ operation: result.operation,
18253
+ sessionId: result.sessionId,
18254
+ runId: result.runId,
18255
+ startedAt: result.startedAt
18256
+ };
18064
18257
  }
18065
18258
  async function listUsers(callRPC) {
18066
18259
  const data = await callRPC("bichat.user.list", {});
@@ -18179,6 +18372,9 @@ var TERMINAL_TYPES = /* @__PURE__ */ new Set(["done", "error"]);
18179
18372
  async function* parseBichatStream(reader) {
18180
18373
  let yieldedTerminal = false;
18181
18374
  for await (const event of parseSSEStream(reader)) {
18375
+ if (event.type === "ping") {
18376
+ continue;
18377
+ }
18182
18378
  const parsed = event;
18183
18379
  const inferredType = parsed.type || (parsed.content ? "content" : "error");
18184
18380
  const normalized = {
@@ -18516,7 +18712,10 @@ async function* sendMessage(deps, sessionId, content, attachments = [], signal,
18516
18712
  replaceFromMessageId: options?.replaceFromMessageID,
18517
18713
  attachments: streamAttachments
18518
18714
  };
18519
- const timeoutMs = deps.timeout ?? 0;
18715
+ if (options?.reasoningEffort) {
18716
+ payload.reasoningEffort = options.reasoningEffort;
18717
+ }
18718
+ const timeoutMs = deps.streamConnectTimeoutMs ?? 0;
18520
18719
  if (timeoutMs > 0) {
18521
18720
  connectionTimeoutID = setTimeout(() => {
18522
18721
  connectionTimedOut = true;
@@ -18551,7 +18750,7 @@ async function* sendMessage(deps, sessionId, content, attachments = [], signal,
18551
18750
  if (err.name === "AbortError") {
18552
18751
  yield {
18553
18752
  type: "error",
18554
- error: connectionTimedOut ? `Stream request timed out after ${deps.timeout}ms` : "Stream cancelled"
18753
+ error: connectionTimedOut ? `Stream request timed out after ${deps.streamConnectTimeoutMs}ms` : "Stream cancelled"
18555
18754
  };
18556
18755
  } else {
18557
18756
  yield {
@@ -18639,7 +18838,7 @@ async function resumeStream(deps, sessionId, runId, onChunk, signal) {
18639
18838
  const url = buildStreamUrl(deps, "/resume");
18640
18839
  const controller = new AbortController();
18641
18840
  let timeoutId;
18642
- const timeoutMs = deps.timeout;
18841
+ const timeoutMs = deps.connectTimeoutMs;
18643
18842
  if (timeoutMs != null && timeoutMs > 0) {
18644
18843
  timeoutId = setTimeout(() => controller.abort(), timeoutMs);
18645
18844
  }
@@ -18656,6 +18855,10 @@ async function resumeStream(deps, sessionId, runId, onChunk, signal) {
18656
18855
  if (!response.ok) {
18657
18856
  throw new Error(`Resume stream failed: HTTP ${response.status}`);
18658
18857
  }
18858
+ if (timeoutId !== void 0) {
18859
+ clearTimeout(timeoutId);
18860
+ timeoutId = void 0;
18861
+ }
18659
18862
  if (!response.body) {
18660
18863
  throw new Error("Resume response body is null");
18661
18864
  }
@@ -18689,11 +18892,7 @@ async function submitQuestionAnswers(callRPC, sessionId, questionId, answers) {
18689
18892
  });
18690
18893
  return {
18691
18894
  success: true,
18692
- data: {
18693
- session: toSession(result.session),
18694
- turns: normalizeTurns(sanitizeConversationTurns(result.turns, sessionId)),
18695
- pendingQuestion: sanitizePendingQuestion(result.pendingQuestion, sessionId)
18696
- }
18895
+ data: normalizeAsyncRunAccepted(result)
18697
18896
  };
18698
18897
  } catch (err) {
18699
18898
  return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
@@ -18701,12 +18900,33 @@ async function submitQuestionAnswers(callRPC, sessionId, questionId, answers) {
18701
18900
  }
18702
18901
  async function rejectPendingQuestion(callRPC, sessionId) {
18703
18902
  try {
18704
- await callRPC("bichat.question.reject", { sessionId });
18705
- return { success: true };
18903
+ const result = await callRPC("bichat.question.reject", { sessionId });
18904
+ return { success: true, data: normalizeAsyncRunAccepted(result) };
18706
18905
  } catch (err) {
18707
18906
  return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
18708
18907
  }
18709
18908
  }
18909
+ function isAsyncRunOperation(value) {
18910
+ return value === "question_submit" || value === "question_reject" || value === "session_compact";
18911
+ }
18912
+ function normalizeAsyncRunAccepted(input) {
18913
+ if (!input.accepted) {
18914
+ throw new Error("Async run request was not accepted");
18915
+ }
18916
+ if (!isAsyncRunOperation(input.operation)) {
18917
+ throw new Error(`Unexpected async operation: ${input.operation}`);
18918
+ }
18919
+ if (!input.sessionId || !input.runId) {
18920
+ throw new Error("Missing async run metadata");
18921
+ }
18922
+ return {
18923
+ accepted: true,
18924
+ operation: input.operation,
18925
+ sessionId: input.sessionId,
18926
+ runId: input.runId,
18927
+ startedAt: input.startedAt
18928
+ };
18929
+ }
18710
18930
 
18711
18931
  // ui/src/bichat/data/ArtifactManager.ts
18712
18932
  async function fetchSessionArtifacts(callRPC, sessionId, options) {
@@ -18778,15 +18998,13 @@ var HttpDataSource = class {
18778
18998
  this.config = {
18779
18999
  streamEndpoint: "/stream",
18780
19000
  uploadEndpoint: "/api/uploads",
18781
- timeout: 12e4,
18782
- ...config
19001
+ ...config,
19002
+ rpcTimeoutMs: typeof config.rpcTimeoutMs === "number" ? config.rpcTimeoutMs : 12e4,
19003
+ streamConnectTimeoutMs: typeof config.streamConnectTimeoutMs === "number" ? config.streamConnectTimeoutMs : 3e4
18783
19004
  };
18784
- if (config.navigateToSession) {
18785
- this.navigateToSession = config.navigateToSession;
18786
- }
18787
19005
  this.rpc = createAppletRPCClient({
18788
19006
  endpoint: `${this.config.baseUrl}${this.config.rpcEndpoint}`,
18789
- timeoutMs: this.config.timeout
19007
+ timeoutMs: this.config.rpcTimeoutMs
18790
19008
  });
18791
19009
  }
18792
19010
  // -------------------------------------------------------------------------
@@ -18906,7 +19124,7 @@ var HttpDataSource = class {
18906
19124
  baseUrl: this.config.baseUrl,
18907
19125
  streamEndpoint: this.config.streamEndpoint,
18908
19126
  createHeaders: (h) => this.createHeaders(h),
18909
- timeoutMs: this.config.timeout
19127
+ timeoutMs: this.config.rpcTimeoutMs
18910
19128
  },
18911
19129
  sessionId
18912
19130
  );
@@ -18917,7 +19135,7 @@ var HttpDataSource = class {
18917
19135
  baseUrl: this.config.baseUrl,
18918
19136
  streamEndpoint: this.config.streamEndpoint,
18919
19137
  createHeaders: (h) => this.createHeaders(h),
18920
- timeout: this.config.timeout
19138
+ connectTimeoutMs: this.config.streamConnectTimeoutMs
18921
19139
  },
18922
19140
  sessionId,
18923
19141
  runId,
@@ -18941,7 +19159,8 @@ var HttpDataSource = class {
18941
19159
  callRPC: this.boundCallRPC,
18942
19160
  baseUrl: this.config.baseUrl,
18943
19161
  streamEndpoint: this.config.streamEndpoint,
18944
- timeout: this.config.timeout,
19162
+ rpcTimeoutMs: this.config.rpcTimeoutMs,
19163
+ streamConnectTimeoutMs: this.config.streamConnectTimeoutMs,
18945
19164
  createHeaders: (additional) => this.createHeaders(additional),
18946
19165
  uploadFileFn: this.boundUploadFile,
18947
19166
  logAttachmentLifecycle: () => {
@@ -18992,17 +19211,6 @@ var HttpDataSource = class {
18992
19211
  async deleteSessionArtifact(artifactId) {
18993
19212
  return deleteSessionArtifact(this.boundCallRPC, artifactId);
18994
19213
  }
18995
- // -------------------------------------------------------------------------
18996
- // Navigation (optional, deprecated)
18997
- // -------------------------------------------------------------------------
18998
- /**
18999
- * @deprecated Pass `onSessionCreated` to `ChatSessionProvider` instead.
19000
- */
19001
- navigateToSession(sessionId) {
19002
- if (typeof window !== "undefined") {
19003
- window.location.href = `/chat/${sessionId}`;
19004
- }
19005
- }
19006
19214
  };
19007
19215
  function createHttpDataSource(config) {
19008
19216
  return new HttpDataSource(config);