Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions apps/mobile/e2e/remote-cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ prepare_env() {
|| { echo "CLI install failed; see $CLI_HOME/install.log" >&2; tail -n 20 "$CLI_HOME/install.log" >&2; exit 1; }
fi

# Isolate the CLI's XDG data/config dirs from the machine's global kilo
# install. The CLI stores its OAuth login in $XDG_DATA_HOME/kilo/auth.json
# (default ~/.local/share/kilo); if a developer is logged in there, the CLI
# uses that production credential for AI-gateway calls and ignores the minted
# KILO_API_KEY below, so the local gateway rejects it ("You need to sign in to
# use this model" / "not a member of the organization"). Pointing both XDG
# dirs into the disposable per-worktree home forces the CLI to fall back to
# the minted local token against this worktree's stack.
local xdg_data="${CLI_HOME}/xdg/data" xdg_config="${CLI_HOME}/xdg/config"
mkdir -p "$xdg_data" "$xdg_config"

# Env file carries the token; keep it private and out of the process table.
umask 077
cat >"$ENV_FILE" <<EOF
Expand All @@ -103,6 +114,8 @@ export KILO_AUTH_CONTENT="${token}"
export KILO_SESSION_INGEST_URL="http://localhost:${ingest_port}"
$([ -n "$event_port" ] && echo "export KILO_EVENT_SERVICE_URL=\"ws://localhost:${event_port}\"")
export KILO_CONFIG_DIR="${CLI_HOME}/.config"
export XDG_DATA_HOME="${xdg_data}"
export XDG_CONFIG_HOME="${xdg_config}"
export KILO_DISABLE_AUTOUPDATE="true"
export PATH="${CLI_HOME}/node_modules/.bin:\$PATH"
EOF
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ vi.mock('react-native-reanimated', () => ({
LinearTransition: { duration: () => ({}) },
useReducedMotion: () => true,
}));
vi.mock('@/components/agents/session-row', () => ({
vi.mock('@/components/agents/remote-session-row', () => ({
RemoteSessionRow: 'RemoteSessionRow',
}));
vi.mock('@/components/agents/session-list-section-header', () => ({
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/src/components/agents/active-now-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Animated, {
useReducedMotion,
} from 'react-native-reanimated';

import { RemoteSessionRow } from '@/components/agents/session-row';
import { RemoteSessionRow } from '@/components/agents/remote-session-row';
import { SessionListSectionHeader } from '@/components/agents/session-list-section-header';
import { ACTIVE_NOW_TRAY_CAP, selectTrayWindow } from '@/components/agents/active-now-window';
import { Text } from '@/components/ui/text';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ describe('getContextSheetContent', () => {
expect(content.percentage).toBe('125%');
expect(content.remainingTokens).toBe('0');
expect(content.remainingPercentage).toBe('0%');
expect(content.cost).toBeNull();
expect(content.cost).toBe('$0.0000');
expect(content.tone).toBe('destructive');
});

Expand All @@ -244,14 +244,14 @@ describe('getContextSheetContent', () => {
expect(content.windowUnavailable).toBe(true);
expect(content.percentage).toBeNull();
expect(content.remainingTokens).toBeNull();
expect(content.cost).toBeNull();
expect(content.cost).toBe('$0.0000');
expect(content.windowUnavailableLabel).toBe('Context-window size unavailable');
expect(content.tone).toBe('neutral');
});

it('omits the cost line when total cost is zero', () => {
it('shows the cost line as $0.0000 when total cost is zero', () => {
const content = getContextSheetContent(info({ percentage: 20 }), 0);
expect(content.cost).toBeNull();
expect(content.cost).toBe('$0.0000');
});
});

Expand Down
4 changes: 2 additions & 2 deletions apps/mobile/src/components/agents/context-usage-display.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ type ContextSheetContent = {
percentage: string | null;
remainingTokens: string | null;
remainingPercentage: string | null;
cost: string | null;
cost: string;
tone: ContextTone;
};

Expand All @@ -124,7 +124,7 @@ export function getContextSheetContent(
): ContextSheetContent {
const tone = getContextTone(info.percentage);
const usedTokens = formatExactTokens(info.contextTokens);
const cost = totalCost > 0 ? formatCost(totalCost) : null;
const cost = formatCost(totalCost);
if (info.contextWindow === undefined) {
return {
usedTokens,
Expand Down
17 changes: 17 additions & 0 deletions apps/mobile/src/components/agents/message-bubble.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ type MessageBubbleProps = {
onOpenChildSession?: OpenChildSession;
/** Per-user-message delivery state. v1 surfaces only a "Queued" badge. */
deliveryState?: MessageDeliveryState;
/**
* Subtle model label for an assistant message, precomputed by the parent
* via `computeMessageModelLabels`. Only the assistant branch renders it
* (and only when truthy); the user branch and the unlabelled
* same-model follow-ups render nothing.
*/
modelLabel?: string;
};

export function MessageBubble({
Expand All @@ -34,6 +41,7 @@ export function MessageBubble({
defaultReasoningExpanded,
onOpenChildSession,
deliveryState,
modelLabel,
}: Readonly<MessageBubbleProps>) {
const isUser = message.info.role === 'user';
const { copyMessage } = useMessageCopy();
Expand Down Expand Up @@ -131,6 +139,15 @@ export function MessageBubble({
onOpenChildSession={onOpenChildSession}
/>
))}
{modelLabel ? (
<Text
className="text-xs text-muted-foreground"
accessibilityRole="text"
accessibilityLabel={`Model: ${modelLabel}`}
>
{modelLabel}
</Text>
) : null}
</View>
</Pressable>
);
Expand Down
Loading