Skip to content

Commit 2bfaad6

Browse files
hlsitechioclaude
andcommitted
merge: sync with upstream v0.0.5
Merge upstream changes including v0.0.5 release, wss fix, and duplicate text fix. Resolved version conflict in apps/web/package.json. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2 parents f9e3418 + 5dd36bc commit 2bfaad6

19 files changed

Lines changed: 110 additions & 36 deletions

apps/desktop/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@t3tools/desktop",
3-
"version": "0.0.4-alpha.1",
3+
"version": "0.0.5",
44
"private": true,
55
"main": "dist-electron/main.js",
66
"scripts": {

apps/server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "t3",
3-
"version": "0.0.4-alpha.1",
3+
"version": "0.0.5",
44
"repository": {
55
"type": "git",
66
"url": "https://github.com/pingdotgg/t3code",

apps/server/scripts/cli.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ const buildCmd = Command.make(
133133
cwd: serverDir,
134134
stdout: config.verbose ? "inherit" : "ignore",
135135
stderr: "inherit",
136+
shell: process.platform === "win32",
136137
})`bun tsdown`,
137138
);
138139

@@ -239,6 +240,7 @@ const publishCmd = Command.make(
239240
cwd: serverDir,
240241
stdout: config.verbose ? "inherit" : "ignore",
241242
stderr: "inherit",
243+
shell: process.platform === "win32",
242244
}),
243245
);
244246
}),

apps/server/src/orchestration/Layers/ProviderCommandReactor.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
type ProviderModelOptions,
77
type ProviderKind,
88
type ProviderServiceTier,
9+
type ProviderStartOptions,
910
type OrchestrationSession,
1011
ThreadId,
1112
type ProviderSession,
@@ -144,6 +145,8 @@ const make = Effect.gen(function* () {
144145
),
145146
);
146147

148+
const threadProviderOptions = new Map<string, ProviderStartOptions>();
149+
147150
const appendProviderFailureActivity = (input: {
148151
readonly threadId: ThreadId;
149152
readonly kind:
@@ -203,6 +206,7 @@ const make = Effect.gen(function* () {
203206
readonly model?: string;
204207
readonly modelOptions?: ProviderModelOptions;
205208
readonly serviceTier?: ProviderServiceTier | null;
209+
readonly providerOptions?: ProviderStartOptions;
206210
},
207211
) {
208212
const readModel = yield* orchestrationEngine.getReadModel();
@@ -239,6 +243,7 @@ const make = Effect.gen(function* () {
239243
...(desiredModel ? { model: desiredModel } : {}),
240244
...(options?.serviceTier !== undefined ? { serviceTier: options.serviceTier } : {}),
241245
...(options?.modelOptions !== undefined ? { modelOptions: options.modelOptions } : {}),
246+
...(options?.providerOptions !== undefined ? { providerOptions: options.providerOptions } : {}),
242247
...(input?.resumeCursor !== undefined ? { resumeCursor: input.resumeCursor } : {}),
243248
runtimeMode: desiredRuntimeMode,
244249
});
@@ -325,18 +330,23 @@ const make = Effect.gen(function* () {
325330
readonly model?: string;
326331
readonly serviceTier?: ProviderServiceTier | null;
327332
readonly modelOptions?: ProviderModelOptions;
333+
readonly providerOptions?: ProviderStartOptions;
328334
readonly interactionMode?: "default" | "plan";
329335
readonly createdAt: string;
330336
}) {
331337
const thread = yield* resolveThread(input.threadId);
332338
if (!thread) {
333339
return;
334340
}
341+
if (input.providerOptions !== undefined) {
342+
threadProviderOptions.set(input.threadId, input.providerOptions);
343+
}
335344
yield* ensureSessionForThread(input.threadId, input.createdAt, {
336345
...(input.provider !== undefined ? { provider: input.provider } : {}),
337346
...(input.model !== undefined ? { model: input.model } : {}),
338347
...(input.serviceTier !== undefined ? { serviceTier: input.serviceTier } : {}),
339348
...(input.modelOptions !== undefined ? { modelOptions: input.modelOptions } : {}),
349+
...(input.providerOptions !== undefined ? { providerOptions: input.providerOptions } : {}),
340350
});
341351
const normalizedInput = toNonEmptyProviderInput(input.messageText);
342352
const normalizedAttachments = input.attachments ?? [];
@@ -472,6 +482,7 @@ const make = Effect.gen(function* () {
472482
...(event.payload.model !== undefined ? { model: event.payload.model } : {}),
473483
...(event.payload.serviceTier !== undefined ? { serviceTier: event.payload.serviceTier } : {}),
474484
...(event.payload.modelOptions !== undefined ? { modelOptions: event.payload.modelOptions } : {}),
485+
...(event.payload.providerOptions !== undefined ? { providerOptions: event.payload.providerOptions } : {}),
475486
interactionMode: event.payload.interactionMode,
476487
createdAt: event.payload.createdAt,
477488
});
@@ -627,7 +638,10 @@ const make = Effect.gen(function* () {
627638
if (!thread?.session || thread.session.status === "stopped") {
628639
return;
629640
}
630-
yield* ensureSessionForThread(event.payload.threadId, event.occurredAt);
641+
const cachedProviderOptions = threadProviderOptions.get(event.payload.threadId);
642+
yield* ensureSessionForThread(event.payload.threadId, event.occurredAt, {
643+
...(cachedProviderOptions !== undefined ? { providerOptions: cachedProviderOptions } : {}),
644+
});
631645
return;
632646
}
633647
case "thread.turn-start-requested":

apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,7 @@ describe("ProviderRuntimeIngestion", () => {
834834
payload: {
835835
itemType: "assistant_message",
836836
status: "completed",
837+
detail: "hello live",
837838
},
838839
});
839840

apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,10 @@ const make = Effect.gen(function* () {
951951
if (assistantCompletion) {
952952
const assistantMessageId = assistantCompletion.messageId;
953953
const turnId = toTurnId(event.turnId);
954+
const existingAssistantMessage = thread.messages.find((entry) => entry.id === assistantMessageId);
955+
const shouldApplyFallbackCompletionText =
956+
!existingAssistantMessage ||
957+
existingAssistantMessage.text.length === 0;
954958
if (turnId) {
955959
yield* rememberAssistantMessageId(thread.id, turnId, assistantMessageId);
956960
}
@@ -963,7 +967,7 @@ const make = Effect.gen(function* () {
963967
createdAt: now,
964968
commandTag: "assistant-complete",
965969
finalDeltaCommandTag: "assistant-delta-finalize",
966-
...(assistantCompletion.fallbackText !== undefined
970+
...(assistantCompletion.fallbackText !== undefined && shouldApplyFallbackCompletionText
967971
? { fallbackText: assistantCompletion.fallbackText }
968972
: {}),
969973
});

apps/server/src/orchestration/decider.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand"
303303
...(command.model !== undefined ? { model: command.model } : {}),
304304
...(command.serviceTier !== undefined ? { serviceTier: command.serviceTier } : {}),
305305
...(command.modelOptions !== undefined ? { modelOptions: command.modelOptions } : {}),
306+
...(command.providerOptions !== undefined ? { providerOptions: command.providerOptions } : {}),
306307
assistantDeliveryMode: command.assistantDeliveryMode ?? DEFAULT_ASSISTANT_DELIVERY_MODE,
307308
runtimeMode:
308309
readModel.threads.find((entry) => entry.id === command.threadId)?.runtimeMode ??

apps/server/src/provider/Layers/ProviderService.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,30 @@ function toRuntimeStatus(session: ProviderSession): "starting" | "running" | "st
8686
}
8787
}
8888

89-
function toRuntimePayloadFromSession(session: ProviderSession): Record<string, unknown> {
89+
function toRuntimePayloadFromSession(
90+
session: ProviderSession,
91+
extra?: { readonly providerOptions?: unknown },
92+
): Record<string, unknown> {
9093
return {
9194
cwd: session.cwd ?? null,
9295
model: session.model ?? null,
9396
activeTurnId: session.activeTurnId ?? null,
9497
lastError: session.lastError ?? null,
98+
...(extra?.providerOptions !== undefined ? { providerOptions: extra.providerOptions } : {}),
9599
};
96100
}
97101

102+
function readPersistedProviderOptions(
103+
runtimePayload: ProviderRuntimeBinding["runtimePayload"],
104+
): Record<string, unknown> | undefined {
105+
if (!runtimePayload || typeof runtimePayload !== "object" || Array.isArray(runtimePayload)) {
106+
return undefined;
107+
}
108+
const raw = "providerOptions" in runtimePayload ? runtimePayload.providerOptions : undefined;
109+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return undefined;
110+
return raw as Record<string, unknown>;
111+
}
112+
98113
function readPersistedCwd(
99114
runtimePayload: ProviderRuntimeBinding["runtimePayload"],
100115
): string | undefined {
@@ -137,14 +152,15 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>
137152
const upsertSessionBinding = (
138153
session: ProviderSession,
139154
threadId: ThreadId,
155+
extra?: { readonly providerOptions?: unknown },
140156
) =>
141157
directory.upsert({
142158
threadId,
143159
provider: session.provider,
144160
runtimeMode: session.runtimeMode,
145161
status: toRuntimeStatus(session),
146162
...(session.resumeCursor !== undefined ? { resumeCursor: session.resumeCursor } : {}),
147-
runtimePayload: toRuntimePayloadFromSession(session),
163+
runtimePayload: toRuntimePayloadFromSession(session, extra),
148164
});
149165

150166
const providers = yield* registry.listProviders();
@@ -197,11 +213,13 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>
197213
}
198214

199215
const persistedCwd = readPersistedCwd(input.binding.runtimePayload);
216+
const persistedProviderOptions = readPersistedProviderOptions(input.binding.runtimePayload);
200217

201218
const resumed = yield* adapter.startSession({
202219
threadId: input.binding.threadId,
203220
provider: input.binding.provider,
204221
...(persistedCwd ? { cwd: persistedCwd } : {}),
222+
...(persistedProviderOptions ? { providerOptions: persistedProviderOptions } : {}),
205223
...(hasResumeCursor ? { resumeCursor: input.binding.resumeCursor } : {}),
206224
runtimeMode: input.binding.runtimeMode ?? "full-access",
207225
});
@@ -273,7 +291,9 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>
273291
);
274292
}
275293

276-
yield* upsertSessionBinding(session, threadId);
294+
yield* upsertSessionBinding(session, threadId, {
295+
...(input.providerOptions !== undefined ? { providerOptions: input.providerOptions } : {}),
296+
});
277297
yield* analytics.record("provider.session.started", {
278298
provider: session.provider,
279299
runtimeMode: input.runtimeMode,

apps/web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@t3tools/web",
3-
"version": "0.0.4-alpha.2",
3+
"version": "0.0.5",
44
"private": true,
55
"type": "module",
66
"scripts": {

apps/web/src/components/ChatView.tsx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,17 @@ export default function ChatView({ threadId, mode = "default" }: ChatViewProps)
10071007
};
10081008
return Object.keys(codexOptions).length > 0 ? { codex: codexOptions } : undefined;
10091009
}, [selectedCodexFastModeEnabled, selectedEffort, selectedProvider, supportsReasoningEffort]);
1010+
const providerOptionsForDispatch = useMemo(() => {
1011+
if (!settings.codexBinaryPath && !settings.codexHomePath) {
1012+
return undefined;
1013+
}
1014+
return {
1015+
codex: {
1016+
...(settings.codexBinaryPath ? { binaryPath: settings.codexBinaryPath } : {}),
1017+
...(settings.codexHomePath ? { homePath: settings.codexHomePath } : {}),
1018+
},
1019+
};
1020+
}, [settings.codexBinaryPath, settings.codexHomePath]);
10101021
const selectedModelForPicker = selectedModel;
10111022
const modelOptionsByProvider = useMemo(
10121023
() => getCustomModelOptionsByProvider(settings),
@@ -3038,6 +3049,9 @@ export default function ChatView({ threadId, mode = "default" }: ChatViewProps)
30383049
...(selectedModelOptionsForDispatch
30393050
? { modelOptions: selectedModelOptionsForDispatch }
30403051
: {}),
3052+
...(providerOptionsForDispatch
3053+
? { providerOptions: providerOptionsForDispatch }
3054+
: {}),
30413055
provider: selectedProvider,
30423056
assistantDeliveryMode: settings.enableAssistantStreaming ? "streaming" : "buffered",
30433057
runtimeMode,
@@ -3315,6 +3329,9 @@ export default function ChatView({ threadId, mode = "default" }: ChatViewProps)
33153329
...(selectedModelOptionsForDispatch
33163330
? { modelOptions: selectedModelOptionsForDispatch }
33173331
: {}),
3332+
...(providerOptionsForDispatch
3333+
? { providerOptions: providerOptionsForDispatch }
3334+
: {}),
33183335
assistantDeliveryMode: settings.enableAssistantStreaming ? "streaming" : "buffered",
33193336
runtimeMode,
33203337
interactionMode: nextInteractionMode,
@@ -3345,6 +3362,7 @@ export default function ChatView({ threadId, mode = "default" }: ChatViewProps)
33453362
runtimeMode,
33463363
selectedModel,
33473364
selectedModelOptionsForDispatch,
3365+
providerOptionsForDispatch,
33483366
selectedProvider,
33493367
setComposerDraftInteractionMode,
33503368
setThreadError,
@@ -3399,8 +3417,8 @@ export default function ChatView({ threadId, mode = "default" }: ChatViewProps)
33993417
worktreePath: activeThread.worktreePath,
34003418
createdAt,
34013419
})
3402-
.then(() =>
3403-
api.orchestration.dispatchCommand({
3420+
.then(() => {
3421+
return api.orchestration.dispatchCommand({
34043422
type: "thread.turn.start",
34053423
commandId: newCommandId(),
34063424
threadId: nextThreadId,
@@ -3415,12 +3433,15 @@ export default function ChatView({ threadId, mode = "default" }: ChatViewProps)
34153433
...(selectedModelOptionsForDispatch
34163434
? { modelOptions: selectedModelOptionsForDispatch }
34173435
: {}),
3436+
...(providerOptionsForDispatch
3437+
? { providerOptions: providerOptionsForDispatch }
3438+
: {}),
34183439
assistantDeliveryMode: settings.enableAssistantStreaming ? "streaming" : "buffered",
34193440
runtimeMode,
34203441
interactionMode: "default",
34213442
createdAt,
3422-
}),
3423-
)
3443+
});
3444+
})
34243445
.then(() => api.orchestration.getSnapshot())
34253446
.then((snapshot) => {
34263447
syncServerReadModel(snapshot);
@@ -3464,6 +3485,7 @@ export default function ChatView({ threadId, mode = "default" }: ChatViewProps)
34643485
runtimeMode,
34653486
selectedModel,
34663487
selectedModelOptionsForDispatch,
3488+
providerOptionsForDispatch,
34673489
selectedProvider,
34683490
settings.enableAssistantStreaming,
34693491
syncServerReadModel,
@@ -5743,8 +5765,7 @@ const MessagesTimeline = memo(function MessagesTimeline({
57435765
)}
57445766

57455767
{row.kind === "working" && (
5746-
<div className="flex items-center gap-2 py-0.5 pl-1.5">
5747-
<span className="h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/30" />
5768+
<div className="py-0.5 pl-1.5">
57485769
<div className="flex items-center gap-2 pt-1 text-[11px] text-muted-foreground/70">
57495770
<span className="inline-flex items-center gap-[3px]">
57505771
<span className="h-1 w-1 rounded-full bg-muted-foreground/30 animate-pulse" />

0 commit comments

Comments
 (0)