smart context v3 (#1022)
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Adds Smart Context v3 with selectable modes (Off, Conservative,
Balanced) and surfaces token savings in chat. Also improves token
estimation by counting per-file tokens when Smart Context is enabled.
- **New Features**
- Smart Context selector in Pro settings with three options.
Conservative is the default when enabled without an explicit choice.
- New setting: proSmartContextOption ("balanced"); undefined implies
Conservative.
- Engine now receives enable_smart_files_context and smart_context_mode.
- Chat shows a DyadTokenSavings card when the message contains
token-savings?original-tokens=...&smart-context-tokens=..., with percent
saved and a tooltip for exact tokens.
- Token estimation uses extracted file contents for accuracy when Pro +
Smart Context is on; otherwise falls back to formatted codebase output.
<!-- End of auto-generated description by cubic. -->
This commit is contained in:
@@ -41,7 +41,7 @@ test("manage context - smart context", async ({ po }) => {
|
|||||||
// Disabling smart context will automatically disable
|
// Disabling smart context will automatically disable
|
||||||
// the auto-includes.
|
// the auto-includes.
|
||||||
const proModesDialog = await po.openProModesDialog();
|
const proModesDialog = await po.openProModesDialog();
|
||||||
await proModesDialog.toggleSmartContext();
|
await proModesDialog.setSmartContextMode("off");
|
||||||
await proModesDialog.close();
|
await proModesDialog.close();
|
||||||
|
|
||||||
await po.sendPrompt("[dump]");
|
await po.sendPrompt("[dump]");
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import { testSkipIfWindows } from "./helpers/test_helper";
|
|||||||
|
|
||||||
testSkipIfWindows("send message to engine", async ({ po }) => {
|
testSkipIfWindows("send message to engine", async ({ po }) => {
|
||||||
await po.setUpDyadPro();
|
await po.setUpDyadPro();
|
||||||
// By default, it's using auto which points to Flash 2.5 and doesn't
|
|
||||||
// use engine.
|
|
||||||
await po.selectModel({ provider: "Google", model: "Gemini 2.5 Pro" });
|
await po.selectModel({ provider: "Google", model: "Gemini 2.5 Pro" });
|
||||||
await po.sendPrompt("[dump] tc=turbo-edits");
|
await po.sendPrompt("[dump] tc=turbo-edits");
|
||||||
|
|
||||||
@@ -11,6 +9,23 @@ testSkipIfWindows("send message to engine", async ({ po }) => {
|
|||||||
await po.snapshotMessages({ replaceDumpPath: true });
|
await po.snapshotMessages({ replaceDumpPath: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testSkipIfWindows(
|
||||||
|
"send message to engine - smart context balanced",
|
||||||
|
async ({ po }) => {
|
||||||
|
await po.setUpDyadPro();
|
||||||
|
const proModesDialog = await po.openProModesDialog({
|
||||||
|
location: "home-chat-input-container",
|
||||||
|
});
|
||||||
|
await proModesDialog.setSmartContextMode("balanced");
|
||||||
|
await proModesDialog.close();
|
||||||
|
await po.selectModel({ provider: "Google", model: "Gemini 2.5 Pro" });
|
||||||
|
await po.sendPrompt("[dump] tc=turbo-edits");
|
||||||
|
|
||||||
|
await po.snapshotServerDump("request");
|
||||||
|
await po.snapshotMessages({ replaceDumpPath: true });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
testSkipIfWindows("send message to engine - openai gpt-4.1", async ({ po }) => {
|
testSkipIfWindows("send message to engine - openai gpt-4.1", async ({ po }) => {
|
||||||
await po.setUpDyadPro();
|
await po.setUpDyadPro();
|
||||||
// By default, it's using auto which points to Flash 2.5 and doesn't
|
// By default, it's using auto which points to Flash 2.5 and doesn't
|
||||||
@@ -52,7 +67,7 @@ testSkipIfWindows(
|
|||||||
const proModesDialog = await po.openProModesDialog({
|
const proModesDialog = await po.openProModesDialog({
|
||||||
location: "home-chat-input-container",
|
location: "home-chat-input-container",
|
||||||
});
|
});
|
||||||
await proModesDialog.toggleSmartContext();
|
await proModesDialog.setSmartContextMode("off");
|
||||||
await proModesDialog.close();
|
await proModesDialog.close();
|
||||||
await po.sendPrompt("[dump] tc=turbo-edits");
|
await po.sendPrompt("[dump] tc=turbo-edits");
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ testSkipIfWindows("claude 4 sonnet", async ({ po }) => {
|
|||||||
location: "home-chat-input-container",
|
location: "home-chat-input-container",
|
||||||
});
|
});
|
||||||
await proModesDialog.toggleTurboEdits();
|
await proModesDialog.toggleTurboEdits();
|
||||||
await proModesDialog.toggleSmartContext();
|
await proModesDialog.setSmartContextMode("off");
|
||||||
await proModesDialog.close();
|
await proModesDialog.close();
|
||||||
|
|
||||||
await po.selectModel({ provider: "Anthropic", model: "Claude 4 Sonnet" });
|
await po.selectModel({ provider: "Anthropic", model: "Claude 4 Sonnet" });
|
||||||
|
|||||||
@@ -67,8 +67,12 @@ class ProModesDialog {
|
|||||||
public close: () => Promise<void>,
|
public close: () => Promise<void>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async toggleSmartContext() {
|
async setSmartContextMode(mode: "balanced" | "off" | "conservative") {
|
||||||
await this.page.getByRole("switch", { name: "Smart Context" }).click();
|
await this.page
|
||||||
|
.getByRole("button", {
|
||||||
|
name: mode.charAt(0).toUpperCase() + mode.slice(1),
|
||||||
|
})
|
||||||
|
.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
async toggleTurboEdits() {
|
async toggleTurboEdits() {
|
||||||
|
|||||||
15
e2e-tests/smart_context_options.spec.ts
Normal file
15
e2e-tests/smart_context_options.spec.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { test } from "./helpers/test_helper";
|
||||||
|
|
||||||
|
test("switching smart context mode saves the right setting", async ({ po }) => {
|
||||||
|
await po.setUpDyadPro();
|
||||||
|
const proModesDialog = await po.openProModesDialog({
|
||||||
|
location: "home-chat-input-container",
|
||||||
|
});
|
||||||
|
await po.snapshotSettings();
|
||||||
|
await proModesDialog.setSmartContextMode("balanced");
|
||||||
|
await po.snapshotSettings();
|
||||||
|
await proModesDialog.setSmartContextMode("off");
|
||||||
|
await po.snapshotSettings();
|
||||||
|
await proModesDialog.setSmartContextMode("conservative");
|
||||||
|
await po.snapshotSettings();
|
||||||
|
});
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
- paragraph: "[dump] tc=turbo-edits"
|
||||||
|
- paragraph: "[[dyad-dump-path=*]]"
|
||||||
|
- img
|
||||||
|
- text: less than a minute ago
|
||||||
|
- button "Retry":
|
||||||
|
- img
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"selectedModel": {
|
||||||
|
"name": "auto",
|
||||||
|
"provider": "auto"
|
||||||
|
},
|
||||||
|
"providerSettings": {
|
||||||
|
"auto": {
|
||||||
|
"apiKey": {
|
||||||
|
"value": "testdyadkey",
|
||||||
|
"encryptionType": "plaintext"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"telemetryConsent": "unset",
|
||||||
|
"telemetryUserId": "[UUID]",
|
||||||
|
"hasRunBefore": true,
|
||||||
|
"enableDyadPro": true,
|
||||||
|
"experiments": {},
|
||||||
|
"lastShownReleaseNotesVersion": "[scrubbed]",
|
||||||
|
"enableProLazyEditsMode": true,
|
||||||
|
"enableProSmartFilesContextMode": true,
|
||||||
|
"selectedTemplateId": "react",
|
||||||
|
"selectedChatMode": "build",
|
||||||
|
"enableAutoFixProblems": false,
|
||||||
|
"enableAutoUpdate": true,
|
||||||
|
"releaseChannel": "stable",
|
||||||
|
"isTestMode": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"selectedModel": {
|
||||||
|
"name": "auto",
|
||||||
|
"provider": "auto"
|
||||||
|
},
|
||||||
|
"providerSettings": {
|
||||||
|
"auto": {
|
||||||
|
"apiKey": {
|
||||||
|
"value": "testdyadkey",
|
||||||
|
"encryptionType": "plaintext"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"telemetryConsent": "unset",
|
||||||
|
"telemetryUserId": "[UUID]",
|
||||||
|
"hasRunBefore": true,
|
||||||
|
"enableDyadPro": true,
|
||||||
|
"experiments": {},
|
||||||
|
"lastShownReleaseNotesVersion": "[scrubbed]",
|
||||||
|
"enableProLazyEditsMode": true,
|
||||||
|
"enableProSmartFilesContextMode": true,
|
||||||
|
"proSmartContextOption": "balanced",
|
||||||
|
"selectedTemplateId": "react",
|
||||||
|
"selectedChatMode": "build",
|
||||||
|
"enableAutoFixProblems": false,
|
||||||
|
"enableAutoUpdate": true,
|
||||||
|
"releaseChannel": "stable",
|
||||||
|
"isTestMode": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"selectedModel": {
|
||||||
|
"name": "auto",
|
||||||
|
"provider": "auto"
|
||||||
|
},
|
||||||
|
"providerSettings": {
|
||||||
|
"auto": {
|
||||||
|
"apiKey": {
|
||||||
|
"value": "testdyadkey",
|
||||||
|
"encryptionType": "plaintext"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"telemetryConsent": "unset",
|
||||||
|
"telemetryUserId": "[UUID]",
|
||||||
|
"hasRunBefore": true,
|
||||||
|
"enableDyadPro": true,
|
||||||
|
"experiments": {},
|
||||||
|
"lastShownReleaseNotesVersion": "[scrubbed]",
|
||||||
|
"enableProLazyEditsMode": true,
|
||||||
|
"enableProSmartFilesContextMode": false,
|
||||||
|
"selectedTemplateId": "react",
|
||||||
|
"selectedChatMode": "build",
|
||||||
|
"enableAutoFixProblems": false,
|
||||||
|
"enableAutoUpdate": true,
|
||||||
|
"releaseChannel": "stable",
|
||||||
|
"isTestMode": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"selectedModel": {
|
||||||
|
"name": "auto",
|
||||||
|
"provider": "auto"
|
||||||
|
},
|
||||||
|
"providerSettings": {
|
||||||
|
"auto": {
|
||||||
|
"apiKey": {
|
||||||
|
"value": "testdyadkey",
|
||||||
|
"encryptionType": "plaintext"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"telemetryConsent": "unset",
|
||||||
|
"telemetryUserId": "[UUID]",
|
||||||
|
"hasRunBefore": true,
|
||||||
|
"enableDyadPro": true,
|
||||||
|
"experiments": {},
|
||||||
|
"lastShownReleaseNotesVersion": "[scrubbed]",
|
||||||
|
"enableProLazyEditsMode": true,
|
||||||
|
"enableProSmartFilesContextMode": true,
|
||||||
|
"selectedTemplateId": "react",
|
||||||
|
"selectedChatMode": "build",
|
||||||
|
"enableAutoFixProblems": false,
|
||||||
|
"enableAutoUpdate": true,
|
||||||
|
"releaseChannel": "stable",
|
||||||
|
"isTestMode": true
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@ import { Label } from "@/components/ui/label";
|
|||||||
import { Sparkles, Info } from "lucide-react";
|
import { Sparkles, Info } from "lucide-react";
|
||||||
import { useSettings } from "@/hooks/useSettings";
|
import { useSettings } from "@/hooks/useSettings";
|
||||||
import { IpcClient } from "@/ipc/ipc_client";
|
import { IpcClient } from "@/ipc/ipc_client";
|
||||||
import { hasDyadProKey } from "@/lib/schemas";
|
import { hasDyadProKey, type UserSettings } from "@/lib/schemas";
|
||||||
|
|
||||||
export function ProModeSelector() {
|
export function ProModeSelector() {
|
||||||
const { settings, updateSettings } = useSettings();
|
const { settings, updateSettings } = useSettings();
|
||||||
@@ -25,10 +25,25 @@ export function ProModeSelector() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleSmartContext = () => {
|
const handleSmartContextChange = (
|
||||||
|
newValue: "off" | "conservative" | "balanced",
|
||||||
|
) => {
|
||||||
|
if (newValue === "off") {
|
||||||
updateSettings({
|
updateSettings({
|
||||||
enableProSmartFilesContextMode: !settings?.enableProSmartFilesContextMode,
|
enableProSmartFilesContextMode: false,
|
||||||
|
proSmartContextOption: undefined,
|
||||||
});
|
});
|
||||||
|
} else if (newValue === "conservative") {
|
||||||
|
updateSettings({
|
||||||
|
enableProSmartFilesContextMode: true,
|
||||||
|
proSmartContextOption: undefined, // Conservative is the default when enabled but no option set
|
||||||
|
});
|
||||||
|
} else if (newValue === "balanced") {
|
||||||
|
updateSettings({
|
||||||
|
enableProSmartFilesContextMode: true,
|
||||||
|
proSmartContextOption: "balanced",
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleProEnabled = () => {
|
const toggleProEnabled = () => {
|
||||||
@@ -99,14 +114,10 @@ export function ProModeSelector() {
|
|||||||
settingEnabled={Boolean(settings?.enableProLazyEditsMode)}
|
settingEnabled={Boolean(settings?.enableProLazyEditsMode)}
|
||||||
toggle={toggleLazyEdits}
|
toggle={toggleLazyEdits}
|
||||||
/>
|
/>
|
||||||
<SelectorRow
|
<SmartContextSelector
|
||||||
id="smart-context"
|
|
||||||
label="Smart Context"
|
|
||||||
description="Optimizes your AI's code context"
|
|
||||||
tooltip="Improve efficiency and save credits working on large codebases."
|
|
||||||
isTogglable={proModeTogglable}
|
isTogglable={proModeTogglable}
|
||||||
settingEnabled={Boolean(settings?.enableProSmartFilesContextMode)}
|
settings={settings}
|
||||||
toggle={toggleSmartContext}
|
onValueChange={handleSmartContextChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -168,3 +179,83 @@ function SelectorRow({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SmartContextSelector({
|
||||||
|
isTogglable,
|
||||||
|
settings,
|
||||||
|
onValueChange,
|
||||||
|
}: {
|
||||||
|
isTogglable: boolean;
|
||||||
|
settings: UserSettings | null;
|
||||||
|
onValueChange: (value: "off" | "conservative" | "balanced") => void;
|
||||||
|
}) {
|
||||||
|
// Determine current value based on settings
|
||||||
|
const getCurrentValue = (): "off" | "conservative" | "balanced" => {
|
||||||
|
if (!settings?.enableProSmartFilesContextMode) {
|
||||||
|
return "off";
|
||||||
|
}
|
||||||
|
if (settings?.proSmartContextOption === "balanced") {
|
||||||
|
return "balanced";
|
||||||
|
}
|
||||||
|
// If enabled but no option set (undefined/falsey), it's conservative
|
||||||
|
return "conservative";
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentValue = getCurrentValue();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label className={!isTogglable ? "text-muted-foreground/50" : ""}>
|
||||||
|
Smart Context
|
||||||
|
</Label>
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Info
|
||||||
|
className={`h-4 w-4 cursor-help ${!isTogglable ? "text-muted-foreground/50" : "text-muted-foreground"}`}
|
||||||
|
/>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="right" className="max-w-72">
|
||||||
|
Improve efficiency and save credits working on large codebases.
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
<p
|
||||||
|
className={`text-xs ${!isTogglable ? "text-muted-foreground/50" : "text-muted-foreground"}`}
|
||||||
|
>
|
||||||
|
Optimizes your AI's code context
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="inline-flex rounded-md border border-input">
|
||||||
|
<Button
|
||||||
|
variant={currentValue === "off" ? "default" : "ghost"}
|
||||||
|
size="sm"
|
||||||
|
onClick={() => onValueChange("off")}
|
||||||
|
disabled={!isTogglable}
|
||||||
|
className="rounded-r-none border-r border-input h-8 px-3 text-xs flex-shrink-0"
|
||||||
|
>
|
||||||
|
Off
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={currentValue === "conservative" ? "default" : "ghost"}
|
||||||
|
size="sm"
|
||||||
|
onClick={() => onValueChange("conservative")}
|
||||||
|
disabled={!isTogglable}
|
||||||
|
className="rounded-none border-r border-input h-8 px-3 text-xs flex-shrink-0"
|
||||||
|
>
|
||||||
|
Conservative
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={currentValue === "balanced" ? "default" : "ghost"}
|
||||||
|
size="sm"
|
||||||
|
onClick={() => onValueChange("balanced")}
|
||||||
|
disabled={!isTogglable}
|
||||||
|
className="rounded-l-none h-8 px-3 text-xs flex-shrink-0"
|
||||||
|
>
|
||||||
|
Balanced
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react";
|
|||||||
import { Brain, ChevronDown, ChevronUp, Loader } from "lucide-react";
|
import { Brain, ChevronDown, ChevronUp, Loader } from "lucide-react";
|
||||||
import { VanillaMarkdownParser } from "./DyadMarkdownParser";
|
import { VanillaMarkdownParser } from "./DyadMarkdownParser";
|
||||||
import { CustomTagState } from "./stateTypes";
|
import { CustomTagState } from "./stateTypes";
|
||||||
|
import { DyadTokenSavings } from "./DyadTokenSavings";
|
||||||
|
|
||||||
interface DyadThinkProps {
|
interface DyadThinkProps {
|
||||||
node?: any;
|
node?: any;
|
||||||
@@ -13,6 +14,26 @@ export const DyadThink: React.FC<DyadThinkProps> = ({ children, node }) => {
|
|||||||
const inProgress = state === "pending";
|
const inProgress = state === "pending";
|
||||||
const [isExpanded, setIsExpanded] = useState(inProgress);
|
const [isExpanded, setIsExpanded] = useState(inProgress);
|
||||||
|
|
||||||
|
// Check if content matches token savings format
|
||||||
|
const tokenSavingsMatch =
|
||||||
|
typeof children === "string"
|
||||||
|
? children.match(
|
||||||
|
/^dyad-token-savings\?original-tokens=([0-9.]+)&smart-context-tokens=([0-9.]+)$/,
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// If it's token savings format, render DyadTokenSavings component
|
||||||
|
if (tokenSavingsMatch) {
|
||||||
|
const originalTokens = parseFloat(tokenSavingsMatch[1]);
|
||||||
|
const smartContextTokens = parseFloat(tokenSavingsMatch[2]);
|
||||||
|
return (
|
||||||
|
<DyadTokenSavings
|
||||||
|
originalTokens={originalTokens}
|
||||||
|
smartContextTokens={smartContextTokens}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Collapse when transitioning from in-progress to not-in-progress
|
// Collapse when transitioning from in-progress to not-in-progress
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!inProgress && isExpanded) {
|
if (!inProgress && isExpanded) {
|
||||||
|
|||||||
36
src/components/chat/DyadTokenSavings.tsx
Normal file
36
src/components/chat/DyadTokenSavings.tsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Zap } from "lucide-react";
|
||||||
|
import { Tooltip, TooltipTrigger, TooltipContent } from "../ui/tooltip";
|
||||||
|
|
||||||
|
interface DyadTokenSavingsProps {
|
||||||
|
originalTokens: number;
|
||||||
|
smartContextTokens: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DyadTokenSavings: React.FC<DyadTokenSavingsProps> = ({
|
||||||
|
originalTokens,
|
||||||
|
smartContextTokens,
|
||||||
|
}) => {
|
||||||
|
const tokensSaved = originalTokens - smartContextTokens;
|
||||||
|
const percentageSaved = Math.round((tokensSaved / originalTokens) * 100);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<div className="bg-green-50 dark:bg-green-950 hover:bg-green-100 dark:hover:bg-green-900 rounded-lg px-4 py-2 border border-green-200 dark:border-green-800 my-2 cursor-pointer">
|
||||||
|
<div className="flex items-center gap-2 text-green-700 dark:text-green-300">
|
||||||
|
<Zap size={16} className="text-green-600 dark:text-green-400" />
|
||||||
|
<span className="text-xs font-medium">
|
||||||
|
Saved {percentageSaved}% of codebase tokens with Smart Context
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="top" align="center">
|
||||||
|
<div className="text-left">
|
||||||
|
Saved {Math.round(tokensSaved).toLocaleString()} tokens
|
||||||
|
</div>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -86,13 +86,23 @@ export function registerTokenCountHandlers() {
|
|||||||
|
|
||||||
if (chat.app) {
|
if (chat.app) {
|
||||||
const appPath = getDyadAppPath(chat.app.path);
|
const appPath = getDyadAppPath(chat.app.path);
|
||||||
codebaseInfo = (
|
const { formattedOutput, files } = await extractCodebase({
|
||||||
await extractCodebase({
|
|
||||||
appPath,
|
appPath,
|
||||||
chatContext: validateChatContext(chat.app.chatContext),
|
chatContext: validateChatContext(chat.app.chatContext),
|
||||||
})
|
});
|
||||||
).formattedOutput;
|
codebaseInfo = formattedOutput;
|
||||||
|
if (settings.enableDyadPro && settings.enableProSmartFilesContextMode) {
|
||||||
|
codebaseTokens = estimateTokens(
|
||||||
|
files
|
||||||
|
// It doesn't need to be the exact format but it's just to get a token estimate
|
||||||
|
.map(
|
||||||
|
(file) => `<dyad-file=${file.path}>${file.content}</dyad-file>`,
|
||||||
|
)
|
||||||
|
.join("\n\n"),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
codebaseTokens = estimateTokens(codebaseInfo);
|
codebaseTokens = estimateTokens(codebaseInfo);
|
||||||
|
}
|
||||||
logger.log(
|
logger.log(
|
||||||
`Extracted codebase information from ${appPath}, tokens: ${codebaseTokens}`,
|
`Extracted codebase information from ${appPath}, tokens: ${codebaseTokens}`,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ export async function getModelClient(
|
|||||||
? false
|
? false
|
||||||
: settings.enableProLazyEditsMode,
|
: settings.enableProLazyEditsMode,
|
||||||
enableSmartFilesContext: settings.enableProSmartFilesContextMode,
|
enableSmartFilesContext: settings.enableProSmartFilesContextMode,
|
||||||
|
smartContextMode: settings.proSmartContextOption,
|
||||||
},
|
},
|
||||||
settings,
|
settings,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ or to provide a custom fetch implementation for e.g. testing.
|
|||||||
dyadOptions: {
|
dyadOptions: {
|
||||||
enableLazyEdits?: boolean;
|
enableLazyEdits?: boolean;
|
||||||
enableSmartFilesContext?: boolean;
|
enableSmartFilesContext?: boolean;
|
||||||
|
smartContextMode?: "balanced";
|
||||||
};
|
};
|
||||||
settings: UserSettings;
|
settings: UserSettings;
|
||||||
}
|
}
|
||||||
@@ -149,6 +150,7 @@ export function createDyadEngine(
|
|||||||
enable_lazy_edits: options.dyadOptions.enableLazyEdits,
|
enable_lazy_edits: options.dyadOptions.enableLazyEdits,
|
||||||
enable_smart_files_context:
|
enable_smart_files_context:
|
||||||
options.dyadOptions.enableSmartFilesContext,
|
options.dyadOptions.enableSmartFilesContext,
|
||||||
|
smart_context_mode: options.dyadOptions.smartContextMode,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ export const UserSettingsSchema = z.object({
|
|||||||
thinkingBudget: z.enum(["low", "medium", "high"]).optional(),
|
thinkingBudget: z.enum(["low", "medium", "high"]).optional(),
|
||||||
enableProLazyEditsMode: z.boolean().optional(),
|
enableProLazyEditsMode: z.boolean().optional(),
|
||||||
enableProSmartFilesContextMode: z.boolean().optional(),
|
enableProSmartFilesContextMode: z.boolean().optional(),
|
||||||
|
proSmartContextOption: z.enum(["balanced"]).optional(),
|
||||||
selectedTemplateId: z.string(),
|
selectedTemplateId: z.string(),
|
||||||
enableSupabaseWriteSqlMigration: z.boolean().optional(),
|
enableSupabaseWriteSqlMigration: z.boolean().optional(),
|
||||||
selectedChatMode: ChatModeSchema.optional(),
|
selectedChatMode: ChatModeSchema.optional(),
|
||||||
|
|||||||
Reference in New Issue
Block a user