You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by as...@apache.org on 2026/09/01 15:30:09 UTC

(maka) 05/19: feat(desktop): show request prefix continuity

This is an automated email from the ASF dual-hosted git repository.

Astro-Han pushed a commit to branch feat/4299-semantic-prefix-continuity
in repository https://gitbox.apache.org/repos/asf/maka.git

commit 7f2cfb192ceb18161e4af717e0f0807fef939b71
Author: AstroHan <le...@outlook.com>
AuthorDate: Tue Sep 1 01:46:32 2026 +0800

    feat(desktop): show request prefix continuity
    
    Generated-by: Codex
---
 .../session-inspector-composition.test.ts          | 22 ++++++++++-
 .../session-inspector-panel-model.test.ts          | 19 +++++++++
 .../src/renderer/features/workbar/testing.ts       |  6 ++-
 .../inspector/session-inspector-overview-model.ts  |  5 +++
 .../tools/inspector/session-inspector-panel.tsx    | 45 +++++++++++++++++++++-
 .../src/renderer/locales/conversation-copy.ts      | 32 +++++++++++++++
 6 files changed, 126 insertions(+), 3 deletions(-)

diff --git a/apps/desktop/src/main/__tests__/session-inspector-composition.test.ts b/apps/desktop/src/main/__tests__/session-inspector-composition.test.ts
index 03adbe1432..570bd5ead6 100644
--- a/apps/desktop/src/main/__tests__/session-inspector-composition.test.ts
+++ b/apps/desktop/src/main/__tests__/session-inspector-composition.test.ts
@@ -21,7 +21,10 @@ import assert from 'node:assert/strict';
 import { test } from 'node:test';
 import { createElement } from 'react';
 import { renderToStaticMarkup } from 'react-dom/server';
-import { InspectorCompositionSection } from '../../renderer/features/workbar/testing.js';
+import {
+  InspectorCompositionSection,
+  InspectorRequestPrefixBadge,
+} from '../../renderer/features/workbar/testing.js';
 import { getDesktopConversationCopy } from '../../renderer/locales/conversation-copy.js';
 
 test('maps each request-composition category to the same colour in the chart and legend', () => {
@@ -60,3 +63,20 @@ test('maps each request-composition category to the same colour in the chart and
     );
   }
 });
+
+test('renders the Runtime divergence location as a compact badge', () => {
+  const markup = renderToStaticMarkup(
+    createElement(InspectorRequestPrefixBadge, {
+      copy: getDesktopConversationCopy('en').inspector,
+      requestPrefix: {
+        status: 'diverged',
+        previousSegmentCount: 8,
+        preservedSegmentCount: 2,
+        firstDivergentSegment: { kind: 'message', index: 2 },
+      },
+    }),
+  );
+
+  assert.match(markup, /Request prefix diverged at message 3/);
+  assert.match(markup, /data-maka-contract="request-prefix-continuity"/);
+});
diff --git a/apps/desktop/src/main/__tests__/session-inspector-panel-model.test.ts b/apps/desktop/src/main/__tests__/session-inspector-panel-model.test.ts
index e301fd4ec7..61adc3e6d7 100644
--- a/apps/desktop/src/main/__tests__/session-inspector-panel-model.test.ts
+++ b/apps/desktop/src/main/__tests__/session-inspector-panel-model.test.ts
@@ -138,6 +138,25 @@ test('does not estimate a cache-hit ratio from partial usage', () => {
 
   assert.equal(overview.cacheHitRate, undefined);
 });
+
+test('passes the Runtime request-prefix verdict through without recomputing it', () => {
+  const requestPrefix = {
+    status: 'diverged' as const,
+    previousSegmentCount: 8,
+    preservedSegmentCount: 2,
+    firstDivergentSegment: { kind: 'message' as const, index: 2, role: 'user' },
+  };
+  const overview = deriveInspectorOverviewModel({
+    status: 'available',
+    providerId: 'anthropic',
+    modelId: 'claude',
+    completedAt: 10,
+    requestPrefix,
+  });
+
+  assert.equal(overview.requestPrefix, requestPrefix);
+});
+
 test('derives per-turn cost only from priced model-call step totals', () => {
   const cases: readonly {
     name: string;
diff --git a/apps/desktop/src/renderer/features/workbar/testing.ts b/apps/desktop/src/renderer/features/workbar/testing.ts
index 8bf5c6bb0a..ddc51e71f5 100644
--- a/apps/desktop/src/renderer/features/workbar/testing.ts
+++ b/apps/desktop/src/renderer/features/workbar/testing.ts
@@ -32,7 +32,11 @@ export * from './model/workbar-tool-definitions.js';
 export * from './tools/artifacts/artifact-list-keyboard.js';
 export * from './tools/artifacts/artifact-visibility.js';
 export * from './tools/inspector/session-inspector-panel-model.js';
-export { compactNumberFormatter, InspectorCompositionSection } from './tools/inspector/session-inspector-panel.js';
+export {
+  compactNumberFormatter,
+  InspectorCompositionSection,
+  InspectorRequestPrefixBadge,
+} from './tools/inspector/session-inspector-panel.js';
 export * from './tools/inspector/session-inspector-overview-model.js';
 export * from './tools/side-chat/quote-companion-panel-state.js';
 export * from './tools/side-chat/quote-companion-core.js';
diff --git a/apps/desktop/src/renderer/features/workbar/tools/inspector/session-inspector-overview-model.ts b/apps/desktop/src/renderer/features/workbar/tools/inspector/session-inspector-overview-model.ts
index 36e835d81f..17302c8e02 100644
--- a/apps/desktop/src/renderer/features/workbar/tools/inspector/session-inspector-overview-model.ts
+++ b/apps/desktop/src/renderer/features/workbar/tools/inspector/session-inspector-overview-model.ts
@@ -140,6 +140,8 @@ export interface InspectorOverviewModel {
    * the run ledger; three statements of the same tokens is two too many.
    */
   cacheHitRate?: number;
+  /** Runtime-owned semantic prefix verdict; Desktop only presents it. */
+  requestPrefix?: Extract<ContextDiagnosticsResult, { status: 'available' }>['requestPrefix'];
 }
 
 export function estimatedSessionCost(
@@ -186,6 +188,9 @@ export function deriveInspectorOverviewModel(
     ...(context ? { context } : {}),
     ...(composition ? { composition } : {}),
     ...(cacheHitRate !== undefined ? { cacheHitRate } : {}),
+    ...(diagnostics?.status === 'available' && diagnostics.requestPrefix
+      ? { requestPrefix: diagnostics.requestPrefix }
+      : {}),
   };
 }
 
diff --git a/apps/desktop/src/renderer/features/workbar/tools/inspector/session-inspector-panel.tsx b/apps/desktop/src/renderer/features/workbar/tools/inspector/session-inspector-panel.tsx
index 86749b04dc..498cdadbbc 100644
--- a/apps/desktop/src/renderer/features/workbar/tools/inspector/session-inspector-panel.tsx
+++ b/apps/desktop/src/renderer/features/workbar/tools/inspector/session-inspector-panel.tsx
@@ -19,6 +19,7 @@
 
 import { type ReactNode, useMemo } from 'react';
 import { Banner } from '@astryxdesign/core/Banner';
+import { Badge } from '@astryxdesign/core/Badge';
 import { Button } from '@astryxdesign/core/Button';
 import { EmptyState } from '@astryxdesign/core/EmptyState';
 import { Heading } from '@astryxdesign/core/Heading';
@@ -148,7 +149,7 @@ export function SessionInspectorPanel(props: { sessionId: string; active: boolea
             {copy.summaryUnavailable}
           </Text>
         )}
-        {(snapshot.summary || overview.context || overview.composition) && (
+        {(snapshot.summary || overview.context || overview.composition || overview.requestPrefix) && (
           <InspectorOverview
             copy={copy}
             locale={locale}
@@ -272,6 +273,9 @@ function InspectorOverview(props: {
 
   return (
     <VStack gap={6} data-maka-contract="session-inspector-overview">
+      {overview.requestPrefix && (
+        <InspectorRequestPrefixBadge copy={copy} requestPrefix={overview.requestPrefix} />
+      )}
       {props.showTotals && (
         <VStack gap={2} data-maka-contract="session-inspector-stats">
           <InspectorOverviewStat
@@ -310,6 +314,45 @@ function InspectorOverview(props: {
   );
 }
 
+export function InspectorRequestPrefixBadge(props: {
+  copy: InspectorCopy;
+  requestPrefix: NonNullable<ReturnType<typeof deriveInspectorOverviewModel>['requestPrefix']>;
+}) {
+  const { requestPrefix, copy } = props;
+  if (requestPrefix.status === 'no_predecessor') return null;
+  if (requestPrefix.status === 'preserved') {
+    return (
+      <Badge
+        variant="neutral"
+        label={copy.overview.requestPrefix.preserved(
+          requestPrefix.preservedSegmentCount,
+          requestPrefix.previousSegmentCount,
+        )}
+        data-maka-contract="request-prefix-continuity"
+      />
+    );
+  }
+  if (requestPrefix.status === 'diverged') {
+    return (
+      <Badge
+        variant="error"
+        label={copy.overview.requestPrefix.diverged(
+          copy.overview.requestPrefix.segment[requestPrefix.firstDivergentSegment.kind],
+          requestPrefix.firstDivergentSegment.index + 1,
+        )}
+        data-maka-contract="request-prefix-continuity"
+      />
+    );
+  }
+  return (
+    <Badge
+      variant={requestPrefix.status === 'unknown' ? 'warning' : 'neutral'}
+      label={copy.overview.requestPrefix.cannotJudge}
+      data-maka-contract="request-prefix-continuity"
+    />
+  );
+}
+
 /**
  * One overview total on the same title/readout rhythm as the sections below.
  * These figures answer parallel questions, so changing typography between the
diff --git a/apps/desktop/src/renderer/locales/conversation-copy.ts b/apps/desktop/src/renderer/locales/conversation-copy.ts
index a41bc754a7..a9a301e0b8 100644
--- a/apps/desktop/src/renderer/locales/conversation-copy.ts
+++ b/apps/desktop/src/renderer/locales/conversation-copy.ts
@@ -262,6 +262,15 @@ export interface DesktopConversationCopy {
       };
       /** The three figures a reader opens this tab for, as headline stats. */
       cacheHit: string;
+      requestPrefix: {
+        preserved: (preserved: number, previous: number) => string;
+        diverged: (segment: string, index: number) => string;
+        cannotJudge: string;
+        segment: Record<
+          'tool_schema' | 'system_prompt' | 'message' | 'provider_options',
+          string
+        >;
+      };
       /** Heading over the causal record. */
       timelineTab: string;
       /**
@@ -596,6 +605,17 @@ const COPY = {
           free: '剩余',
         },
         cacheHit: '缓存命中率',
+        requestPrefix: {
+          preserved: (preserved, previous) => `请求前缀 ${preserved}/${previous} 保持`,
+          diverged: (segment, index) => `请求前缀在${segment} ${index}处分叉`,
+          cannotJudge: '请求前缀无法判断',
+          segment: {
+            tool_schema: '工具',
+            system_prompt: '系统提示',
+            message: '消息',
+            provider_options: '模型选项',
+          },
+        },
         timelineTab: '时间轴',
         composition: {
           title: '构成估算',
@@ -831,6 +851,18 @@ const COPY = {
           free: 'Remaining',
         },
         cacheHit: 'Cache hit rate',
+        requestPrefix: {
+          preserved: (preserved, previous) =>
+            `Request prefix ${preserved}/${previous} preserved`,
+          diverged: (segment, index) => `Request prefix diverged at ${segment} ${index}`,
+          cannotJudge: 'Request prefix unavailable',
+          segment: {
+            tool_schema: 'tool',
+            system_prompt: 'system prompt',
+            message: 'message',
+            provider_options: 'model option',
+          },
+        },
         timelineTab: 'Timeline',
         composition: {
           title: 'Estimated composition',


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org