Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
62ee668
feat(tarko): add TTFT display for assistant messages
ulivz Aug 22, 2025
fd87951
feat(tarko): implement elapsedMs calculation for assistant messages
ulivz Aug 25, 2025
85e47b2
feat(tarko): implement proper TTFT calculation and enhance timing dis…
ulivz Aug 25, 2025
a52e2d1
refactor(tarko): improve timing field naming to follow industry stand…
ulivz Aug 25, 2025
5631888
chore(tarko): ttft does not keep for backward compatibility
ulivz Aug 25, 2025
56e4705
chore: remove debugger
ulivz Aug 25, 2025
2d5552c
chore(tarko): ttft does not keep for backward compatibility 2
ulivz Aug 25, 2025
653f7fa
refactor(tarko): using TTLT
ulivz Aug 25, 2025
bb73c9e
test(tarko-agent-snapshot): do not compare `ttftMs` and `ttltMs`
ulivz Aug 25, 2025
798dc28
test(tarko-agent): update snapshot
ulivz Aug 25, 2025
50a6db9
feat(tarko): integrate TTFT display into message footer
ulivz Aug 25, 2025
a96e954
refactor(tarko): consolidate TTFT display into MessageFooter
ulivz Aug 25, 2025
df2cd20
fix(tarko): improve TTFT/TTLT display precision and clarity
ulivz Aug 25, 2025
b726d11
fix(tarko): enhance TTFT/TTLT tooltip visibility
ulivz Aug 25, 2025
7785a06
fix(tarko): use MUI Tooltip for TTFT/TTLT hover tooltips
ulivz Aug 25, 2025
1d66327
fix(tarko): remove cursor-help and arrow from TTFT/TTLT tooltips
ulivz Aug 25, 2025
2362c15
chore: tweaks
ulivz Aug 25, 2025
8f21a21
fix(tarko): improve TTFT/TTLT tooltip styling
ulivz Aug 25, 2025
209dd59
refactor(tarko): extract tooltip styling to avoid code duplication
ulivz Aug 25, 2025
6779f4b
fix(tarko): restore arrow and improve tooltip styling
ulivz Aug 25, 2025
c92b5f3
fix(tarko): add dark mode support for TTFT/TTLT tooltips
ulivz Aug 25, 2025
96e2404
Revert "fix(tarko): add dark mode support for TTFT/TTLT tooltips"
ulivz Aug 25, 2025
5acfd74
chore: tweaks
ulivz Aug 25, 2025
9a614f2
chore(tarko): TTFT does not check chunk result
ulivz Aug 25, 2025
e276388
feat(tarko): add metric option to control TTFT/TTLT collection
ulivz Aug 26, 2025
10eeb3a
refactor(tarko): optimize metric collection to avoid unnecessary comp…
ulivz Aug 26, 2025
1298a00
chore: revert snapshot change
ulivz Aug 26, 2025
aa9964b
chore: tweks
ulivz Aug 26, 2025
2915b56
refactor: code naming
ulivz Aug 26, 2025
b6c103a
chore: update test snapshot
ulivz Aug 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions multimodal/tarko/agent-interface/src/agent-event-stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,23 @@ export namespace AgentEventStream {
/** How the response was finished */
finishReason?: string;

/** Time taken to generate this response */
elapsedMs?: number;
/**
* Time to First Token (TTFT) in milliseconds - time from request start to first content chunk.
* The time it takes for the model to return the first token of the response after it receives the prompt.
*
* @see https://modal.com/llm-almanac/how-to-benchmark
* @see https://cloud.google.com/vertex-ai/generative-ai/docs/learn/prompt-best-practices
*/
ttftMs?: number;

/**
* Time to Last Token (TTLT) in milliseconds - time from request start to response completion.
* The overall time taken by the model to process the prompt and generate the complete response.
*
* @see https://modal.com/llm-almanac/how-to-benchmark
* @see https://cloud.google.com/vertex-ai/generative-ai/docs/learn/prompt-best-practices
*/
ttltMs?: number;

/**
* Unique message identifier that links streaming messages to their final message
Expand Down
18 changes: 18 additions & 0 deletions multimodal/tarko/agent-interface/src/agent-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,19 @@ export interface AgentMemoryOptions {
enableStreamingToolCallEvents?: boolean;
}

/**
* Metric configuration options for performance monitoring
*/
export interface AgentMetricOptions {
/**
* Whether to enable metric collection (TTFT, TTLT, etc.)
* When disabled, timing metrics will not be collected or included in event streams.
*
* @defaultValue `false`
*/
enable?: boolean;
}

/**
* Miscellaneous configuration options for logging and debugging
*/
Expand All @@ -194,6 +207,11 @@ export interface AgentMiscOptions {
* @defaultValue `LogLevel.INFO` in development, `LogLevel.WARN` in production
*/
logLevel?: LogLevel;

/**
* Metric collection settings
*/
metric?: AgentMetricOptions;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ const DEFAULT_CONFIG: AgentNormalizerConfig = {
{ pattern: 'toolCallId', replacement: '<<toolCallId>>' },
{ pattern: 'sessionId', replacement: '<<sessionId>>' },
{ pattern: 'messageId', replacement: '<<messageId>>' },
{ pattern: 'ttftMs', replacement: '<<ttftMs>>' },
{ pattern: 'ttltMs', replacement: '<<ttltMs>>' },
{ pattern: /Time$/, replacement: '<<TIMESTAMP>>' },
],
fieldsToIgnore: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ export class AssistantMessageHandler
toolCalls: event.toolCalls,
finishReason: event.finishReason,
isStreaming: false,
ttftMs: event.ttftMs,
ttltMs: event.ttltMs,
};

return {
Expand All @@ -114,6 +116,8 @@ export class AssistantMessageHandler
toolCalls: event.toolCalls,
finishReason: event.finishReason,
messageId: messageId,
ttftMs: event.ttftMs,
ttltMs: event.ttltMs,
},
],
};
Expand Down
6 changes: 2 additions & 4 deletions multimodal/tarko/agent-web-ui/src/common/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ export type { SanitizedAgentOptions, WorkspaceInfo, SessionItemInfo };

export type { ChatCompletionContentPart, ChatCompletionMessageToolCall };



/**
* Tool result type with categorization and timing information
*/
Expand Down Expand Up @@ -46,6 +44,8 @@ export interface Message {
description?: string; // Added for environment inputs
isDeepResearch?: boolean; // Added for final answer events
title?: string; // Added for research report title
ttftMs?: number; // Time to First Token (TTFT) in milliseconds
ttltMs?: number; // Total response time in milliseconds

// System message specific properties
level?: 'info' | 'warning' | 'error';
Expand Down Expand Up @@ -102,5 +102,3 @@ export interface ReplayEventMarker {
position: number; // 0-1 normalized position on timeline
content?: string | any;
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React from 'react';
import { FiClock, FiCheck, FiCopy, FiZap, FiActivity } from 'react-icons/fi';
import { Tooltip, TooltipProps } from '@mui/material';
import { formatTimestamp } from '@/common/utils/formatters';
import { Message as MessageType, ChatCompletionContentPart } from '@/common/types';
import { useCopyToClipboard } from '../hooks/useCopyToClipboard';

interface MessageFooterProps {
message: MessageType;
className?: string;
}

/**
* MessageFooter Component
* Displays timestamp, copy functionality, and TTFT information for messages
*/
export const MessageFooter: React.FC<MessageFooterProps> = ({ message, className = '' }) => {
const { isCopied, copyToClipboard } = useCopyToClipboard();
const showTTFT = message.role === 'assistant' && message.ttftMs !== undefined;

const handleCopy = () => {
const textToCopy =
typeof message.content === 'string'
? message.content
: (message.content as ChatCompletionContentPart[])
.filter((part) => part.type === 'text')
.map((part) => part.text)
.join('\n');

copyToClipboard(textToCopy);
};

// Helper function to format elapsed time for display (always in ms for precision)
const formatElapsedTime = (ms: number): string => {
return `${ms}ms`;
};

// Tooltip styling for consistent appearance
const tooltipProps: Partial<TooltipProps> = {
arrow: true,
componentsProps: {
tooltip: {
sx: {
backgroundColor: '#000000',
color: '#ffffff',
fontSize: '13px',
fontWeight: 500,
padding: '8px 12px',
borderRadius: '6px',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
'.MuiTooltip-arrow': {
color: '#000000',
},
},
},
},
};

return (
<div className={`mt-1 mb-2 ${className}`}>
<div className="flex items-center justify-between text-xs text-gray-500 dark:text-gray-400 px-2">
<div className="flex items-center gap-3">
{/* Timestamp */}
<div className="flex items-center">
<FiClock size={10} className="mr-1" />
{formatTimestamp(message.timestamp)}
</div>

{/* TTFT & TTLT Display with icons and consistent styling */}
{showTTFT && (
<div className="flex items-center gap-2">
{/* TTFT */}
<Tooltip
title="Time to First Token (TTFT) - Time from request start to first token received"
{...tooltipProps}
>
<div className="flex items-center">
<FiZap size={10} className="mr-1 text-gray-500 dark:text-gray-400" />
<span className="text-gray-500 dark:text-gray-400">
{formatElapsedTime(message.ttftMs!)}
</span>
</div>
</Tooltip>

{/* TTLT (if different from TTFT) */}
{message.ttltMs && message.ttltMs !== message.ttftMs && (
<Tooltip
title="Time to Last Token (TTLT) - Total time from request start to completion"
{...tooltipProps}
>
<div className="flex items-center">
<FiActivity size={10} className="mr-1 text-gray-500 dark:text-gray-400" />
<span className="text-gray-500 dark:text-gray-400">
{formatElapsedTime(message.ttltMs)}
</span>
</div>
</Tooltip>
)}
</div>
)}
</div>

{/* Copy functionality */}
<button
onClick={handleCopy}
className="flex items-center text-gray-400 hover:text-accent-500 dark:hover:text-accent-400 transition-colors"
title="Copy message"
>
{isCopied ? <FiCheck size={12} /> : <FiCopy size={12} />}
<span className="ml-1">{isCopied ? 'Copied' : 'Copy'}</span>
</button>
</div>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import React from 'react';
import { Message as MessageType } from '@/common/types';
import { Message } from '../index';
import { FiClock } from 'react-icons/fi';
import { formatTimestamp } from '@/common/utils/formatters';
import { isMultimodalContent } from '@/common/utils/typeGuards';
import { MessageTimestamp } from './MessageTimestamp';
import { MessageFooter } from './MessageFooter';
import { ThinkingAnimation } from './ThinkingAnimation';
import { SkeletonLoader } from './SkeletonLoader';
import { useAtomValue } from 'jotai';
import { agentStatusAtom } from '@/common/state/atoms/ui';
import { AgentProcessingPhase } from '@tarko/interface';
import { getAgentTitle } from '@/common/constants';

interface MessageGroupProps {
Expand Down Expand Up @@ -117,25 +114,8 @@ export const MessageGroup: React.FC<MessageGroupProps> = ({ messages, isThinking
</div>
)}

{/* Timestamp and copy functionality */}
{!isThinking && lastResponseMessage && (
<div className="mt-1 mb-2">
<div className="flex items-center justify-between text-xs text-gray-500 dark:text-gray-400 px-2">
<div className="flex items-center">
<FiClock size={10} className="mr-1" />
{formatTimestamp(lastResponseMessage.timestamp)}
</div>

{/* Integrated copy function button - now uses the last message */}
<MessageTimestamp
timestamp={lastResponseMessage.timestamp}
content={lastResponseMessage.content}
role={lastResponseMessage.role}
inlineStyle={true}
/>
</div>
</div>
)}
{/* Message footer with timestamp, TTFT, and copy functionality */}
{!isThinking && lastResponseMessage && <MessageFooter message={lastResponseMessage} />}
</div>
);
};

This file was deleted.

Loading