Skip to content

Commit 8bd6c07

Browse files
authored
Merge pull request #4 from dafzthomas/havenCode/merge-upstream-pr179-update
Merge upstream PR pingdotgg#179 updates (Claude adapter + storage refactor)
2 parents 2db1273 + 25b28e3 commit 8bd6c07

10 files changed

Lines changed: 452 additions & 292 deletions

apps/web/src/components/ChatView.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2456,7 +2456,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
24562456
? parseStandaloneComposerSlashCommand(trimmed)
24572457
: null;
24582458
if (standaloneSlashCommand) {
2459-
await handleInteractionModeChange(standaloneSlashCommand);
2459+
handleInteractionModeChange(standaloneSlashCommand);
24602460
promptRef.current = "";
24612461
clearComposerDraftContent(activeThread.id);
24622462
setComposerHighlightedItemId(null);
@@ -2512,7 +2512,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
25122512
const outgoingMessageText = formatOutgoingPrompt({
25132513
provider: selectedProvider,
25142514
effort: selectedPromptEffort,
2515-
text: trimmed || IMAGE_ONLY_BOOTSTRAP_PROMPT,
2515+
text: messageTextForSend || IMAGE_ONLY_BOOTSTRAP_PROMPT,
25162516
});
25172517
const turnAttachmentsPromise = Promise.all(
25182518
composerImagesSnapshot.map(async (image) => ({
@@ -3670,8 +3670,6 @@ export default function ChatView({ threadId }: ChatViewProps) {
36703670
/>
36713671
</div>
36723672
) : null}
3673-
3674-
{/* Textarea area */}
36753673
<div
36763674
className={cn(
36773675
"relative px-3 pb-2 sm:px-4",
@@ -4068,7 +4066,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
40684066
disabled={isSendBusy || isConnecting}
40694067
onClick={() => void onImplementPlanInNewThread()}
40704068
>
4071-
Implement in new thread
4069+
Implement in a new thread
40724070
</MenuItem>
40734071
</MenuPopup>
40744072
</Menu>
@@ -4079,9 +4077,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
40794077
type="submit"
40804078
className="flex h-9 w-9 items-center justify-center rounded-full bg-primary/90 text-primary-foreground transition-all duration-150 hover:bg-primary hover:scale-105 disabled:opacity-30 disabled:hover:scale-100 sm:h-8 sm:w-8"
40814079
disabled={
4082-
isSendBusy ||
4083-
isConnecting ||
4084-
(!prompt.trim() && composerImages.length === 0)
4080+
isSendBusy || isConnecting || !composerSendState.hasSendableContent
40854081
}
40864082
aria-label={
40874083
isConnecting

apps/web/src/components/chat/ClaudeTraitsPicker.browser.tsx

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,29 @@ async function mountPicker(props?: {
1616
fastModeEnabled?: boolean;
1717
}) {
1818
const threadId = ThreadId.makeUnsafe("thread-claude-traits");
19-
useComposerDraftStore.setState({
20-
draftsByThreadId: {
21-
[threadId]: {
22-
prompt: props?.prompt ?? "",
23-
images: [],
24-
nonPersistedImageIds: [],
25-
persistedAttachments: [],
26-
terminalContexts: [],
27-
provider: "claudeAgent",
28-
model: props?.model ?? "claude-opus-4-6",
29-
modelOptions: {
30-
claudeAgent: {
31-
...(props?.effort ? { effort: props.effort } : {}),
32-
...(props?.thinkingEnabled === false ? { thinking: false } : {}),
33-
...(props?.fastModeEnabled ? { fastMode: true } : {}),
34-
},
35-
},
36-
runtimeMode: null,
37-
interactionMode: null,
19+
const draftsByThreadId = {} as ReturnType<
20+
typeof useComposerDraftStore.getState
21+
>["draftsByThreadId"];
22+
draftsByThreadId[threadId] = {
23+
prompt: props?.prompt ?? "",
24+
images: [],
25+
nonPersistedImageIds: [],
26+
persistedAttachments: [],
27+
terminalContexts: [],
28+
provider: "claudeAgent",
29+
model: props?.model ?? "claude-opus-4-6",
30+
modelOptions: {
31+
claudeAgent: {
32+
...(props?.effort ? { effort: props.effort } : {}),
33+
...(props?.thinkingEnabled === false ? { thinking: false } : {}),
34+
...(props?.fastModeEnabled ? { fastMode: true } : {}),
3835
},
3936
},
37+
runtimeMode: null,
38+
interactionMode: null,
39+
};
40+
useComposerDraftStore.setState({
41+
draftsByThreadId,
4042
draftThreadsByThreadId: {},
4143
projectDraftThreadIdByProjectId: {},
4244
});

apps/web/src/components/chat/CodexTraitsPicker.browser.tsx

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,28 @@ async function mountPicker(props: {
1313
fastModeEnabled: boolean;
1414
}) {
1515
const threadId = ThreadId.makeUnsafe("thread-codex-traits");
16-
useComposerDraftStore.setState({
17-
draftsByThreadId: {
18-
[threadId]: {
19-
prompt: "",
20-
images: [],
21-
nonPersistedImageIds: [],
22-
persistedAttachments: [],
23-
terminalContexts: [],
24-
provider: "codex",
25-
model: null,
26-
modelOptions: {
27-
codex: {
28-
...(props.reasoningEffort ? { reasoningEffort: props.reasoningEffort } : {}),
29-
...(props.fastModeEnabled ? { fastMode: true } : {}),
30-
},
31-
},
32-
runtimeMode: null,
33-
interactionMode: null,
16+
const draftsByThreadId = {} as ReturnType<
17+
typeof useComposerDraftStore.getState
18+
>["draftsByThreadId"];
19+
draftsByThreadId[threadId] = {
20+
prompt: "",
21+
images: [],
22+
nonPersistedImageIds: [],
23+
persistedAttachments: [],
24+
terminalContexts: [],
25+
provider: "codex",
26+
model: null,
27+
modelOptions: {
28+
codex: {
29+
...(props.reasoningEffort ? { reasoningEffort: props.reasoningEffort } : {}),
30+
...(props.fastModeEnabled ? { fastMode: true } : {}),
3431
},
3532
},
33+
runtimeMode: null,
34+
interactionMode: null,
35+
};
36+
useComposerDraftStore.setState({
37+
draftsByThreadId,
3638
draftThreadsByThreadId: {},
3739
projectDraftThreadIdByProjectId: {
3840
[ProjectId.makeUnsafe("project-codex-traits")]: threadId,

apps/web/src/components/chat/CodexTraitsPicker.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import {
2-
type CodexModelOptions,
3-
type CodexReasoningEffort,
4-
type ProviderModelOptions,
5-
type ThreadId,
1+
import type {
2+
CodexModelOptions,
3+
CodexReasoningEffort,
4+
ProviderModelOptions,
5+
ThreadId,
66
} from "@t3tools/contracts";
77
import {
88
getDefaultReasoningEffort,
@@ -132,12 +132,14 @@ export const CodexTraitsPicker = memo(function CodexTraitsPicker(props: { thread
132132
<Button
133133
size="sm"
134134
variant="ghost"
135-
className="shrink-0 whitespace-nowrap px-2 text-muted-foreground/70 hover:text-foreground/80 sm:px-3"
135+
className="min-w-0 max-w-40 shrink justify-start overflow-hidden whitespace-nowrap px-2 text-muted-foreground/70 hover:text-foreground/80 sm:max-w-48 sm:px-3 [&_svg]:mx-0"
136136
/>
137137
}
138138
>
139-
<span>{triggerLabel}</span>
140-
<ChevronDownIcon aria-hidden="true" className="size-3 opacity-60" />
139+
<span className="flex min-w-0 w-full items-center gap-2 overflow-hidden">
140+
{triggerLabel}
141+
<ChevronDownIcon aria-hidden="true" className="size-3 shrink-0 opacity-60" />
142+
</span>
141143
</MenuTrigger>
142144
<MenuPopup align="start">
143145
<CodexTraitsMenuContent threadId={props.threadId} />

apps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx

Lines changed: 28 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ThreadId } from "@t3tools/contracts";
1+
import { type ProviderModelOptions, ThreadId } from "@t3tools/contracts";
22
import "../../index.css";
33

44
import { page } from "vitest/browser";
@@ -14,47 +14,27 @@ async function mountMenu(props?: {
1414
model?: string;
1515
prompt?: string;
1616
provider?: "codex" | "claudeAgent";
17-
codexEffort?: "low" | "medium" | "high" | "xhigh";
18-
codexFastMode?: boolean;
19-
claudeEffort?: "low" | "medium" | "high" | "max" | "ultrathink";
20-
claudeThinking?: boolean;
21-
claudeFastMode?: boolean;
17+
modelOptions?: ProviderModelOptions | null;
2218
}) {
2319
const threadId = ThreadId.makeUnsafe("thread-compact-menu");
2420
const provider = props?.provider ?? "claudeAgent";
21+
const draftsByThreadId = {} as ReturnType<
22+
typeof useComposerDraftStore.getState
23+
>["draftsByThreadId"];
24+
draftsByThreadId[threadId] = {
25+
prompt: props?.prompt ?? "",
26+
images: [],
27+
nonPersistedImageIds: [],
28+
persistedAttachments: [],
29+
terminalContexts: [],
30+
provider,
31+
model: props?.model ?? "claude-opus-4-6",
32+
modelOptions: props?.modelOptions ?? null,
33+
runtimeMode: null,
34+
interactionMode: null,
35+
};
2536
useComposerDraftStore.setState({
26-
draftsByThreadId: {
27-
[threadId]: {
28-
prompt: props?.prompt ?? "",
29-
images: [],
30-
nonPersistedImageIds: [],
31-
persistedAttachments: [],
32-
terminalContexts: [],
33-
provider,
34-
model: props?.model ?? "claude-opus-4-6",
35-
modelOptions: {
36-
...(provider === "codex"
37-
? {
38-
codex: {
39-
...(props?.codexEffort ? { reasoningEffort: props.codexEffort } : {}),
40-
...(props?.codexFastMode ? { fastMode: true } : {}),
41-
},
42-
}
43-
: {}),
44-
...(provider === "claudeAgent"
45-
? {
46-
claudeAgent: {
47-
...(props?.claudeEffort ? { effort: props.claudeEffort } : {}),
48-
...(props?.claudeThinking === false ? { thinking: false } : {}),
49-
...(props?.claudeFastMode ? { fastMode: true } : {}),
50-
},
51-
}
52-
: {}),
53-
},
54-
runtimeMode: null,
55-
interactionMode: null,
56-
},
57-
},
37+
draftsByThreadId,
5838
draftThreadsByThreadId: {},
5939
projectDraftThreadIdByProjectId: {},
6040
});
@@ -158,7 +138,11 @@ describe("CompactComposerControlsMenu", () => {
158138
it("shows a Claude thinking on/off section for Haiku", async () => {
159139
const mounted = await mountMenu({
160140
model: "claude-haiku-4-5",
161-
claudeThinking: true,
141+
modelOptions: {
142+
claudeAgent: {
143+
thinking: true,
144+
},
145+
},
162146
});
163147

164148
try {
@@ -179,7 +163,11 @@ describe("CompactComposerControlsMenu", () => {
179163
const mounted = await mountMenu({
180164
model: "claude-opus-4-6",
181165
prompt: "Ultrathink:\nInvestigate this",
182-
claudeEffort: "high",
166+
modelOptions: {
167+
claudeAgent: {
168+
effort: "high",
169+
},
170+
},
183171
});
184172

185173
try {

apps/web/src/components/chat/ProviderModelPicker.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,18 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: {
136136
size="sm"
137137
variant="ghost"
138138
className={cn(
139-
"min-w-0 shrink-0 whitespace-nowrap px-2 text-muted-foreground/70 hover:text-foreground/80",
140-
props.compact ? "max-w-42" : "sm:px-3",
139+
"min-w-0 justify-start overflow-hidden whitespace-nowrap px-2 text-muted-foreground/70 hover:text-foreground/80 [&_svg]:mx-0",
140+
props.compact ? "max-w-42 shrink-0" : "max-w-48 shrink sm:max-w-56 sm:px-3",
141141
)}
142142
disabled={props.disabled}
143143
/>
144144
}
145145
>
146146
<span
147-
className={cn("flex min-w-0 items-center gap-2", props.compact ? "max-w-36" : undefined)}
147+
className={cn(
148+
"flex min-w-0 w-full items-center gap-2 overflow-hidden",
149+
props.compact ? "max-w-36" : undefined,
150+
)}
148151
>
149152
<ProviderIcon
150153
aria-hidden="true"
@@ -156,13 +159,13 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: {
156159
: undefined,
157160
)}
158161
/>
159-
<span className="truncate">{selectedModelLabel}</span>
162+
<span className="min-w-0 flex-1 truncate">{selectedModelLabel}</span>
160163
{props.bedrockActive && activeProvider === "claudeAgent" && (
161164
<span className="shrink-0 rounded bg-amber-500/15 px-1 py-px text-[10px] font-medium text-amber-600 dark:text-amber-400">
162165
Bedrock
163166
</span>
164167
)}
165-
<ChevronDownIcon aria-hidden="true" className="size-3 opacity-60" />
168+
<ChevronDownIcon aria-hidden="true" className="size-3 shrink-0 opacity-60" />
166169
</span>
167170
</MenuTrigger>
168171
<MenuPopup align="start">

0 commit comments

Comments
 (0)