({
context: {
@@ -5888,10 +5894,12 @@ export default function ChatView(props: ChatViewProps) {
? (pendingServerThreadStartFromOriginByThreadId[activeThread?.id ?? ""] ??
activeProjectSettings.settings.newWorktreesStartFromOrigin)
: false;
- const sendEnvMode = resolveSendEnvMode({
- requestedEnvMode: envMode,
- isGitRepo,
- });
+ const firstLaunchScope = draftThread?.executionScope ?? "coding";
+ const sendEnvMode = isLocalDraftThread
+ ? firstLaunchScope === "coding"
+ ? "worktree"
+ : "local"
+ : resolveSendEnvMode({ requestedEnvMode: envMode, isGitRepo });
const localCheckoutBranchMismatch = useMemo(
() =>
isServerThread
@@ -7724,7 +7732,10 @@ export default function ChatView(props: ChatViewProps) {
const shouldCreateWorktree =
isFirstMessage && sendEnvMode === "worktree" && !activeThread.worktreePath;
if (shouldCreateWorktree && !activeThreadBranch) {
- setThreadError(threadIdForSend, "Select a base branch before sending in New worktree mode.");
+ setThreadError(
+ threadIdForSend,
+ "Coding needs a Git repository and a committed base branch. Select a repository project or choose Coordinator for noncoding work.",
+ );
return;
}
@@ -8066,6 +8077,7 @@ export default function ChatView(props: ChatViewProps) {
bootstrap: {
createThread: {
projectId: activeProject.id,
+ executionScope: "coding",
title,
modelSelection: target.selection,
runtimeMode,
@@ -8403,6 +8415,7 @@ export default function ChatView(props: ChatViewProps) {
? {
createThread: {
projectId: activeProject.id,
+ executionScope: firstLaunchScope,
title,
modelSelection: threadCreateModelSelection,
runtimeMode,
@@ -10240,12 +10253,52 @@ export default function ChatView(props: ChatViewProps) {
>
{mountComposerContextStrip && (
+ {isLocalDraftThread && (
+
+ )}
()(
worktreePath: nextWorktreePath,
envMode:
options.envMode ?? (nextWorktreePath ? "worktree" : (existing.envMode ?? "local")),
+ executionScope: options.executionScope ?? existing.executionScope ?? "coding",
startFromOrigin: nextStartFromOrigin,
promotedTo: existing.promotedTo ?? null,
};
@@ -2804,6 +2817,7 @@ const composerDraftStore = create()(
nextDraftThread.branch === existing.branch &&
nextDraftThread.worktreePath === existing.worktreePath &&
nextDraftThread.envMode === existing.envMode &&
+ nextDraftThread.executionScope === existing.executionScope &&
nextDraftThread.startFromOrigin === existing.startFromOrigin &&
scopedThreadRefsEqual(nextDraftThread.promotedTo, existing.promotedTo);
if (isUnchanged) {
diff --git a/packages/contracts/src/orchestration.ts b/packages/contracts/src/orchestration.ts
index 71b03419ab1f..9a82c5599f0e 100644
--- a/packages/contracts/src/orchestration.ts
+++ b/packages/contracts/src/orchestration.ts
@@ -837,6 +837,10 @@ export const ThreadPullRequestLink = Schema.Struct({
});
export type ThreadPullRequestLink = typeof ThreadPullRequestLink.Type;
+// Null/absent belongs to pre-isolation history; new creates default to coding on the server.
+export const ThreadExecutionScope = Schema.Literals(["coding", "coordinator"]);
+export type ThreadExecutionScope = typeof ThreadExecutionScope.Type;
+
export const OrchestrationThread = Schema.Struct({
id: ThreadId,
projectId: ProjectId,
@@ -848,6 +852,7 @@ export const OrchestrationThread = Schema.Struct({
),
branch: Schema.NullOr(TrimmedNonEmptyString),
worktreePath: Schema.NullOr(TrimmedNonEmptyString),
+ executionScope: Schema.optional(Schema.NullOr(ThreadExecutionScope)),
linkedPullRequest: Schema.optional(Schema.NullOr(ThreadLinkedPullRequest)),
// Optional so payloads from pre-link servers still decode.
pullRequests: Schema.Array(ThreadPullRequestLink).pipe(
@@ -935,6 +940,7 @@ export const OrchestrationThreadShell = Schema.Struct({
),
branch: Schema.NullOr(TrimmedNonEmptyString),
worktreePath: Schema.NullOr(TrimmedNonEmptyString),
+ executionScope: Schema.optional(Schema.NullOr(ThreadExecutionScope)),
linkedPullRequest: Schema.optional(Schema.NullOr(ThreadLinkedPullRequest)),
pullRequests: Schema.Array(ThreadPullRequestLink).pipe(
Schema.withDecodingDefault(Effect.succeed([])),
@@ -1174,6 +1180,7 @@ const ThreadCreateCommand = Schema.Struct({
),
branch: Schema.NullOr(TrimmedNonEmptyString),
worktreePath: Schema.NullOr(TrimmedNonEmptyString),
+ executionScope: Schema.optional(Schema.NullOr(ThreadExecutionScope)),
createdAt: IsoDateTime,
historyImport: Schema.optional(Schema.Literal(true)),
});
@@ -1334,6 +1341,7 @@ const ThreadTurnStartBootstrapCreateThread = Schema.Struct({
interactionMode: ProviderInteractionMode,
branch: Schema.NullOr(TrimmedNonEmptyString),
worktreePath: Schema.NullOr(TrimmedNonEmptyString),
+ executionScope: Schema.optional(Schema.NullOr(ThreadExecutionScope)),
createdAt: IsoDateTime,
});
@@ -1816,6 +1824,7 @@ export const ThreadCreatedPayload = Schema.Struct({
),
branch: Schema.NullOr(TrimmedNonEmptyString),
worktreePath: Schema.NullOr(TrimmedNonEmptyString),
+ executionScope: Schema.optional(Schema.NullOr(ThreadExecutionScope)),
createdAt: IsoDateTime,
updatedAt: IsoDateTime,
});