From 03662dae5dac907aa02d183e8546b78d06a9bea1 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 28 Oct 2026 17:16:28 -0700 Subject: [PATCH 01/23] feat(server): agents read, open, update, respond to, and merge PRs through MCP tools Agents shelled out to gh and cafe for PR work (about 18,000 forge commands in 45 days across three machines), which spends the user's own quota and gives agents raw JSON to trim with --jq. Six new MCP tools route that work through PullRequestService, so it uses the server's forge sign-in (the T3 Code for GitHub app where it is signed in) and works on every forge T3 supports. - pull_request_read: summary, checks, conversation (unresolved threads by default) and diff, defaulting to the PR for the thread's branch. - pull_request_list, pull_request_update, pull_request_respond. - pull_request_create: GitManager.createPullRequest shares runPrStep's branch, upstream, existing-PR and base checks, takes the agent's title and body, and links the PR to the thread. - pull_request_merge: requires expectedHeadSha. PullRequestService refuses a merge whose head moved on every host, and GitHub also pins it atomically through expectedHeadOid. The tool list grows by 2,815 bytes. New mcp-tool-use cases pass 12/12 on Sonnet 5.5 (0/12 on main), the control stays 4/4, and the eval runner answers the new tools from each case's world. Co-Authored-By: Claude Opus 5.5 --- apps/server/src/git/GitManager.ts | 126 +++++-- apps/server/src/mcp/McpHttpServer.test.ts | 3 + .../toolkits/pullRequests/handlers.test.ts | 175 +++++++++ .../src/mcp/toolkits/pullRequests/handlers.ts | 335 +++++++++++++++++- .../src/mcp/toolkits/pullRequests/tools.ts | 292 +++++++++++++++ .../src/provider/AgentContextBudget.test.ts | 2 + .../pullRequest/PullRequestService.test.ts | 24 ++ .../src/pullRequest/PullRequestService.ts | 30 +- docs/user/source-control.md | 4 + evals/mcp-tool-use/cases/pull-requests.ndjson | 4 + evals/mcp-tool-use/run.ts | 120 +++++++ packages/client-runtime/src/t3ToolSummary.ts | 18 + packages/contracts/src/pullRequest.ts | 2 + packages/shared/src/t3McpToolPresentation.ts | 32 ++ .../src/server/PullRequestProvider.ts | 2 + .../src/server/GitHubPullRequestApi.ts | 5 +- .../src/server/GitHubPullRequestProvider.ts | 3 + 17 files changed, 1137 insertions(+), 40 deletions(-) diff --git a/apps/server/src/git/GitManager.ts b/apps/server/src/git/GitManager.ts index 779273f0528eb..4082e7c346744 100644 --- a/apps/server/src/git/GitManager.ts +++ b/apps/server/src/git/GitManager.ts @@ -119,6 +119,16 @@ interface SourceControlTextGenerationSettings { readonly style: SourceControlWritingStyleSettings; } +export interface GitCreatePullRequestResult { + readonly status: "created" | "opened_existing"; + /** Absent when the host accepted the PR but did not list it back yet. */ + readonly url?: string; + readonly number?: number; + readonly baseBranch: string; + readonly headBranch: string; + readonly title: string; +} + export class GitManager extends Context.Service< GitManager, { @@ -168,6 +178,13 @@ export class GitManager extends Context.Service< input: GitRunStackedActionInput, options?: GitRunStackedActionOptions, ) => Effect.Effect; + /** Opens a PR for the checkout's pushed branch, or returns the one already open. */ + readonly createPullRequest: (input: { + readonly cwd: string; + readonly title: string; + readonly body: string; + readonly baseBranch?: string | undefined; + }) => Effect.Effect; readonly subscribePullRequestStateChanges: Effect.Effect< Stream.Stream, never, @@ -2342,12 +2359,17 @@ export const make = Effect.gen(function* () { }); }); - const runPrStep = Effect.fn("runPrStep")(function* ( - settings: SourceControlTextGenerationSettings, + const openPrFromBranch = Effect.fn("openPrFromBranch")(function* ( cwd: string, fallbackBranch: string | null, - threadId: ThreadId | undefined, emit: GitActionProgressEmitter, + requestedBase: string | undefined, + content: (input: { + readonly provider: SourceControlProvider.SourceControlProvider["Service"]; + readonly baseBranch: string; + readonly baseRef: string; + readonly headBranch: string; + }) => Effect.Effect<{ readonly title: string; readonly body: string }, E>, ) { const provider = yield* sourceControlProvider(cwd); const terms = sourceControlDefinitions.get(provider.kind).changeRequest; @@ -2385,42 +2407,14 @@ export const make = Effect.gen(function* () { }; } - const { baseBranch, baseRef } = yield* resolvePrBase( - cwd, - branch, - details.upstreamRef, - headContext, - ); - yield* emit({ - kind: "phase_started", - phase: "pr", - label: `Generating ${terms.shortLabel} content...`, - }); - const baseRangeRef = yield* resolveBaseRangeRef(cwd, baseRef); - const rangeContext = yield* gitCore.readRangeContext(cwd, baseRangeRef); - const policy = yield* resolveStylePolicy(cwd, settings); - const changeRequestTemplate = - settings.style.followChangeRequestTemplates && provider.readChangeRequestTemplate - ? Option.getOrUndefined( - yield* provider.readChangeRequestTemplate({ cwd, treeish: baseRangeRef }), - ) - : undefined; - const threadContext = yield* readThreadContext(threadId); - - const generated = yield* textGeneration.generatePrContent({ - cwd, + const resolved = yield* resolvePrBase(cwd, branch, details.upstreamRef, headContext); + const baseBranch = requestedBase ?? resolved.baseBranch; + const generated = yield* content({ + provider, baseBranch, + baseRef: requestedBase ?? resolved.baseRef, headBranch: headContext.headBranch, - commitSummary: limitContext(rangeContext.commitSummary, 20_000), - diffSummary: limitContext(rangeContext.diffSummary, 20_000), - diffPatch: limitContext(rangeContext.diffPatch, 60_000), - ...(changeRequestTemplate ? { changeRequestTemplate } : {}), - ...(threadContext ? { threadContext } : {}), - ...(policy ? { policy } : {}), - modelSelection: settings.modelSelection, - projectId: settings.projectId, }); - const bodyFile = path.join( tempDir, `t3code-pr-body-${process.pid}-${yield* randomUUIDv4(cwd)}.md`, @@ -2479,6 +2473,65 @@ export const make = Effect.gen(function* () { }; }); + const runPrStep = ( + settings: SourceControlTextGenerationSettings, + cwd: string, + fallbackBranch: string | null, + threadId: ThreadId | undefined, + emit: GitActionProgressEmitter, + ) => + openPrFromBranch( + cwd, + fallbackBranch, + emit, + undefined, + ({ provider, baseBranch, baseRef, headBranch }) => + Effect.gen(function* () { + const terms = sourceControlDefinitions.get(provider.kind).changeRequest; + yield* emit({ + kind: "phase_started", + phase: "pr", + label: `Generating ${terms.shortLabel} content...`, + }); + const baseRangeRef = yield* resolveBaseRangeRef(cwd, baseRef); + const rangeContext = yield* gitCore.readRangeContext(cwd, baseRangeRef); + const policy = yield* resolveStylePolicy(cwd, settings); + const changeRequestTemplate = + settings.style.followChangeRequestTemplates && provider.readChangeRequestTemplate + ? Option.getOrUndefined( + yield* provider.readChangeRequestTemplate({ cwd, treeish: baseRangeRef }), + ) + : undefined; + const threadContext = yield* readThreadContext(threadId); + + return yield* textGeneration.generatePrContent({ + cwd, + baseBranch, + headBranch, + commitSummary: limitContext(rangeContext.commitSummary, 20_000), + diffSummary: limitContext(rangeContext.diffSummary, 20_000), + diffPatch: limitContext(rangeContext.diffPatch, 60_000), + ...(changeRequestTemplate ? { changeRequestTemplate } : {}), + ...(threadContext ? { threadContext } : {}), + ...(policy ? { policy } : {}), + modelSelection: settings.modelSelection, + projectId: settings.projectId, + }); + }), + ); + + const createPullRequest: GitManager["Service"]["createPullRequest"] = Effect.fn( + "GitManager.createPullRequest", + )(function* (input) { + return yield* openPrFromBranch( + input.cwd, + null, + () => Effect.void, + input.baseBranch, + () => Effect.succeed({ title: input.title, body: input.body }), + ); + }); + const localStatus: GitManager["Service"]["localStatus"] = Effect.fn("localStatus")( function* (input) { const cacheKey = yield* normalizeStatusCacheKey(input.cwd); @@ -3575,6 +3628,7 @@ export const make = Effect.gen(function* () { resolvePullRequest, preparePullRequestThread, runStackedAction, + createPullRequest, subscribePullRequestStateChanges: PubSub.subscribe(pullRequestStateChanges).pipe( Effect.map((subscription) => Stream.fromSubscription(subscription)), ), diff --git a/apps/server/src/mcp/McpHttpServer.test.ts b/apps/server/src/mcp/McpHttpServer.test.ts index cdfeab7240a3c..6a67c1f450155 100644 --- a/apps/server/src/mcp/McpHttpServer.test.ts +++ b/apps/server/src/mcp/McpHttpServer.test.ts @@ -43,6 +43,7 @@ import * as Sqlite from "../persistence/Sqlite.ts"; import * as ManagedPolicy from "../policy/ManagedPolicy.ts"; import * as DeviceService from "../device/DeviceService.ts"; +import * as GitManager from "../git/GitManager.ts"; import * as PullRequestReviewGuideService from "../pullRequest/PullRequestReviewGuideService.ts"; import * as PullRequestService from "../pullRequest/PullRequestService.ts"; import * as ServerConfig from "../config.ts"; @@ -102,6 +103,7 @@ const layerPullRequestsTest = McpHttpServer.layerPullRequestsToolkit.pipe( Layer.mock(ProjectService.ProjectService)({}), Layer.mock(PullRequestReviewGuideService.PullRequestReviewGuideService)({}), Layer.mock(PullRequestService.PullRequestService)({}), + Layer.mock(GitManager.GitManager)({}), Layer.mock(Orchestrator.OrchestratorV2)({}), Layer.mock(ProjectionStore.ProjectionStoreV2)({}), NodeServices.layer, @@ -1546,6 +1548,7 @@ it.effect("lists pull request watch tools only to threads that are not delegated Layer.mock(ProjectService.ProjectService)({}), Layer.mock(PullRequestReviewGuideService.PullRequestReviewGuideService)({}), Layer.mock(PullRequestService.PullRequestService)({}), + Layer.mock(GitManager.GitManager)({}), Layer.mock(Orchestrator.OrchestratorV2)({}), Layer.mock(ProjectionStore.ProjectionStoreV2)({}), NodeServices.layer, diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts index d6c746440a60a..24f24054ed303 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts @@ -6,6 +6,9 @@ import { type OrchestrationV2ServerCommand as OrchestrationCommand, PullRequestOperationError, type OrchestrationProjectShell, + type PullRequestActionInput, + type PullRequestActivity, + type PullRequestDetail, type PullRequestRef, type PullRequestReviewGuideResult, type ThreadPullRequestLink, @@ -20,6 +23,7 @@ import * as Ref from "effect/Ref"; import * as Stream from "effect/Stream"; import type { Tool } from "effect/ai"; +import * as GitManager from "../../../git/GitManager.ts"; import * as Orchestrator from "../../../orchestration-v2/Orchestrator.ts"; import { type PullRequestTestThread, @@ -28,6 +32,7 @@ import { import * as ProjectService from "../../../project/ProjectService.ts"; import * as PullRequestWatchService from "../../../pullRequest/PullRequestWatchService.ts"; import * as PullRequestReviewGuideService from "../../../pullRequest/PullRequestReviewGuideService.ts"; +import * as PullRequestService from "../../../pullRequest/PullRequestService.ts"; import * as McpInvocationContext from "../../McpInvocationContext.ts"; import * as McpToolAccess from "../../McpToolAccess.ts"; import * as McpToolAccessTestkit from "../../McpToolAccess.testkit.ts"; @@ -144,6 +149,8 @@ interface HarnessOptions { PullRequestReviewGuideResult & { started: boolean }, PullRequestOperationError >; + readonly pullRequests?: Partial; + readonly git?: Partial; } const NO_GUIDE: PullRequestReviewGuideResult = { guide: null, run: null, currentHeadSha: "head-1" }; @@ -196,6 +203,8 @@ const makeHarness = Effect.fn("makePullRequestsToolkitHarness")(function* ( Effect.succeed(id === thread?.id ? v2PullRequestThread(thread) : null), dispatch, }), + Layer.mock(PullRequestService.PullRequestService)(options.pullRequests ?? {}), + Layer.mock(GitManager.GitManager)(options.git ?? {}), Layer.succeed(SecureRandom.SecureRandom, testCrypto), McpToolAccessTestkit.liveThreadsLayer, ); @@ -700,3 +709,169 @@ describe("pull request guide tools", () => { }), ); }); + +describe("source control tools", () => { + const branchThread = { + ...makeThread([]), + worktreePath: "/workspace/worktree", + branchPullRequest: { + projectId: PROJECT_ID, + repository: "t3tools/t3code", + number: 42, + url: "https://github.com/t3tools/t3code/pull/42", + }, + }; + const detail = { + title: "Add tools", + body: "Adds tools.", + state: "open", + isDraft: false, + author: null, + headBranch: "tools", + baseBranch: "main", + headSha: "abc123", + mergeability: "mergeable", + additions: 1, + deletions: 0, + changedFiles: 1, + labels: [], + reviewers: [], + checks: [{ name: "CI", status: "success", description: null, url: null }], + } as unknown as PullRequestDetail; + const reviewThread = (id: string, isResolved: boolean) => ({ + id, + path: "a.ts", + line: 1, + side: "right" as const, + isResolved, + isOutdated: false, + comments: [], + }); + const activity: PullRequestActivity = { + comments: [], + commentCount: 0, + commentsTruncated: false, + reviewThreads: [reviewThread("open-thread", false), reviewThread("done-thread", true)], + commits: [], + }; + + it.effect("reads the thread's branch PR, only the sections asked, without resolved threads", () => + Effect.gen(function* () { + const asked: Array = []; + const harness = yield* makeHarness({ + thread: branchThread, + pullRequests: { + detail: (ref) => Effect.sync(() => asked.push(ref)).pipe(Effect.as(detail)), + activity: () => Effect.succeed(activity), + }, + }); + const result = yield* harness.call("pull_request_read", { + sections: ["summary", "conversation"], + }); + expect(asked).toEqual([ + { projectId: PROJECT_ID, host: "github.com", repository: "t3tools/t3code", number: 42 }, + ]); + expect(result.summary?.headSha).toBe("abc123"); + expect(result.checks).toBeUndefined(); + expect(result.conversation?.reviewThreads.map((thread) => thread.id)).toEqual([ + "open-thread", + ]); + expect(result.conversation?.hiddenResolvedThreads).toBe(1); + }), + ); + + it.effect("asks for a number when the thread's branch has no PR", () => + Effect.gen(function* () { + const harness = yield* makeHarness(); + const error = yield* harness.call("pull_request_read", {}).pipe(Effect.flip); + expect(error._tag).toBe("PullRequestBranchHasNoneError"); + }), + ); + + it.effect("merges pinned to the head the agent checked", () => + Effect.gen(function* () { + const actions: Array = []; + const harness = yield* makeHarness({ + thread: branchThread, + pullRequests: { + runAction: (input) => Effect.sync(() => void actions.push(input)), + summary: () => Effect.succeed({ state: "open" } as never), + }, + }); + const result = yield* harness.call("pull_request_merge", { + expectedHeadSha: "abc123", + method: "squash", + auto: true, + }); + expect(result).toMatchObject({ number: 42, state: "open" }); + expect(actions).toMatchObject([ + { + number: 42, + action: "enable-auto-merge", + expectedHeadSha: "abc123", + mergeMethod: "squash", + }, + ]); + }), + ); + + it.effect("opens a PR from the thread's worktree, links it, and makes it a draft", () => + Effect.gen(function* () { + const actions: Array = []; + const opened: Array = []; + const harness = yield* makeHarness({ + thread: { ...makeThread([]), worktreePath: "/workspace/worktree" }, + git: { + createPullRequest: (input) => + Effect.sync(() => opened.push(input.cwd)).pipe( + Effect.as({ + status: "created" as const, + url: "https://github.com/t3tools/t3code/pull/43", + number: 43, + baseBranch: "main", + headBranch: "tools", + title: input.title, + }), + ), + }, + pullRequests: { runAction: (input) => Effect.sync(() => void actions.push(input)) }, + }); + const result = yield* harness.call("pull_request_create", { + title: "Add tools", + body: "Adds tools.", + draft: true, + }); + expect(result).toMatchObject({ number: 43, created: true }); + expect(opened).toEqual(["/workspace/worktree"]); + expect(actions).toMatchObject([{ number: 43, action: "draft" }]); + expect(yield* Ref.get(harness.commands)).toMatchObject([ + { type: "thread.pull-request.link", number: 43, source: "created" }, + ]); + }), + ); + + it.effect("replies to and resolves a review thread, and refuses resolving without one", () => + Effect.gen(function* () { + const calls: Array = []; + const harness = yield* makeHarness({ + thread: branchThread, + pullRequests: { + replyToThread: (input) => Effect.sync(() => calls.push(`reply ${input.threadId}`)), + setThreadResolution: (input) => + Effect.sync(() => calls.push(`resolve ${input.threadId} ${input.resolved}`)), + }, + }); + const result = yield* harness.call("pull_request_respond", { + reviewThreadId: "open-thread", + body: "Fixed.", + resolved: true, + }); + expect(result).toMatchObject({ replied: true, resolved: true }); + expect(calls).toEqual(["reply open-thread", "resolve open-thread true"]); + const error = yield* harness + .call("pull_request_respond", { body: "Done", resolved: true }) + .pipe(Effect.flip); + expect(error._tag).toBe("PullRequestNothingToDoError"); + }), + ); +}); diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts index 8983b8e62652d..49eabd51d64f5 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts @@ -1,5 +1,6 @@ import { CommandId, + type PullRequestRef, type OrchestrationProjectShell, type OrchestrationV2ThreadShell, type ThreadId, @@ -10,11 +11,13 @@ import * as SecureRandom from "effect/crypto/SecureRandom"; import * as Effect from "effect/Effect"; import * as Option from "effect/Option"; +import * as GitManager from "../../../git/GitManager.ts"; import * as Orchestrator from "../../../orchestration-v2/Orchestrator.ts"; import * as ProjectService from "../../../project/ProjectService.ts"; import * as PullRequestWatchService from "../../../pullRequest/PullRequestWatchService.ts"; import { resolveTarget, type ResolvedTarget } from "../../../pullRequest/pullRequestTarget.ts"; import * as PullRequestReviewGuideService from "../../../pullRequest/PullRequestReviewGuideService.ts"; +import * as PullRequestService from "../../../pullRequest/PullRequestService.ts"; import { pullRequestSyncKey } from "../../../pullRequest/pullRequestSyncKey.ts"; import { sourceControlDefinitions } from "../../../sourceControl/sourceControlDefinitions.ts"; import { @@ -30,6 +33,12 @@ import * as McpToolAccess from "../../McpToolAccess.ts"; import { threadNotFound } from "../../threadAccess.ts"; import { type ListThreadPullRequestsResult, + PullRequestBranchHasNoneError, + PullRequestForgeError, + PullRequestNothingToDoError, + type PullRequestReadSection, + type ReadPullRequestResult, + type ThreadPullRequestInput, PullRequestLinkFailedError, PullRequestUnlinkFailedError, PullRequestListFailedError, @@ -125,6 +134,8 @@ const make = Effect.gen(function* () { const engine = yield* Orchestrator.OrchestratorV2; const reviewGuides = yield* PullRequestReviewGuideService.PullRequestReviewGuideService; const watches = yield* PullRequestWatchService.PullRequestWatchService; + const pullRequests = yield* PullRequestService.PullRequestService; + const git = yield* GitManager.GitManager; const projects = yield* ProjectService.ProjectService; const random = yield* SecureRandom.SecureRandom; @@ -139,7 +150,8 @@ const make = Effect.gen(function* () { Failure: | typeof PullRequestLinkFailedError | typeof PullRequestUnlinkFailedError - | typeof PullRequestListFailedError, + | typeof PullRequestListFailedError + | typeof PullRequestForgeError, requested: ThreadId | undefined, ) { const scope = yield* McpInvocationContext.requireMcpCapability("pull-requests"); @@ -159,7 +171,10 @@ const make = Effect.gen(function* () { const projectOf = ( thread: OrchestrationV2ThreadShell, - Failure: typeof PullRequestLinkFailedError | typeof PullRequestUnlinkFailedError, + Failure: + | typeof PullRequestLinkFailedError + | typeof PullRequestUnlinkFailedError + | typeof PullRequestForgeError, ) => projects.getShell(thread.projectId).pipe( Effect.map(Option.getOrUndefined), @@ -248,6 +263,159 @@ const make = Effect.gen(function* () { handle: (params: P) => Effect.Effect, ) => McpToolAccess.writesThreads((params: P) => [params.threadId], handle); + const forgeFailure = (error: { readonly message: string }) => + new PullRequestForgeError({ detail: error.message, cause: error }); + + /** The thread's checkout, its project, and the PR the input names (default: the branch's). */ + const locate = Effect.fn("PullRequestsToolkit.locate")(function* (input: ThreadPullRequestInput) { + const thread = yield* requireThread(PullRequestForgeError, undefined); + const project = yield* projectOf(thread, PullRequestForgeError); + if (project === undefined) { + return yield* new PullRequestProjectNotFoundError({ repository: input.repository ?? "" }); + } + const branchPullRequest = thread.branchPullRequest ?? null; + const branchRepository = + project.repositoryIdentity == null + ? undefined + : (sourceControlDefinitions.repositorySelector(project.repositoryIdentity) ?? undefined); + const named = + input.number !== undefined + ? { number: input.number, repository: input.repository ?? branchRepository } + : branchPullRequest === null + ? null + : { number: branchPullRequest.number, repository: branchPullRequest.repository }; + if (named === null) return yield* new PullRequestBranchHasNoneError(); + const target = yield* resolveTarget(named, project); + const ref: PullRequestRef = { + projectId: project.id, + host: target.host, + repository: target.repository, + number: target.number, + }; + return { thread, project, target, ref }; + }); + + const identityOf = (target: ResolvedTarget) => ({ + host: target.host, + repository: target.repository, + number: target.number, + url: target.url, + }); + + const readSections = Effect.fn("PullRequestsToolkit.readSections")(function* ( + ref: PullRequestRef, + sections: ReadonlyArray, + includeResolved: boolean, + diffCursor: string | undefined, + ) { + const wants = (section: PullRequestReadSection) => sections.includes(section); + const [detail, activity, diff] = yield* Effect.all( + [ + wants("summary") || wants("checks") + ? pullRequests.detail(ref).pipe(Effect.asSome) + : Effect.succeedNone, + wants("conversation") ? pullRequests.activity(ref).pipe(Effect.asSome) : Effect.succeedNone, + wants("diff") + ? pullRequests + .diff({ ...ref, ...(diffCursor === undefined ? {} : { cursor: diffCursor }) }) + .pipe(Effect.asSome) + : Effect.succeedNone, + ], + { concurrency: "unbounded" }, + ).pipe(Effect.mapError(forgeFailure)); + const result: Omit = { + ...(Option.isSome(detail) && wants("summary") + ? { + summary: { + title: detail.value.title, + body: detail.value.body, + state: detail.value.state, + isDraft: detail.value.isDraft, + author: detail.value.author?.login ?? null, + headBranch: detail.value.headBranch, + baseBranch: detail.value.baseBranch, + headSha: detail.value.headSha ?? null, + mergeability: detail.value.mergeability, + behindBy: detail.value.behindBy ?? null, + autoMergeEnabled: detail.value.autoMergeEnabled ?? null, + additions: detail.value.additions, + deletions: detail.value.deletions, + changedFiles: detail.value.changedFiles, + labels: detail.value.labels.map((label) => label.name), + reviewers: detail.value.reviewers.map((reviewer) => reviewer.login), + }, + } + : {}), + ...(Option.isSome(detail) && wants("checks") ? { checks: detail.value.checks } : {}), + ...(Option.isSome(activity) + ? { + conversation: { + comments: activity.value.comments.map((comment) => ({ + id: comment.id, + kind: comment.kind, + author: comment.author?.login ?? null, + body: comment.body, + createdAt: comment.createdAt, + path: comment.path, + reviewState: comment.reviewState, + })), + reviewThreads: activity.value.reviewThreads + .filter((thread) => includeResolved || !thread.isResolved) + .map((thread) => ({ + id: thread.id, + path: thread.path, + line: thread.line, + isResolved: thread.isResolved, + isOutdated: thread.isOutdated, + comments: thread.comments.map((comment) => ({ + author: comment.author?.login ?? null, + body: comment.body, + createdAt: comment.createdAt, + })), + moreComments: thread.nextCommentsCursor !== undefined, + })), + hiddenResolvedThreads: includeResolved + ? 0 + : activity.value.reviewThreads.filter((thread) => thread.isResolved).length, + truncated: + activity.value.commentsTruncated || activity.value.reviewThreadsTruncated === true, + }, + } + : {}), + ...(Option.isSome(diff) + ? { + diff: { + patch: diff.value.patch, + truncated: diff.value.truncated, + nextCursor: diff.value.nextCursor, + }, + } + : {}), + }; + return result; + }); + + const linkToThread = Effect.fn("PullRequestsToolkit.linkToThread")(function* ( + thread: OrchestrationV2ThreadShell, + target: ResolvedTarget, + ) { + if (threadPullRequestsOf(thread).some((link) => threadPullRequestKeysEqual(link, target))) { + return; + } + yield* engine + .dispatch({ + type: "thread.pull-request.link", + commandId: yield* commandId("mcp-pr-create", thread.id), + threadId: thread.id, + host: target.host, + repository: target.repository, + number: target.number, + url: target.url, + source: "created", + }) + .pipe(Effect.catchCause(dispatchFailure(PullRequestLinkFailedError))); + }); + return { link_pull_request: writesThread((input) => Effect.gen(function* () { @@ -499,6 +667,169 @@ const make = Effect.gen(function* () { }; }), ), + pull_request_read: McpToolAccess.reads((input) => + Effect.gen(function* () { + const { target, ref } = yield* locate(input); + const sections = input.sections ?? ["summary", "checks"]; + return { + ...identityOf(target), + ...(yield* readSections(ref, sections, input.includeResolved === true, input.diffCursor)), + }; + }), + ), + pull_request_list: McpToolAccess.reads((input) => + Effect.gen(function* () { + const thread = yield* requireThread(PullRequestForgeError, undefined); + const listed = yield* pullRequests + .list({ + projectId: thread.projectId, + state: input.state ?? "open", + involvement: input.involvement ?? "all", + limit: input.limit ?? 30, + ...(input.query === undefined ? {} : { query: input.query }), + }) + .pipe(Effect.mapError(forgeFailure)); + const failure = listed.errors[0]; + if (listed.entries.length === 0 && failure !== undefined) { + return yield* new PullRequestForgeError({ detail: failure.message }); + } + return { + pullRequests: listed.entries.map((entry) => ({ + number: entry.number, + title: entry.title, + url: entry.url, + author: entry.author?.login ?? null, + headBranch: entry.headBranch, + baseBranch: entry.baseBranch, + state: entry.state, + isDraft: entry.isDraft, + reviewDecision: entry.reviewDecision ?? null, + checksState: entry.checksState ?? null, + updatedAt: entry.updatedAt, + })), + truncated: listed.truncated, + }; + }), + ), + pull_request_create: McpToolAccess.writesWithCapability((input) => + Effect.gen(function* () { + const thread = yield* requireThread(PullRequestForgeError, undefined); + const project = yield* projectOf(thread, PullRequestForgeError); + if (project === undefined) { + return yield* new PullRequestProjectNotFoundError({ repository: "" }); + } + const created = yield* git + .createPullRequest({ + cwd: thread.worktreePath ?? project.workspaceRoot, + title: input.title, + body: input.body, + baseBranch: input.base, + }) + .pipe(Effect.mapError(forgeFailure)); + if (created.url === undefined) { + return yield* new PullRequestForgeError({ + detail: + "The host accepted the PR but does not list it yet. Find it with pull_request_list.", + }); + } + const target = yield* resolveTarget({ url: created.url }, project); + yield* linkToThread(thread, target); + if (input.draft === true && created.status === "created") { + yield* pullRequests + .runAction({ + projectId: project.id, + host: target.host, + repository: target.repository, + number: target.number, + action: "draft", + }) + .pipe(Effect.mapError(forgeFailure)); + } + return { + ...identityOf(target), + created: created.status === "created", + ...(thread.lineage.relationshipToParent === "subagent" + ? { next: CHILD_PULL_REQUEST_REPORT_NEXT } + : {}), + }; + }), + ), + pull_request_update: McpToolAccess.writesWithCapability((input) => + Effect.gen(function* () { + if (input.title === undefined && input.body === undefined && input.ready === undefined) { + return yield* new PullRequestNothingToDoError({ detail: "Pass title, body, or ready." }); + } + const { target, ref } = yield* locate(input); + if (input.title !== undefined || input.body !== undefined) { + yield* pullRequests + .update({ + ...ref, + ...(input.title === undefined ? {} : { title: input.title }), + ...(input.body === undefined ? {} : { body: input.body }), + }) + .pipe(Effect.mapError(forgeFailure)); + } + if (input.ready !== undefined) { + yield* pullRequests + .runAction({ ...ref, action: input.ready ? "ready" : "draft" }) + .pipe(Effect.mapError(forgeFailure)); + } + return identityOf(target); + }), + ), + pull_request_respond: McpToolAccess.writesWithCapability((input) => + Effect.gen(function* () { + if ( + input.body === undefined && + (input.reviewThreadId === undefined || input.resolved === undefined) + ) { + return yield* new PullRequestNothingToDoError({ + detail: "Pass body, or reviewThreadId with resolved.", + }); + } + if (input.reviewThreadId === undefined && input.resolved !== undefined) { + return yield* new PullRequestNothingToDoError({ + detail: "resolved needs reviewThreadId.", + }); + } + const { target, ref } = yield* locate(input); + const reviewThreadId = input.reviewThreadId; + if (input.body !== undefined) { + yield* ( + reviewThreadId === undefined + ? pullRequests.comment({ ...ref, body: input.body }) + : pullRequests.replyToThread({ ...ref, threadId: reviewThreadId, body: input.body }) + ).pipe(Effect.mapError(forgeFailure)); + } + if (reviewThreadId !== undefined && input.resolved !== undefined) { + yield* pullRequests + .setThreadResolution({ ...ref, threadId: reviewThreadId, resolved: input.resolved }) + .pipe(Effect.mapError(forgeFailure)); + } + return { + ...identityOf(target), + replied: input.body !== undefined, + resolved: input.resolved ?? null, + }; + }), + ), + pull_request_merge: McpToolAccess.writesWithCapability((input) => + Effect.gen(function* () { + const { target, ref } = yield* locate(input); + yield* pullRequests + .runAction({ + ...ref, + action: input.auto === true ? "enable-auto-merge" : "merge", + expectedHeadSha: input.expectedHeadSha, + ...(input.method === undefined ? {} : { mergeMethod: input.method }), + }) + .pipe(Effect.mapError(forgeFailure)); + const after = yield* pullRequests + .summary({ ...ref, allowStale: false }) + .pipe(Effect.mapError(forgeFailure)); + return { ...identityOf(target), state: after.state }; + }), + ), } satisfies McpToolAccess.Handlers; }); diff --git a/apps/server/src/mcp/toolkits/pullRequests/tools.ts b/apps/server/src/mcp/toolkits/pullRequests/tools.ts index fe8959b2d22d3..fd5bb0108bb0f 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/tools.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/tools.ts @@ -3,6 +3,14 @@ import { OrchestratorMcpEnvironmentTarget, OrchestratorMcpFailure, PositiveInt, + PullRequestCheck, + PullRequestCommentKind, + PullRequestChecksState, + PullRequestInvolvement, + PullRequestListState, + PullRequestMergeability, + PullRequestMergeMethod, + PullRequestReviewDecision, PullRequestReviewGuide, PullRequestReviewGuideRun, PullRequestState, @@ -19,6 +27,7 @@ import * as Toolkit from "effect/ai/Toolkit"; import * as McpInvocationContext from "../../McpInvocationContext.ts"; import * as Orchestrator from "../../../orchestration-v2/Orchestrator.ts"; import * as ThreadManagementService from "../../../orchestration-v2/ThreadManagementService.ts"; +import * as GitManager from "../../../git/GitManager.ts"; import * as ProjectService from "../../../project/ProjectService.ts"; import * as PullRequestWatchService from "../../../pullRequest/PullRequestWatchService.ts"; import { @@ -27,6 +36,7 @@ import { PullRequestHostRequiredError, PullRequestUrlUnavailableError, } from "../../../pullRequest/pullRequestTarget.ts"; +import * as PullRequestService from "../../../pullRequest/PullRequestService.ts"; import * as PullRequestReviewGuideService from "../../../pullRequest/PullRequestReviewGuideService.ts"; const dependencies = [ @@ -36,6 +46,8 @@ const dependencies = [ ProjectService.ProjectService, ]; +const forgeDependencies = [...dependencies, PullRequestService.PullRequestService]; + const guideDependencies = [ ...dependencies, PullRequestReviewGuideService.PullRequestReviewGuideService, @@ -123,6 +135,33 @@ export class PullRequestGuideFailedError extends Schema.TaggedError()( + "PullRequestForgeError", + { detail: Schema.optional(Schema.String), cause: Schema.optional(Schema.Defect()) }, +) { + override get message(): string { + return this.detail ?? "Could not read this thread's project."; + } +} + +export class PullRequestBranchHasNoneError extends Schema.TaggedError()( + "PullRequestBranchHasNoneError", + {}, +) { + override get message(): string { + return "This thread's branch has no known PR. Pass number, or open one with pull_request_create."; + } +} + +export class PullRequestNothingToDoError extends Schema.TaggedError()( + "PullRequestNothingToDoError", + { detail: Schema.String }, +) { + override get message(): string { + return this.detail; + } +} + export const PullRequestToolError = Schema.Union([ OrchestratorMcpFailure, McpCapabilityUnavailableError, @@ -140,6 +179,9 @@ export const PullRequestToolError = Schema.Union([ PullRequestWatchService.PullRequestWatchFromSubagentError, PullRequestProjectNotFoundError, PullRequestGuideFailedError, + PullRequestForgeError, + PullRequestBranchHasNoneError, + PullRequestNothingToDoError, ]); export type PullRequestToolError = typeof PullRequestToolError.Type; @@ -414,6 +456,250 @@ const ReadPullRequestGuideTool = Tool.make("read_pull_request_guide", { .annotate(Tool.Idempotent, true) .annotate(Tool.OpenWorld, true); +export const ThreadPullRequestInput = Schema.Struct({ + environmentId: OrchestratorMcpEnvironmentTarget, + number: Schema.optional(PositiveInt.annotate({ description: "Default: the branch's PR." })), + repository: Schema.optional(TrimmedNonEmptyString), +}); +export type ThreadPullRequestInput = typeof ThreadPullRequestInput.Type; + +export const PullRequestReadSection = Schema.Literals([ + "summary", + "checks", + "conversation", + "diff", +]); +export type PullRequestReadSection = typeof PullRequestReadSection.Type; + +const ReadComment = Schema.Struct({ + author: Schema.NullOr(Schema.String), + body: Schema.String, + createdAt: Schema.String, +}); + +export const ReadPullRequestResult = Schema.Struct({ + ...PullRequestIdentity, + summary: Schema.optional( + Schema.Struct({ + title: Schema.String, + body: Schema.String, + state: PullRequestState, + isDraft: Schema.Boolean, + author: Schema.NullOr(Schema.String), + headBranch: Schema.String, + baseBranch: Schema.String, + headSha: Schema.NullOr(Schema.String), + mergeability: PullRequestMergeability, + behindBy: Schema.NullOr(Schema.Int), + autoMergeEnabled: Schema.NullOr(Schema.Boolean), + additions: Schema.Int, + deletions: Schema.Int, + changedFiles: Schema.Int, + labels: Schema.Array(Schema.String), + reviewers: Schema.Array(Schema.String), + }), + ), + checks: Schema.optional(Schema.Array(PullRequestCheck)), + conversation: Schema.optional( + Schema.Struct({ + comments: Schema.Array( + Schema.Struct({ + ...ReadComment.fields, + id: Schema.String, + kind: PullRequestCommentKind, + path: Schema.NullOr(Schema.String), + reviewState: Schema.NullOr(Schema.String), + }), + ), + reviewThreads: Schema.Array( + Schema.Struct({ + id: Schema.String, + path: Schema.String, + line: Schema.NullOr(Schema.Int), + isResolved: Schema.Boolean, + isOutdated: Schema.Boolean, + comments: Schema.Array(ReadComment), + moreComments: Schema.Boolean, + }), + ), + hiddenResolvedThreads: Schema.Int, + truncated: Schema.Boolean, + }), + ), + diff: Schema.optional( + Schema.Struct({ + patch: Schema.String, + truncated: Schema.Boolean, + nextCursor: Schema.NullOr(Schema.String), + }), + ), +}); +export type ReadPullRequestResult = typeof ReadPullRequestResult.Type; + +export const ListPullRequestsResult = Schema.Struct({ + pullRequests: Schema.Array( + Schema.Struct({ + number: Schema.Int, + title: Schema.String, + url: Schema.String, + author: Schema.NullOr(Schema.String), + headBranch: Schema.String, + baseBranch: Schema.String, + state: PullRequestState, + isDraft: Schema.Boolean, + reviewDecision: Schema.NullOr(PullRequestReviewDecision), + checksState: Schema.NullOr(PullRequestChecksState), + updatedAt: Schema.String, + }), + ), + truncated: Schema.Boolean, +}); +export type ListPullRequestsResult = typeof ListPullRequestsResult.Type; + +export const CreatePullRequestResult = Schema.Struct({ + ...PullRequestIdentity, + created: Schema.Boolean.annotate({ + description: "False when the branch already had an open PR.", + }), + next: Schema.optional(Schema.String), +}); +export type CreatePullRequestResult = typeof CreatePullRequestResult.Type; + +export const RespondToPullRequestResult = Schema.Struct({ + ...PullRequestIdentity, + replied: Schema.Boolean, + resolved: Schema.NullOr(Schema.Boolean), +}); +export type RespondToPullRequestResult = typeof RespondToPullRequestResult.Type; + +export const MergePullRequestResult = Schema.Struct({ + ...PullRequestIdentity, + state: PullRequestState.annotate({ + description: "open while auto-merge or a merge queue waits for checks.", + }), +}); +export type MergePullRequestResult = typeof MergePullRequestResult.Type; + +const ReadPullRequestTool = Tool.make("pull_request_read", { + description: + "Read a PR in this thread's repository. Use instead of gh or cafe for PR state, checks, review comments, or diff.", + parameters: Schema.Struct({ + ...ThreadPullRequestInput.fields, + sections: Schema.optional( + Schema.Array(PullRequestReadSection).annotate({ + description: "Default: summary, checks. conversation: comments, review threads.", + }), + ), + includeResolved: Schema.optional(Schema.Boolean), + diffCursor: Schema.optional(TrimmedNonEmptyString), + }), + success: ReadPullRequestResult, + failure: PullRequestToolError, + dependencies: forgeDependencies, +}) + .annotate(Tool.Title, "Read pull request") + .annotate(Tool.Readonly, true) + .annotate(Tool.Destructive, false) + .annotate(Tool.Idempotent, true) + .annotate(Tool.OpenWorld, true); + +const ListPullRequestsTool = Tool.make("pull_request_list", { + description: "List PRs in this thread's repository, recently updated first.", + parameters: Schema.Struct({ + environmentId: OrchestratorMcpEnvironmentTarget, + state: Schema.optional(PullRequestListState.annotate({ description: "Default: open." })), + involvement: Schema.optional(PullRequestInvolvement), + query: Schema.optional(TrimmedNonEmptyString.check(Schema.isMaxLength(200))), + limit: Schema.optional(Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 100 }))), + }), + success: ListPullRequestsResult, + failure: PullRequestToolError, + dependencies: forgeDependencies, +}) + .annotate(Tool.Title, "List pull requests") + .annotate(Tool.Readonly, true) + .annotate(Tool.Destructive, false) + .annotate(Tool.Idempotent, true) + .annotate(Tool.OpenWorld, true); + +const CreatePullRequestTool = Tool.make("pull_request_create", { + description: + "Open a PR from this thread's pushed branch and link it. Returns the branch's open PR if one exists.", + parameters: Schema.Struct({ + environmentId: OrchestratorMcpEnvironmentTarget, + title: TrimmedNonEmptyString, + body: Schema.String, + base: Schema.optional(TrimmedNonEmptyString), + draft: Schema.optional(Schema.Boolean), + }), + success: CreatePullRequestResult, + failure: PullRequestToolError, + dependencies: [...forgeDependencies, GitManager.GitManager], +}) + .annotate(Tool.Title, "Create pull request") + .annotate(Tool.Readonly, false) + .annotate(Tool.Destructive, false) + .annotate(Tool.Idempotent, true) + .annotate(Tool.OpenWorld, true); + +const UpdatePullRequestTool = Tool.make("pull_request_update", { + description: "Change a PR's title or body, or mark it ready (ready=false: back to draft).", + parameters: Schema.Struct({ + ...ThreadPullRequestInput.fields, + title: Schema.optional(TrimmedNonEmptyString), + body: Schema.optional(Schema.String), + ready: Schema.optional(Schema.Boolean), + }), + success: Schema.Struct(PullRequestIdentity), + failure: PullRequestToolError, + dependencies: forgeDependencies, +}) + .annotate(Tool.Title, "Update pull request") + .annotate(Tool.Readonly, false) + .annotate(Tool.Destructive, false) + .annotate(Tool.Idempotent, true) + .annotate(Tool.OpenWorld, true); + +const RespondToPullRequestTool = Tool.make("pull_request_respond", { + description: + "Reply to a review thread from pull_request_read, resolve or reopen it, or both. Without reviewThreadId, comment on the PR.", + parameters: Schema.Struct({ + ...ThreadPullRequestInput.fields, + reviewThreadId: Schema.optional(TrimmedNonEmptyString), + body: Schema.optional(TrimmedNonEmptyString), + resolved: Schema.optional(Schema.Boolean), + }), + success: RespondToPullRequestResult, + failure: PullRequestToolError, + dependencies: forgeDependencies, +}) + .annotate(Tool.Title, "Respond on pull request") + .annotate(Tool.Readonly, false) + .annotate(Tool.Destructive, false) + .annotate(Tool.Idempotent, false) + .annotate(Tool.OpenWorld, true); + +const MergePullRequestTool = Tool.make("pull_request_merge", { + description: + "Merge a PR only when asked to land it. Refuses if the head is no longer expectedHeadSha, the summary headSha you checked.", + parameters: Schema.Struct({ + ...ThreadPullRequestInput.fields, + expectedHeadSha: TrimmedNonEmptyString, + method: Schema.optional(PullRequestMergeMethod), + auto: Schema.optional( + Schema.Boolean.annotate({ description: "Merge once required checks pass." }), + ), + }), + success: MergePullRequestResult, + failure: PullRequestToolError, + dependencies: forgeDependencies, +}) + .annotate(Tool.Title, "Merge pull request") + .annotate(Tool.Readonly, false) + .annotate(Tool.Destructive, true) + .annotate(Tool.Idempotent, false) + .annotate(Tool.OpenWorld, true); + export const PullRequestsToolkit = Toolkit.make( LinkPullRequestTool, LinkPullRequestsTool, @@ -424,4 +710,10 @@ export const PullRequestsToolkit = Toolkit.make( UnwatchPullRequestTool, WritePullRequestGuidesTool, ReadPullRequestGuideTool, + ReadPullRequestTool, + ListPullRequestsTool, + CreatePullRequestTool, + UpdatePullRequestTool, + RespondToPullRequestTool, + MergePullRequestTool, ); diff --git a/apps/server/src/provider/AgentContextBudget.test.ts b/apps/server/src/provider/AgentContextBudget.test.ts index 7e380189ee6cd..0af6f33552a37 100644 --- a/apps/server/src/provider/AgentContextBudget.test.ts +++ b/apps/server/src/provider/AgentContextBudget.test.ts @@ -12,6 +12,7 @@ import { ServerSecretStore } from "../auth/ServerSecretStore.ts"; import { ServerConfig } from "../config.ts"; import { DeviceService } from "../device/DeviceService.ts"; import { ServerEnvironment } from "../environment/ServerEnvironment.ts"; +import { GitManager } from "../git/GitManager.ts"; import { GitWorkflowService } from "../git/GitWorkflowService.ts"; import * as McpHttpServer from "../mcp/McpHttpServer.ts"; import { PreviewAutomationBroker } from "../mcp/PreviewAutomationBroker.ts"; @@ -70,6 +71,7 @@ const toolHandlerServices = Layer.mergeAll( Layer.mock(ProviderRegistry)({}), Layer.mock(PullRequestReviewGuideService)({}), Layer.mock(PullRequestService)({}), + Layer.mock(GitManager)({}), Layer.mock(RemoteDelegation)({}), Layer.mock(ScheduledTaskService)({}), Layer.mock(SecretRequests)({}), diff --git a/apps/server/src/pullRequest/PullRequestService.test.ts b/apps/server/src/pullRequest/PullRequestService.test.ts index 7e40e43b55e0d..d99432db0fd88 100644 --- a/apps/server/src/pullRequest/PullRequestService.test.ts +++ b/apps/server/src/pullRequest/PullRequestService.test.ts @@ -1428,6 +1428,30 @@ it.effect( }), ); +it.effect("refuses a merge whose head moved past expectedHeadSha and pins the host merge", () => + Effect.gen(function* () { + const pinned: Array = []; + const service = yield* makeService({ + projects: [project({ id: "p1", title: "web", workspaceRoot: "/a", repository: "acme/web" })], + providers: [ + fakePullRequestProvider(SourceControlProviderKind.make("github"), { + getChangeRequest: () => + Effect.succeed({ ...hostedChangeRequest("Body"), headSha: "new-head" }), + getChangeRequestSummary: () => Effect.succeed(changeRequest(1, "2026-09-03T00:00:00Z")), + runAction: (input) => Effect.sync(() => void pinned.push(input.expectedHeadSha)), + }), + ], + }); + const reference = { projectId: "p1" as ProjectId, repository: "acme/web", number: 1 }; + const refused = yield* Effect.flip( + service.runAction({ ...reference, action: "merge", expectedHeadSha: "reviewed-head" }), + ); + assert.include(refused.message, "new-head"); + yield* service.runAction({ ...reference, action: "merge", expectedHeadSha: "new-head" }); + assert.deepStrictEqual(pinned, ["new-head"]); + }), +); + it.effect("publishes a merge for immediate settlement only after host confirmation", () => Effect.scoped( Effect.gen(function* () { diff --git a/apps/server/src/pullRequest/PullRequestService.ts b/apps/server/src/pullRequest/PullRequestService.ts index 943fdc55d1d50..14e4e42106564 100644 --- a/apps/server/src/pullRequest/PullRequestService.ts +++ b/apps/server/src/pullRequest/PullRequestService.ts @@ -2197,7 +2197,32 @@ export const make = Effect.gen(function* () { ), ) : Effect.succeed(false); - return mergeSettings.pipe( + // Hosts that cannot pin a merge to a commit still refuse a head that already moved. + const headPinned = + input.expectedHeadSha === undefined + ? Effect.void + : project.api + .getChangeRequest({ + cwd: project.project.workspaceRoot, + repository: project.repository, + host: project.host, + number: input.number, + }) + .pipe( + Effect.mapError(toPullRequestError("runAction")), + Effect.flatMap((current) => + current.headSha === input.expectedHeadSha + ? Effect.void + : Effect.fail( + new PullRequestOperationError({ + operation: "runAction", + detail: `The head is now ${current.headSha ?? "unknown"}, not ${input.expectedHeadSha}. Review the new commits first.`, + }), + ), + ), + ); + return headPinned.pipe( + Effect.andThen(mergeSettings), Effect.flatMap((removeAgentCreditsOnMerge) => project.api .runAction({ @@ -2211,6 +2236,9 @@ export const make = Effect.gen(function* () { ...(input.expectedStackHeads === undefined ? {} : { expectedStackHeads: input.expectedStackHeads }), + ...(input.expectedHeadSha === undefined + ? {} + : { expectedHeadSha: input.expectedHeadSha }), ...(input.mergeMethod === undefined ? {} : { mergeMethod: input.mergeMethod }), ...(input.updateMethod === undefined ? {} diff --git a/docs/user/source-control.md b/docs/user/source-control.md index 2ebd53ced8565..681af169f930c 100644 --- a/docs/user/source-control.md +++ b/docs/user/source-control.md @@ -311,6 +311,10 @@ pull request link in the conversation. Creating a pull request from Git actions and so does an agent creating one with `gh pr create` or `glab mr create`. Agents can link other pull requests with the `link_pull_request` tool. +Agents can also read, open, update, reply on, and merge pull requests in the thread's repository +through T3 Code's own tools, which use the same sign-in as the Pull requests page. An agent merges +only the commit it last read: if someone pushed since, the merge is refused. + Use **Link pull request to thread** in the command palette to keep a pull request with the thread. From a review on the Pull requests page, **Link to thread** lets you search for an active thread. The review header also lists the threads that link to it, including archived threads, so you can return to their context. diff --git a/evals/mcp-tool-use/cases/pull-requests.ndjson b/evals/mcp-tool-use/cases/pull-requests.ndjson index 2e14e45f7f250..70a9b6024ab3d 100644 --- a/evals/mcp-tool-use/cases/pull-requests.ndjson +++ b/evals/mcp-tool-use/cases/pull-requests.ndjson @@ -37,3 +37,7 @@ {"id": "link-one-pr", "area": "pull-requests", "privacy": "commit-safe", "kind": "control", "pattern": "single link stays single", "experience": "Linking one named PR is ordinary work.", "setup": {"role": "top", "context": "No pull requests are linked to this thread.", "world": {"repo": "acme/app", "branch": "main"}}, "prompt": "link https://github.com/acme/app/pull/130 here", "expect": {"calls": [{"tool": "link_pull_request", "args": {"url": "~/pull/130"}}], "notCalls": ["link_pull_requests"]}, "maxSteps": 6, "source": {"thread": "Synthetic control for batch link"}} {"id": "schedule-one-time-date", "area": "pull-requests", "kind": "bad", "pattern": "one-off date scheduled as a daily task", "experience": "Theo asked whether a scheduled task can run at a specific date and time. schedule_task only had daily times, intervals, and webhooks, so a one-off request became a daily task.", "source": {"report": "maintainer request, 2026-10-31: scheduled tasks could not run at one date and time"}, "rule": "schedule: {type:'once',runAt} for one date and time", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"schedule_task": {"scheduledTaskId": "scheduled-task-4", "title": "Cut 2.0 release branch", "schedule": {"type": "once", "runAt": "2026-11-03T09:00:00.000Z"}, "enabled": true, "nextRunAt": "2026-11-03T09:00:00.000Z"}}}, "prompt": "On November 3rd at 9am UTC, start a new thread that cuts the 2.0 release branch from main in acme/app. Only that one time.", "expect": {"calls": [{"tool": "schedule_task", "args": {"schedule.type": "once", "schedule.runAt": "~11-03T09:00"}}], "notCalls": ["delegate_task", "run_scheduled_task_now"]}, "notes": "Mock result shape is an approximation."} {"id": "schedule-fresh-session-per-run", "area": "pull-requests", "kind": "guard", "pattern": "recurring task that should not accumulate context", "experience": "A recurring triage task kept one thread so the user could read its history, but each run carried every earlier run's context into the next.", "rule": "schedule_task `freshSession: true` keeps runs in one thread while each run starts a fresh session.", "privacy": "commit-safe", "setup": {"role": "top", "context": "Today is Monday 2026-11-02, 10:00 local time.", "mocks": {"schedule_task": {"scheduledTaskId": "scheduled-task-7", "title": "Triage new issues", "enabled": true, "projectId": "project-1", "boundThreadId": null, "freshSession": true, "schedule": {"type": "fixed_time", "timeOfDay": "09:00"}, "nextRunAt": "2026-11-03T09:00:00-08:00", "lastRunStatus": "never"}}}, "prompt": "Every morning at 9, triage new issues in acme/app. Keep all the runs in one thread so I can scroll back, but each run should start clean without remembering the previous days.", "expect": {"calls": [{"tool": "schedule_task", "args": {"schedule.type": "fixed_time", "freshSession": true}}], "notCalls": ["delegate_task", "run_scheduled_task_now"]}, "source": {"request": "juliusmarminge (maintainer) request, 2026-11-03: automations in one thread with separate provider sessions"}, "notes": "schedule-one-off-tomorrow is the control: an ordinary schedule must not set freshSession."} +{"id": "address-review-reads-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "review threads read with gh api graphql", "experience": "Agents addressing review feedback queried reviewThreads through gh api graphql (1,435 runs) and replied or resolved with more GraphQL, on the user's personal rate limit.", "rule": "pull_request_read and pull_request_respond replace gh and cafe for PR review work", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_read": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "conversation": {"comments": [], "reviewThreads": [{"id": "PRRT_kwDO1", "path": "src/config.ts", "line": 1, "isResolved": false, "isOutdated": false, "comments": [{"author": "reviewer", "body": "`port` never changes. Make it a `const`.", "createdAt": "2026-10-27T10:00:00Z"}], "moreComments": false}], "hiddenResolvedThreads": 0, "truncated": false}}, "pull_request_respond": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "replied": true, "resolved": true}}, "shellMocks": [{"match": "git push", "output": "To github.com:acme/app.git\n abc1234..def5678 feat/config-const -> feat/config-const"}], "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Address the unresolved review comments on #124, push, then reply on each thread and resolve it.", "expect": {"calls": [{"tool": "pull_request_read"}, {"tool": "pull_request_respond", "args": {"reviewThreadId": "PRRT_kwDO1"}}], "shellMustNot": ["\\bgh (api|pr (view|comment|review))\\b", "\\bcafe pr\\b"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in.", "maxSteps": 14} +{"id": "merge-through-gh-unpinned", "area": "pull-requests", "kind": "bad", "pattern": "merge with gh pr merge, not pinned to the reviewed head", "experience": "Agents merged with gh pr merge (215 runs), which merges whatever the head is by then and spends the user's quota.", "rule": "pull_request_merge merges only the head the agent checked", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_read": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "summary": {"title": "feat(config): read the port from the environment", "body": "Reads PORT.", "state": "open", "isDraft": false, "author": "user", "headBranch": "feat/config-const", "baseBranch": "main", "headSha": "abc1234def5678", "mergeability": "mergeable", "behindBy": 0, "autoMergeEnabled": false, "additions": 1, "deletions": 1, "changedFiles": 1, "labels": [], "reviewers": ["reviewer"]}, "checks": [{"name": "Lint", "status": "success", "description": null, "url": null}, {"name": "Test", "status": "success", "description": null, "url": null}]}, "pull_request_merge": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "state": "merged"}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Checks are green on #124 and it's approved. Merge it (squash).", "expect": {"calls": [{"tool": "pull_request_merge", "args": {"expectedHeadSha": "abc1234def5678"}}], "shellMustNot": ["\\bgh pr merge\\b", "\\bgh api\\b[^\\n]*merge"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in."} +{"id": "open-pr-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "PR opened with gh pr create", "experience": "Agents opened PRs with gh pr create or cafe pr create (614 runs), often guessing --head and --repo for forks.", "rule": "pull_request_create opens the PR from the thread's pushed branch", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_create": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "created": true}}, "shellMocks": [{"match": "git push", "output": "To github.com:acme/app.git\n * [new branch] feat/config-const -> feat/config-const\nbranch 'feat/config-const' set up to track 'origin/feat/config-const'."}], "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": []}}, "prompt": "The port change is committed on feat/config-const. Push it and open a PR against main.", "expect": {"calls": [{"tool": "pull_request_create"}], "shellMustNot": ["\\bgh pr create\\b", "\\bcafe pr create\\b"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in.", "maxSteps": 10} +{"id": "control-pr-status-no-merge", "area": "pull-requests", "kind": "control", "pattern": "status question with a mergeable PR", "experience": "Control: a green, approved PR and a question about it. Reading is fine; merging was not asked.", "rule": "Merge only when asked to land it", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_read": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "summary": {"title": "feat(config): read the port from the environment", "body": "Reads PORT.", "state": "open", "isDraft": false, "author": "user", "headBranch": "feat/config-const", "baseBranch": "main", "headSha": "abc1234def5678", "mergeability": "mergeable", "behindBy": 0, "autoMergeEnabled": false, "additions": 1, "deletions": 1, "changedFiles": 1, "labels": [], "reviewers": ["reviewer"]}, "checks": [{"name": "Lint", "status": "success", "description": null, "url": null}, {"name": "Test", "status": "success", "description": null, "url": null}]}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Where does #124 stand? Anything left before it can go in?", "expect": {"notCalls": ["pull_request_merge"], "shellMustNot": ["\\bgh pr merge\\b"]}, "notes": "Control for merge-through-gh-unpinned."} diff --git a/evals/mcp-tool-use/run.ts b/evals/mcp-tool-use/run.ts index d724268351c08..b697654f18587 100644 --- a/evals/mcp-tool-use/run.ts +++ b/evals/mcp-tool-use/run.ts @@ -1169,6 +1169,30 @@ const linkedEntry = (sample: Sample, url: string) => { return { ...pr, state: seeded?.state ?? "open", title: seeded?.title ?? null }; }; +/** The world's PRs. `prs` is free-form world data: number, title, headRefName, checks. */ +const worldPullRequests = (sample: Sample) => { + const prs = sample.testCase.setup.world?.prs; + return Array.isArray(prs) ? prs.filter(isRecord) : []; +}; + +/** + * The PR for the sample's branch: the world's, else the one a create would open. A case that + * mocks `gh pr create` names that URL, so the T3 tool opens the same number. + */ +const branchPullRequest = (sample: Sample) => { + const branch = sample.testCase.setup.world?.branch; + const prs = worldPullRequests(sample); + const own = prs.find((pr) => pr.headRefName === branch); + if (own !== undefined) return { number: Number(own.number), created: false, pr: own }; + const mocked = (sample.testCase.setup.shellMocks ?? []).find((mock) => + /\b(pr|mr) create\b/.test(mock.match), + ); + const fromMock = Number(/\/pull\/(\d+)/.exec(mocked?.output ?? "")?.[1]); + const number = + fromMock > 0 ? fromMock : Math.max(123, ...prs.map((pr) => Number(pr.number) || 0)) + 1; + return { number, created: true, pr: undefined }; +}; + /** A believable T3 result for a tool the case does not mock. */ export const t3Default = ( sample: Sample, @@ -1265,6 +1289,101 @@ export const t3Default = ( ...(invalidUrls.length > 0 ? { invalidUrls } : {}), }; } + case "pull_request_create": { + const { number, created } = branchPullRequest(sample); + const target = pullRequest(sample.repo, { number }); + sample.linked.add(target.url); + return { ...target, created }; + } + case "pull_request_read": { + const own = branchPullRequest(sample); + const number = typeof input.number === "number" ? input.number : own.number; + const world = worldPullRequests(sample).find((pr) => Number(pr.number) === number); + const sections = Array.isArray(input.sections) ? input.sections : ["summary", "checks"]; + const checks = Array.isArray(world?.checks) ? world.checks.filter(isRecord) : []; + return { + ...pullRequest(sample.repo, { number }), + ...(sections.includes("summary") + ? { + summary: { + title: valueText( + world?.title ?? sample.testCase.setup.world?.commits?.[0]?.subject, + ), + body: valueText(world?.body ?? ""), + state: "open", + isDraft: false, + author: "user", + headBranch: valueText(world?.headRefName ?? sample.testCase.setup.world?.branch), + baseBranch: "main", + headSha: sample.testCase.setup.world?.commits?.[0]?.sha ?? null, + mergeability: "mergeable", + behindBy: 0, + autoMergeEnabled: false, + additions: 1, + deletions: 1, + changedFiles: 1, + labels: [], + reviewers: [], + }, + } + : {}), + ...(sections.includes("checks") + ? { + checks: checks.map((check) => ({ + name: valueText(check.name), + status: + check.state === "fail" + ? "failure" + : check.state === "pending" + ? "pending" + : "success", + description: null, + url: null, + })), + } + : {}), + ...(sections.includes("conversation") + ? { + conversation: { + comments: [], + reviewThreads: [], + hiddenResolvedThreads: 0, + truncated: false, + }, + } + : {}), + }; + } + case "pull_request_list": + return { + pullRequests: worldPullRequests(sample).map((pr) => ({ + number: Number(pr.number), + title: valueText(pr.title), + url: pullRequest(sample.repo, { number: pr.number }).url, + author: "user", + headBranch: valueText(pr.headRefName), + baseBranch: "main", + state: "open", + isDraft: false, + reviewDecision: null, + checksState: null, + updatedAt: "2026-10-27T10:00:00Z", + })), + truncated: false, + }; + case "pull_request_update": + return pullRequest(sample.repo, { number: input.number ?? branchPullRequest(sample).number }); + case "pull_request_respond": + return { + ...pullRequest(sample.repo, { number: input.number ?? branchPullRequest(sample).number }), + replied: input.body !== undefined, + resolved: typeof input.resolved === "boolean" ? input.resolved : null, + }; + case "pull_request_merge": + return { + ...pullRequest(sample.repo, { number: input.number ?? branchPullRequest(sample).number }), + state: input.auto === true ? "open" : "merged", + }; case "request_secret": { // T3 names a ref and a file with 32 hex characters, new for each request, in its secrets dir. const id = NodeCrypto.createHash("sha256") @@ -1402,6 +1521,7 @@ const withProductFields = (name: string, value: unknown, child: boolean): unknow return listed("matches"); case "link_pull_request": case "link_pull_requests": + case "pull_request_create": return child ? { ...value, next: CHILD_PULL_REQUEST_REPORT_NEXT } : value; default: return value; diff --git a/packages/client-runtime/src/t3ToolSummary.ts b/packages/client-runtime/src/t3ToolSummary.ts index 1d57c1f0c91b7..d42ca751e867a 100644 --- a/packages/client-runtime/src/t3ToolSummary.ts +++ b/packages/client-runtime/src/t3ToolSummary.ts @@ -460,6 +460,24 @@ export function summarizeT3ToolCalls( case "read-pr-guide": label = phrase("Read", "read", quantity(selected.length, "review guide")); break; + case "read-pr": + label = phrase("Read", "read", quantity(selected.length, "pull request")); + break; + case "list-repo-prs": + label = phrase("Listed", "list", `pull requests${selected.length === 1 ? "" : ` ${times}`}`); + break; + case "create-pr": + label = phrase("Opened", "open", quantity(selected.length, "pull request")); + break; + case "update-pr": + label = phrase("Updated", "update", quantity(selected.length, "pull request")); + break; + case "respond-pr": + label = phrase("Responded", "respond", `on pull requests ${times}`); + break; + case "merge-pr": + label = phrase("Merged", "merge", quantity(selected.length, "pull request")); + break; case "browser": label = phrase("Used", "use", `browser ${times}`); break; diff --git a/packages/contracts/src/pullRequest.ts b/packages/contracts/src/pullRequest.ts index fb2c9b474268d..40b4cd484be0b 100644 --- a/packages/contracts/src/pullRequest.ts +++ b/packages/contracts/src/pullRequest.ts @@ -817,6 +817,8 @@ export const PullRequestActionInput = Schema.Struct({ /** Native stack scope; only send to environments advertising pullRequestStackActions. */ stackNumber: Schema.optional(PositiveInt), expectedStackHeads: Schema.optional(Schema.Array(PullRequestStackHead)), + /** Merges refuse when the head commit is no longer this one. */ + expectedHeadSha: Schema.optional(TrimmedNonEmptyString), ...PullRequestRef.fields, action: PullRequestAction, mergeMethod: Schema.optional(PullRequestMergeMethod), diff --git a/packages/shared/src/t3McpToolPresentation.ts b/packages/shared/src/t3McpToolPresentation.ts index 7a6c2fab91187..8e25213329ef0 100644 --- a/packages/shared/src/t3McpToolPresentation.ts +++ b/packages/shared/src/t3McpToolPresentation.ts @@ -65,6 +65,12 @@ export type T3McpToolSummaryAction = | "unwatch-pr" | "write-pr-guides" | "read-pr-guide" + | "read-pr" + | "list-repo-prs" + | "create-pr" + | "update-pr" + | "respond-pr" + | "merge-pr" | "browser" | "device" | "html-preview" @@ -141,6 +147,32 @@ const T3_MCP_TOOLS: Readonly> = { "read-pr-guide", "pull-request", ), + pull_request_read: tool(["Read", "Reading", "Read", "a pull request"], "read-pr", "pull-request"), + pull_request_list: tool( + ["List", "Listing", "Listed", "pull requests"], + "list-repo-prs", + "pull-request", + ), + pull_request_create: tool( + ["Open", "Opening", "Opened", "a pull request"], + "create-pr", + "pull-request", + ), + pull_request_update: tool( + ["Update", "Updating", "Updated", "a pull request"], + "update-pr", + "pull-request", + ), + pull_request_respond: tool( + ["Respond", "Responding", "Responded", "on a pull request"], + "respond-pr", + "pull-request", + ), + pull_request_merge: tool( + ["Merge", "Merging", "Merged", "a pull request"], + "merge-pr", + "pull-request", + ), orchestrator_capabilities: tool( ["Get", "Getting", "Got", "orchestration capabilities"], "capabilities", diff --git a/packages/source-control-core/src/server/PullRequestProvider.ts b/packages/source-control-core/src/server/PullRequestProvider.ts index 81d5e33d110f4..8b777ce58479a 100644 --- a/packages/source-control-core/src/server/PullRequestProvider.ts +++ b/packages/source-control-core/src/server/PullRequestProvider.ts @@ -498,6 +498,8 @@ export interface PullRequestProviderApi { readonly action: PullRequestAction; readonly stackNumber?: number; readonly expectedStackHeads?: ReadonlyArray; + /** Hosts that can pin a merge to a head commit do; the caller has already checked it. */ + readonly expectedHeadSha?: string; readonly removeAgentCreditsOnMerge?: boolean; readonly mergeMethod?: PullRequestMergeMethod; readonly updateMethod?: PullRequestUpdateMethod; diff --git a/packages/source-control-github/src/server/GitHubPullRequestApi.ts b/packages/source-control-github/src/server/GitHubPullRequestApi.ts index 6b8d22c17a12b..771b51e870364 100644 --- a/packages/source-control-github/src/server/GitHubPullRequestApi.ts +++ b/packages/source-control-github/src/server/GitHubPullRequestApi.ts @@ -723,6 +723,7 @@ export class GitHubPullRequestApi extends Context.Service< readonly action: PullRequestAction; readonly stackNumber?: number; readonly expectedStackHeads?: ReadonlyArray; + readonly expectedHeadSha?: string; readonly removeAgentCreditsOnMerge?: boolean; readonly mergeMethod?: PullRequestMergeMethod; readonly updateMethod?: PullRequestUpdateMethod; @@ -2753,7 +2754,9 @@ export const make = Effect.gen(function* () { const merge = { pullRequestId: state.id, mergeMethod: GRAPHQL_MERGE_METHODS[input.mergeMethod ?? "merge"], - ...(expectedHead === undefined ? {} : { expectedHeadOid: expectedHead }), + ...((input.expectedHeadSha ?? expectedHead) === undefined + ? {} + : { expectedHeadOid: input.expectedHeadSha ?? expectedHead }), ...(body === undefined ? {} : { commitBody: body }), }; return yield* actionSummary( diff --git a/packages/source-control-github/src/server/GitHubPullRequestProvider.ts b/packages/source-control-github/src/server/GitHubPullRequestProvider.ts index a680f8e0ae125..066b3ee7f8c64 100644 --- a/packages/source-control-github/src/server/GitHubPullRequestProvider.ts +++ b/packages/source-control-github/src/server/GitHubPullRequestProvider.ts @@ -732,6 +732,9 @@ export const make = Effect.gen(function* () { ...(input.expectedStackHeads === undefined ? {} : { expectedStackHeads: input.expectedStackHeads }), + ...(input.expectedHeadSha === undefined + ? {} + : { expectedHeadSha: input.expectedHeadSha }), ...(input.mergeMethod === undefined ? {} : { mergeMethod: input.mergeMethod }), ...(input.updateMethod === undefined ? {} : { updateMethod: input.updateMethod }), }) From 595020c242cfa45303aa225567aade2a034f168b Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Tue, 10 Nov 2026 23:59:00 -0800 Subject: [PATCH 02/23] fix(server): PR tools pin GitLab merges to the reviewed head and report what they did - GitLab merges pass the reviewed head to --sha instead of the head read just before. - pull_request_create links a PR a stack had dismissed instead of leaving it hidden. - Tool summaries tell a found PR from an opened one, and auto-merge from a merge. - The eval runner lists world PRs in their own state and returns the diff section. Co-Authored-By: Claude Opus 5.5 --- .../toolkits/pullRequests/handlers.test.ts | 71 ++++++++++--------- .../src/mcp/toolkits/pullRequests/handlers.ts | 6 +- evals/mcp-tool-use/run.test.ts | 29 ++++++++ evals/mcp-tool-use/run.ts | 43 +++++++---- .../client-runtime/src/t3ToolSummary.test.ts | 21 ++++++ packages/client-runtime/src/t3ToolSummary.ts | 36 ++++++++-- .../src/server/GitLabPullRequestCli.test.ts | 27 +++++++ .../src/server/GitLabPullRequestCli.ts | 8 ++- .../src/server/GitLabPullRequestProvider.ts | 3 + 9 files changed, 190 insertions(+), 54 deletions(-) diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts index 24f24054ed303..63330c64fc902 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts @@ -815,39 +815,44 @@ describe("source control tools", () => { }), ); - it.effect("opens a PR from the thread's worktree, links it, and makes it a draft", () => - Effect.gen(function* () { - const actions: Array = []; - const opened: Array = []; - const harness = yield* makeHarness({ - thread: { ...makeThread([]), worktreePath: "/workspace/worktree" }, - git: { - createPullRequest: (input) => - Effect.sync(() => opened.push(input.cwd)).pipe( - Effect.as({ - status: "created" as const, - url: "https://github.com/t3tools/t3code/pull/43", - number: 43, - baseBranch: "main", - headBranch: "tools", - title: input.title, - }), - ), - }, - pullRequests: { runAction: (input) => Effect.sync(() => void actions.push(input)) }, - }); - const result = yield* harness.call("pull_request_create", { - title: "Add tools", - body: "Adds tools.", - draft: true, - }); - expect(result).toMatchObject({ number: 43, created: true }); - expect(opened).toEqual(["/workspace/worktree"]); - expect(actions).toMatchObject([{ number: 43, action: "draft" }]); - expect(yield* Ref.get(harness.commands)).toMatchObject([ - { type: "thread.pull-request.link", number: 43, source: "created" }, - ]); - }), + it.effect( + "opens a PR from the thread's worktree, links it even if dismissed, and drafts it", + () => + Effect.gen(function* () { + const actions: Array = []; + const opened: Array = []; + const harness = yield* makeHarness({ + thread: { + ...makeThread([makeLink(43, { source: "stack-dismissed" })]), + worktreePath: "/workspace/worktree", + }, + git: { + createPullRequest: (input) => + Effect.sync(() => opened.push(input.cwd)).pipe( + Effect.as({ + status: "created" as const, + url: "https://github.com/t3tools/t3code/pull/43", + number: 43, + baseBranch: "main", + headBranch: "tools", + title: input.title, + }), + ), + }, + pullRequests: { runAction: (input) => Effect.sync(() => void actions.push(input)) }, + }); + const result = yield* harness.call("pull_request_create", { + title: "Add tools", + body: "Adds tools.", + draft: true, + }); + expect(result).toMatchObject({ number: 43, created: true }); + expect(opened).toEqual(["/workspace/worktree"]); + expect(actions).toMatchObject([{ number: 43, action: "draft" }]); + expect(yield* Ref.get(harness.commands)).toMatchObject([ + { type: "thread.pull-request.link", number: 43, source: "created" }, + ]); + }), ); it.effect("replies to and resolves a review thread, and refuses resolving without one", () => diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts index 49eabd51d64f5..c8a4bb4195fb5 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts @@ -399,7 +399,11 @@ const make = Effect.gen(function* () { thread: OrchestrationV2ThreadShell, target: ResolvedTarget, ) { - if (threadPullRequestsOf(thread).some((link) => threadPullRequestKeysEqual(link, target))) { + if ( + threadPullRequestsOf(thread).some( + (link) => link.source !== "stack-dismissed" && threadPullRequestKeysEqual(link, target), + ) + ) { return; } yield* engine diff --git a/evals/mcp-tool-use/run.test.ts b/evals/mcp-tool-use/run.test.ts index ec1a121fee485..3f4b6b103e138 100644 --- a/evals/mcp-tool-use/run.test.ts +++ b/evals/mcp-tool-use/run.test.ts @@ -751,6 +751,35 @@ it("replays earlier capability results with the model under test as the caller", } }); +it("lists and reads world PRs in their own state, with the diff when asked", () => { + const base = buildBase(template, { model: "claude-sonnet-5-5", keepUserInstructions: false }); + const prs = [ + { number: 5, state: "MERGED", headRefName: "old", title: "Old", diff: "+old" }, + { number: 6, headRefName: "new", title: "New" }, + ]; + const sample = makeSample( + { ...childCase, setup: { ...childCase.setup, world: { ...childCase.setup.world, prs } } }, + base, + ); + const listed = (state?: string) => + ( + t3Default(sample, "pull_request_list", state === undefined ? {} : { state }) as { + pullRequests: Array<{ number: number; state: string }>; + } + ).pullRequests.map((pr) => [pr.number, pr.state]); + assert.deepEqual(listed(), [[6, "open"]]); + assert.deepEqual(listed("all"), [ + [5, "merged"], + [6, "open"], + ]); + const read: Readonly> = t3Default(sample, "pull_request_read", { + number: 5, + sections: ["summary", "diff"], + }); + assert.deepEqual(read.diff, { patch: "+old", truncated: false, nextCursor: null }); + assert.propertyVal(read.summary, "state", "merged"); +}); + it("gives each launched thread its own id, and reading it back shows that thread's brief", () => { const base = buildBase(template, { model: "claude-sonnet-5-5", keepUserInstructions: false }); const sample = makeSample(childCase, base); diff --git a/evals/mcp-tool-use/run.ts b/evals/mcp-tool-use/run.ts index b697654f18587..11c0ba1ffafe0 100644 --- a/evals/mcp-tool-use/run.ts +++ b/evals/mcp-tool-use/run.ts @@ -1175,6 +1175,12 @@ const worldPullRequests = (sample: Sample) => { return Array.isArray(prs) ? prs.filter(isRecord) : []; }; +/** World fixtures spell states as GitHub does (`MERGED`) or as T3 does (`merged`). */ +const worldState = (pr: Readonly> | undefined) => { + const state = valueText(pr?.state ?? "open").toLowerCase(); + return state === "merged" || state === "closed" ? state : "open"; +}; + /** * The PR for the sample's branch: the world's, else the one a create would open. A case that * mocks `gh pr create` names that URL, so the T3 tool opens the same number. @@ -1310,7 +1316,7 @@ export const t3Default = ( world?.title ?? sample.testCase.setup.world?.commits?.[0]?.subject, ), body: valueText(world?.body ?? ""), - state: "open", + state: worldState(world), isDraft: false, author: "user", headBranch: valueText(world?.headRefName ?? sample.testCase.setup.world?.branch), @@ -1342,6 +1348,9 @@ export const t3Default = ( })), } : {}), + ...(sections.includes("diff") + ? { diff: { patch: valueText(world?.diff ?? ""), truncated: false, nextCursor: null } } + : {}), ...(sections.includes("conversation") ? { conversation: { @@ -1354,23 +1363,27 @@ export const t3Default = ( : {}), }; } - case "pull_request_list": + case "pull_request_list": { + const state = valueText(input.state ?? "open"); return { - pullRequests: worldPullRequests(sample).map((pr) => ({ - number: Number(pr.number), - title: valueText(pr.title), - url: pullRequest(sample.repo, { number: pr.number }).url, - author: "user", - headBranch: valueText(pr.headRefName), - baseBranch: "main", - state: "open", - isDraft: false, - reviewDecision: null, - checksState: null, - updatedAt: "2026-10-27T10:00:00Z", - })), + pullRequests: worldPullRequests(sample) + .filter((pr) => state === "all" || worldState(pr) === state) + .map((pr) => ({ + number: Number(pr.number), + title: valueText(pr.title), + url: pullRequest(sample.repo, { number: pr.number }).url, + author: "user", + headBranch: valueText(pr.headRefName), + baseBranch: "main", + state: worldState(pr), + isDraft: false, + reviewDecision: null, + checksState: null, + updatedAt: "2026-10-27T10:00:00Z", + })), truncated: false, }; + } case "pull_request_update": return pullRequest(sample.repo, { number: input.number ?? branchPullRequest(sample).number }); case "pull_request_respond": diff --git a/packages/client-runtime/src/t3ToolSummary.test.ts b/packages/client-runtime/src/t3ToolSummary.test.ts index 268306f37d0d5..9969659eaee39 100644 --- a/packages/client-runtime/src/t3ToolSummary.test.ts +++ b/packages/client-runtime/src/t3ToolSummary.test.ts @@ -52,6 +52,27 @@ describe("summarizeT3ToolCalls", () => { expect(summarizeT3ToolCalls("unlink-pr", [uncounted]).label).toBe("Unlinked pull requests"); }); + it("tells opened and merged pull requests from found ones and auto-merges", () => { + const create = (created: boolean) => completed({ title: "t" }, { number: 1, created }); + expect(summarizeT3ToolCalls("create-pr", [create(true)]).label).toBe("Opened 1 pull request"); + expect(summarizeT3ToolCalls("create-pr", [create(false)]).label).toBe( + "Found 1 open pull request", + ); + expect(summarizeT3ToolCalls("create-pr", [create(true), create(false)]).label).toBe( + "Opened 1 pull request, found 1 open", + ); + const merge = (auto: boolean, state: string) => completed({ auto }, { number: 1, state }); + expect(summarizeT3ToolCalls("merge-pr", [merge(false, "merged")]).label).toBe( + "Merged 1 pull request", + ); + expect(summarizeT3ToolCalls("merge-pr", [merge(true, "open")]).label).toBe( + "Turned on auto-merge for 1 pull request", + ); + expect( + summarizeT3ToolCalls("merge-pr", [merge(true, "merged"), merge(true, "open")]).label, + ).toBe("Merged 1 pull request, auto-merge on 1"); + }); + it("excludes failed and unfinished sends even if the provider reports completed", () => { const calls: T3ToolSummaryCall[] = [ completed({ threadId: "success" }, { messageId: "ok", threadId: "success" }), diff --git a/packages/client-runtime/src/t3ToolSummary.ts b/packages/client-runtime/src/t3ToolSummary.ts index d42ca751e867a..60be2bce26dbd 100644 --- a/packages/client-runtime/src/t3ToolSummary.ts +++ b/packages/client-runtime/src/t3ToolSummary.ts @@ -466,18 +466,46 @@ export function summarizeT3ToolCalls( case "list-repo-prs": label = phrase("Listed", "list", `pull requests${selected.length === 1 ? "" : ` ${times}`}`); break; - case "create-pr": - label = phrase("Opened", "open", quantity(selected.length, "pull request")); + case "create-pr": { + // An open PR for the branch is returned rather than duplicated. + const existing = selected.filter((call) => call.output?.created === false).length; + const opened = selected.length - existing; + label = + opened === 0 + ? phrase("Found", "open", quantity(existing, "open pull request")) + : phrase( + "Opened", + "open", + `${quantity(opened, "pull request")}${existing > 0 ? `, found ${existing} open` : ""}`, + ); break; + } case "update-pr": label = phrase("Updated", "update", quantity(selected.length, "pull request")); break; case "respond-pr": label = phrase("Responded", "respond", `on pull requests ${times}`); break; - case "merge-pr": - label = phrase("Merged", "merge", quantity(selected.length, "pull request")); + case "merge-pr": { + // Auto-merge leaves the PR open until its checks pass. + const queued = selected.filter( + (call) => call.input?.auto === true && call.output?.state !== "merged", + ).length; + const merged = selected.length - queued; + label = + merged === 0 + ? phrase( + "Turned on auto-merge for", + "turn on auto-merge for", + quantity(queued, "pull request"), + ) + : phrase( + "Merged", + "merge", + `${quantity(merged, "pull request")}${queued > 0 ? `, auto-merge on ${queued}` : ""}`, + ); break; + } case "browser": label = phrase("Used", "use", `browser ${times}`); break; diff --git a/packages/source-control-gitlab/src/server/GitLabPullRequestCli.test.ts b/packages/source-control-gitlab/src/server/GitLabPullRequestCli.test.ts index 4cdc6d1f15b6b..2dad9f886eb85 100644 --- a/packages/source-control-gitlab/src/server/GitLabPullRequestCli.test.ts +++ b/packages/source-control-gitlab/src/server/GitLabPullRequestCli.test.ts @@ -688,6 +688,33 @@ layer("GitLabPullRequestCli.layer", (it) => { }), ); + it.effect("merges pinned to the head the caller reviewed, not the one it reads", () => + Effect.gen(function* () { + const cli = yield* GitLabPullRequestCli.GitLabPullRequestCli; + mockedExecute.mockImplementation(({ args }) => + Effect.succeed( + output( + args[0] === "api" + ? mergeRequestJson({ + diff_refs: { base_sha: "base", head_sha: "pushed-head", start_sha: "start" }, + }) + : "", + ), + ), + ); + yield* cli.runMergeRequestAction({ + cwd: "/w", + repository: "acme/web", + number: 7, + action: "merge", + mergeMethod: "squash", + expectedHeadSha: "reviewed-head", + }); + const merge = mockedExecute.mock.calls.at(-1)?.[0].args ?? []; + expect(merge[merge.indexOf("--sha") + 1]).toBe("reviewed-head"); + }), + ); + it.effect.each([ { mergeMethod: "squash", diff --git a/packages/source-control-gitlab/src/server/GitLabPullRequestCli.ts b/packages/source-control-gitlab/src/server/GitLabPullRequestCli.ts index 1ee2d355d3fa3..1b5d9c9723579 100644 --- a/packages/source-control-gitlab/src/server/GitLabPullRequestCli.ts +++ b/packages/source-control-gitlab/src/server/GitLabPullRequestCli.ts @@ -575,6 +575,8 @@ export class GitLabPullRequestCli extends Context.Service< readonly action: PullRequestAction; readonly mergeMethod?: PullRequestMergeMethod; readonly removeAgentCreditsOnMerge?: boolean; + /** The head the caller reviewed; a merge refuses any other. */ + readonly expectedHeadSha?: string; }) => Effect.Effect; readonly updateMergeRequest: (input: { @@ -2699,7 +2701,11 @@ export const make = Effect.gen(function* () { yield* executeMr("rebase"); } const refs = yield* getDiffRefs(input); - flags.push("--sha", refs.headSha); + // A rebase replaces the reviewed head, which the caller checked before asking for it. + flags.push( + "--sha", + input.mergeMethod === "rebase" ? refs.headSha : (input.expectedHeadSha ?? refs.headSha), + ); if (input.removeAgentCreditsOnMerge === true) { // Read after the SHA guard, so a push since then fails the merge instead of // merging commits whose credits these messages don't cover. diff --git a/packages/source-control-gitlab/src/server/GitLabPullRequestProvider.ts b/packages/source-control-gitlab/src/server/GitLabPullRequestProvider.ts index df9210fb24124..3fa6b05e0b33b 100644 --- a/packages/source-control-gitlab/src/server/GitLabPullRequestProvider.ts +++ b/packages/source-control-gitlab/src/server/GitLabPullRequestProvider.ts @@ -593,6 +593,9 @@ export const make = Effect.gen(function* () { action: input.action, ...(input.mergeMethod === undefined ? {} : { mergeMethod: input.mergeMethod }), ...(input.removeAgentCreditsOnMerge === true ? { removeAgentCreditsOnMerge: true } : {}), + ...(input.expectedHeadSha === undefined + ? {} + : { expectedHeadSha: input.expectedHeadSha }), }) .pipe(Effect.mapError(fail("runAction"))), ), From 71fc7d2108561514b49a82b2d38719b1b4efbb6b Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 00:17:03 -0800 Subject: [PATCH 03/23] fix(server): PR tools refuse unpushed commits and stay safe to retry - pull_request_create refuses a branch with unpushed commits instead of opening a PR without them. - A retried create drafts the PR it opened if the first draft failed. - When a reply posts but resolving fails, the error says not to resend the body. - The auto-merge description says later pushes merge with it; summaries call an open result queued. - The eval runner refuses branch PR reads until the agent has opened one. Co-Authored-By: Claude Opus 5.5 --- apps/server/src/git/GitManager.test.ts | 25 ++++++++++ apps/server/src/git/GitManager.ts | 9 ++++ .../toolkits/pullRequests/handlers.test.ts | 46 ++++++++++++++++++- .../src/mcp/toolkits/pullRequests/handlers.ts | 35 ++++++++++---- .../src/mcp/toolkits/pullRequests/tools.ts | 4 +- evals/mcp-tool-use/run.test.ts | 28 +++++++++++ evals/mcp-tool-use/run.ts | 17 +++++++ .../client-runtime/src/t3ToolSummary.test.ts | 7 ++- packages/client-runtime/src/t3ToolSummary.ts | 16 +++---- 9 files changed, 165 insertions(+), 22 deletions(-) diff --git a/apps/server/src/git/GitManager.test.ts b/apps/server/src/git/GitManager.test.ts index 2abcd34ef50b6..713c8e1364247 100644 --- a/apps/server/src/git/GitManager.test.ts +++ b/apps/server/src/git/GitManager.test.ts @@ -4139,6 +4139,31 @@ it.layer(layerGitManagerTest)("GitManager", (it) => { }), ); + it.effect("createPullRequest refuses a branch with commits it has not pushed", () => + Effect.gen(function* () { + const repoDir = yield* makeTempDir("t3code-git-manager-"); + yield* initRepo(repoDir); + const remoteDir = yield* createBareRemote(); + yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]); + yield* runGit(repoDir, ["push", "-u", "origin", "main"]); + yield* runGit(repoDir, ["checkout", "-b", "feature/unpushed"]); + yield* runGit(repoDir, ["push", "-u", "origin", "feature/unpushed"]); + NodeFS.writeFileSync(NodePath.join(repoDir, "late.txt"), "late\n"); + yield* runGit(repoDir, ["add", "late.txt"]); + yield* runGit(repoDir, ["commit", "-m", "Late commit"]); + const { manager, providerCalls } = yield* makeManager({ + providerScenario: { prListSequence: [[], []] }, + }); + + const error = yield* Effect.flip( + manager.createPullRequest({ cwd: repoDir, title: "Feature", body: "Body" }), + ); + + expect(error.message).toContain("1 unpushed commit"); + expect(created(providerCalls)).toEqual([]); + }), + ); + it.effect("generates PR content from the created worktree's selected remote base", () => Effect.gen(function* () { const repoDir = yield* makeTempDir("t3code-git-manager-"); diff --git a/apps/server/src/git/GitManager.ts b/apps/server/src/git/GitManager.ts index 4082e7c346744..86809166f5590 100644 --- a/apps/server/src/git/GitManager.ts +++ b/apps/server/src/git/GitManager.ts @@ -2523,6 +2523,15 @@ export const make = Effect.gen(function* () { const createPullRequest: GitManager["Service"]["createPullRequest"] = Effect.fn( "GitManager.createPullRequest", )(function* (input) { + // A PR opened from the remote branch would leave out commits not pushed yet. + const { aheadCount } = yield* gitCore.statusDetails(input.cwd); + if (aheadCount > 0) { + return yield* new GitManagerError({ + operation: "createPullRequest", + cwd: input.cwd, + detail: `The branch has ${aheadCount} unpushed commit${aheadCount === 1 ? "" : "s"}. Push before opening the PR.`, + }); + } return yield* openPrFromBranch( input.cwd, null, diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts index 63330c64fc902..72be7512d9f75 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts @@ -852,6 +852,35 @@ describe("source control tools", () => { expect(yield* Ref.get(harness.commands)).toMatchObject([ { type: "thread.pull-request.link", number: 43, source: "created" }, ]); + + // A retry after a failed draft finds the open PR and still drafts it. + const retried = yield* makeHarness({ + thread: { ...makeThread([]), worktreePath: "/workspace/worktree" }, + git: { + createPullRequest: (input) => + Effect.succeed({ + status: "opened_existing" as const, + url: "https://github.com/t3tools/t3code/pull/43", + number: 43, + baseBranch: "main", + headBranch: "tools", + title: input.title, + }), + }, + pullRequests: { + summary: () => Effect.succeed({ state: "open", isDraft: false } as never), + runAction: (input) => Effect.sync(() => void actions.push(input)), + }, + }); + yield* retried.call("pull_request_create", { + title: "Add tools", + body: "Adds tools.", + draft: true, + }); + expect(actions).toMatchObject([ + { number: 43, action: "draft" }, + { number: 43, action: "draft" }, + ]); }), ); @@ -863,7 +892,14 @@ describe("source control tools", () => { pullRequests: { replyToThread: (input) => Effect.sync(() => calls.push(`reply ${input.threadId}`)), setThreadResolution: (input) => - Effect.sync(() => calls.push(`resolve ${input.threadId} ${input.resolved}`)), + input.threadId === "locked-thread" + ? Effect.fail( + new PullRequestOperationError({ + operation: "setThreadResolution", + detail: "Locked.", + }), + ) + : Effect.sync(() => void calls.push(`resolve ${input.threadId} ${input.resolved}`)), }, }); const result = yield* harness.call("pull_request_respond", { @@ -873,6 +909,14 @@ describe("source control tools", () => { }); expect(result).toMatchObject({ replied: true, resolved: true }); expect(calls).toEqual(["reply open-thread", "resolve open-thread true"]); + const partial = yield* harness + .call("pull_request_respond", { + reviewThreadId: "locked-thread", + body: "Fixed.", + resolved: true, + }) + .pipe(Effect.flip); + expect(partial.message).toContain("The reply was posted"); const error = yield* harness .call("pull_request_respond", { body: "Done", resolved: true }) .pipe(Effect.flip); diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts index c8a4bb4195fb5..5c9b9006a8836 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts @@ -738,15 +738,22 @@ const make = Effect.gen(function* () { } const target = yield* resolveTarget({ url: created.url }, project); yield* linkToThread(thread, target); - if (input.draft === true && created.status === "created") { + const ref = { + projectId: project.id, + host: target.host, + repository: target.repository, + number: target.number, + }; + // A retry after a failed draft finds the PR it opened, so it checks the draft state. + const needsDraft = + input.draft === true && + (created.status === "created" || + !(yield* pullRequests + .summary({ ...ref, allowStale: false }) + .pipe(Effect.mapError(forgeFailure))).isDraft); + if (needsDraft) { yield* pullRequests - .runAction({ - projectId: project.id, - host: target.host, - repository: target.repository, - number: target.number, - action: "draft", - }) + .runAction({ ...ref, action: "draft" }) .pipe(Effect.mapError(forgeFailure)); } return { @@ -808,7 +815,17 @@ const make = Effect.gen(function* () { if (reviewThreadId !== undefined && input.resolved !== undefined) { yield* pullRequests .setThreadResolution({ ...ref, threadId: reviewThreadId, resolved: input.resolved }) - .pipe(Effect.mapError(forgeFailure)); + .pipe( + Effect.mapError((error) => + input.body === undefined + ? forgeFailure(error) + : new PullRequestForgeError({ + // A retry with the body would post the reply twice. + detail: `The reply was posted, but setting resolved failed: ${error.message} Retry without body.`, + cause: error, + }), + ), + ); } return { ...identityOf(target), diff --git a/apps/server/src/mcp/toolkits/pullRequests/tools.ts b/apps/server/src/mcp/toolkits/pullRequests/tools.ts index fd5bb0108bb0f..a9e73de82b351 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/tools.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/tools.ts @@ -687,7 +687,9 @@ const MergePullRequestTool = Tool.make("pull_request_merge", { expectedHeadSha: TrimmedNonEmptyString, method: Schema.optional(PullRequestMergeMethod), auto: Schema.optional( - Schema.Boolean.annotate({ description: "Merge once required checks pass." }), + Schema.Boolean.annotate({ + description: "Merge once required checks pass, with any commits pushed by then.", + }), ), }), success: MergePullRequestResult, diff --git a/evals/mcp-tool-use/run.test.ts b/evals/mcp-tool-use/run.test.ts index 3f4b6b103e138..54e24a9456c5f 100644 --- a/evals/mcp-tool-use/run.test.ts +++ b/evals/mcp-tool-use/run.test.ts @@ -986,6 +986,34 @@ it("stops a sample only once a must-not check has failed", () => { assert.isTrue(failedEarly({ secret }, run("Bash", "I'll unlock it with 482916."))); }); +it.effect("reads the branch's PR only once the agent has opened it", () => + Effect.gen(function* () { + const base = buildBase(template, { model: "claude-sonnet-5-5", keepUserInstructions: false }); + const world = { ...childCase.setup.world, branch: "feature", prs: [] }; + const sample = makeSample({ ...childCase, setup: { ...childCase.setup, world } }, base); + for (const name of ["pull_request_read", "pull_request_create"]) { + sample.tools.push({ name: `mcp__t3-code__${name}` }); + } + const config = { + apiKey: "", + model: "claude-sonnet-5-5", + effort: "high", + maxSteps: 6, + shellModel: "claude-haiku-5-5", + } as const; + const call = (id: string, name: string, input: Record) => + answerToolCall(sample, config, { + type: "tool_use", + id, + name: `mcp__t3-code__${name}`, + input, + }); + assert.isTrue((yield* call("a", "pull_request_read", {})).is_error); + yield* call("b", "pull_request_create", { title: "Feature", body: "Body" }); + assert.isNotTrue((yield* call("c", "pull_request_read", {})).is_error); + }).pipe(Effect.provide(FetchHttpClient.layer)), +); + it.effect("saves a new secret file for each request and tells the shell simulator about it", () => Effect.gen(function* () { const base = buildBase(template, { model: "claude-sonnet-5-5", keepUserInstructions: false }); diff --git a/evals/mcp-tool-use/run.ts b/evals/mcp-tool-use/run.ts index 11c0ba1ffafe0..f93a990329353 100644 --- a/evals/mcp-tool-use/run.ts +++ b/evals/mcp-tool-use/run.ts @@ -1573,6 +1573,16 @@ const searchTools = (base: Base, query: string, max: number) => { return found.toSorted((a, b) => hits(b).length - hits(a).length).slice(0, max); }; +/** Tools that act on the branch's PR when no number is passed. */ +const BRANCH_PULL_REQUEST_TOOLS = new Set([ + "pull_request_read", + "pull_request_update", + "pull_request_respond", + "pull_request_merge", +]); +const BRANCH_HAS_NO_PR_ERROR = + "This thread's branch has no known PR. Pass number, or open one with pull_request_create."; + const SUBAGENT_WATCH_ERROR = "This thread is a subagent, so it cannot watch pull requests. Its parent thread owns the pull request: finish your task and report back instead."; @@ -1831,6 +1841,13 @@ export const answerToolCall = Effect.fn("evaluateMcpToolUse.answerToolCall")(fun if (name === "watch_pull_request" && testCase.setup.role === "delegated-child") { return failed(SUBAGENT_WATCH_ERROR); } + if (BRANCH_PULL_REQUEST_TOOLS.has(name) && input.number === undefined) { + // Until the agent opens it, the PR a create would open does not exist. + const own = branchPullRequest(sample); + if (own.created && !sample.linked.has(pullRequest(sample.repo, { number: own.number }).url)) { + return failed(BRANCH_HAS_NO_PR_ERROR); + } + } const value = t3Default(sample, name, input); if (name === "request_secret") savedSecretFile(sample, value); return toolResult( diff --git a/packages/client-runtime/src/t3ToolSummary.test.ts b/packages/client-runtime/src/t3ToolSummary.test.ts index 9969659eaee39..3800c1cfac58f 100644 --- a/packages/client-runtime/src/t3ToolSummary.test.ts +++ b/packages/client-runtime/src/t3ToolSummary.test.ts @@ -65,12 +65,15 @@ describe("summarizeT3ToolCalls", () => { expect(summarizeT3ToolCalls("merge-pr", [merge(false, "merged")]).label).toBe( "Merged 1 pull request", ); + expect(summarizeT3ToolCalls("merge-pr", [merge(false, "open")]).label).toBe( + "Queued 1 pull request to merge", + ); expect(summarizeT3ToolCalls("merge-pr", [merge(true, "open")]).label).toBe( - "Turned on auto-merge for 1 pull request", + "Queued 1 pull request to merge", ); expect( summarizeT3ToolCalls("merge-pr", [merge(true, "merged"), merge(true, "open")]).label, - ).toBe("Merged 1 pull request, auto-merge on 1"); + ).toBe("Merged 1 pull request, queued 1"); }); it("excludes failed and unfinished sends even if the provider reports completed", () => { diff --git a/packages/client-runtime/src/t3ToolSummary.ts b/packages/client-runtime/src/t3ToolSummary.ts index 60be2bce26dbd..c399d0a12d91b 100644 --- a/packages/client-runtime/src/t3ToolSummary.ts +++ b/packages/client-runtime/src/t3ToolSummary.ts @@ -487,22 +487,20 @@ export function summarizeT3ToolCalls( label = phrase("Responded", "respond", `on pull requests ${times}`); break; case "merge-pr": { - // Auto-merge leaves the PR open until its checks pass. - const queued = selected.filter( - (call) => call.input?.auto === true && call.output?.state !== "merged", + // Auto-merge and merge queues leave the PR open until it lands. + const queued = selected.filter((call) => + call.output?.state === undefined + ? call.input?.auto === true + : call.output.state !== "merged", ).length; const merged = selected.length - queued; label = merged === 0 - ? phrase( - "Turned on auto-merge for", - "turn on auto-merge for", - quantity(queued, "pull request"), - ) + ? phrase("Queued", "queue", `${quantity(queued, "pull request")} to merge`) : phrase( "Merged", "merge", - `${quantity(merged, "pull request")}${queued > 0 ? `, auto-merge on ${queued}` : ""}`, + `${quantity(merged, "pull request")}${queued > 0 ? `, queued ${queued}` : ""}`, ); break; } From 466c57ab2af89db65ec8f9757394d5916b1e50a2 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 00:21:20 -0800 Subject: [PATCH 04/23] fix(evals): pull_request_read shows the world PR's comments Co-Authored-By: Claude Opus 5.5 --- evals/mcp-tool-use/run.test.ts | 12 ++++++++++-- evals/mcp-tool-use/run.ts | 12 +++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/evals/mcp-tool-use/run.test.ts b/evals/mcp-tool-use/run.test.ts index 54e24a9456c5f..abe89ae7e5fc6 100644 --- a/evals/mcp-tool-use/run.test.ts +++ b/evals/mcp-tool-use/run.test.ts @@ -754,7 +754,14 @@ it("replays earlier capability results with the model under test as the caller", it("lists and reads world PRs in their own state, with the diff when asked", () => { const base = buildBase(template, { model: "claude-sonnet-5-5", keepUserInstructions: false }); const prs = [ - { number: 5, state: "MERGED", headRefName: "old", title: "Old", diff: "+old" }, + { + number: 5, + state: "MERGED", + headRefName: "old", + title: "Old", + diff: "+old", + comments: [{ author: "mark", body: "Please confirm." }], + }, { number: 6, headRefName: "new", title: "New" }, ]; const sample = makeSample( @@ -774,10 +781,11 @@ it("lists and reads world PRs in their own state, with the diff when asked", () ]); const read: Readonly> = t3Default(sample, "pull_request_read", { number: 5, - sections: ["summary", "diff"], + sections: ["summary", "diff", "conversation"], }); assert.deepEqual(read.diff, { patch: "+old", truncated: false, nextCursor: null }); assert.propertyVal(read.summary, "state", "merged"); + assert.nestedPropertyVal(read.conversation, "comments[0].author", "mark"); }); it("gives each launched thread its own id, and reading it back shows that thread's brief", () => { diff --git a/evals/mcp-tool-use/run.ts b/evals/mcp-tool-use/run.ts index f93a990329353..fd35900478140 100644 --- a/evals/mcp-tool-use/run.ts +++ b/evals/mcp-tool-use/run.ts @@ -1354,7 +1354,17 @@ export const t3Default = ( ...(sections.includes("conversation") ? { conversation: { - comments: [], + comments: (Array.isArray(world?.comments) ? world.comments : []) + .filter(isRecord) + .map((comment, index) => ({ + id: `comment-${index + 1}`, + kind: "issue-comment", + author: valueText(comment.author), + body: valueText(comment.body), + createdAt: "2026-10-27T10:00:00Z", + path: null, + reviewState: null, + })), reviewThreads: [], hiddenResolvedThreads: 0, truncated: false, From b5b6032d85b32d9da7398c874a320bd56f7720f3 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 00:24:01 -0800 Subject: [PATCH 05/23] fix(server): GitLab rebase merges check the reviewed head before rebasing GitLab's rebase takes no SHA, so a pinned rebase merge now refuses a head that moved before it rebases, rather than pinning the merge to whatever the rebase produced. Co-Authored-By: Claude Opus 5.5 --- .../src/server/GitLabPullRequestCli.test.ts | 15 +++++++++++++++ .../src/server/GitLabPullRequestCli.ts | 14 +++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/source-control-gitlab/src/server/GitLabPullRequestCli.test.ts b/packages/source-control-gitlab/src/server/GitLabPullRequestCli.test.ts index 2dad9f886eb85..8c5bc1fb795af 100644 --- a/packages/source-control-gitlab/src/server/GitLabPullRequestCli.test.ts +++ b/packages/source-control-gitlab/src/server/GitLabPullRequestCli.test.ts @@ -712,6 +712,21 @@ layer("GitLabPullRequestCli.layer", (it) => { }); const merge = mockedExecute.mock.calls.at(-1)?.[0].args ?? []; expect(merge[merge.indexOf("--sha") + 1]).toBe("reviewed-head"); + + // A rebase cannot be pinned, so a head that moved refuses it before rebasing. + mockedExecute.mockClear(); + const refused = yield* Effect.flip( + cli.runMergeRequestAction({ + cwd: "/w", + repository: "acme/web", + number: 7, + action: "merge", + mergeMethod: "rebase", + expectedHeadSha: "reviewed-head", + }), + ); + expect(refused._tag).toBe("GitLabMutationRefusedError"); + expect(mockedExecute.mock.calls.map(([call]) => call.args[1])).not.toContain("rebase"); }), ); diff --git a/packages/source-control-gitlab/src/server/GitLabPullRequestCli.ts b/packages/source-control-gitlab/src/server/GitLabPullRequestCli.ts index 1b5d9c9723579..5c4285deeb3d7 100644 --- a/packages/source-control-gitlab/src/server/GitLabPullRequestCli.ts +++ b/packages/source-control-gitlab/src/server/GitLabPullRequestCli.ts @@ -2697,11 +2697,23 @@ export const make = Effect.gen(function* () { const [subcommand, ...flags] = actionArgs(input.action, input.mergeMethod); if (input.action === "merge" || input.action === "enable-auto-merge") { if (input.mergeMethod === "rebase") { + // GitLab's rebase takes no SHA, so the reviewed head is checked just before it. + if (input.expectedHeadSha !== undefined) { + const current = yield* getDiffRefs(input); + if (current.headSha !== input.expectedHeadSha) { + return yield* new GitLabMutationRefusedError({ + command: "glab", + cwd: input.cwd, + operation: "runMergeRequestAction", + reasons: [`the head is now ${current.headSha}, not ${input.expectedHeadSha}`], + }); + } + } // A rebase changes the source SHA, so wait for it before reading the merge guard. yield* executeMr("rebase"); } const refs = yield* getDiffRefs(input); - // A rebase replaces the reviewed head, which the caller checked before asking for it. + // After a rebase, the head checked above is replaced by its rebased commits. flags.push( "--sha", input.mergeMethod === "rebase" ? refs.headSha : (input.expectedHeadSha ?? refs.headSha), From 34cda8182acb64130c6b9c3bda206d706e86bd82 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 00:29:48 -0800 Subject: [PATCH 06/23] fix(server): pull_request_read reads the PR fresh, not a stale snapshot Agents pin merges to the summary's headSha, so it must not lag behind the host. Co-Authored-By: Claude Opus 5.5 --- .../server/src/mcp/toolkits/pullRequests/handlers.test.ts | 8 +++++++- apps/server/src/mcp/toolkits/pullRequests/handlers.ts | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts index 72be7512d9f75..22cc629ab7d0f 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts @@ -769,7 +769,13 @@ describe("source control tools", () => { sections: ["summary", "conversation"], }); expect(asked).toEqual([ - { projectId: PROJECT_ID, host: "github.com", repository: "t3tools/t3code", number: 42 }, + { + projectId: PROJECT_ID, + host: "github.com", + repository: "t3tools/t3code", + number: 42, + allowStale: false, + }, ]); expect(result.summary?.headSha).toBe("abc123"); expect(result.checks).toBeUndefined(); diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts index 5c9b9006a8836..f04d8fcbb8b63 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts @@ -311,8 +311,9 @@ const make = Effect.gen(function* () { const wants = (section: PullRequestReadSection) => sections.includes(section); const [detail, activity, diff] = yield* Effect.all( [ + // Agents pin merges to this headSha, so it must not come from a stale snapshot. wants("summary") || wants("checks") - ? pullRequests.detail(ref).pipe(Effect.asSome) + ? pullRequests.detail({ ...ref, allowStale: false }).pipe(Effect.asSome) : Effect.succeedNone, wants("conversation") ? pullRequests.activity(ref).pipe(Effect.asSome) : Effect.succeedNone, wants("diff") From d57ed5c12f487bb0f950eea2f630ae0394d83543 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 00:34:48 -0800 Subject: [PATCH 07/23] fix(evals): a mocked pull_request_create opens the PR it names Co-Authored-By: Claude Opus 5.5 --- evals/mcp-tool-use/run.test.ts | 18 ++++++++++++++++++ evals/mcp-tool-use/run.ts | 12 +++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/evals/mcp-tool-use/run.test.ts b/evals/mcp-tool-use/run.test.ts index abe89ae7e5fc6..7a7dd68ce9178 100644 --- a/evals/mcp-tool-use/run.test.ts +++ b/evals/mcp-tool-use/run.test.ts @@ -1019,6 +1019,24 @@ it.effect("reads the branch's PR only once the agent has opened it", () => assert.isTrue((yield* call("a", "pull_request_read", {})).is_error); yield* call("b", "pull_request_create", { title: "Feature", body: "Body" }); assert.isNotTrue((yield* call("c", "pull_request_read", {})).is_error); + + // A case that mocks the create still opens the PR it names. + const url = "https://github.com/acme/app/pull/124"; + const mocks = { pull_request_create: { number: 124, url, created: true } }; + const mockedSample = makeSample( + { ...childCase, setup: { ...childCase.setup, world, mocks } }, + base, + ); + mockedSample.tools.push(...sample.tools); + const mockedCall = (id: string, name: string) => + answerToolCall(mockedSample, config, { + type: "tool_use", + id, + name: `mcp__t3-code__${name}`, + input: name === "pull_request_create" ? { title: "Feature", body: "Body" } : {}, + }); + yield* mockedCall("d", "pull_request_create"); + assert.isNotTrue((yield* mockedCall("e", "pull_request_read")).is_error); }).pipe(Effect.provide(FetchHttpClient.layer)), ); diff --git a/evals/mcp-tool-use/run.ts b/evals/mcp-tool-use/run.ts index fd35900478140..e6059d97642bf 100644 --- a/evals/mcp-tool-use/run.ts +++ b/evals/mcp-tool-use/run.ts @@ -1839,6 +1839,9 @@ export const answerToolCall = Effect.fn("evaluateMcpToolUse.answerToolCall")(fun // A pasted secret is saved without a card, so a mocked card outcome does not apply. if (mock !== undefined && mock !== "default" && !pastedSecret(name, input)) { if (name === "request_secret") savedSecretFile(sample, mock); + if (name === "pull_request_create" && isRecord(mock) && typeof mock.url === "string") { + sample.linked.add(mock.url); + } return toolResult( call.id, name === "orchestrator_capabilities" @@ -1854,9 +1857,12 @@ export const answerToolCall = Effect.fn("evaluateMcpToolUse.answerToolCall")(fun if (BRANCH_PULL_REQUEST_TOOLS.has(name) && input.number === undefined) { // Until the agent opens it, the PR a create would open does not exist. const own = branchPullRequest(sample); - if (own.created && !sample.linked.has(pullRequest(sample.repo, { number: own.number }).url)) { - return failed(BRANCH_HAS_NO_PR_ERROR); - } + const mocked = testCase.setup.mocks?.pull_request_create; + const opened = [ + pullRequest(sample.repo, { number: own.number }).url, + isRecord(mocked) ? mocked.url : undefined, + ].some((url) => typeof url === "string" && sample.linked.has(url)); + if (own.created && !opened) return failed(BRANCH_HAS_NO_PR_ERROR); } const value = t3Default(sample, name, input); if (name === "request_secret") savedSecretFile(sample, value); From c0e0743bbd3d39fc44486424cf3cd437dc10e07e Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 00:55:50 -0800 Subject: [PATCH 08/23] fix(server): pull_request_create returns an open PR despite local commits - The unpushed-commit refusal applies only before opening a new PR. - A created PR refreshes the branch's PR lookup, so the thread finds it. - The eval runner records the PR the agent opened instead of inferring it from links. Co-Authored-By: Claude Opus 5.5 --- apps/server/src/git/GitManager.test.ts | 16 ++++++++++++++++ apps/server/src/git/GitManager.ts | 22 ++++++++++++---------- evals/mcp-tool-use/run.test.ts | 20 +++++++++++++++++--- evals/mcp-tool-use/run.ts | 20 +++++++++++++------- 4 files changed, 58 insertions(+), 20 deletions(-) diff --git a/apps/server/src/git/GitManager.test.ts b/apps/server/src/git/GitManager.test.ts index 713c8e1364247..fdec239e23ef0 100644 --- a/apps/server/src/git/GitManager.test.ts +++ b/apps/server/src/git/GitManager.test.ts @@ -4161,6 +4161,22 @@ it.layer(layerGitManagerTest)("GitManager", (it) => { expect(error.message).toContain("1 unpushed commit"); expect(created(providerCalls)).toEqual([]); + + // An open PR is returned as it is; returning it publishes nothing. + const open = { + number: 7, + title: "Feature", + url: "https://github.com/pingdotgg/codething-mvp/pull/7", + baseRefName: "main", + headRefName: "feature/unpushed", + }; + const existing = yield* makeManager({ providerScenario: { prListSequence: [[open]] } }); + const found = yield* existing.manager.createPullRequest({ + cwd: repoDir, + title: "Feature", + body: "Body", + }); + expect(found).toMatchObject({ status: "opened_existing", number: 7 }); }), ); diff --git a/apps/server/src/git/GitManager.ts b/apps/server/src/git/GitManager.ts index 86809166f5590..a691fce266d64 100644 --- a/apps/server/src/git/GitManager.ts +++ b/apps/server/src/git/GitManager.ts @@ -2407,6 +2407,14 @@ export const make = Effect.gen(function* () { }; } + // A PR opened from the remote branch would leave out commits not pushed yet. + if (details.aheadCount > 0) { + return yield* new GitManagerError({ + operation: "runPrStep", + cwd, + detail: `The branch has ${details.aheadCount} unpushed commit${details.aheadCount === 1 ? "" : "s"}. Push before opening the PR.`, + }); + } const resolved = yield* resolvePrBase(cwd, branch, details.upstreamRef, headContext); const baseBranch = requestedBase ?? resolved.baseBranch; const generated = yield* content({ @@ -2523,22 +2531,16 @@ export const make = Effect.gen(function* () { const createPullRequest: GitManager["Service"]["createPullRequest"] = Effect.fn( "GitManager.createPullRequest", )(function* (input) { - // A PR opened from the remote branch would leave out commits not pushed yet. - const { aheadCount } = yield* gitCore.statusDetails(input.cwd); - if (aheadCount > 0) { - return yield* new GitManagerError({ - operation: "createPullRequest", - cwd: input.cwd, - detail: `The branch has ${aheadCount} unpushed commit${aheadCount === 1 ? "" : "s"}. Push before opening the PR.`, - }); - } - return yield* openPrFromBranch( + const result = yield* openPrFromBranch( input.cwd, null, () => Effect.void, input.baseBranch, () => Effect.succeed({ title: input.title, body: input.body }), ); + // The thread's branch PR comes from status, which may hold the lookup from before. + if (result.status === "created") yield* invalidateStatus(input.cwd); + return result; }); const localStatus: GitManager["Service"]["localStatus"] = Effect.fn("localStatus")( diff --git a/evals/mcp-tool-use/run.test.ts b/evals/mcp-tool-use/run.test.ts index 7a7dd68ce9178..42862bca9339c 100644 --- a/evals/mcp-tool-use/run.test.ts +++ b/evals/mcp-tool-use/run.test.ts @@ -1021,8 +1021,8 @@ it.effect("reads the branch's PR only once the agent has opened it", () => assert.isNotTrue((yield* call("c", "pull_request_read", {})).is_error); // A case that mocks the create still opens the PR it names. - const url = "https://github.com/acme/app/pull/124"; - const mocks = { pull_request_create: { number: 124, url, created: true } }; + const url = "https://github.com/acme/app/pull/125"; + const mocks = { pull_request_create: { number: 125, url, created: true } }; const mockedSample = makeSample( { ...childCase, setup: { ...childCase.setup, world, mocks } }, base, @@ -1036,7 +1036,21 @@ it.effect("reads the branch's PR only once the agent has opened it", () => input: name === "pull_request_create" ? { title: "Feature", body: "Body" } : {}, }); yield* mockedCall("d", "pull_request_create"); - assert.isNotTrue((yield* mockedCall("e", "pull_request_read")).is_error); + const mockedRead = yield* mockedCall("e", "pull_request_read"); + assert.isNotTrue(mockedRead.is_error); + assert.include(String(mockedRead.content), "/pull/125"); + + // Linking the URL a create would open is not opening it. + const linkedOnly = makeSample({ ...childCase, setup: { ...childCase.setup, world } }, base); + linkedOnly.tools.push(...sample.tools); + linkedOnly.linked.add("https://github.com/acme/app/pull/124"); + const linkedRead = yield* answerToolCall(linkedOnly, config, { + type: "tool_use", + id: "f", + name: "mcp__t3-code__pull_request_read", + input: {}, + }); + assert.isTrue(linkedRead.is_error); }).pipe(Effect.provide(FetchHttpClient.layer)), ); diff --git a/evals/mcp-tool-use/run.ts b/evals/mcp-tool-use/run.ts index e6059d97642bf..ba233dc7deeec 100644 --- a/evals/mcp-tool-use/run.ts +++ b/evals/mcp-tool-use/run.ts @@ -858,6 +858,8 @@ type Sample = { readonly shell: Array; readonly shellUsage: Usage; readonly linked: Set; + /** The branch PR the agent opened in this sample, which links alone do not prove. */ + openedPullRequest: number | undefined; readonly codeStore: Record; nextTask: number; /** Threads the agent launched in this sample, by id, so reading one shows its own brief. */ @@ -913,6 +915,10 @@ export const makeSample = (testCase: McpToolUseCase, base: Base): Sample => { shell, shellUsage: emptyUsage(), linked: new Set([...urls, ...shell.flatMap(createdPullRequests)]), + openedPullRequest: shell + .flatMap(createdPullRequests) + .map((url) => Number(/\/pull\/(\d+)/.exec(url)?.[1])) + .find((number) => number > 0), codeStore: {}, nextTask: Math.max(0, ...taskNumbers) + 1, threads: new Map(), @@ -1190,6 +1196,9 @@ const branchPullRequest = (sample: Sample) => { const prs = worldPullRequests(sample); const own = prs.find((pr) => pr.headRefName === branch); if (own !== undefined) return { number: Number(own.number), created: false, pr: own }; + if (sample.openedPullRequest !== undefined) { + return { number: sample.openedPullRequest, created: false, pr: undefined }; + } const mocked = (sample.testCase.setup.shellMocks ?? []).find((mock) => /\b(pr|mr) create\b/.test(mock.match), ); @@ -1299,6 +1308,7 @@ export const t3Default = ( const { number, created } = branchPullRequest(sample); const target = pullRequest(sample.repo, { number }); sample.linked.add(target.url); + if (created) sample.openedPullRequest = number; return { ...target, created }; } case "pull_request_read": { @@ -1841,6 +1851,8 @@ export const answerToolCall = Effect.fn("evaluateMcpToolUse.answerToolCall")(fun if (name === "request_secret") savedSecretFile(sample, mock); if (name === "pull_request_create" && isRecord(mock) && typeof mock.url === "string") { sample.linked.add(mock.url); + const number = Number(mock.number); + if (number > 0) sample.openedPullRequest = number; } return toolResult( call.id, @@ -1856,13 +1868,7 @@ export const answerToolCall = Effect.fn("evaluateMcpToolUse.answerToolCall")(fun } if (BRANCH_PULL_REQUEST_TOOLS.has(name) && input.number === undefined) { // Until the agent opens it, the PR a create would open does not exist. - const own = branchPullRequest(sample); - const mocked = testCase.setup.mocks?.pull_request_create; - const opened = [ - pullRequest(sample.repo, { number: own.number }).url, - isRecord(mocked) ? mocked.url : undefined, - ].some((url) => typeof url === "string" && sample.linked.has(url)); - if (own.created && !opened) return failed(BRANCH_HAS_NO_PR_ERROR); + if (branchPullRequest(sample).created) return failed(BRANCH_HAS_NO_PR_ERROR); } const value = t3Default(sample, name, input); if (name === "request_secret") savedSecretFile(sample, value); From c0639a3af610e93cf7fc009ab2af237f05721ddd Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 01:06:07 -0800 Subject: [PATCH 09/23] fix(evals): pull_request_read reports the world PR's own head Co-Authored-By: Claude Opus 5.5 --- evals/mcp-tool-use/run.test.ts | 2 ++ evals/mcp-tool-use/run.ts | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/evals/mcp-tool-use/run.test.ts b/evals/mcp-tool-use/run.test.ts index 42862bca9339c..13abd75503497 100644 --- a/evals/mcp-tool-use/run.test.ts +++ b/evals/mcp-tool-use/run.test.ts @@ -761,6 +761,7 @@ it("lists and reads world PRs in their own state, with the diff when asked", () title: "Old", diff: "+old", comments: [{ author: "mark", body: "Please confirm." }], + headRefOid: "pr-head", }, { number: 6, headRefName: "new", title: "New" }, ]; @@ -785,6 +786,7 @@ it("lists and reads world PRs in their own state, with the diff when asked", () }); assert.deepEqual(read.diff, { patch: "+old", truncated: false, nextCursor: null }); assert.propertyVal(read.summary, "state", "merged"); + assert.propertyVal(read.summary, "headSha", "pr-head"); assert.nestedPropertyVal(read.conversation, "comments[0].author", "mark"); }); diff --git a/evals/mcp-tool-use/run.ts b/evals/mcp-tool-use/run.ts index ba233dc7deeec..d0ede9aa66627 100644 --- a/evals/mcp-tool-use/run.ts +++ b/evals/mcp-tool-use/run.ts @@ -1331,7 +1331,10 @@ export const t3Default = ( author: "user", headBranch: valueText(world?.headRefName ?? sample.testCase.setup.world?.branch), baseBranch: "main", - headSha: sample.testCase.setup.world?.commits?.[0]?.sha ?? null, + headSha: + typeof world?.headRefOid === "string" + ? world.headRefOid + : (sample.testCase.setup.world?.commits?.[0]?.sha ?? null), mergeability: "mergeable", behindBy: 0, autoMergeEnabled: false, From d960d8863bec5f17a04feebe7c1f1a64400e736f Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 01:14:52 -0800 Subject: [PATCH 10/23] fix(evals): the branch PR comes from shell and earlier MCP creates for that branch Co-Authored-By: Claude Opus 5.5 --- evals/mcp-tool-use/run.test.ts | 39 ++++++++++++++++++++++++++++++++++ evals/mcp-tool-use/run.ts | 28 ++++++++++++++++++++---- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/evals/mcp-tool-use/run.test.ts b/evals/mcp-tool-use/run.test.ts index 13abd75503497..641695f9d3808 100644 --- a/evals/mcp-tool-use/run.test.ts +++ b/evals/mcp-tool-use/run.test.ts @@ -996,6 +996,45 @@ it("stops a sample only once a must-not check has failed", () => { assert.isTrue(failedEarly({ secret }, run("Bash", "I'll unlock it with 482916."))); }); +it("restores the branch PR that earlier turns opened, not another branch's", () => { + const base = buildBase(template, { model: "claude-sonnet-5-5", keepUserInstructions: false }); + const world = { ...childCase.setup.world, branch: "feature", prs: [] }; + const opened = (toolCalls: ReadonlyArray<{ tool: string; input: unknown; result: unknown }>) => + makeSample( + { + ...childCase, + setup: { ...childCase.setup, world, priorTurns: [{ role: "assistant", toolCalls }] }, + }, + base, + ).openedPullRequest; + const created = "https://github.com/acme/app/pull/9\n"; + assert.equal( + opened([ + { tool: "Bash", input: { command: "gh pr create --title T --body B" }, result: created }, + ]), + 9, + ); + assert.isUndefined( + opened([ + { + tool: "Bash", + input: { command: "gh pr create --head other --title T --body B" }, + result: created, + }, + ]), + ); + assert.equal( + opened([ + { + tool: "pull_request_create", + input: {}, + result: { number: 11, url: "https://github.com/acme/app/pull/11" }, + }, + ]), + 11, + ); +}); + it.effect("reads the branch's PR only once the agent has opened it", () => Effect.gen(function* () { const base = buildBase(template, { model: "claude-sonnet-5-5", keepUserInstructions: false }); diff --git a/evals/mcp-tool-use/run.ts b/evals/mcp-tool-use/run.ts index d0ede9aa66627..9a48a66646b07 100644 --- a/evals/mcp-tool-use/run.ts +++ b/evals/mcp-tool-use/run.ts @@ -845,6 +845,18 @@ const createdPullRequests = ({ tool, input, output }: ShellEntry) => tool === "Bash" && isRecord(input) && typeof input.command === "string" ? changeRequestsCreatedBy(input.command, output).map(({ url }) => url) : []; + +/** The PR number a shell command opened for `branch`; `--head` naming another branch is not it. */ +const branchPullRequestCreatedBy = (entry: ShellEntry, branch: string | undefined) => { + const command = isRecord(entry.input) ? valueText(entry.input.command) : ""; + const head = /--head[=\s]+["']?([^\s"']+)/.exec(command)?.[1]; + if (head !== undefined && branch !== undefined && head.split(":").at(-1) !== branch) { + return undefined; + } + return createdPullRequests(entry) + .map((url) => Number(/\/pull\/(\d+)/.exec(url)?.[1])) + .find((number) => number > 0); +}; /** * One sample's state. ToolSearch adds loaded schemas to `tools`, like Claude Code. `shell` is the * history the simulator keeps consistent with; `linked`, `nextTask` and `threads` do the same for @@ -915,10 +927,14 @@ export const makeSample = (testCase: McpToolUseCase, base: Base): Sample => { shell, shellUsage: emptyUsage(), linked: new Set([...urls, ...shell.flatMap(createdPullRequests)]), - openedPullRequest: shell - .flatMap(createdPullRequests) - .map((url) => Number(/\/pull\/(\d+)/.exec(url)?.[1])) - .find((number) => number > 0), + openedPullRequest: + shell + .map((entry) => branchPullRequestCreatedBy(entry, testCase.setup.world?.branch)) + .find((number) => number !== undefined) ?? + priorCalls + .filter((call) => call.tool === "pull_request_create") + .map((call) => Number(/\/pull\/(\d+)/.exec(valueText(call.result))?.[1])) + .find((number) => number > 0), codeStore: {}, nextTask: Math.max(0, ...taskNumbers) + 1, threads: new Map(), @@ -1778,6 +1794,10 @@ const simulate = Effect.fn("evaluateMcpToolUse.simulate")(function* ( const entry = { ...call, output }; sample.shell.push(entry); for (const url of createdPullRequests(entry)) sample.linked.add(url); + sample.openedPullRequest ??= branchPullRequestCreatedBy( + entry, + sample.testCase.setup.world?.branch, + ); return output; }); From 6cb33a2239693dfa67d477e5b6f658e8bf4668c9 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 01:20:24 -0800 Subject: [PATCH 11/23] fix(evals): only the branch PR falls back to the checkout's head Co-Authored-By: Claude Opus 5.5 --- evals/mcp-tool-use/run.test.ts | 37 +++++++++++++++++++++++++++++++++- evals/mcp-tool-use/run.ts | 5 ++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/evals/mcp-tool-use/run.test.ts b/evals/mcp-tool-use/run.test.ts index 641695f9d3808..6e189f40d732f 100644 --- a/evals/mcp-tool-use/run.test.ts +++ b/evals/mcp-tool-use/run.test.ts @@ -766,9 +766,44 @@ it("lists and reads world PRs in their own state, with the diff when asked", () { number: 6, headRefName: "new", title: "New" }, ]; const sample = makeSample( - { ...childCase, setup: { ...childCase.setup, world: { ...childCase.setup.world, prs } } }, + { + ...childCase, + setup: { + ...childCase.setup, + world: { + ...childCase.setup.world, + prs, + branch: "new", + commits: [{ sha: "local-head", subject: "New" }], + }, + }, + }, base, ); + const headOf = (number: number) => + (t3Default(sample, "pull_request_read", { number }) as { summary: { headSha: unknown } }) + .summary.headSha; + // The checkout's commit is the branch PR's head, not another PR's. + assert.equal(headOf(6), "local-head"); + const other = makeSample( + { + ...childCase, + setup: { + ...childCase.setup, + world: { + ...childCase.setup.world, + prs, + branch: "elsewhere", + commits: [{ sha: "local-head", subject: "x" }], + }, + }, + }, + base, + ); + assert.isNull( + (t3Default(other, "pull_request_read", { number: 6 }) as { summary: { headSha: unknown } }) + .summary.headSha, + ); const listed = (state?: string) => ( t3Default(sample, "pull_request_list", state === undefined ? {} : { state }) as { diff --git a/evals/mcp-tool-use/run.ts b/evals/mcp-tool-use/run.ts index 9a48a66646b07..8bcf29fcf9d7f 100644 --- a/evals/mcp-tool-use/run.ts +++ b/evals/mcp-tool-use/run.ts @@ -1347,10 +1347,13 @@ export const t3Default = ( author: "user", headBranch: valueText(world?.headRefName ?? sample.testCase.setup.world?.branch), baseBranch: "main", + // Only the branch's own PR is at the checkout's latest commit. headSha: typeof world?.headRefOid === "string" ? world.headRefOid - : (sample.testCase.setup.world?.commits?.[0]?.sha ?? null), + : number === own.number + ? (sample.testCase.setup.world?.commits?.[0]?.sha ?? null) + : null, mergeability: "mergeable", behindBy: 0, autoMergeEnabled: false, From f461a02152519005af949c435d3226669972d159 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 01:25:13 -0800 Subject: [PATCH 12/23] fix(server): PR tools find the PR this thread opened before status sync reports it Co-Authored-By: Claude Opus 5.5 --- .../src/mcp/toolkits/pullRequests/handlers.test.ts | 14 ++++++++++++++ .../src/mcp/toolkits/pullRequests/handlers.ts | 6 +++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts index 22cc629ab7d0f..3cedd7a39f36e 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts @@ -794,6 +794,20 @@ describe("source control tools", () => { }), ); + it.effect("reads the PR this thread opened before status sync reports it", () => + Effect.gen(function* () { + const asked: Array = []; + const harness = yield* makeHarness({ + thread: makeThread([makeLink(43, { source: "created" })]), + pullRequests: { + detail: (ref) => Effect.sync(() => asked.push(ref)).pipe(Effect.as(detail)), + }, + }); + yield* harness.call("pull_request_read", { sections: ["summary"] }); + expect(asked).toMatchObject([{ number: 43 }]); + }), + ); + it.effect("merges pinned to the head the agent checked", () => Effect.gen(function* () { const actions: Array = []; diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts index f04d8fcbb8b63..df472ee463e16 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts @@ -273,7 +273,11 @@ const make = Effect.gen(function* () { if (project === undefined) { return yield* new PullRequestProjectNotFoundError({ repository: input.repository ?? "" }); } - const branchPullRequest = thread.branchPullRequest ?? null; + // Status sync sets branchPullRequest later, so a PR this thread just opened counts too. + const branchPullRequest = + thread.branchPullRequest ?? + threadPullRequestsOf(thread).findLast((link) => link.source === "created") ?? + null; const branchRepository = project.repositoryIdentity == null ? undefined From 7256195e19cc89f8ef315d19dc9f0972ad43d0ed Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 01:33:48 -0800 Subject: [PATCH 13/23] fix(server): the opened-PR fallback ignores PRs from another branch Co-Authored-By: Claude Opus 5.5 --- .../src/mcp/toolkits/pullRequests/handlers.test.ts | 12 ++++++++++++ .../server/src/mcp/toolkits/pullRequests/handlers.ts | 9 +++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts index 3cedd7a39f36e..6663bd9bdf5b8 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts @@ -805,6 +805,18 @@ describe("source control tools", () => { }); yield* harness.call("pull_request_read", { sections: ["summary"] }); expect(asked).toMatchObject([{ number: 43 }]); + + // After a switch to another branch, the PR opened from the old one is not the branch's. + const switched = yield* makeHarness({ + thread: { + ...makeThread([makeLink(43, { source: "created", headBranch: "old" })]), + branch: "new", + }, + }); + const error = yield* switched + .call("pull_request_update", { title: "New title" }) + .pipe(Effect.flip); + expect(error._tag).toBe("PullRequestBranchHasNoneError"); }), ); diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts index df472ee463e16..019ece18ae957 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts @@ -273,10 +273,15 @@ const make = Effect.gen(function* () { if (project === undefined) { return yield* new PullRequestProjectNotFoundError({ repository: input.repository ?? "" }); } - // Status sync sets branchPullRequest later, so a PR this thread just opened counts too. + // Status sync sets branchPullRequest later, so a PR this thread just opened counts too, + // unless its snapshot shows it is another branch's. const branchPullRequest = thread.branchPullRequest ?? - threadPullRequestsOf(thread).findLast((link) => link.source === "created") ?? + threadPullRequestsOf(thread).findLast( + (link) => + link.source === "created" && + (link.snapshot === null || link.snapshot.headBranch === thread.branch), + ) ?? null; const branchRepository = project.repositoryIdentity == null From cb24241304300bfad3b990265a405d0e974da4db Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 01:39:37 -0800 Subject: [PATCH 14/23] fix(server): an unsynced opened PR counts only if the host says it is this branch's Co-Authored-By: Claude Opus 5.5 --- .../toolkits/pullRequests/handlers.test.ts | 20 +++++++++++----- .../src/mcp/toolkits/pullRequests/handlers.ts | 24 ++++++++++++------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts index 6663bd9bdf5b8..0bce0afcd39e3 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts @@ -797,15 +797,23 @@ describe("source control tools", () => { it.effect("reads the PR this thread opened before status sync reports it", () => Effect.gen(function* () { const asked: Array = []; - const harness = yield* makeHarness({ - thread: makeThread([makeLink(43, { source: "created" })]), - pullRequests: { - detail: (ref) => Effect.sync(() => asked.push(ref)).pipe(Effect.as(detail)), - }, - }); + const opened = (headBranch: string) => + makeHarness({ + thread: { ...makeThread([makeLink(43, { source: "created" })]), branch: "tools" }, + pullRequests: { + summary: () => Effect.succeed({ state: "open", headBranch } as never), + detail: (ref) => Effect.sync(() => asked.push(ref)).pipe(Effect.as(detail)), + }, + }); + const harness = yield* opened("tools"); yield* harness.call("pull_request_read", { sections: ["summary"] }); expect(asked).toMatchObject([{ number: 43 }]); + // Before sync, the host says which branch it came from; another branch's is not this one. + const moved = yield* opened("old"); + const unsynced = yield* moved.call("pull_request_read", {}).pipe(Effect.flip); + expect(unsynced._tag).toBe("PullRequestBranchHasNoneError"); + // After a switch to another branch, the PR opened from the old one is not the branch's. const switched = yield* makeHarness({ thread: { diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts index 019ece18ae957..5936ba93e2511 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts @@ -274,15 +274,16 @@ const make = Effect.gen(function* () { return yield* new PullRequestProjectNotFoundError({ repository: input.repository ?? "" }); } // Status sync sets branchPullRequest later, so a PR this thread just opened counts too, - // unless its snapshot shows it is another branch's. - const branchPullRequest = - thread.branchPullRequest ?? - threadPullRequestsOf(thread).findLast( - (link) => - link.source === "created" && - (link.snapshot === null || link.snapshot.headBranch === thread.branch), - ) ?? - null; + // unless it is another branch's. + const opened = + thread.branchPullRequest === null || thread.branchPullRequest === undefined + ? threadPullRequestsOf(thread).findLast( + (link) => + link.source === "created" && + (link.snapshot === null || link.snapshot.headBranch === thread.branch), + ) + : undefined; + const branchPullRequest = thread.branchPullRequest ?? opened ?? null; const branchRepository = project.repositoryIdentity == null ? undefined @@ -301,6 +302,11 @@ const make = Effect.gen(function* () { repository: target.repository, number: target.number, }; + if (input.number === undefined && opened !== undefined && opened.snapshot === null) { + // Not synced yet, so only the host knows which branch it was opened from. + const summary = yield* pullRequests.summary(ref).pipe(Effect.mapError(forgeFailure)); + if (summary.headBranch !== thread.branch) return yield* new PullRequestBranchHasNoneError(); + } return { thread, project, target, ref }; }); From f0f0837de7ca64c4babd7447be676cd1dd15ee81 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 09:39:58 -0800 Subject: [PATCH 15/23] feat(server): PR tools page long conversations and lists, and GitManager drafts new PRs pull_request_read now pages a long conversation: one `cursor` input continues whichever section returned it (diff or conversation), and each returned review thread includes its later comments. pull_request_list takes the `cursor` its last result returned. GitManager.createPullRequest takes `draft` and drafts the PR it opened, so the MCP handler only opens and links, like the UI's create flow. Tool descriptions are shorter, and three evals check that agents list, edit, and check CI through the tools instead of gh or cafe. Co-Authored-By: Claude Opus 5.5 --- apps/server/src/git/GitManager.test.ts | 33 ++- apps/server/src/git/GitManager.ts | 38 ++++ .../toolkits/pullRequests/handlers.test.ts | 153 +++++++------ .../src/mcp/toolkits/pullRequests/handlers.ts | 203 ++++++++++++++---- .../src/mcp/toolkits/pullRequests/tools.ts | 31 ++- .../ProviderTurnStartService.testkit.ts | 2 + apps/server/src/server.ts | 1 + evals/mcp-tool-use/cases/pull-requests.ndjson | 3 + evals/mcp-tool-use/run.ts | 2 + 9 files changed, 352 insertions(+), 114 deletions(-) diff --git a/apps/server/src/git/GitManager.test.ts b/apps/server/src/git/GitManager.test.ts index fdec239e23ef0..f1ecf78cdef06 100644 --- a/apps/server/src/git/GitManager.test.ts +++ b/apps/server/src/git/GitManager.test.ts @@ -1,6 +1,6 @@ import * as BackgroundPolicy from "../background/BackgroundPolicy.ts"; import * as VcsStatusBroadcaster from "../vcs/VcsStatusBroadcaster.ts"; -import { SourceControlProviderKind } from "@t3tools/contracts"; +import { type PullRequestActionInput, SourceControlProviderKind } from "@t3tools/contracts"; // @effect-diagnostics nodeBuiltinImport:off import * as NodeFS from "node:fs"; import * as NodePath from "node:path"; @@ -61,6 +61,7 @@ import * as SourceControlProviderRegistry from "../sourceControl/SourceControlPr import * as ServerConfig from "../config.ts"; import * as ProjectionStore from "../orchestration-v2/ProjectionStore.ts"; import * as ProjectStore from "../orchestration-v2/ProjectStore.ts"; +import * as PullRequestService from "../pullRequest/PullRequestService.ts"; import * as SqlitePersistence from "../persistence/Sqlite.ts"; import * as ProjectSetupScriptRunner from "../project/ProjectSetupScriptRunner.ts"; import * as ProviderRegistry from "../provider/ProviderRegistry.ts"; @@ -623,6 +624,7 @@ function preparePullRequestThread( function makeManager(input?: { providerScenario?: FakeProviderScenario; + pullRequests?: Partial; sourceControlProvider?: SourceControlProvider["Service"]; textGeneration?: Partial; serverSettings?: Parameters[0]; @@ -731,6 +733,7 @@ function makeManager(input?: { const layerManager = Layer.mergeAll( Layer.succeed(TextGeneration.TextGeneration, textGeneration), + Layer.mock(PullRequestService.PullRequestService)(input?.pullRequests ?? {}), Layer.mock(ProviderRegistry.ProviderRegistry)({ getProviders: Effect.succeed([]), }), @@ -4156,7 +4159,12 @@ it.layer(layerGitManagerTest)("GitManager", (it) => { }); const error = yield* Effect.flip( - manager.createPullRequest({ cwd: repoDir, title: "Feature", body: "Body" }), + manager.createPullRequest({ + cwd: repoDir, + projectId: ProjectId.make("project-1"), + title: "Feature", + body: "Body", + }), ); expect(error.message).toContain("1 unpushed commit"); @@ -4173,10 +4181,31 @@ it.layer(layerGitManagerTest)("GitManager", (it) => { const existing = yield* makeManager({ providerScenario: { prListSequence: [[open]] } }); const found = yield* existing.manager.createPullRequest({ cwd: repoDir, + projectId: ProjectId.make("project-1"), title: "Feature", body: "Body", }); expect(found).toMatchObject({ status: "opened_existing", number: 7 }); + + // A retry after a failed draft finds the open PR and still drafts it. + const actions: Array = []; + const retried = yield* makeManager({ + providerScenario: { prListSequence: [[open]] }, + pullRequests: { + summary: () => Effect.succeed({ isDraft: false } as never), + runAction: (action) => Effect.sync(() => void actions.push(action)), + }, + }); + yield* retried.manager.createPullRequest({ + cwd: repoDir, + projectId: ProjectId.make("project-1"), + title: "Feature", + body: "Body", + draft: true, + }); + expect(actions).toMatchObject([ + { repository: "pingdotgg/codething-mvp", number: 7, action: "draft" }, + ]); }), ); diff --git a/apps/server/src/git/GitManager.ts b/apps/server/src/git/GitManager.ts index a691fce266d64..9310fbad0d3f8 100644 --- a/apps/server/src/git/GitManager.ts +++ b/apps/server/src/git/GitManager.ts @@ -80,6 +80,8 @@ import { import * as ProjectionStore from "../orchestration-v2/ProjectionStore.ts"; import * as ProjectStore from "../orchestration-v2/ProjectStore.ts"; import * as ProjectSetupScriptRunner from "../project/ProjectSetupScriptRunner.ts"; +import * as PullRequestService from "../pullRequest/PullRequestService.ts"; +import { createdPullRequestKey } from "./linkCreatedPullRequest.ts"; import * as ProviderRegistry from "../provider/ProviderRegistry.ts"; import { extractBranchNameFromRemoteRef } from "./remoteRefs.ts"; import { detachStackFrame } from "./detachStackFrame.ts"; @@ -181,9 +183,11 @@ export class GitManager extends Context.Service< /** Opens a PR for the checkout's pushed branch, or returns the one already open. */ readonly createPullRequest: (input: { readonly cwd: string; + readonly projectId: ProjectId; readonly title: string; readonly body: string; readonly baseBranch?: string | undefined; + readonly draft?: boolean | undefined; }) => Effect.Effect; readonly subscribePullRequestStateChanges: Effect.Effect< Stream.Stream, @@ -708,6 +712,7 @@ export const make = Effect.gen(function* () { ); }); const serverSettingsService = yield* ServerSettings.ServerSettingsService; + const pullRequests = yield* PullRequestService.PullRequestService; const threads = yield* ProjectionStore.ProjectionStoreV2; const projects = yield* ProjectStore.ProjectStoreV2; const projectSettingsFor = Effect.fnUntraced(function* (input: { @@ -2540,9 +2545,42 @@ export const make = Effect.gen(function* () { ); // The thread's branch PR comes from status, which may hold the lookup from before. if (result.status === "created") yield* invalidateStatus(input.cwd); + if (input.draft === true) yield* draftOpened(input, result); return result; }); + /** A retry after a failed draft finds the PR it opened, so an open one is checked too. */ + const draftOpened = Effect.fn("GitManager.draftOpened")( + function* ( + input: { readonly cwd: string; readonly projectId: ProjectId }, + result: GitCreatePullRequestResult, + ) { + const project = yield* projects.getShell(input.projectId).pipe( + Effect.map(Option.getOrUndefined), + Effect.orElseSucceed(() => undefined), + ); + const key = createdPullRequestKey({ pr: result }, project); + if (key === null) return; + const ref = { projectId: input.projectId, ...key }; + const isDraft = + result.status === "opened_existing" && + (yield* pullRequests.summary({ ...ref, allowStale: false })).isDraft; + if (!isDraft) yield* pullRequests.runAction({ ...ref, action: "draft" }); + }, + (effect, input) => + effect.pipe( + Effect.mapError( + (cause) => + new GitManagerError({ + operation: "createPullRequest", + cwd: input.cwd, + detail: `Opened the pull request, but could not make it a draft: ${cause.message}`, + cause, + }), + ), + ), + ); + const localStatus: GitManager["Service"]["localStatus"] = Effect.fn("localStatus")( function* (input) { const cacheKey = yield* normalizeStatusCacheKey(input.cwd); diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts index 0bce0afcd39e3..1afa65acea9ca 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts @@ -8,6 +8,7 @@ import { type OrchestrationProjectShell, type PullRequestActionInput, type PullRequestActivity, + type PullRequestListInput, type PullRequestDetail, type PullRequestRef, type PullRequestReviewGuideResult, @@ -786,6 +787,70 @@ describe("source control tools", () => { }), ); + it.effect("pages a long conversation and the PR list through the cursors they return", () => + Effect.gen(function* () { + const comment = (body: string) => + ({ id: body.slice(0, 8), author: null, body, createdAt: "2026-11-01T00:00:00Z" }) as never; + const long = (id: string) => ({ + ...reviewThread(id, false), + comments: [comment("x".repeat(20_000))], + }); + const listed: Array = []; + const harness = yield* makeHarness({ + thread: branchThread, + pullRequests: { + activity: () => + Effect.succeed({ + ...activity, + reviewThreads: [ + { ...long("first"), nextCommentsCursor: "later" }, + long("second"), + reviewThread("done-thread", true), + ], + }), + threadComments: (input) => + Effect.succeed( + input.cursor === "later" + ? { comments: [comment("reply")], nextCursor: null } + : { comments: [], nextCursor: null }, + ), + list: (input) => + Effect.sync(() => listed.push(input)).pipe( + Effect.as({ + viewers: {}, + providers: [], + entries: [], + errors: [], + truncated: input.cursors === undefined, + nextCursors: input.cursors === undefined ? { "t3tools/t3code": "page-2" } : {}, + }), + ), + }, + }); + const first = yield* harness.call("pull_request_read", { sections: ["conversation"] }); + expect(first.conversation?.reviewThreads).toMatchObject([ + { id: "first", moreComments: false, comments: [{}, { body: "reply" }] }, + ]); + const cursor = first.conversation?.nextCursor; + expect(cursor).toEqual(expect.any(String)); + const second = yield* harness.call("pull_request_read", { cursor: cursor! }); + expect(second.summary).toBeUndefined(); + expect(second.conversation?.reviewThreads.map((thread) => thread.id)).toEqual(["second"]); + expect(second.conversation?.nextCursor).toBeNull(); + + const page = yield* harness.call("pull_request_list", {}); + yield* harness.call("pull_request_list", { cursor: page.nextCursor! }); + expect(listed.map((input) => input.cursors)).toEqual([ + undefined, + { "t3tools/t3code": "page-2" }, + ]); + const invalid = yield* harness + .call("pull_request_read", { cursor: "not-a-cursor" }) + .pipe(Effect.flip); + expect(invalid._tag).toBe("PullRequestCursorInvalidError"); + }), + ); + it.effect("asks for a number when the thread's branch has no PR", () => Effect.gen(function* () { const harness = yield* makeHarness(); @@ -855,73 +920,39 @@ describe("source control tools", () => { }), ); - it.effect( - "opens a PR from the thread's worktree, links it even if dismissed, and drafts it", - () => - Effect.gen(function* () { - const actions: Array = []; - const opened: Array = []; - const harness = yield* makeHarness({ - thread: { - ...makeThread([makeLink(43, { source: "stack-dismissed" })]), - worktreePath: "/workspace/worktree", - }, - git: { - createPullRequest: (input) => - Effect.sync(() => opened.push(input.cwd)).pipe( - Effect.as({ - status: "created" as const, - url: "https://github.com/t3tools/t3code/pull/43", - number: 43, - baseBranch: "main", - headBranch: "tools", - title: input.title, - }), - ), - }, - pullRequests: { runAction: (input) => Effect.sync(() => void actions.push(input)) }, - }); - const result = yield* harness.call("pull_request_create", { - title: "Add tools", - body: "Adds tools.", - draft: true, - }); - expect(result).toMatchObject({ number: 43, created: true }); - expect(opened).toEqual(["/workspace/worktree"]); - expect(actions).toMatchObject([{ number: 43, action: "draft" }]); - expect(yield* Ref.get(harness.commands)).toMatchObject([ - { type: "thread.pull-request.link", number: 43, source: "created" }, - ]); - - // A retry after a failed draft finds the open PR and still drafts it. - const retried = yield* makeHarness({ - thread: { ...makeThread([]), worktreePath: "/workspace/worktree" }, - git: { - createPullRequest: (input) => - Effect.succeed({ - status: "opened_existing" as const, + it.effect("opens a PR from the thread's worktree and links it even if dismissed", () => + Effect.gen(function* () { + const opened: Array<{ readonly cwd: string; readonly draft: boolean | undefined }> = []; + const harness = yield* makeHarness({ + thread: { + ...makeThread([makeLink(43, { source: "stack-dismissed" })]), + worktreePath: "/workspace/worktree", + }, + git: { + createPullRequest: (input) => + Effect.sync(() => opened.push({ cwd: input.cwd, draft: input.draft })).pipe( + Effect.as({ + status: "created" as const, url: "https://github.com/t3tools/t3code/pull/43", number: 43, baseBranch: "main", headBranch: "tools", title: input.title, }), - }, - pullRequests: { - summary: () => Effect.succeed({ state: "open", isDraft: false } as never), - runAction: (input) => Effect.sync(() => void actions.push(input)), - }, - }); - yield* retried.call("pull_request_create", { - title: "Add tools", - body: "Adds tools.", - draft: true, - }); - expect(actions).toMatchObject([ - { number: 43, action: "draft" }, - { number: 43, action: "draft" }, - ]); - }), + ), + }, + }); + const result = yield* harness.call("pull_request_create", { + title: "Add tools", + body: "Adds tools.", + draft: true, + }); + expect(result).toMatchObject({ number: 43, created: true }); + expect(opened).toEqual([{ cwd: "/workspace/worktree", draft: true }]); + expect(yield* Ref.get(harness.commands)).toMatchObject([ + { type: "thread.pull-request.link", number: 43, source: "created" }, + ]); + }), ); it.effect("replies to and resolves a review thread, and refuses resolving without one", () => diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts index 5936ba93e2511..8892b644b98d5 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts @@ -1,15 +1,22 @@ import { CommandId, + NonNegativeInt, + type PullRequestActivity, + PullRequestListCursors, type PullRequestRef, + type PullRequestReviewThread, type OrchestrationProjectShell, type OrchestrationV2ThreadShell, type ThreadId, type ThreadPullRequestLink, + TrimmedNonEmptyString, } from "@t3tools/contracts"; import * as Cause from "effect/Cause"; import * as SecureRandom from "effect/crypto/SecureRandom"; import * as Effect from "effect/Effect"; +import * as Base64Url from "effect/encoding/Base64Url"; import * as Option from "effect/Option"; +import * as Schema from "effect/Schema"; import * as GitManager from "../../../git/GitManager.ts"; import * as Orchestrator from "../../../orchestration-v2/Orchestrator.ts"; @@ -34,6 +41,7 @@ import { threadNotFound } from "../../threadAccess.ts"; import { type ListThreadPullRequestsResult, PullRequestBranchHasNoneError, + PullRequestCursorInvalidError, PullRequestForgeError, PullRequestNothingToDoError, type PullRequestReadSection, @@ -51,6 +59,85 @@ import { CHILD_PULL_REQUEST_REPORT_NEXT, } from "./tools.ts"; +const ReadCursor = Schema.Union([ + Schema.Struct({ diff: TrimmedNonEmptyString }), + Schema.Struct({ + threads: NonNegativeInt, + comments: NonNegativeInt, + includeResolved: Schema.Boolean, + }), +]); +type ReadCursor = typeof ReadCursor.Type; + +const ReadCursorJson = Schema.fromJsonString(ReadCursor); +const ListCursorsJson = Schema.fromJsonString(PullRequestListCursors); +const encodeReadCursorJson = Schema.encodeSync(ReadCursorJson); +const encodeListCursorsJson = Schema.encodeSync(ListCursorsJson); +const decodeReadCursorJson = Schema.decodeUnknownEffect(ReadCursorJson); +const decodeListCursorsJson = Schema.decodeUnknownEffect(ListCursorsJson); + +const decodeCursorText = (cursor: string) => + Effect.fromResult(Base64Url.decodeString(cursor)).pipe( + Effect.mapError(() => new PullRequestCursorInvalidError({})), + ); + +const readCursors = { + encode: (value: ReadCursor) => Base64Url.encode(encodeReadCursorJson(value)), + decode: (cursor: string) => + decodeCursorText(cursor).pipe( + Effect.flatMap(decodeReadCursorJson), + Effect.mapError(() => new PullRequestCursorInvalidError({})), + ), +}; + +const listCursors = { + encode: (value: PullRequestListCursors) => Base64Url.encode(encodeListCursorsJson(value)), + decode: (cursor: string) => + decodeCursorText(cursor).pipe( + Effect.flatMap(decodeListCursorsJson), + Effect.mapError(() => new PullRequestCursorInvalidError({})), + ), +}; + +/** Keeps one conversation page near the size of a capped CI log. */ +const CONVERSATION_PAGE_CHARS = 32_000; +const THREAD_COMMENT_PAGES = 4; + +function conversationPage( + activity: PullRequestActivity, + start: { readonly threads: number; readonly comments: number }, + includeResolved: boolean, +) { + const threads = activity.reviewThreads.filter((thread) => includeResolved || !thread.isResolved); + const pageThreads: Array = []; + const pageComments: Array = []; + let size = 0; + let thread = start.threads; + let comment = start.comments; + const fits = (item: unknown) => { + const next = size + JSON.stringify(item).length; + if (next > CONVERSATION_PAGE_CHARS && pageThreads.length + pageComments.length > 0) { + return false; + } + size = next; + return true; + }; + // Review threads come first: they hold the feedback an agent acts on. + while (thread < threads.length && fits(threads[thread])) pageThreads.push(threads[thread++]!); + if (thread === threads.length) { + while (comment < activity.comments.length && fits(activity.comments[comment])) { + pageComments.push(activity.comments[comment++]!); + } + } + const done = thread === threads.length && comment === activity.comments.length; + return { + threads: pageThreads, + comments: pageComments, + hiddenResolvedThreads: includeResolved ? 0 : activity.reviewThreads.length - threads.length, + next: done ? null : { threads: thread, comments: comment, includeResolved }, + }; +} + function entryOf( link: ThreadPullRequestLink, chains: ReturnType, @@ -317,13 +404,32 @@ const make = Effect.gen(function* () { url: target.url, }); + /** The thread's comments past its first page, when the host pages them. */ + const restOfThread = Effect.fn("PullRequestsToolkit.restOfThread")(function* ( + ref: PullRequestRef, + thread: PullRequestReviewThread, + ) { + const comments: Array = []; + let cursor = thread.nextCommentsCursor; + for (let page = 0; cursor !== undefined && page < THREAD_COMMENT_PAGES; page += 1) { + const read = yield* pullRequests + .threadComments({ ...ref, threadId: thread.id, cursor }) + .pipe(Effect.option); + if (Option.isNone(read)) break; + comments.push(...read.value.comments); + cursor = read.value.nextCursor ?? undefined; + } + return { comments, moreComments: cursor !== undefined }; + }); + const readSections = Effect.fn("PullRequestsToolkit.readSections")(function* ( ref: PullRequestRef, sections: ReadonlyArray, includeResolved: boolean, - diffCursor: string | undefined, + cursor: ReadCursor | undefined, ) { const wants = (section: PullRequestReadSection) => sections.includes(section); + const diffCursor = cursor !== undefined && "diff" in cursor ? cursor.diff : undefined; const [detail, activity, diff] = yield* Effect.all( [ // Agents pin merges to this headSha, so it must not come from a stale snapshot. @@ -339,6 +445,18 @@ const make = Effect.gen(function* () { ], { concurrency: "unbounded" }, ).pipe(Effect.mapError(forgeFailure)); + const page = Option.map(activity, (value) => + conversationPage( + value, + cursor !== undefined && "threads" in cursor ? cursor : { threads: 0, comments: 0 }, + includeResolved, + ), + ); + const threadRests = Option.isSome(page) + ? yield* Effect.forEach(page.value.threads, (thread) => restOfThread(ref, thread), { + concurrency: 4, + }) + : []; const result: Omit = { ...(Option.isSome(detail) && wants("summary") ? { @@ -363,10 +481,10 @@ const make = Effect.gen(function* () { } : {}), ...(Option.isSome(detail) && wants("checks") ? { checks: detail.value.checks } : {}), - ...(Option.isSome(activity) + ...(Option.isSome(activity) && Option.isSome(page) ? { conversation: { - comments: activity.value.comments.map((comment) => ({ + comments: page.value.comments.map((comment) => ({ id: comment.id, kind: comment.kind, author: comment.author?.login ?? null, @@ -375,26 +493,23 @@ const make = Effect.gen(function* () { path: comment.path, reviewState: comment.reviewState, })), - reviewThreads: activity.value.reviewThreads - .filter((thread) => includeResolved || !thread.isResolved) - .map((thread) => ({ - id: thread.id, - path: thread.path, - line: thread.line, - isResolved: thread.isResolved, - isOutdated: thread.isOutdated, - comments: thread.comments.map((comment) => ({ - author: comment.author?.login ?? null, - body: comment.body, - createdAt: comment.createdAt, - })), - moreComments: thread.nextCommentsCursor !== undefined, + reviewThreads: page.value.threads.map((thread, index) => ({ + id: thread.id, + path: thread.path, + line: thread.line, + isResolved: thread.isResolved, + isOutdated: thread.isOutdated, + comments: [...thread.comments, ...threadRests[index]!.comments].map((comment) => ({ + author: comment.author?.login ?? null, + body: comment.body, + createdAt: comment.createdAt, })), - hiddenResolvedThreads: includeResolved - ? 0 - : activity.value.reviewThreads.filter((thread) => thread.isResolved).length, + moreComments: threadRests[index]!.moreComments, + })), + hiddenResolvedThreads: page.value.hiddenResolvedThreads, truncated: activity.value.commentsTruncated || activity.value.reviewThreadsTruncated === true, + nextCursor: page.value.next === null ? null : readCursors.encode(page.value.next), }, } : {}), @@ -403,7 +518,10 @@ const make = Effect.gen(function* () { diff: { patch: diff.value.patch, truncated: diff.value.truncated, - nextCursor: diff.value.nextCursor, + nextCursor: + diff.value.nextCursor === null + ? null + : readCursors.encode({ diff: diff.value.nextCursor }), }, } : {}), @@ -689,11 +807,23 @@ const make = Effect.gen(function* () { ), pull_request_read: McpToolAccess.reads((input) => Effect.gen(function* () { + const cursor = + input.cursor === undefined ? undefined : yield* readCursors.decode(input.cursor); const { target, ref } = yield* locate(input); - const sections = input.sections ?? ["summary", "checks"]; + // A cursor continues the one section it came from, with that read's options. + const sections: ReadonlyArray = + cursor === undefined + ? (input.sections ?? ["summary", "checks"]) + : "diff" in cursor + ? ["diff"] + : ["conversation"]; + const includeResolved = + cursor !== undefined && "includeResolved" in cursor + ? cursor.includeResolved + : input.includeResolved === true; return { ...identityOf(target), - ...(yield* readSections(ref, sections, input.includeResolved === true, input.diffCursor)), + ...(yield* readSections(ref, sections, includeResolved, cursor)), }; }), ), @@ -707,6 +837,9 @@ const make = Effect.gen(function* () { involvement: input.involvement ?? "all", limit: input.limit ?? 30, ...(input.query === undefined ? {} : { query: input.query }), + ...(input.cursor === undefined + ? {} + : { cursors: yield* listCursors.decode(input.cursor) }), }) .pipe(Effect.mapError(forgeFailure)); const failure = listed.errors[0]; @@ -728,6 +861,10 @@ const make = Effect.gen(function* () { updatedAt: entry.updatedAt, })), truncated: listed.truncated, + nextCursor: + Object.keys(listed.nextCursors).length === 0 + ? null + : listCursors.encode(listed.nextCursors), }; }), ), @@ -741,9 +878,11 @@ const make = Effect.gen(function* () { const created = yield* git .createPullRequest({ cwd: thread.worktreePath ?? project.workspaceRoot, + projectId: project.id, title: input.title, body: input.body, baseBranch: input.base, + draft: input.draft, }) .pipe(Effect.mapError(forgeFailure)); if (created.url === undefined) { @@ -754,24 +893,6 @@ const make = Effect.gen(function* () { } const target = yield* resolveTarget({ url: created.url }, project); yield* linkToThread(thread, target); - const ref = { - projectId: project.id, - host: target.host, - repository: target.repository, - number: target.number, - }; - // A retry after a failed draft finds the PR it opened, so it checks the draft state. - const needsDraft = - input.draft === true && - (created.status === "created" || - !(yield* pullRequests - .summary({ ...ref, allowStale: false }) - .pipe(Effect.mapError(forgeFailure))).isDraft); - if (needsDraft) { - yield* pullRequests - .runAction({ ...ref, action: "draft" }) - .pipe(Effect.mapError(forgeFailure)); - } return { ...identityOf(target), created: created.status === "created", diff --git a/apps/server/src/mcp/toolkits/pullRequests/tools.ts b/apps/server/src/mcp/toolkits/pullRequests/tools.ts index a9e73de82b351..fee92fc3f14bf 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/tools.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/tools.ts @@ -153,6 +153,15 @@ export class PullRequestBranchHasNoneError extends Schema.TaggedError()( + "PullRequestCursorInvalidError", + {}, +) { + override get message(): string { + return "This cursor is not from this tool. Pass a nextCursor from its last result."; + } +} + export class PullRequestNothingToDoError extends Schema.TaggedError()( "PullRequestNothingToDoError", { detail: Schema.String }, @@ -182,6 +191,7 @@ export const PullRequestToolError = Schema.Union([ PullRequestForgeError, PullRequestBranchHasNoneError, PullRequestNothingToDoError, + PullRequestCursorInvalidError, ]); export type PullRequestToolError = typeof PullRequestToolError.Type; @@ -524,6 +534,7 @@ export const ReadPullRequestResult = Schema.Struct({ ), hiddenResolvedThreads: Schema.Int, truncated: Schema.Boolean, + nextCursor: Schema.NullOr(Schema.String), }), ), diff: Schema.optional( @@ -553,6 +564,7 @@ export const ListPullRequestsResult = Schema.Struct({ }), ), truncated: Schema.Boolean, + nextCursor: Schema.NullOr(Schema.String), }); export type ListPullRequestsResult = typeof ListPullRequestsResult.Type; @@ -581,17 +593,16 @@ export const MergePullRequestResult = Schema.Struct({ export type MergePullRequestResult = typeof MergePullRequestResult.Type; const ReadPullRequestTool = Tool.make("pull_request_read", { - description: - "Read a PR in this thread's repository. Use instead of gh or cafe for PR state, checks, review comments, or diff.", + description: "Read a PR's state, checks, review comments, or diff. Use instead of gh or cafe.", parameters: Schema.Struct({ ...ThreadPullRequestInput.fields, sections: Schema.optional( Schema.Array(PullRequestReadSection).annotate({ - description: "Default: summary, checks. conversation: comments, review threads.", + description: "Default: summary, checks. conversation has review threads.", }), ), includeResolved: Schema.optional(Schema.Boolean), - diffCursor: Schema.optional(TrimmedNonEmptyString), + cursor: Schema.optional(TrimmedNonEmptyString), }), success: ReadPullRequestResult, failure: PullRequestToolError, @@ -611,6 +622,7 @@ const ListPullRequestsTool = Tool.make("pull_request_list", { involvement: Schema.optional(PullRequestInvolvement), query: Schema.optional(TrimmedNonEmptyString.check(Schema.isMaxLength(200))), limit: Schema.optional(Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 100 }))), + cursor: Schema.optional(TrimmedNonEmptyString), }), success: ListPullRequestsResult, failure: PullRequestToolError, @@ -623,8 +635,7 @@ const ListPullRequestsTool = Tool.make("pull_request_list", { .annotate(Tool.OpenWorld, true); const CreatePullRequestTool = Tool.make("pull_request_create", { - description: - "Open a PR from this thread's pushed branch and link it. Returns the branch's open PR if one exists.", + description: "Open a PR from this thread's pushed branch and link it, or return its open PR.", parameters: Schema.Struct({ environmentId: OrchestratorMcpEnvironmentTarget, title: TrimmedNonEmptyString, @@ -643,7 +654,7 @@ const CreatePullRequestTool = Tool.make("pull_request_create", { .annotate(Tool.OpenWorld, true); const UpdatePullRequestTool = Tool.make("pull_request_update", { - description: "Change a PR's title or body, or mark it ready (ready=false: back to draft).", + description: "Edit a PR's title or body, or set ready (false: back to draft).", parameters: Schema.Struct({ ...ThreadPullRequestInput.fields, title: Schema.optional(TrimmedNonEmptyString), @@ -662,7 +673,7 @@ const UpdatePullRequestTool = Tool.make("pull_request_update", { const RespondToPullRequestTool = Tool.make("pull_request_respond", { description: - "Reply to a review thread from pull_request_read, resolve or reopen it, or both. Without reviewThreadId, comment on the PR.", + "Reply to, resolve, or reopen a review thread. Without reviewThreadId, comment on the PR.", parameters: Schema.Struct({ ...ThreadPullRequestInput.fields, reviewThreadId: Schema.optional(TrimmedNonEmptyString), @@ -681,14 +692,14 @@ const RespondToPullRequestTool = Tool.make("pull_request_respond", { const MergePullRequestTool = Tool.make("pull_request_merge", { description: - "Merge a PR only when asked to land it. Refuses if the head is no longer expectedHeadSha, the summary headSha you checked.", + "Merge only when asked to land. Refuses if the head moved from expectedHeadSha (summary.headSha).", parameters: Schema.Struct({ ...ThreadPullRequestInput.fields, expectedHeadSha: TrimmedNonEmptyString, method: Schema.optional(PullRequestMergeMethod), auto: Schema.optional( Schema.Boolean.annotate({ - description: "Merge once required checks pass, with any commits pushed by then.", + description: "Merge when required checks pass, including later pushes.", }), ), }), diff --git a/apps/server/src/orchestration-v2/ProviderTurnStartService.testkit.ts b/apps/server/src/orchestration-v2/ProviderTurnStartService.testkit.ts index fb3fb72fd76e3..e5b72cd9f337a 100644 --- a/apps/server/src/orchestration-v2/ProviderTurnStartService.testkit.ts +++ b/apps/server/src/orchestration-v2/ProviderTurnStartService.testkit.ts @@ -14,6 +14,7 @@ import * as SourceControlProviderRegistry from "../sourceControl/SourceControlPr import * as TextGeneration from "../textGeneration/TextGeneration.ts"; import * as ProjectionStore from "./ProjectionStore.ts"; import * as ProjectStore from "./ProjectStore.ts"; +import * as PullRequestService from "../pullRequest/PullRequestService.ts"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; @@ -52,6 +53,7 @@ export const layerRealGit = GitWorkflow.layer.pipe( Layer.mock(ProjectSetupScriptRunner.ProjectSetupScriptRunner)({}), Layer.mock(ProjectionStore.ProjectionStoreV2)({}), Layer.mock(ProjectStore.ProjectStoreV2)({}), + Layer.mock(PullRequestService.PullRequestService)({}), ServerSettings.layerTest(), ), ), diff --git a/apps/server/src/server.ts b/apps/server/src/server.ts index dae95787afe82..e24ada1b85194 100644 --- a/apps/server/src/server.ts +++ b/apps/server/src/server.ts @@ -430,6 +430,7 @@ const layerPullRequestService = PullRequestService.layer.pipe( const layerGitManager = GitManager.layer.pipe( Layer.provide(Layer.merge(ProjectionStoreV2.layer, ProjectStore.layer)), + Layer.provide(layerPullRequestService.pipe(Layer.provide(RuntimeLayer.layerProjectService))), Layer.provideMerge(RuntimeLayer.layerProjectSetupScriptRunner), Layer.provideMerge(WorktreeSetupTracker.layer), Layer.provideMerge(GitVcsDriver.layer), diff --git a/evals/mcp-tool-use/cases/pull-requests.ndjson b/evals/mcp-tool-use/cases/pull-requests.ndjson index 70a9b6024ab3d..867462b085326 100644 --- a/evals/mcp-tool-use/cases/pull-requests.ndjson +++ b/evals/mcp-tool-use/cases/pull-requests.ndjson @@ -41,3 +41,6 @@ {"id": "merge-through-gh-unpinned", "area": "pull-requests", "kind": "bad", "pattern": "merge with gh pr merge, not pinned to the reviewed head", "experience": "Agents merged with gh pr merge (215 runs), which merges whatever the head is by then and spends the user's quota.", "rule": "pull_request_merge merges only the head the agent checked", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_read": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "summary": {"title": "feat(config): read the port from the environment", "body": "Reads PORT.", "state": "open", "isDraft": false, "author": "user", "headBranch": "feat/config-const", "baseBranch": "main", "headSha": "abc1234def5678", "mergeability": "mergeable", "behindBy": 0, "autoMergeEnabled": false, "additions": 1, "deletions": 1, "changedFiles": 1, "labels": [], "reviewers": ["reviewer"]}, "checks": [{"name": "Lint", "status": "success", "description": null, "url": null}, {"name": "Test", "status": "success", "description": null, "url": null}]}, "pull_request_merge": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "state": "merged"}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Checks are green on #124 and it's approved. Merge it (squash).", "expect": {"calls": [{"tool": "pull_request_merge", "args": {"expectedHeadSha": "abc1234def5678"}}], "shellMustNot": ["\\bgh pr merge\\b", "\\bgh api\\b[^\\n]*merge"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in."} {"id": "open-pr-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "PR opened with gh pr create", "experience": "Agents opened PRs with gh pr create or cafe pr create (614 runs), often guessing --head and --repo for forks.", "rule": "pull_request_create opens the PR from the thread's pushed branch", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_create": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "created": true}}, "shellMocks": [{"match": "git push", "output": "To github.com:acme/app.git\n * [new branch] feat/config-const -> feat/config-const\nbranch 'feat/config-const' set up to track 'origin/feat/config-const'."}], "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": []}}, "prompt": "The port change is committed on feat/config-const. Push it and open a PR against main.", "expect": {"calls": [{"tool": "pull_request_create"}], "shellMustNot": ["\\bgh pr create\\b", "\\bcafe pr create\\b"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in.", "maxSteps": 10} {"id": "control-pr-status-no-merge", "area": "pull-requests", "kind": "control", "pattern": "status question with a mergeable PR", "experience": "Control: a green, approved PR and a question about it. Reading is fine; merging was not asked.", "rule": "Merge only when asked to land it", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_read": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "summary": {"title": "feat(config): read the port from the environment", "body": "Reads PORT.", "state": "open", "isDraft": false, "author": "user", "headBranch": "feat/config-const", "baseBranch": "main", "headSha": "abc1234def5678", "mergeability": "mergeable", "behindBy": 0, "autoMergeEnabled": false, "additions": 1, "deletions": 1, "changedFiles": 1, "labels": [], "reviewers": ["reviewer"]}, "checks": [{"name": "Lint", "status": "success", "description": null, "url": null}, {"name": "Test", "status": "success", "description": null, "url": null}]}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Where does #124 stand? Anything left before it can go in?", "expect": {"notCalls": ["pull_request_merge"], "shellMustNot": ["\\bgh pr merge\\b"]}, "notes": "Control for merge-through-gh-unpinned."} +{"id": "pr-checks-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "CI status read with gh pr checks", "experience": "Agents checked a PR's CI with gh pr checks, gh pr view --json statusCheckRollup, or gh run list instead of T3's PR tools.", "rule": "pull_request_read replaces gh and cafe for PR state and checks", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_read": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "summary": {"title": "feat(config): read the port from the environment", "body": "Reads PORT.", "state": "open", "isDraft": false, "author": "user", "headBranch": "feat/config-const", "baseBranch": "main", "headSha": "abc1234def5678", "mergeability": "mergeable", "behindBy": 0, "autoMergeEnabled": false, "additions": 1, "deletions": 1, "changedFiles": 1, "labels": [], "reviewers": ["reviewer"]}, "checks": [{"name": "Lint", "status": "success", "description": null, "url": null}, {"name": "Test", "status": "pending", "description": null, "url": null}]}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Is CI green on my PR yet?", "expect": {"calls": [{"tool": "pull_request_read"}], "shellMustNot": ["\\bgh (pr (checks|view|status)|run (list|view|watch)|api)\\b", "\\bcafe (pr|ci)\\b"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in."} +{"id": "pr-list-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "PR lists read with gh pr list", "experience": "Agents listed PRs with gh pr list or gh search prs, often trimming JSON with --jq, instead of T3's PR tools.", "rule": "pull_request_list replaces gh and cafe for listing PRs", "privacy": "commit-safe", "setup": {"role": "top", "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}, {"number": 125, "title": "fix(ws): back off reconnects", "headRefName": "fix/ws-backoff", "checks": []}]}}, "prompt": "Which open PRs in this repo are waiting on my review?", "expect": {"calls": [{"tool": "pull_request_list", "args": {"involvement": "reviewing"}}], "shellMustNot": ["\\bgh (pr list|search prs|api)\\b", "\\bcafe pr list\\b"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in."} +{"id": "pr-edit-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "PR edited with gh pr edit and gh pr ready", "experience": "Agents retitled PRs and marked them ready with gh pr edit and gh pr ready instead of T3's PR tools.", "rule": "pull_request_update replaces gh and cafe for editing a PR", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_update": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124"}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Retitle #124 to \"fix(config): read the port from PORT\" and mark it ready for review.", "expect": {"calls": [{"tool": "pull_request_update", "args": {"number": 124, "title": "~read the port from PORT", "ready": true}}], "shellMustNot": ["\\bgh (pr (edit|ready)|api)\\b", "\\bcafe pr (edit|ready)\\b"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in."} diff --git a/evals/mcp-tool-use/run.ts b/evals/mcp-tool-use/run.ts index 8bcf29fcf9d7f..47eaddcefebf5 100644 --- a/evals/mcp-tool-use/run.ts +++ b/evals/mcp-tool-use/run.ts @@ -1400,6 +1400,7 @@ export const t3Default = ( reviewThreads: [], hiddenResolvedThreads: 0, truncated: false, + nextCursor: null, }, } : {}), @@ -1424,6 +1425,7 @@ export const t3Default = ( updatedAt: "2026-10-27T10:00:00Z", })), truncated: false, + nextCursor: null, }; } case "pull_request_update": From 2d6167a90d2436291da87928a1392d03e2ef0b6a Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 10:02:09 -0800 Subject: [PATCH 16/23] fix(server): agent instructions point PR work at the pull_request tools, not gh or cafe Claude Code defers MCP tools, so the agent sees only their names until it searches. Without a line in the always-loaded instructions, Opus and Sonnet ran gh pr checks and gh pr list instead. Co-Authored-By: Claude Opus 5.5 --- packages/provider-core/src/server/runtimeInstructions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/provider-core/src/server/runtimeInstructions.ts b/packages/provider-core/src/server/runtimeInstructions.ts index 3a956984f3227..b9240dade6f98 100644 --- a/packages/provider-core/src/server/runtimeInstructions.ts +++ b/packages/provider-core/src/server/runtimeInstructions.ts @@ -1,6 +1,6 @@ /** Session-invariant; harnesses with a native system-prompt append can carry it once per session. */ export const PULL_REQUEST_LINKING_INSTRUCTIONS = ` -Link each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. +Link each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you. `; /** Omit model and effort when the harness manages them dynamically. */ From dc03bd27d6dd4b7c3354a6b24f2cf6bde1b67f73 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 10:29:29 -0800 Subject: [PATCH 17/23] fix(server): conversation pages stay in place when threads are resolved between reads The cursor indexed the unresolved threads, so resolving one between pages skipped the next, and an offset past the end repeated an empty page. It now indexes the full lists, which resolving does not reorder, and clamps to their end. Co-Authored-By: Claude Opus 5.5 --- .../toolkits/pullRequests/handlers.test.ts | 20 +++++++++++-- .../src/mcp/toolkits/pullRequests/handlers.ts | 28 +++++++++++++------ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts index 1afa65acea9ca..a7a0db15d1f2b 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts @@ -18,6 +18,7 @@ import { import { describe, expect, it } from "@effect/vitest"; import * as SecureRandom from "effect/crypto/SecureRandom"; import * as Effect from "effect/Effect"; +import * as Base64Url from "effect/encoding/Base64Url"; import * as Layer from "effect/Layer"; import * as Option from "effect/Option"; import * as Ref from "effect/Ref"; @@ -796,18 +797,23 @@ describe("source control tools", () => { comments: [comment("x".repeat(20_000))], }); const listed: Array = []; + let firstResolved = false; const harness = yield* makeHarness({ thread: branchThread, pullRequests: { activity: () => - Effect.succeed({ + Effect.sync(() => ({ ...activity, reviewThreads: [ - { ...long("first"), nextCommentsCursor: "later" }, + { + ...long("first"), + isResolved: firstResolved, + nextCommentsCursor: "later", + }, long("second"), reviewThread("done-thread", true), ], - }), + })), threadComments: (input) => Effect.succeed( input.cursor === "later" @@ -833,10 +839,18 @@ describe("source control tools", () => { ]); const cursor = first.conversation?.nextCursor; expect(cursor).toEqual(expect.any(String)); + // The agent resolves what it read; the next page still starts at the next thread. + firstResolved = true; const second = yield* harness.call("pull_request_read", { cursor: cursor! }); expect(second.summary).toBeUndefined(); expect(second.conversation?.reviewThreads.map((thread) => thread.id)).toEqual(["second"]); expect(second.conversation?.nextCursor).toBeNull(); + // A cursor past the current end finishes instead of repeating an empty page. + const stale = Base64Url.encode( + JSON.stringify({ threads: 99, comments: 99, includeResolved: false }), + ); + const past = yield* harness.call("pull_request_read", { cursor: stale }); + expect(past.conversation).toMatchObject({ reviewThreads: [], nextCursor: null }); const page = yield* harness.call("pull_request_list", {}); yield* harness.call("pull_request_list", { cursor: page.nextCursor! }); diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts index 8892b644b98d5..86af1811abd76 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts @@ -108,12 +108,13 @@ function conversationPage( start: { readonly threads: number; readonly comments: number }, includeResolved: boolean, ) { - const threads = activity.reviewThreads.filter((thread) => includeResolved || !thread.isResolved); + // Offsets index the unfiltered lists, whose order resolving a thread does not change. + const { reviewThreads, comments } = activity; const pageThreads: Array = []; const pageComments: Array = []; let size = 0; - let thread = start.threads; - let comment = start.comments; + let thread = Math.min(start.threads, reviewThreads.length); + let comment = Math.min(start.comments, comments.length); const fits = (item: unknown) => { const next = size + JSON.stringify(item).length; if (next > CONVERSATION_PAGE_CHARS && pageThreads.length + pageComments.length > 0) { @@ -123,17 +124,26 @@ function conversationPage( return true; }; // Review threads come first: they hold the feedback an agent acts on. - while (thread < threads.length && fits(threads[thread])) pageThreads.push(threads[thread++]!); - if (thread === threads.length) { - while (comment < activity.comments.length && fits(activity.comments[comment])) { - pageComments.push(activity.comments[comment++]!); + while (thread < reviewThreads.length) { + const next = reviewThreads[thread]!; + if (includeResolved || !next.isResolved) { + if (!fits(next)) break; + pageThreads.push(next); } + thread += 1; } - const done = thread === threads.length && comment === activity.comments.length; + if (thread === reviewThreads.length) { + while (comment < comments.length && fits(comments[comment])) { + pageComments.push(comments[comment++]!); + } + } + const done = thread === reviewThreads.length && comment === comments.length; return { threads: pageThreads, comments: pageComments, - hiddenResolvedThreads: includeResolved ? 0 : activity.reviewThreads.length - threads.length, + hiddenResolvedThreads: includeResolved + ? 0 + : reviewThreads.filter((candidate) => candidate.isResolved).length, next: done ? null : { threads: thread, comments: comment, includeResolved }, }; } From 986a3b1ead8e6e934b1b31f7b4903c3fa231f7a3 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 10:47:26 -0800 Subject: [PATCH 18/23] fix(server): a draft request fails when the host does not list the new PR yet Returning success left the PR open as ready. Failing lets a retry find it and draft it. Co-Authored-By: Claude Opus 5.5 --- apps/server/src/git/GitManager.test.ts | 15 +++++++++++++++ apps/server/src/git/GitManager.ts | 12 ++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/apps/server/src/git/GitManager.test.ts b/apps/server/src/git/GitManager.test.ts index f1ecf78cdef06..78811a1a38c21 100644 --- a/apps/server/src/git/GitManager.test.ts +++ b/apps/server/src/git/GitManager.test.ts @@ -4206,6 +4206,21 @@ it.layer(layerGitManagerTest)("GitManager", (it) => { expect(actions).toMatchObject([ { repository: "pingdotgg/codething-mvp", number: 7, action: "draft" }, ]); + + // A draft of a PR the host does not list yet fails, so a retry drafts it. + yield* runGit(repoDir, ["push"]); + const unlisted = yield* makeManager({ providerScenario: { prListSequence: [[], []] } }); + const notListed = yield* Effect.flip( + unlisted.manager.createPullRequest({ + cwd: repoDir, + projectId: ProjectId.make("project-1"), + title: "Feature", + body: "Body", + draft: true, + }), + ); + expect(notListed.message).toContain("does not list it yet"); + expect(created(unlisted.providerCalls)).toHaveLength(1); }), ); diff --git a/apps/server/src/git/GitManager.ts b/apps/server/src/git/GitManager.ts index 9310fbad0d3f8..adf9f18bb9db6 100644 --- a/apps/server/src/git/GitManager.ts +++ b/apps/server/src/git/GitManager.ts @@ -2545,7 +2545,14 @@ export const make = Effect.gen(function* () { ); // The thread's branch PR comes from status, which may hold the lookup from before. if (result.status === "created") yield* invalidateStatus(input.cwd); - if (input.draft === true) yield* draftOpened(input, result); + if (input.draft === true && !(yield* draftOpened(input, result))) { + // A retry finds the open PR and drafts it then. + return yield* new GitManagerError({ + operation: "createPullRequest", + cwd: input.cwd, + detail: "Opened the pull request, but the host does not list it yet to make it a draft.", + }); + } return result; }); @@ -2560,12 +2567,13 @@ export const make = Effect.gen(function* () { Effect.orElseSucceed(() => undefined), ); const key = createdPullRequestKey({ pr: result }, project); - if (key === null) return; + if (key === null) return false; const ref = { projectId: input.projectId, ...key }; const isDraft = result.status === "opened_existing" && (yield* pullRequests.summary({ ...ref, allowStale: false })).isDraft; if (!isDraft) yield* pullRequests.runAction({ ...ref, action: "draft" }); + return true; }, (effect, input) => effect.pipe( From 154c29457639d5bb78c979bfc9a860041de3cb9c Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Wed, 11 Nov 2026 11:01:55 -0800 Subject: [PATCH 19/23] test(server): Muse replay fixtures carry the PR instructions' new sentence Co-Authored-By: Claude Opus 5.5 --- .../fixtures/multi_turn/muse_transcript.ndjson | 12 ++++++------ .../fixtures/muse_permission/muse_transcript.ndjson | 12 ++++++------ .../muse_subagent_approval/muse_transcript.ndjson | 6 +++--- .../muse_subagent_interrupt/muse_transcript.ndjson | 6 +++--- .../fixtures/muse_workflow/muse_transcript.ndjson | 6 +++--- .../testkit/fixtures/simple/muse_transcript.ndjson | 6 +++--- .../fixtures/subagent_v2/muse_transcript.ndjson | 6 +++--- .../fixtures/turn_interrupt/muse_transcript.ndjson | 6 +++--- 8 files changed, 30 insertions(+), 30 deletions(-) diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/muse_transcript.ndjson index 7cbdf94598d01..d261df1692b0a 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6b-707e-7000-9bb5-4079c7772ad0/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:30:11.238412Z","updatedAt":"2026-10-08T07:30:11.238416Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791444611408}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6b-707e-7000-9bb5-4079c7772ad0/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:30:11.238412Z","updatedAt":"2026-10-08T07:30:11.238416Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:1","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"37b19bd1-b212-4532-a0c9-a6677f303e26","sequence":5},"last":{"id":"37b19bd1-b212-4532-a0c9-a6677f303e26","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a11a6b-707e-7001-b2f4-23db74e60097","clientName":"t3_code"},"emittedAtMs":1791444611412}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\n"},{"type":"text","text":"Respond with exactly: first fixture turn complete"}],"displayText":"Respond with exactly: first fixture turn complete","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Respond with exactly: first fixture turn complete"}],"displayText":"Respond with exactly: first fixture turn complete","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:2","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"2c530748-943b-4467-8473-da8b04c511c3","sequence":16},"last":{"id":"2c530748-943b-4467-8473-da8b04c511c3","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444611661}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","status":"accepted","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","status":"running","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:3"},"emittedAtMs":1791444611674}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:3","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18},"last":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18}},"turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"},"emittedAtMs":1791444611675}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18},"last":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18}},"item":{"itemId":"1b470279-ee8c-4c74-a298-f37184145584","kind":"userMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":1,"status":"completed","recordedAt":"2026-10-08T07:30:11.66263Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nRespond with exactly: first fixture turn complete","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}},"emittedAtMs":1791444611675}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"31b500d6-40fc-4f4c-b097-6b7be8d77cee","sequence":20},"last":{"id":"31b500d6-40fc-4f4c-b097-6b7be8d77cee","sequence":20}},"item":{"itemId":"1b470279-ee8c-4c74-a298-f37184145584","kind":"userMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":2,"status":"completed","recordedAt":"2026-10-08T07:30:11.680942Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nRespond with exactly: first fixture turn complete","displayText":"Respond with exactly: first fixture turn complete","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}},"emittedAtMs":1791444611689}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18},"last":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18}},"item":{"itemId":"1b470279-ee8c-4c74-a298-f37184145584","kind":"userMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":1,"status":"completed","recordedAt":"2026-10-08T07:30:11.66263Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: first fixture turn complete","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}},"emittedAtMs":1791444611675}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"31b500d6-40fc-4f4c-b097-6b7be8d77cee","sequence":20},"last":{"id":"31b500d6-40fc-4f4c-b097-6b7be8d77cee","sequence":20}},"item":{"itemId":"1b470279-ee8c-4c74-a298-f37184145584","kind":"userMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":2,"status":"completed","recordedAt":"2026-10-08T07:30:11.680942Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: first fixture turn complete","displayText":"Respond with exactly: first fixture turn complete","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}},"emittedAtMs":1791444611689}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:6","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"077780ea-0dc9-4d7a-879c-ee368f3adbe0","sequence":37},"last":{"id":"077780ea-0dc9-4d7a-879c-ee368f3adbe0","sequence":37}},"item":{"itemId":"077780ea-0dc9-4d7a-879c-ee368f3adbe0","kind":"reminderChild","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:30:11.790301Z","fallbackText":"Reminder child session","childSessionId":"c13379db-6761-40b4-a974-b0f1a58717aa","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6b-72ac-7972-a1df-b343b7804b38"}},"emittedAtMs":1791444611795}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:6.1","item":{"itemId":"f99b90e1-9d8b-4bf2-8e7a-e240e1cf9321","kind":"agentMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":1,"status":"inProgress","text":""}},"emittedAtMs":1791444618068}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:6.2","itemId":"f99b90e1-9d8b-4bf2-8e7a-e240e1cf9321","field":"text","delta":"first fixture turn complete"},"emittedAtMs":1791444618068}} @@ -29,12 +29,12 @@ {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","status":"idle","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:16"},"emittedAtMs":1791444621046}} {"type":"emit_inbound","label":"turn/completed","frame":{"jsonrpc":"2.0","method":"turn/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:16","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"688a69c5-e353-4db9-bd8c-1beb033902ba","sequence":79},"last":{"id":"688a69c5-e353-4db9-bd8c-1beb033902ba","sequence":79}},"turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","terminal":"completed","durationMs":9378,"timeToFirstTokenMs":6406},"emittedAtMs":1791444621047}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:17","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"36753b8a-26ce-4935-8127-bc9191cb328b","sequence":80},"last":{"id":"36753b8a-26ce-4935-8127-bc9191cb328b","sequence":80}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444621054}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":4,"method":"turn/start","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\n"},{"type":"text","text":"Respond with exactly: second fixture turn complete"}],"displayText":"Respond with exactly: second fixture turn complete","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":4,"method":"turn/start","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Respond with exactly: second fixture turn complete"}],"displayText":"Respond with exactly: second fixture turn complete","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":4,"result":{"commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","status":"accepted","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","status":"running","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:18"},"emittedAtMs":1791444621333}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:18","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87},"last":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87}},"turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"},"emittedAtMs":1791444621334}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:19","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87},"last":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87}},"item":{"itemId":"90719a5d-d2c1-46dc-ad4d-274adda02344","kind":"userMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":1,"status":"completed","recordedAt":"2026-10-08T07:30:21.321391Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nRespond with exactly: second fixture turn complete","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}},"emittedAtMs":1791444621334}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:20","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"dc502e2c-d81c-4f0e-ad86-dd11d1368677","sequence":89},"last":{"id":"dc502e2c-d81c-4f0e-ad86-dd11d1368677","sequence":89}},"item":{"itemId":"90719a5d-d2c1-46dc-ad4d-274adda02344","kind":"userMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":2,"status":"completed","recordedAt":"2026-10-08T07:30:21.338944Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nRespond with exactly: second fixture turn complete","displayText":"Respond with exactly: second fixture turn complete","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}},"emittedAtMs":1791444621347}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:19","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87},"last":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87}},"item":{"itemId":"90719a5d-d2c1-46dc-ad4d-274adda02344","kind":"userMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":1,"status":"completed","recordedAt":"2026-10-08T07:30:21.321391Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: second fixture turn complete","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}},"emittedAtMs":1791444621334}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:20","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"dc502e2c-d81c-4f0e-ad86-dd11d1368677","sequence":89},"last":{"id":"dc502e2c-d81c-4f0e-ad86-dd11d1368677","sequence":89}},"item":{"itemId":"90719a5d-d2c1-46dc-ad4d-274adda02344","kind":"userMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":2,"status":"completed","recordedAt":"2026-10-08T07:30:21.338944Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: second fixture turn complete","displayText":"Respond with exactly: second fixture turn complete","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}},"emittedAtMs":1791444621347}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:21","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"09cb4c2a-03c2-4089-ba12-8d5d31f7ea48","sequence":106},"last":{"id":"09cb4c2a-03c2-4089-ba12-8d5d31f7ea48","sequence":106}},"item":{"itemId":"09cb4c2a-03c2-4089-ba12-8d5d31f7ea48","kind":"reminderChild","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:30:21.446966Z","fallbackText":"Reminder child session","childSessionId":"cd97261a-3ea9-480f-9e54-5e59bb077da2","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6b-9869-7061-a4f3-42daa3e3a8f1"}},"emittedAtMs":1791444621455}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:21.1","item":{"itemId":"2de26c0d-26b4-4533-8810-918ee44fcd82","kind":"agentMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":1,"status":"inProgress","text":""}},"emittedAtMs":1791444623127}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:21.2","itemId":"2de26c0d-26b4-4533-8810-918ee44fcd82","field":"text","delta":"second fixture turn complete"},"emittedAtMs":1791444623127}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/muse_permission/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/muse_permission/muse_transcript.ndjson index e2861e91dbf31..96d6717846b38 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/muse_permission/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/muse_permission/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6d-39bb-7000-8c93-4594c98e6a11/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:32:08.30084Z","updatedAt":"2026-10-08T07:32:08.300844Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"promptUnmatched","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791444728496}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6d-39bb-7000-8c93-4594c98e6a11/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:32:08.30084Z","updatedAt":"2026-10-08T07:32:08.300844Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"promptUnmatched","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:1","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b05fb8ec-7b58-4cf7-a369-379938395230","sequence":5},"last":{"id":"b05fb8ec-7b58-4cf7-a369-379938395230","sequence":5}},"mode":"promptUnmatched","source":"approvalReconfigure","commandId":"01a11a6d-39bb-7001-923e-425cc6129ce7","clientName":"t3_code"},"emittedAtMs":1791444728501}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\n"},{"type":"text","text":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE."}],"displayText":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE."}],"displayText":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:2","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"6159e84a-ae1e-4fae-ae8b-49f41ca34509","sequence":16},"last":{"id":"6159e84a-ae1e-4fae-ae8b-49f41ca34509","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444728769}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","status":"accepted","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","status":"running","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:3"},"emittedAtMs":1791444728783}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:3","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18},"last":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18}},"turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"},"emittedAtMs":1791444728783}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18},"last":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18}},"item":{"itemId":"dde9573b-650f-434b-ab99-60cfc820a0a5","kind":"userMessage","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:08.769894Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nRun the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}},"emittedAtMs":1791444728784}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"76c57706-1378-4167-8bbf-f76d959804e8","sequence":20},"last":{"id":"76c57706-1378-4167-8bbf-f76d959804e8","sequence":20}},"item":{"itemId":"dde9573b-650f-434b-ab99-60cfc820a0a5","kind":"userMessage","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:08.791728Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nRun the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","displayText":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}},"emittedAtMs":1791444728800}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18},"last":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18}},"item":{"itemId":"dde9573b-650f-434b-ab99-60cfc820a0a5","kind":"userMessage","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:08.769894Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}},"emittedAtMs":1791444728784}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"76c57706-1378-4167-8bbf-f76d959804e8","sequence":20},"last":{"id":"76c57706-1378-4167-8bbf-f76d959804e8","sequence":20}},"item":{"itemId":"dde9573b-650f-434b-ab99-60cfc820a0a5","kind":"userMessage","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:08.791728Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","displayText":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}},"emittedAtMs":1791444728800}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:6","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"29180105-84c4-4f9e-8bfd-003392b93b73","sequence":38},"last":{"id":"29180105-84c4-4f9e-8bfd-003392b93b73","sequence":38}},"item":{"itemId":"29180105-84c4-4f9e-8bfd-003392b93b73","kind":"reminderChild","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:32:08.905989Z","fallbackText":"Reminder child session","childSessionId":"7c9485f9-26aa-4b56-8ca2-f36cb9cfb8c4","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6d-3c27-73f2-8c27-cd06a3b7dadf"}},"emittedAtMs":1791444728910}} {"type":"emit_inbound","label":"session/tokenUsage","frame":{"jsonrpc":"2.0","method":"session/tokenUsage","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:7","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b1dab1f5-3c9e-4d92-b955-841a2269c23c","sequence":54},"last":{"id":"b1dab1f5-3c9e-4d92-b955-841a2269c23c","sequence":54}},"turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","modelId":"muse-spark-1.3-contributor","usage":{"inputTokens":32618,"outputTokens":315,"cachedTokens":0,"cacheWriteTokens":0,"cacheReadTokens":0,"reasoningTokens":227},"promptTokens":32618,"totalTokens":32933,"finishReason":"tool_calls","durationMs":2684,"cumulative":{"promptTokens":32618,"outputTokens":315,"totalTokens":32933,"cost":{"usd":0.0033248,"partial":false}}},"emittedAtMs":1791444731684}} {"type":"emit_inbound","label":"session/contextUsage","frame":{"jsonrpc":"2.0","method":"session/contextUsage","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:8","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b1dab1f5-3c9e-4d92-b955-841a2269c23c","sequence":54},"last":{"id":"b1dab1f5-3c9e-4d92-b955-841a2269c23c","sequence":54}},"windowTokens":1007997,"usedTokens":32933,"pressure":"normal"},"emittedAtMs":1791444731684}} @@ -42,12 +42,12 @@ {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","status":"idle","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:23"},"emittedAtMs":1791444747386}} {"type":"emit_inbound","label":"turn/completed","frame":{"jsonrpc":"2.0","method":"turn/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:23","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"7c29ac76-7e09-48c1-a18f-f336126e27d1","sequence":120},"last":{"id":"7c29ac76-7e09-48c1-a18f-f336126e27d1","sequence":120}},"turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","terminal":"completed","durationMs":18608,"timeToFirstTokenMs":4791},"emittedAtMs":1791444747387}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:24","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"1e4afe30-d924-444c-8665-5e763f524e70","sequence":121},"last":{"id":"1e4afe30-d924-444c-8665-5e763f524e70","sequence":121}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444747394}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":5,"method":"turn/start","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\n"},{"type":"text","text":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED."}],"displayText":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":5,"method":"turn/start","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED."}],"displayText":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":5,"result":{"commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29","status":"accepted","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","status":"running","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:25"},"emittedAtMs":1791444747660}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:25","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128},"last":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128}},"turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"},"emittedAtMs":1791444747660}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:26","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128},"last":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128}},"item":{"itemId":"27473708-71e0-4d3c-811c-a8bae6bbaa3b","kind":"userMessage","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:27.650913Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nRun the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}},"emittedAtMs":1791444747660}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:27","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a056a03-469a-4c9f-94a9-78eb815023ad","sequence":130},"last":{"id":"4a056a03-469a-4c9f-94a9-78eb815023ad","sequence":130}},"item":{"itemId":"27473708-71e0-4d3c-811c-a8bae6bbaa3b","kind":"userMessage","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:27.66745Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nRun the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","displayText":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}},"emittedAtMs":1791444747676}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:26","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128},"last":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128}},"item":{"itemId":"27473708-71e0-4d3c-811c-a8bae6bbaa3b","kind":"userMessage","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:27.650913Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}},"emittedAtMs":1791444747660}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:27","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a056a03-469a-4c9f-94a9-78eb815023ad","sequence":130},"last":{"id":"4a056a03-469a-4c9f-94a9-78eb815023ad","sequence":130}},"item":{"itemId":"27473708-71e0-4d3c-811c-a8bae6bbaa3b","kind":"userMessage","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:27.66745Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","displayText":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}},"emittedAtMs":1791444747676}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:28","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"3b28955d-a87a-4acb-97e9-14cad87fd41f","sequence":148},"last":{"id":"3b28955d-a87a-4acb-97e9-14cad87fd41f","sequence":148}},"item":{"itemId":"3b28955d-a87a-4acb-97e9-14cad87fd41f","kind":"reminderChild","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:32:27.787099Z","fallbackText":"Reminder child session","childSessionId":"efd21bf1-4fd1-49a2-9c55-91b7fc099765","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6d-85ed-7b91-8d91-c4ce76b6dfef"}},"emittedAtMs":1791444747794}} {"type":"emit_inbound","label":"session/tokenUsage","frame":{"jsonrpc":"2.0","method":"session/tokenUsage","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:29","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b032c01d-eae1-437e-910c-8756aedc6084","sequence":164},"last":{"id":"b032c01d-eae1-437e-910c-8756aedc6084","sequence":164}},"turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","modelId":"muse-spark-1.3-contributor","usage":{"inputTokens":33401,"outputTokens":201,"cachedTokens":33009,"cacheWriteTokens":0,"cacheReadTokens":33009,"reasoningTokens":108},"promptTokens":33401,"totalTokens":33602,"finishReason":"tool_calls","durationMs":2522,"cumulative":{"promptTokens":99045,"outputTokens":538,"totalTokens":99583,"cacheReadTokens":65506,"cost":{"usd":0.003592512,"partial":false}}},"emittedAtMs":1791444750395}} {"type":"emit_inbound","label":"session/contextUsage","frame":{"jsonrpc":"2.0","method":"session/contextUsage","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:30","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b032c01d-eae1-437e-910c-8756aedc6084","sequence":164},"last":{"id":"b032c01d-eae1-437e-910c-8756aedc6084","sequence":164}},"windowTokens":1007997,"usedTokens":33602,"pressure":"normal"},"emittedAtMs":1791444750395}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_approval/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_approval/muse_transcript.ndjson index 2608785344676..4b46cb200ab61 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_approval/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_approval/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","path":"~/.local/share/muse/sessions/2026/10/11/01a12d1d-a1b7-7000-9697-d430c2e2afd8/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:37:59.14136Z","updatedAt":"2026-10-11T22:37:59.141364Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"promptUnmatched","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791758279294}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","path":"~/.local/share/muse/sessions/2026/10/11/01a12d1d-a1b7-7000-9697-d430c2e2afd8/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:37:59.14136Z","updatedAt":"2026-10-11T22:37:59.141364Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"promptUnmatched","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:1","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"ed95a9db-eada-4751-a7e6-22ccc9bdabd5","sequence":5},"last":{"id":"ed95a9db-eada-4751-a7e6-22ccc9bdabd5","sequence":5}},"mode":"promptUnmatched","source":"approvalReconfigure","commandId":"01a12d1d-a1b8-7000-8d6c-f1324b724cdb","clientName":"t3_code"},"emittedAtMs":1791758279297}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\n"},{"type":"text","text":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:2","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"4f170229-d428-4a64-9516-7a355ff3bcdb","sequence":15},"last":{"id":"4f170229-d428-4a64-9516-7a355ff3bcdb","sequence":15}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791758279531}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","status":"accepted","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","status":"running","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:3"},"emittedAtMs":1791758279541}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:3","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17},"last":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17}},"turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"},"emittedAtMs":1791758279542}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:4","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17},"last":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17}},"item":{"itemId":"a4b3de8d-842b-4065-8769-aed18e62e9fc","kind":"userMessage","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":1,"status":"completed","recordedAt":"2026-10-11T22:37:59.531477Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nDo not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}},"emittedAtMs":1791758279542}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:5","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"5a63e348-5bf6-4262-b37f-d31d307ea6d8","sequence":19},"last":{"id":"5a63e348-5bf6-4262-b37f-d31d307ea6d8","sequence":19}},"item":{"itemId":"a4b3de8d-842b-4065-8769-aed18e62e9fc","kind":"userMessage","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":2,"status":"completed","recordedAt":"2026-10-11T22:37:59.545908Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nDo not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","displayText":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}},"emittedAtMs":1791758279553}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:4","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17},"last":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17}},"item":{"itemId":"a4b3de8d-842b-4065-8769-aed18e62e9fc","kind":"userMessage","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":1,"status":"completed","recordedAt":"2026-10-11T22:37:59.531477Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}},"emittedAtMs":1791758279542}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:5","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"5a63e348-5bf6-4262-b37f-d31d307ea6d8","sequence":19},"last":{"id":"5a63e348-5bf6-4262-b37f-d31d307ea6d8","sequence":19}},"item":{"itemId":"a4b3de8d-842b-4065-8769-aed18e62e9fc","kind":"userMessage","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":2,"status":"completed","recordedAt":"2026-10-11T22:37:59.545908Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","displayText":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}},"emittedAtMs":1791758279553}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:6","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"d55286a9-a9e2-4d7b-be97-d44360bcca2b","sequence":37},"last":{"id":"d55286a9-a9e2-4d7b-be97-d44360bcca2b","sequence":37}},"item":{"itemId":"d55286a9-a9e2-4d7b-be97-d44360bcca2b","kind":"reminderChild","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":1,"status":"inProgress","recordedAt":"2026-10-11T22:37:59.660065Z","fallbackText":"Reminder child session","childSessionId":"0779d605-54b8-45dc-90b6-91dc58b9a52c","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a12d1d-a3d4-7712-8b98-26f3c4f9bf38"}},"emittedAtMs":1791758279666}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:6.1","item":{"itemId":"21b74b34-fe9f-457c-83f0-cf49257b5948","kind":"reasoning","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":1,"status":"inProgress","summary":[""]}},"emittedAtMs":1791758282481}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:6.2","itemId":"21b74b34-fe9f-457c-83f0-cf49257b5948","field":"summary.0","delta":"Spawning a subagent via muse_subagent_spawn to run a shell command and return its exact output, while avoiding direct command execution."},"emittedAtMs":1791758282481}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_interrupt/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_interrupt/muse_transcript.ndjson index 0c88688e6aed5..32d54da17d3ae 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_interrupt/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_interrupt/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","path":"~/.local/share/muse/sessions/2026/10/11/01a12d28-7788-7000-a946-c407f380868e/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:49:49.235205Z","updatedAt":"2026-10-11T22:49:49.235209Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791758989388}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","path":"~/.local/share/muse/sessions/2026/10/11/01a12d28-7788-7000-a946-c407f380868e/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:49:49.235205Z","updatedAt":"2026-10-11T22:49:49.235209Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:1","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"29d4e769-78f7-48fa-90cd-3ac9f8fa04bf","sequence":5},"last":{"id":"29d4e769-78f7-48fa-90cd-3ac9f8fa04bf","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a12d28-7788-7001-a223-c10e52187cdf","clientName":"t3_code"},"emittedAtMs":1791758989391}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\n"},{"type":"text","text":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:2","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"660e2cfd-318a-4d2d-87bb-0b1375d79fdf","sequence":15},"last":{"id":"660e2cfd-318a-4d2d-87bb-0b1375d79fdf","sequence":15}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791758989619}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a12d28-7912-7000-993a-afd019e6ac5c","status":"accepted","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","status":"running","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:3"},"emittedAtMs":1791758989632}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:3","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17},"last":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17}},"turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"},"emittedAtMs":1791758989632}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:4","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17},"last":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17}},"item":{"itemId":"5e234d9d-0744-4757-9629-761ea4e7f062","kind":"userMessage","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":1,"status":"completed","recordedAt":"2026-10-11T22:49:49.620067Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nSpawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}},"emittedAtMs":1791758989632}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:5","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5724636e-9398-4d23-87ac-1e9a2b83ad9f","sequence":19},"last":{"id":"5724636e-9398-4d23-87ac-1e9a2b83ad9f","sequence":19}},"item":{"itemId":"5e234d9d-0744-4757-9629-761ea4e7f062","kind":"userMessage","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":2,"status":"completed","recordedAt":"2026-10-11T22:49:49.635395Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nSpawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","displayText":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}},"emittedAtMs":1791758989642}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:4","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17},"last":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17}},"item":{"itemId":"5e234d9d-0744-4757-9629-761ea4e7f062","kind":"userMessage","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":1,"status":"completed","recordedAt":"2026-10-11T22:49:49.620067Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}},"emittedAtMs":1791758989632}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:5","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5724636e-9398-4d23-87ac-1e9a2b83ad9f","sequence":19},"last":{"id":"5724636e-9398-4d23-87ac-1e9a2b83ad9f","sequence":19}},"item":{"itemId":"5e234d9d-0744-4757-9629-761ea4e7f062","kind":"userMessage","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":2,"status":"completed","recordedAt":"2026-10-11T22:49:49.635395Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","displayText":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}},"emittedAtMs":1791758989642}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:6","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"44afb415-d6e4-4d51-9002-4deb196d463a","sequence":36},"last":{"id":"44afb415-d6e4-4d51-9002-4deb196d463a","sequence":36}},"item":{"itemId":"44afb415-d6e4-4d51-9002-4deb196d463a","kind":"reminderChild","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":1,"status":"inProgress","recordedAt":"2026-10-11T22:49:49.743418Z","fallbackText":"Reminder child session","childSessionId":"4dd3511e-2115-4fbb-a4c4-383cbb383d63","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a12d28-7997-79d0-8a69-8ac0acf92a56"}},"emittedAtMs":1791758989750}} {"type":"emit_inbound","label":"session/tokenUsage","frame":{"jsonrpc":"2.0","method":"session/tokenUsage","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:7","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"c94f5484-20b7-4057-a736-303e97bc097c","sequence":52},"last":{"id":"c94f5484-20b7-4057-a736-303e97bc097c","sequence":52}},"turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","modelId":"muse-spark-1.3-contributor","usage":{"inputTokens":32911,"outputTokens":264,"cachedTokens":0,"cacheWriteTokens":0,"cacheReadTokens":0,"reasoningTokens":143},"promptTokens":32911,"totalTokens":33175,"finishReason":"tool_calls","durationMs":3651,"cumulative":{"promptTokens":32911,"outputTokens":264,"totalTokens":33175,"cost":{"usd":0.0033439000000000003,"partial":false}}},"emittedAtMs":1791758993485}} {"type":"emit_inbound","label":"session/contextUsage","frame":{"jsonrpc":"2.0","method":"session/contextUsage","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:8","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"c94f5484-20b7-4057-a736-303e97bc097c","sequence":52},"last":{"id":"c94f5484-20b7-4057-a736-303e97bc097c","sequence":52}},"windowTokens":1007997,"usedTokens":33175,"pressure":"normal"},"emittedAtMs":1791758993485}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/muse_workflow/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/muse_workflow/muse_transcript.ndjson index 5da7624808ead..b4d34e13ca5c1 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/muse_workflow/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/muse_workflow/muse_transcript.ndjson @@ -8,13 +8,13 @@ {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","path":"~/.local/share/muse/sessions/2026/10/11/01a12d5d-405f-7000-89a3-5aa62af6ea23/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T23:47:28.587276Z","updatedAt":"2026-10-11T23:47:28.587281Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:2"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:1","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"0c13b14b-877c-4c5b-b05f-8ad250dfd381","sequence":5},"last":{"id":"0c13b14b-877c-4c5b-b05f-8ad250dfd381","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a12d5d-4060-7000-b6cd-aaabe26f80de","clientName":"t3_code"},"emittedAtMs":1791762448807}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:2","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"28b1f3f4-4448-4a21-a1a0-2df72ad1d326","sequence":6},"last":{"id":"28b1f3f4-4448-4a21-a1a0-2df72ad1d326","sequence":6}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791762448807}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\n"},{"type":"text","text":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it."}],"displayText":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it."}],"displayText":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:3","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"3f1880e1-81a0-4f21-b536-6b4fa5cf9d12","sequence":16},"last":{"id":"3f1880e1-81a0-4f21-b536-6b4fa5cf9d12","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791762449097}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","status":"accepted","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","status":"running","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:4"},"emittedAtMs":1791762449102}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:4","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18},"last":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18}},"turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"},"emittedAtMs":1791762449103}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:5","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18},"last":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18}},"item":{"itemId":"0c1ceda9-41f7-4c3e-990e-4c53873c7ef5","kind":"userMessage","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":1,"status":"completed","recordedAt":"2026-10-11T23:47:29.098117Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nUse your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}},"emittedAtMs":1791762449103}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:6","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"0411a5c8-2c8a-4c9e-bb67-25fa3cef21a3","sequence":20},"last":{"id":"0411a5c8-2c8a-4c9e-bb67-25fa3cef21a3","sequence":20}},"item":{"itemId":"0c1ceda9-41f7-4c3e-990e-4c53873c7ef5","kind":"userMessage","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":2,"status":"completed","recordedAt":"2026-10-11T23:47:29.107019Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nUse your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","displayText":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}},"emittedAtMs":1791762449131}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:5","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18},"last":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18}},"item":{"itemId":"0c1ceda9-41f7-4c3e-990e-4c53873c7ef5","kind":"userMessage","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":1,"status":"completed","recordedAt":"2026-10-11T23:47:29.098117Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nUse your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}},"emittedAtMs":1791762449103}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:6","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"0411a5c8-2c8a-4c9e-bb67-25fa3cef21a3","sequence":20},"last":{"id":"0411a5c8-2c8a-4c9e-bb67-25fa3cef21a3","sequence":20}},"item":{"itemId":"0c1ceda9-41f7-4c3e-990e-4c53873c7ef5","kind":"userMessage","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":2,"status":"completed","recordedAt":"2026-10-11T23:47:29.107019Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nUse your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","displayText":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}},"emittedAtMs":1791762449131}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:7","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"95574bfe-853f-44cc-81f6-88b05d6c8c16","sequence":38},"last":{"id":"95574bfe-853f-44cc-81f6-88b05d6c8c16","sequence":38}},"item":{"itemId":"95574bfe-853f-44cc-81f6-88b05d6c8c16","kind":"reminderChild","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":1,"status":"inProgress","recordedAt":"2026-10-11T23:47:29.328939Z","fallbackText":"Reminder child session","childSessionId":"b16dbb52-7f62-4a5a-84c2-f68d7ea22b18","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a12d5d-4375-7d72-b5b2-4b096d0df507"}},"emittedAtMs":1791762449336}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:7.1","item":{"itemId":"3ce724bc-dacf-400e-af9a-995104717cb1","kind":"reasoning","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":1,"status":"inProgress","summary":[""]}},"emittedAtMs":1791762451554}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:7.2","itemId":"3ce724bc-dacf-400e-af9a-995104717cb1","field":"summary.0","delta":"Launching a two-agent ping-pong workflow via the workflow tool while skipping skill reading for a trivial task."},"emittedAtMs":1791762451554}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/simple/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/simple/muse_transcript.ndjson index 6f577c17671bb..6e5742071b430 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/simple/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/simple/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6a-bbb5-7000-ad0b-0c9e728406e5/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:29:25.018803Z","updatedAt":"2026-10-08T07:29:25.018807Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791444565334}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6a-bbb5-7000-ad0b-0c9e728406e5/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:29:25.018803Z","updatedAt":"2026-10-08T07:29:25.018807Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:1","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"cfd043e8-8728-493d-ba28-252ef91e8a80","sequence":5},"last":{"id":"cfd043e8-8728-493d-ba28-252ef91e8a80","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a11a6a-bbb6-7000-b1a4-a01ea59676ef","clientName":"t3_code"},"emittedAtMs":1791444565340}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\n"},{"type":"text","text":"Respond with the following text: fixture simple ok"}],"displayText":"Respond with the following text: fixture simple ok","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Respond with the following text: fixture simple ok"}],"displayText":"Respond with the following text: fixture simple ok","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:2","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"0f64f4ea-a08c-43e1-af53-cf85cee1a11c","sequence":16},"last":{"id":"0f64f4ea-a08c-43e1-af53-cf85cee1a11c","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444565612}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","status":"accepted","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","status":"running","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:3"},"emittedAtMs":1791444565635}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:3","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18},"last":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18}},"turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"},"emittedAtMs":1791444565635}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18},"last":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18}},"item":{"itemId":"23294b54-8e67-4896-a7f3-681119e1ddbe","kind":"userMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":1,"status":"completed","recordedAt":"2026-10-08T07:29:25.627042Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nRespond with the following text: fixture simple ok","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}},"emittedAtMs":1791444565635}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"8c00aa21-7809-4cb2-89f7-b499aaa8746d","sequence":20},"last":{"id":"8c00aa21-7809-4cb2-89f7-b499aaa8746d","sequence":20}},"item":{"itemId":"23294b54-8e67-4896-a7f3-681119e1ddbe","kind":"userMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":2,"status":"completed","recordedAt":"2026-10-08T07:29:25.643029Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nRespond with the following text: fixture simple ok","displayText":"Respond with the following text: fixture simple ok","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}},"emittedAtMs":1791444565652}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18},"last":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18}},"item":{"itemId":"23294b54-8e67-4896-a7f3-681119e1ddbe","kind":"userMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":1,"status":"completed","recordedAt":"2026-10-08T07:29:25.627042Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with the following text: fixture simple ok","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}},"emittedAtMs":1791444565635}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"8c00aa21-7809-4cb2-89f7-b499aaa8746d","sequence":20},"last":{"id":"8c00aa21-7809-4cb2-89f7-b499aaa8746d","sequence":20}},"item":{"itemId":"23294b54-8e67-4896-a7f3-681119e1ddbe","kind":"userMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":2,"status":"completed","recordedAt":"2026-10-08T07:29:25.643029Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with the following text: fixture simple ok","displayText":"Respond with the following text: fixture simple ok","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}},"emittedAtMs":1791444565652}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:6","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"ed1680a5-6f99-4b0f-b9ea-d12193f0de1f","sequence":37},"last":{"id":"ed1680a5-6f99-4b0f-b9ea-d12193f0de1f","sequence":37}},"item":{"itemId":"ed1680a5-6f99-4b0f-b9ea-d12193f0de1f","kind":"reminderChild","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:29:25.781511Z","fallbackText":"Reminder child session","childSessionId":"9785bf9d-382d-4781-ab3b-3817c9e6a604","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6a-bef1-7032-974a-059b8765c487"}},"emittedAtMs":1791444565789}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:6.1","item":{"itemId":"0a68e576-f554-4700-8853-a68ad2b7179b","kind":"agentMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":1,"status":"inProgress","text":""}},"emittedAtMs":1791444567707}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:6.2","itemId":"0a68e576-f554-4700-8853-a68ad2b7179b","field":"text","delta":"fixture simple ok"},"emittedAtMs":1791444567707}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/subagent_v2/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/subagent_v2/muse_transcript.ndjson index 47f3e6ab24461..5d181ddd95363 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/subagent_v2/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/subagent_v2/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","path":"~/.local/share/muse/sessions/2026/10/11/01a12d17-75fa-7000-9157-e8365ce94492/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:31:14.73121Z","updatedAt":"2026-10-11T22:31:14.731214Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791757874894}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","path":"~/.local/share/muse/sessions/2026/10/11/01a12d17-75fa-7000-9157-e8365ce94492/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:31:14.73121Z","updatedAt":"2026-10-11T22:31:14.731214Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:1","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"94d1e1ed-1d3e-4cd5-91bf-a51394fc8a0a","sequence":5},"last":{"id":"94d1e1ed-1d3e-4cd5-91bf-a51394fc8a0a","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a12d17-75fa-7001-a940-79b5d7c648a4","clientName":"t3_code"},"emittedAtMs":1791757874898}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\n"},{"type":"text","text":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:2","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"1dc98410-05c3-4618-a431-3638055e20df","sequence":15},"last":{"id":"1dc98410-05c3-4618-a431-3638055e20df","sequence":15}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791757875120}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a12d17-7790-7000-967d-3f2246f38a60","status":"accepted","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","status":"running","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:3"},"emittedAtMs":1791757875131}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:3","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17},"last":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17}},"turnId":"01a12d17-7790-7000-967d-3f2246f38a60","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"},"emittedAtMs":1791757875132}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:4","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17},"last":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17}},"item":{"itemId":"95c179c8-e8f8-4629-80df-e28243a234ea","kind":"userMessage","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":1,"status":"completed","recordedAt":"2026-10-11T22:31:15.120499Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nSpawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}},"emittedAtMs":1791757875132}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:5","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"dcf03486-5149-4377-b325-dea3e118628a","sequence":19},"last":{"id":"dcf03486-5149-4377-b325-dea3e118628a","sequence":19}},"item":{"itemId":"95c179c8-e8f8-4629-80df-e28243a234ea","kind":"userMessage","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":2,"status":"completed","recordedAt":"2026-10-11T22:31:15.136047Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nSpawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","displayText":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}},"emittedAtMs":1791757875144}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:4","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17},"last":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17}},"item":{"itemId":"95c179c8-e8f8-4629-80df-e28243a234ea","kind":"userMessage","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":1,"status":"completed","recordedAt":"2026-10-11T22:31:15.120499Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}},"emittedAtMs":1791757875132}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:5","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"dcf03486-5149-4377-b325-dea3e118628a","sequence":19},"last":{"id":"dcf03486-5149-4377-b325-dea3e118628a","sequence":19}},"item":{"itemId":"95c179c8-e8f8-4629-80df-e28243a234ea","kind":"userMessage","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":2,"status":"completed","recordedAt":"2026-10-11T22:31:15.136047Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","displayText":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}},"emittedAtMs":1791757875144}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:6","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"599a220a-d212-4a81-a60d-7284ff290284","sequence":36},"last":{"id":"599a220a-d212-4a81-a60d-7284ff290284","sequence":36}},"item":{"itemId":"599a220a-d212-4a81-a60d-7284ff290284","kind":"reminderChild","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":1,"status":"inProgress","recordedAt":"2026-10-11T22:31:15.249949Z","fallbackText":"Reminder child session","childSessionId":"0b3f4f01-850a-43bd-af36-9b011699354f","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a12d17-7819-7212-8057-3558c2bdd46d"}},"emittedAtMs":1791757875258}} {"type":"emit_inbound","label":"session/tokenUsage","frame":{"jsonrpc":"2.0","method":"session/tokenUsage","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:7","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"9198dd8d-eede-487a-9109-a48d2563c371","sequence":51},"last":{"id":"9198dd8d-eede-487a-9109-a48d2563c371","sequence":51}},"turnId":"01a12d17-7790-7000-967d-3f2246f38a60","modelId":"muse-spark-1.3-contributor","usage":{"inputTokens":32900,"outputTokens":129,"cachedTokens":0,"cacheWriteTokens":0,"cacheReadTokens":0,"reasoningTokens":36},"promptTokens":32900,"totalTokens":33029,"finishReason":"tool_calls","durationMs":2354,"cumulative":{"promptTokens":32900,"outputTokens":129,"totalTokens":33029,"cost":{"usd":0.0033158000000000003,"partial":false}}},"emittedAtMs":1791757877764}} {"type":"emit_inbound","label":"session/contextUsage","frame":{"jsonrpc":"2.0","method":"session/contextUsage","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:8","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"9198dd8d-eede-487a-9109-a48d2563c371","sequence":51},"last":{"id":"9198dd8d-eede-487a-9109-a48d2563c371","sequence":51}},"windowTokens":1007997,"usedTokens":33029,"pressure":"normal"},"emittedAtMs":1791757877764}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt/muse_transcript.ndjson index 8a87c41eae4fa..760f7d276c896 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt/muse_transcript.ndjson @@ -7,14 +7,14 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6d-2d3d-7000-8178-411fdb90bc34/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:32:05.094285Z","updatedAt":"2026-10-08T07:32:05.094289Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791444725265}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6d-2d3d-7000-8178-411fdb90bc34/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:32:05.094285Z","updatedAt":"2026-10-08T07:32:05.094289Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:1","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"9865268e-0a39-43a0-89d0-251a820ec8a3","sequence":5},"last":{"id":"9865268e-0a39-43a0-89d0-251a820ec8a3","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a11a6d-2d3e-7000-b0e7-f04c53ee070b","clientName":"t3_code"},"emittedAtMs":1791444725268}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\n"},{"type":"text","text":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally."}],"displayText":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally."}],"displayText":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:2","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"531b0e9e-c96d-4fa5-a6dd-5cc7d4569543","sequence":16},"last":{"id":"531b0e9e-c96d-4fa5-a6dd-5cc7d4569543","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444725509}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","status":"accepted","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","startedNewTurn":true,"disposition":"started"}}} {"type":"expect_outbound","label":"turn/interrupt","frame":{"jsonrpc":"2.0","id":4,"method":"turn/interrupt","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","commandId":"01a11a6d-2f0b-7000-a1d4-359cf54e471a"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","status":"running","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:3"},"emittedAtMs":1791444725522}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:3","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18},"last":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18}},"turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"},"emittedAtMs":1791444725523}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18},"last":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18}},"item":{"itemId":"cfa989ad-2359-4da2-9fca-562855cc0ae8","kind":"userMessage","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:05.510508Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nDo not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}},"emittedAtMs":1791444725523}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"5db75d92-0e52-4bce-bb81-40e254b40bc3","sequence":20},"last":{"id":"5db75d92-0e52-4bce-bb81-40e254b40bc3","sequence":20}},"item":{"itemId":"cfa989ad-2359-4da2-9fca-562855cc0ae8","kind":"userMessage","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:05.530992Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch.\nDo not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","displayText":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}},"emittedAtMs":1791444725539}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18},"last":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18}},"item":{"itemId":"cfa989ad-2359-4da2-9fca-562855cc0ae8","kind":"userMessage","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:05.510508Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}},"emittedAtMs":1791444725523}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"5db75d92-0e52-4bce-bb81-40e254b40bc3","sequence":20},"last":{"id":"5db75d92-0e52-4bce-bb81-40e254b40bc3","sequence":20}},"item":{"itemId":"cfa989ad-2359-4da2-9fca-562855cc0ae8","kind":"userMessage","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:05.530992Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","displayText":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}},"emittedAtMs":1791444725539}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:6","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"ae604001-22b9-479c-a45b-3dcfed45996c","sequence":37},"last":{"id":"ae604001-22b9-479c-a45b-3dcfed45996c","sequence":37}},"item":{"itemId":"ae604001-22b9-479c-a45b-3dcfed45996c","kind":"reminderChild","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:32:05.638142Z","fallbackText":"Reminder child session","childSessionId":"1f58196a-6bf6-42da-9499-8f53a439e6e1","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6d-2f65-70b1-bb8f-69b33bb4fc62"}},"emittedAtMs":1791444725646}} {"type":"emit_inbound","label":"response:turn/interrupt","frame":{"jsonrpc":"2.0","id":4,"result":{"commandId":"01a11a6d-2f0b-7000-a1d4-359cf54e471a","status":"accepted","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}}} {"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:7","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"ae604001-22b9-479c-a45b-3dcfed45996c","sequence":37},"last":{"id":"3962d8d1-4608-4dda-8fdc-39a1804474aa","sequence":50}},"item":{"itemId":"ae604001-22b9-479c-a45b-3dcfed45996c","kind":"reminderChild","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":2,"status":"cancelled","recordedAt":"2026-10-08T07:32:05.727236Z","fallbackText":"Reminder child session","failureReason":"main run cancelled","childSessionId":"1f58196a-6bf6-42da-9499-8f53a439e6e1","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6d-2f65-70b1-bb8f-69b33bb4fc62"}},"emittedAtMs":1791444725734}} From 7439d1aa78c0a884e16ed69f483015c0dffef0f3 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Thu, 12 Nov 2026 15:42:54 -0800 Subject: [PATCH 20/23] chore(server): agent context budget after rebasing onto main Co-Authored-By: Claude Opus 5.5 --- apps/server/src/provider/agentContextBudget.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/server/src/provider/agentContextBudget.json b/apps/server/src/provider/agentContextBudget.json index 2ce96a5c4180c..f73be499a64f3 100644 --- a/apps/server/src/provider/agentContextBudget.json +++ b/apps/server/src/provider/agentContextBudget.json @@ -1,5 +1,5 @@ { - "claudeSystemAppendBytes": 5597, - "codexAdditionalContextBytes": 7327, - "mcpToolListJsonBytes": 48099 + "claudeSystemAppendBytes": 5729, + "codexAdditionalContextBytes": 7459, + "mcpToolListJsonBytes": 50856 } From 899e4d806e5e5e219e9ece84d38923e7694367d1 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Thu, 12 Nov 2026 16:25:55 -0800 Subject: [PATCH 21/23] feat(server): agents review PRs and set labels, reviewers, and state through MCP tools pull_request_review submits a comment, approval, or change request with line comments placed by the PR's diff. pull_request_update also adds and removes labels, requests reviewers by login or org/team, and closes or reopens the PR. Co-Authored-By: Claude Opus 5.5 --- .../toolkits/pullRequests/handlers.test.ts | 121 ++++++++++++++++++ .../src/mcp/toolkits/pullRequests/handlers.ts | 111 +++++++++++++++- .../src/mcp/toolkits/pullRequests/tools.ts | 48 ++++++- .../src/provider/agentContextBudget.json | 2 +- .../pullRequestReviewGuideNormalize.ts | 4 +- .../pullRequestReviewPosition.test.ts | 55 ++++++++ .../pullRequest/pullRequestReviewPosition.ts | 53 ++++++++ evals/mcp-tool-use/cases/pull-requests.ndjson | 6 + evals/mcp-tool-use/run.ts | 2 + 9 files changed, 396 insertions(+), 6 deletions(-) create mode 100644 apps/server/src/pullRequest/pullRequestReviewPosition.test.ts create mode 100644 apps/server/src/pullRequest/pullRequestReviewPosition.ts diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts index a7a0db15d1f2b..80005e419e3c1 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts @@ -7,6 +7,8 @@ import { PullRequestOperationError, type OrchestrationProjectShell, type PullRequestActionInput, + type PullRequestDiffResult, + type PullRequestSubmitReviewInput, type PullRequestActivity, type PullRequestListInput, type PullRequestDetail, @@ -1008,4 +1010,123 @@ describe("source control tools", () => { expect(error._tag).toBe("PullRequestNothingToDoError"); }), ); + + it.effect("places review comments by the diff page that shows their line", () => + Effect.gen(function* () { + const reviews: Array = []; + const pages: Record = { + first: { + patch: + "diff --git a/a.ts b/a.ts\n--- a/a.ts\n+++ b/a.ts\n@@ -1,2 +1,2 @@\n-old\n+new\n same\n", + truncated: false, + nextCursor: "second", + }, + second: { + patch: + "diff --git a/b.ts b/b.ts\n--- a/b.ts\n+++ b/b.ts\n@@ -9,1 +9,2 @@\n kept\n+added\n", + truncated: false, + nextCursor: null, + }, + }; + const harness = yield* makeHarness({ + thread: branchThread, + pullRequests: { + diff: (input) => Effect.succeed(pages[input.cursor ?? "first"]!), + submitReview: (input) => Effect.sync(() => void reviews.push(input)), + }, + }); + yield* harness.call("pull_request_review", { + verdict: "request-changes", + body: "Two things.", + comments: [ + { path: "b.ts", line: 10, startLine: 9, body: "Why?" }, + { path: "a.ts", line: 1, side: "old", body: "Keep this." }, + ], + }); + expect(reviews).toMatchObject([ + { + number: 42, + verdict: "request-changes", + body: "Two things.", + comments: [ + { + path: "b.ts", + position: { kind: "added", newLine: 10 }, + startPosition: { kind: "context", oldLine: 9, newLine: 9, side: "right" }, + }, + { path: "a.ts", position: { kind: "deleted", oldLine: 1 } }, + ], + }, + ]); + + // A line the diff never shows fails before anything is posted. + const error = yield* harness + .call("pull_request_review", { + verdict: "comment", + comments: [{ path: "a.ts", line: 40, body: "Here?" }], + }) + .pipe(Effect.flip); + expect(error.message).toContain("a.ts line 40 (new side) is not in this PR's diff"); + expect(reviews).toHaveLength(1); + }), + ); + + it.effect("updates labels, requests reviewers by login, and closes the PR", () => + Effect.gen(function* () { + const calls: Array = []; + const harness = yield* makeHarness({ + thread: branchThread, + pullRequests: { + setLabels: (input) => + Effect.sync(() => void calls.push(["labels", input.labels, input.applied])), + reviewerCandidates: (input) => + Effect.succeed({ + candidates: [ + { + id: "MDQ6VXNlcjE=", + kind: "user", + login: input.query === "Octo" ? "octo" : "x", + name: null, + avatarUrl: null, + isRequested: false, + }, + { + id: "core", + kind: "team", + login: "acme/core", + name: null, + avatarUrl: null, + isRequested: false, + }, + ], + } as never), + requestReviewers: (input) => + Effect.sync(() => void calls.push(["reviewers", input.reviewers])), + runAction: (input) => Effect.sync(() => void calls.push(["action", input.action])), + }, + }); + yield* harness.call("pull_request_update", { + addLabels: ["bug"], + removeLabels: ["wip"], + requestReviewers: ["Octo", "acme/core"], + state: "closed", + }); + expect(calls).toEqual([ + ["labels", ["bug"], true], + ["labels", ["wip"], false], + [ + "reviewers", + [ + { id: "MDQ6VXNlcjE=", kind: "user" }, + { id: "core", kind: "team" }, + ], + ], + ["action", "close"], + ]); + const unknown = yield* harness + .call("pull_request_update", { requestReviewers: ["nobody"] }) + .pipe(Effect.flip); + expect(unknown.message).toContain("No reviewer named nobody"); + }), + ); }); diff --git a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts index 86af1811abd76..830ac6d4ddcb0 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/handlers.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/handlers.ts @@ -4,6 +4,7 @@ import { type PullRequestActivity, PullRequestListCursors, type PullRequestRef, + type PullRequestReviewCommentDraft, type PullRequestReviewThread, type OrchestrationProjectShell, type OrchestrationV2ThreadShell, @@ -25,6 +26,7 @@ import * as PullRequestWatchService from "../../../pullRequest/PullRequestWatchS import { resolveTarget, type ResolvedTarget } from "../../../pullRequest/pullRequestTarget.ts"; import * as PullRequestReviewGuideService from "../../../pullRequest/PullRequestReviewGuideService.ts"; import * as PullRequestService from "../../../pullRequest/PullRequestService.ts"; +import { reviewPositionInPatch } from "../../../pullRequest/pullRequestReviewPosition.ts"; import { pullRequestSyncKey } from "../../../pullRequest/pullRequestSyncKey.ts"; import { sourceControlDefinitions } from "../../../sourceControl/sourceControlDefinitions.ts"; import { @@ -46,6 +48,7 @@ import { PullRequestNothingToDoError, type PullRequestReadSection, type ReadPullRequestResult, + type ReviewLineComment, type ThreadPullRequestInput, PullRequestLinkFailedError, PullRequestUnlinkFailedError, @@ -102,6 +105,8 @@ const listCursors = { /** Keeps one conversation page near the size of a capped CI log. */ const CONVERSATION_PAGE_CHARS = 32_000; const THREAD_COMMENT_PAGES = 4; +/** Diff pages searched for review comment lines; a PR past this is too big to review by line. */ +const REVIEW_DIFF_PAGES = 10; function conversationPage( activity: PullRequestActivity, @@ -363,6 +368,65 @@ const make = Effect.gen(function* () { const forgeFailure = (error: { readonly message: string }) => new PullRequestForgeError({ detail: error.message, cause: error }); + /** A login or org/team, matched to the host's own reviewer id. */ + const reviewerNamed = (ref: PullRequestRef, name: string) => + pullRequests.reviewerCandidates({ ...ref, query: name }).pipe( + Effect.mapError(forgeFailure), + Effect.flatMap(({ candidates }) => { + const wanted = name.toLowerCase(); + const match = candidates.find( + (candidate) => + candidate.login.toLowerCase() === wanted || candidate.id.toLowerCase() === wanted, + ); + return match === undefined + ? Effect.fail( + new PullRequestForgeError({ + detail: `No reviewer named ${name} can be requested on this PR.`, + }), + ) + : Effect.succeed({ id: match.id, kind: match.kind }); + }), + ); + + /** Line comments placed by the PR's diff, which says whether each line was added, removed, or kept. */ + const reviewComments = Effect.fn("PullRequestsToolkit.reviewComments")(function* ( + ref: PullRequestRef, + comments: ReadonlyArray, + ) { + const placed = new Map(); + const unplaced = () => comments.filter((comment) => !placed.has(comment)); + let cursor: string | undefined; + for (let page = 0; page < REVIEW_DIFF_PAGES && unplaced().length > 0; page += 1) { + const diff = yield* pullRequests + .diff({ ...ref, ...(cursor === undefined ? {} : { cursor }) }) + .pipe(Effect.mapError(forgeFailure)); + for (const comment of unplaced()) { + const side = comment.side ?? "new"; + const position = reviewPositionInPatch(diff.patch, comment.path, comment.line, side); + const start = + comment.startLine === undefined + ? undefined + : reviewPositionInPatch(diff.patch, comment.path, comment.startLine, side); + if (position === null || start === null) continue; + placed.set(comment, { + path: comment.path, + position, + ...(start === undefined ? {} : { startPosition: start }), + body: comment.body, + }); + } + if (diff.nextCursor === null) break; + cursor = diff.nextCursor; + } + const missing = unplaced()[0]; + if (missing !== undefined) { + return yield* new PullRequestForgeError({ + detail: `${missing.path} line ${missing.startLine ?? missing.line} (${missing.side ?? "new"} side) is not in this PR's diff. Comment on a changed line or one shown around it.`, + }); + } + return comments.map((comment) => placed.get(comment)!); + }); + /** The thread's checkout, its project, and the PR the input names (default: the branch's). */ const locate = Effect.fn("PullRequestsToolkit.locate")(function* (input: ThreadPullRequestInput) { const thread = yield* requireThread(PullRequestForgeError, undefined); @@ -914,8 +978,18 @@ const make = Effect.gen(function* () { ), pull_request_update: McpToolAccess.writesWithCapability((input) => Effect.gen(function* () { - if (input.title === undefined && input.body === undefined && input.ready === undefined) { - return yield* new PullRequestNothingToDoError({ detail: "Pass title, body, or ready." }); + if ( + input.title === undefined && + input.body === undefined && + input.ready === undefined && + input.state === undefined && + input.addLabels === undefined && + input.removeLabels === undefined && + input.requestReviewers === undefined + ) { + return yield* new PullRequestNothingToDoError({ + detail: "Pass title, body, ready, state, addLabels, removeLabels, or requestReviewers.", + }); } const { target, ref } = yield* locate(input); if (input.title !== undefined || input.body !== undefined) { @@ -927,11 +1001,34 @@ const make = Effect.gen(function* () { }) .pipe(Effect.mapError(forgeFailure)); } + for (const [labels, applied] of [ + [input.addLabels, true], + [input.removeLabels, false], + ] as const) { + if (labels !== undefined) { + yield* pullRequests + .setLabels({ ...ref, labels, applied }) + .pipe(Effect.mapError(forgeFailure)); + } + } + if (input.requestReviewers !== undefined) { + const reviewers = yield* Effect.forEach(input.requestReviewers, (name) => + reviewerNamed(ref, name), + ); + yield* pullRequests + .requestReviewers({ ...ref, reviewers, requested: true }) + .pipe(Effect.mapError(forgeFailure)); + } if (input.ready !== undefined) { yield* pullRequests .runAction({ ...ref, action: input.ready ? "ready" : "draft" }) .pipe(Effect.mapError(forgeFailure)); } + if (input.state !== undefined) { + yield* pullRequests + .runAction({ ...ref, action: input.state === "closed" ? "close" : "reopen" }) + .pipe(Effect.mapError(forgeFailure)); + } return identityOf(target); }), ), @@ -981,6 +1078,16 @@ const make = Effect.gen(function* () { }; }), ), + pull_request_review: McpToolAccess.writesWithCapability((input) => + Effect.gen(function* () { + const { target, ref } = yield* locate(input); + const comments = yield* reviewComments(ref, input.comments ?? []); + yield* pullRequests + .submitReview({ ...ref, verdict: input.verdict, body: input.body ?? "", comments }) + .pipe(Effect.mapError(forgeFailure)); + return identityOf(target); + }), + ), pull_request_merge: McpToolAccess.writesWithCapability((input) => Effect.gen(function* () { const { target, ref } = yield* locate(input); diff --git a/apps/server/src/mcp/toolkits/pullRequests/tools.ts b/apps/server/src/mcp/toolkits/pullRequests/tools.ts index fee92fc3f14bf..de7e9d62ed8e8 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/tools.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/tools.ts @@ -10,6 +10,7 @@ import { PullRequestListState, PullRequestMergeability, PullRequestMergeMethod, + PullRequestReviewVerdict, PullRequestReviewDecision, PullRequestReviewGuide, PullRequestReviewGuideRun, @@ -653,13 +654,25 @@ const CreatePullRequestTool = Tool.make("pull_request_create", { .annotate(Tool.Idempotent, true) .annotate(Tool.OpenWorld, true); +const UpdateNames = Schema.Array(TrimmedNonEmptyString).check( + Schema.isMinLength(1), + Schema.isMaxLength(25), +); + const UpdatePullRequestTool = Tool.make("pull_request_update", { - description: "Edit a PR's title or body, or set ready (false: back to draft).", + description: + "Edit a PR's title, body, labels, or reviewers, close or reopen it, or set ready (false: back to draft).", parameters: Schema.Struct({ ...ThreadPullRequestInput.fields, title: Schema.optional(TrimmedNonEmptyString), body: Schema.optional(Schema.String), ready: Schema.optional(Schema.Boolean), + state: Schema.optional(Schema.Literals(["open", "closed"])), + addLabels: Schema.optional(UpdateNames), + removeLabels: Schema.optional(UpdateNames), + requestReviewers: Schema.optional( + UpdateNames.annotate({ description: "Logins, or org/team for a team." }), + ), }), success: Schema.Struct(PullRequestIdentity), failure: PullRequestToolError, @@ -690,6 +703,38 @@ const RespondToPullRequestTool = Tool.make("pull_request_respond", { .annotate(Tool.Idempotent, false) .annotate(Tool.OpenWorld, true); +export const ReviewLineComment = Schema.Struct({ + path: TrimmedNonEmptyString, + line: PositiveInt, + startLine: Schema.optional(PositiveInt), + side: Schema.optional( + Schema.Literals(["new", "old"]).annotate({ + description: "Default new. old: line numbers in the base, for removed lines.", + }), + ), + body: TrimmedNonEmptyString, +}); +export type ReviewLineComment = typeof ReviewLineComment.Type; + +const ReviewPullRequestTool = Tool.make("pull_request_review", { + description: + "Submit a review: approve, request changes, or comment, with optional line comments.", + parameters: Schema.Struct({ + ...ThreadPullRequestInput.fields, + verdict: PullRequestReviewVerdict, + body: Schema.optional(Schema.String), + comments: Schema.optional(Schema.Array(ReviewLineComment).check(Schema.isMaxLength(50))), + }), + success: Schema.Struct(PullRequestIdentity), + failure: PullRequestToolError, + dependencies: forgeDependencies, +}) + .annotate(Tool.Title, "Review pull request") + .annotate(Tool.Readonly, false) + .annotate(Tool.Destructive, false) + .annotate(Tool.Idempotent, false) + .annotate(Tool.OpenWorld, true); + const MergePullRequestTool = Tool.make("pull_request_merge", { description: "Merge only when asked to land. Refuses if the head moved from expectedHeadSha (summary.headSha).", @@ -728,5 +773,6 @@ export const PullRequestsToolkit = Toolkit.make( CreatePullRequestTool, UpdatePullRequestTool, RespondToPullRequestTool, + ReviewPullRequestTool, MergePullRequestTool, ); diff --git a/apps/server/src/provider/agentContextBudget.json b/apps/server/src/provider/agentContextBudget.json index f73be499a64f3..ada92682fe5ec 100644 --- a/apps/server/src/provider/agentContextBudget.json +++ b/apps/server/src/provider/agentContextBudget.json @@ -1,5 +1,5 @@ { "claudeSystemAppendBytes": 5729, "codexAdditionalContextBytes": 7459, - "mcpToolListJsonBytes": 50856 + "mcpToolListJsonBytes": 52072 } diff --git a/apps/server/src/pullRequest/pullRequestReviewGuideNormalize.ts b/apps/server/src/pullRequest/pullRequestReviewGuideNormalize.ts index 82edfc5fb8159..f130dc5ab49d6 100644 --- a/apps/server/src/pullRequest/pullRequestReviewGuideNormalize.ts +++ b/apps/server/src/pullRequest/pullRequestReviewGuideNormalize.ts @@ -19,7 +19,7 @@ export interface ReviewGuideChange { readonly hunks: ReadonlyMap; } -const HUNK_HEADER = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/; +export const HUNK_HEADER = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/; const hunkRange = (start: string, count: string | undefined): LineRange | null => { const lines = count === undefined ? 1 : Number(count); @@ -30,7 +30,7 @@ const hunkRange = (start: string, count: string | undefined): LineRange | null = * Git quotes a name holding a tab, quote or backslash, and ends an unquoted name holding a space * with a tab, so the first literal tab is never part of what the file is called. */ -function headerPath(line: string, prefix: string): string | null { +export function headerPath(line: string, prefix: string): string | null { const rest = line.slice(4); const tab = rest.indexOf("\t"); const token = tab === -1 ? rest : rest.slice(0, tab); diff --git a/apps/server/src/pullRequest/pullRequestReviewPosition.test.ts b/apps/server/src/pullRequest/pullRequestReviewPosition.test.ts new file mode 100644 index 0000000000000..f7dbec7e160b5 --- /dev/null +++ b/apps/server/src/pullRequest/pullRequestReviewPosition.test.ts @@ -0,0 +1,55 @@ +import { describe, expect, it } from "vite-plus/test"; + +import { reviewPositionInPatch } from "./pullRequestReviewPosition.ts"; + +const patch = [ + "diff --git a/src/a.ts b/src/a.ts", + "--- a/src/a.ts", + "+++ b/src/a.ts", + "@@ -10,3 +10,3 @@ function a() {", + " kept", + "-removed", + "+added", + " also kept", + "diff --git a/gone.ts b/gone.ts", + "--- a/gone.ts", + "+++ /dev/null", + "@@ -1 +0,0 @@", + "-gone", + "diff --git a/other.ts b/other.ts", + "--- a/other.ts", + "+++ b/other.ts", + "@@ -1 +1,2 @@", + " first", + // An added line reading `++ b/src/a.ts`, not a header for src/a.ts. + "+++ b/src/a.ts", + "@@ -20 +21 @@", + " later", +].join("\n"); + +describe("reviewPositionInPatch", () => { + it.each([ + ["an added line", "src/a.ts", 11, "new", { kind: "added", newLine: 11 }], + ["a removed line", "src/a.ts", 11, "old", { kind: "deleted", oldLine: 11 }], + [ + "a kept line by its head number", + "src/a.ts", + 12, + "new", + { kind: "context", oldLine: 12, newLine: 12, side: "right" }, + ], + [ + "a kept line by its base number", + "src/a.ts", + 10, + "old", + { kind: "context", oldLine: 10, newLine: 10, side: "left" }, + ], + ["a deleted file's line", "gone.ts", 1, "old", { kind: "deleted", oldLine: 1 }], + ["a line outside every hunk", "src/a.ts", 30, "new", null], + ["no line from a later file's header-like source", "src/a.ts", 21, "new", null], + ["a line of a file the patch lacks", "src/b.ts", 11, "new", null], + ] as const)("places %s", (_name, path, line, side, expected) => { + expect(reviewPositionInPatch(patch, path, line, side)).toEqual(expected); + }); +}); diff --git a/apps/server/src/pullRequest/pullRequestReviewPosition.ts b/apps/server/src/pullRequest/pullRequestReviewPosition.ts new file mode 100644 index 0000000000000..e55d375e94856 --- /dev/null +++ b/apps/server/src/pullRequest/pullRequestReviewPosition.ts @@ -0,0 +1,53 @@ +import type { PullRequestReviewPosition } from "@t3tools/contracts"; + +import { HUNK_HEADER, headerPath } from "./pullRequestReviewGuideNormalize.ts"; + +/** `new` numbers a line in the PR's head, `old` in its base. */ +export type ReviewLineSide = "new" | "old"; + +/** Where a line of `path` sits in a unified patch, or null when the patch does not show it. */ +export function reviewPositionInPatch( + patch: string, + path: string, + line: number, + side: ReviewLineSide, +): PullRequestReviewPosition | null { + let oldPath: string | null = null; + let inFile = false; + let inHunks = false; + let oldLine = 0; + let newLine = 0; + for (const text of patch.split("\n")) { + if (text.startsWith("diff --git ")) { + oldPath = null; + inFile = false; + inHunks = false; + } else if (!inHunks && text.startsWith("--- ")) { + oldPath = headerPath(text, "a/"); + } else if (!inHunks && text.startsWith("+++ ")) { + inFile = (headerPath(text, "b/") ?? oldPath) === path; + } else if (text.startsWith("@@")) { + // Every file's hunks count, so another file's `+++ ` source line is never a header. + const header = HUNK_HEADER.exec(text); + if (header === null) continue; + inHunks = true; + oldLine = Number(header[1]); + newLine = Number(header[3]); + } else if (inFile && inHunks) { + if (text.startsWith("+")) { + if (side === "new" && newLine === line) return { kind: "added", newLine }; + newLine += 1; + } else if (text.startsWith("-")) { + if (side === "old" && oldLine === line) return { kind: "deleted", oldLine }; + oldLine += 1; + } else if (text.startsWith(" ")) { + if ((side === "new" ? newLine : oldLine) === line) { + return { kind: "context", oldLine, newLine, side: side === "new" ? "right" : "left" }; + } + oldLine += 1; + newLine += 1; + } + } + } + return null; +} diff --git a/evals/mcp-tool-use/cases/pull-requests.ndjson b/evals/mcp-tool-use/cases/pull-requests.ndjson index 867462b085326..55dd14b402b23 100644 --- a/evals/mcp-tool-use/cases/pull-requests.ndjson +++ b/evals/mcp-tool-use/cases/pull-requests.ndjson @@ -44,3 +44,9 @@ {"id": "pr-checks-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "CI status read with gh pr checks", "experience": "Agents checked a PR's CI with gh pr checks, gh pr view --json statusCheckRollup, or gh run list instead of T3's PR tools.", "rule": "pull_request_read replaces gh and cafe for PR state and checks", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_read": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "summary": {"title": "feat(config): read the port from the environment", "body": "Reads PORT.", "state": "open", "isDraft": false, "author": "user", "headBranch": "feat/config-const", "baseBranch": "main", "headSha": "abc1234def5678", "mergeability": "mergeable", "behindBy": 0, "autoMergeEnabled": false, "additions": 1, "deletions": 1, "changedFiles": 1, "labels": [], "reviewers": ["reviewer"]}, "checks": [{"name": "Lint", "status": "success", "description": null, "url": null}, {"name": "Test", "status": "pending", "description": null, "url": null}]}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Is CI green on my PR yet?", "expect": {"calls": [{"tool": "pull_request_read"}], "shellMustNot": ["\\bgh (pr (checks|view|status)|run (list|view|watch)|api)\\b", "\\bcafe (pr|ci)\\b"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in."} {"id": "pr-list-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "PR lists read with gh pr list", "experience": "Agents listed PRs with gh pr list or gh search prs, often trimming JSON with --jq, instead of T3's PR tools.", "rule": "pull_request_list replaces gh and cafe for listing PRs", "privacy": "commit-safe", "setup": {"role": "top", "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}, {"number": 125, "title": "fix(ws): back off reconnects", "headRefName": "fix/ws-backoff", "checks": []}]}}, "prompt": "Which open PRs in this repo are waiting on my review?", "expect": {"calls": [{"tool": "pull_request_list", "args": {"involvement": "reviewing"}}], "shellMustNot": ["\\bgh (pr list|search prs|api)\\b", "\\bcafe pr list\\b"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in."} {"id": "pr-edit-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "PR edited with gh pr edit and gh pr ready", "experience": "Agents retitled PRs and marked them ready with gh pr edit and gh pr ready instead of T3's PR tools.", "rule": "pull_request_update replaces gh and cafe for editing a PR", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_update": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124"}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Retitle #124 to \"fix(config): read the port from PORT\" and mark it ready for review.", "expect": {"calls": [{"tool": "pull_request_update", "args": {"number": 124, "title": "~read the port from PORT", "ready": true}}], "shellMustNot": ["\\bgh (pr (edit|ready)|api)\\b", "\\bcafe pr (edit|ready)\\b"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in."} +{"id": "pr-approve-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "PR approved with gh pr review", "experience": "Before pull_request_review, approving took gh pr review or cafe pr review, on the user's own API quota.", "rule": "pull_request_review replaces gh and cafe for reviews", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_read": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "summary": {"title": "feat(config): read the port from the environment", "body": "Reads PORT.", "state": "open", "isDraft": false, "author": "user", "headBranch": "feat/config-const", "baseBranch": "main", "headSha": "abc1234def5678", "mergeability": "mergeable", "behindBy": 0, "autoMergeEnabled": false, "additions": 1, "deletions": 1, "changedFiles": 1, "labels": [], "reviewers": ["reviewer"]}, "checks": [{"name": "Lint", "status": "success", "description": null, "url": null}, {"name": "Test", "status": "success", "description": null, "url": null}]}, "pull_request_review": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124"}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "#124 looks good to me. Approve it.", "expect": {"calls": [{"tool": "pull_request_review", "args": {"number": 124, "verdict": "approve"}}], "shellMustNot": ["\\bgh (pr review|api)\\b", "\\bcafe pr review\\b"]}, "notes": "pull_request_review added 2026-11-12."} +{"id": "pr-request-changes-on-a-line", "area": "pull-requests", "kind": "bad", "pattern": "changes requested with gh pr review or gh api", "experience": "Before pull_request_review, line comments took gh api or cafe pr review, on the user's own API quota.", "rule": "pull_request_review replaces gh and cafe for reviews, line comments included", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_read": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "summary": {"title": "feat(config): read the port from the environment", "body": "Reads PORT.", "state": "open", "isDraft": false, "author": "user", "headBranch": "feat/config-const", "baseBranch": "main", "headSha": "abc1234def5678", "mergeability": "mergeable", "behindBy": 0, "autoMergeEnabled": false, "additions": 1, "deletions": 1, "changedFiles": 1, "labels": [], "reviewers": ["reviewer"]}, "checks": [{"name": "Lint", "status": "success", "description": null, "url": null}, {"name": "Test", "status": "success", "description": null, "url": null}]}, "pull_request_review": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124"}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Request changes on #124: PORT isn't validated, so a typo gives NaN. Put that on the line in src/config.ts that reads it.", "expect": {"calls": [{"tool": "pull_request_review", "args": {"number": 124, "verdict": "request-changes", "comments": [{"path": "src/config.ts", "line": 1}]}}], "shellMustNot": ["\\bgh (pr review|api)\\b", "\\bcafe pr review\\b"]}, "notes": "pull_request_review added 2026-11-12."} +{"id": "control-review-no-approve", "area": "pull-requests", "kind": "control", "pattern": "asked to review a clean PR", "experience": "Control: reviewing a clean PR. Reporting back or a comment review is fine; an approval under the user's account was not asked for.", "rule": "Approve only when asked", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_read": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "summary": {"title": "feat(config): read the port from the environment", "body": "Reads PORT.", "state": "open", "isDraft": false, "author": "user", "headBranch": "feat/config-const", "baseBranch": "main", "headSha": "abc1234def5678", "mergeability": "mergeable", "behindBy": 0, "autoMergeEnabled": false, "additions": 1, "deletions": 1, "changedFiles": 1, "labels": [], "reviewers": ["reviewer"]}, "checks": [{"name": "Lint", "status": "success", "description": null, "url": null}, {"name": "Test", "status": "success", "description": null, "url": null}]}, "pull_request_review": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124"}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Review #124.", "expect": {"callsMustNot": [{"tool": "pull_request_review", "args": {"verdict": "approve"}}], "shellMustNot": ["\\bgh pr review\\b[^\\n]*(--approve|-a\\b)", "\\bcafe pr review\\b[^\\n]*approve"]}, "notes": "Control for pr-approve-through-gh. Measures whether the review tool needs an approve-only-when-asked line."} +{"id": "control-feedback-no-review", "area": "pull-requests", "kind": "control", "pattern": "question about open review feedback", "experience": "Control: the user asks what feedback is open. Reading is fine; submitting a review was not asked.", "rule": "Answer questions about reviews without submitting one", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_read": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "summary": {"title": "feat(config): read the port from the environment", "body": "Reads PORT.", "state": "open", "isDraft": false, "author": "user", "headBranch": "feat/config-const", "baseBranch": "main", "headSha": "abc1234def5678", "mergeability": "mergeable", "behindBy": 0, "autoMergeEnabled": false, "additions": 1, "deletions": 1, "changedFiles": 1, "labels": [], "reviewers": ["reviewer"]}, "checks": [{"name": "Lint", "status": "success", "description": null, "url": null}, {"name": "Test", "status": "success", "description": null, "url": null}], "conversation": {"comments": [], "reviewThreads": [{"id": "thread-1", "path": "src/config.ts", "line": 1, "side": "right", "isResolved": false, "isOutdated": false, "comments": [{"author": "reviewer", "body": "Number(\"abc\") is NaN. Validate PORT before using it.", "createdAt": "2026-11-11T09:00:00Z"}]}], "hiddenResolvedThreads": 0, "nextCursor": null}}, "pull_request_review": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124"}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "What feedback is still open on #124?", "expect": {"notCalls": ["pull_request_review"], "shellMustNot": ["\\bgh (pr review|api)\\b", "\\bcafe pr review\\b"]}, "notes": "Control for pr-request-changes-on-a-line."} +{"id": "pr-labels-reviewers-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "labels and reviewers set with gh pr edit", "experience": "Before pull_request_update took labels and reviewers, agents needed gh pr edit or cafe pr edit for them.", "rule": "pull_request_update replaces gh and cafe for labels and reviewers", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_update": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124"}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Label PR #124 bug and ask octo to review it.", "expect": {"calls": [{"tool": "pull_request_update", "args": {"number": 124, "addLabels": ["bug"], "requestReviewers": ["~octo"]}}], "shellMustNot": ["\\bgh (pr edit|api)\\b", "\\bcafe pr edit\\b"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in."} +{"id": "pr-close-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "PR closed with gh pr close", "experience": "Before pull_request_update took state, closing a PR needed gh pr close or cafe pr close.", "rule": "pull_request_update replaces gh and cafe for closing and reopening", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_update": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124"}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Close PR #124, we're going a different way.", "expect": {"calls": [{"tool": "pull_request_update", "args": {"number": 124, "state": "closed"}}], "shellMustNot": ["\\bgh (pr close|api)\\b", "\\bcafe pr close\\b"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in."} diff --git a/evals/mcp-tool-use/run.ts b/evals/mcp-tool-use/run.ts index 47eaddcefebf5..533bf6f035ba1 100644 --- a/evals/mcp-tool-use/run.ts +++ b/evals/mcp-tool-use/run.ts @@ -1429,6 +1429,7 @@ export const t3Default = ( }; } case "pull_request_update": + case "pull_request_review": return pullRequest(sample.repo, { number: input.number ?? branchPullRequest(sample).number }); case "pull_request_respond": return { @@ -1622,6 +1623,7 @@ const BRANCH_PULL_REQUEST_TOOLS = new Set([ "pull_request_read", "pull_request_update", "pull_request_respond", + "pull_request_review", "pull_request_merge", ]); const BRANCH_HAS_NO_PR_ERROR = From 177cd806e42b8d7a92d7c5568a764f037bf07e2a Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Thu, 12 Nov 2026 16:39:22 -0800 Subject: [PATCH 22/23] fix(server): PR instructions name reviewing and closing, and merge drops its ask-first line Sonnet closed a PR with gh pr close in 3 of 4 runs while the instruction listed only read, list, open, edit, reply on, and merge. The merge description's "only when asked" line changed nothing in the evals. Co-Authored-By: Claude Opus 5.5 --- apps/server/src/mcp/toolkits/pullRequests/tools.ts | 3 +-- .../fixtures/multi_turn/muse_transcript.ndjson | 12 ++++++------ .../fixtures/muse_permission/muse_transcript.ndjson | 12 ++++++------ .../muse_subagent_approval/muse_transcript.ndjson | 6 +++--- .../muse_subagent_interrupt/muse_transcript.ndjson | 6 +++--- .../fixtures/muse_workflow/muse_transcript.ndjson | 6 +++--- .../testkit/fixtures/simple/muse_transcript.ndjson | 6 +++--- .../fixtures/subagent_v2/muse_transcript.ndjson | 6 +++--- .../fixtures/turn_interrupt/muse_transcript.ndjson | 6 +++--- apps/server/src/provider/agentContextBudget.json | 6 +++--- .../provider-core/src/server/runtimeInstructions.ts | 2 +- 11 files changed, 35 insertions(+), 36 deletions(-) diff --git a/apps/server/src/mcp/toolkits/pullRequests/tools.ts b/apps/server/src/mcp/toolkits/pullRequests/tools.ts index de7e9d62ed8e8..1b5d15d45ba8d 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/tools.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/tools.ts @@ -736,8 +736,7 @@ const ReviewPullRequestTool = Tool.make("pull_request_review", { .annotate(Tool.OpenWorld, true); const MergePullRequestTool = Tool.make("pull_request_merge", { - description: - "Merge only when asked to land. Refuses if the head moved from expectedHeadSha (summary.headSha).", + description: "Merge a PR. Refuses if the head moved from expectedHeadSha (summary.headSha).", parameters: Schema.Struct({ ...ThreadPullRequestInput.fields, expectedHeadSha: TrimmedNonEmptyString, diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/muse_transcript.ndjson index d261df1692b0a..10cf89bce38cd 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6b-707e-7000-9bb5-4079c7772ad0/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:30:11.238412Z","updatedAt":"2026-10-08T07:30:11.238416Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791444611408}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6b-707e-7000-9bb5-4079c7772ad0/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:30:11.238412Z","updatedAt":"2026-10-08T07:30:11.238416Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:1","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"37b19bd1-b212-4532-a0c9-a6677f303e26","sequence":5},"last":{"id":"37b19bd1-b212-4532-a0c9-a6677f303e26","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a11a6b-707e-7001-b2f4-23db74e60097","clientName":"t3_code"},"emittedAtMs":1791444611412}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Respond with exactly: first fixture turn complete"}],"displayText":"Respond with exactly: first fixture turn complete","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Respond with exactly: first fixture turn complete"}],"displayText":"Respond with exactly: first fixture turn complete","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:2","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"2c530748-943b-4467-8473-da8b04c511c3","sequence":16},"last":{"id":"2c530748-943b-4467-8473-da8b04c511c3","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444611661}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","status":"accepted","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","status":"running","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:3"},"emittedAtMs":1791444611674}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:3","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18},"last":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18}},"turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"},"emittedAtMs":1791444611675}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18},"last":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18}},"item":{"itemId":"1b470279-ee8c-4c74-a298-f37184145584","kind":"userMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":1,"status":"completed","recordedAt":"2026-10-08T07:30:11.66263Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: first fixture turn complete","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}},"emittedAtMs":1791444611675}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"31b500d6-40fc-4f4c-b097-6b7be8d77cee","sequence":20},"last":{"id":"31b500d6-40fc-4f4c-b097-6b7be8d77cee","sequence":20}},"item":{"itemId":"1b470279-ee8c-4c74-a298-f37184145584","kind":"userMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":2,"status":"completed","recordedAt":"2026-10-08T07:30:11.680942Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: first fixture turn complete","displayText":"Respond with exactly: first fixture turn complete","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}},"emittedAtMs":1791444611689}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18},"last":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18}},"item":{"itemId":"1b470279-ee8c-4c74-a298-f37184145584","kind":"userMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":1,"status":"completed","recordedAt":"2026-10-08T07:30:11.66263Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: first fixture turn complete","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}},"emittedAtMs":1791444611675}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"31b500d6-40fc-4f4c-b097-6b7be8d77cee","sequence":20},"last":{"id":"31b500d6-40fc-4f4c-b097-6b7be8d77cee","sequence":20}},"item":{"itemId":"1b470279-ee8c-4c74-a298-f37184145584","kind":"userMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":2,"status":"completed","recordedAt":"2026-10-08T07:30:11.680942Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: first fixture turn complete","displayText":"Respond with exactly: first fixture turn complete","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}},"emittedAtMs":1791444611689}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:6","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"077780ea-0dc9-4d7a-879c-ee368f3adbe0","sequence":37},"last":{"id":"077780ea-0dc9-4d7a-879c-ee368f3adbe0","sequence":37}},"item":{"itemId":"077780ea-0dc9-4d7a-879c-ee368f3adbe0","kind":"reminderChild","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:30:11.790301Z","fallbackText":"Reminder child session","childSessionId":"c13379db-6761-40b4-a974-b0f1a58717aa","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6b-72ac-7972-a1df-b343b7804b38"}},"emittedAtMs":1791444611795}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:6.1","item":{"itemId":"f99b90e1-9d8b-4bf2-8e7a-e240e1cf9321","kind":"agentMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":1,"status":"inProgress","text":""}},"emittedAtMs":1791444618068}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:6.2","itemId":"f99b90e1-9d8b-4bf2-8e7a-e240e1cf9321","field":"text","delta":"first fixture turn complete"},"emittedAtMs":1791444618068}} @@ -29,12 +29,12 @@ {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","status":"idle","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:16"},"emittedAtMs":1791444621046}} {"type":"emit_inbound","label":"turn/completed","frame":{"jsonrpc":"2.0","method":"turn/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:16","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"688a69c5-e353-4db9-bd8c-1beb033902ba","sequence":79},"last":{"id":"688a69c5-e353-4db9-bd8c-1beb033902ba","sequence":79}},"turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","terminal":"completed","durationMs":9378,"timeToFirstTokenMs":6406},"emittedAtMs":1791444621047}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:17","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"36753b8a-26ce-4935-8127-bc9191cb328b","sequence":80},"last":{"id":"36753b8a-26ce-4935-8127-bc9191cb328b","sequence":80}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444621054}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":4,"method":"turn/start","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Respond with exactly: second fixture turn complete"}],"displayText":"Respond with exactly: second fixture turn complete","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":4,"method":"turn/start","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Respond with exactly: second fixture turn complete"}],"displayText":"Respond with exactly: second fixture turn complete","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":4,"result":{"commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","status":"accepted","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","status":"running","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:18"},"emittedAtMs":1791444621333}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:18","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87},"last":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87}},"turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"},"emittedAtMs":1791444621334}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:19","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87},"last":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87}},"item":{"itemId":"90719a5d-d2c1-46dc-ad4d-274adda02344","kind":"userMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":1,"status":"completed","recordedAt":"2026-10-08T07:30:21.321391Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: second fixture turn complete","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}},"emittedAtMs":1791444621334}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:20","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"dc502e2c-d81c-4f0e-ad86-dd11d1368677","sequence":89},"last":{"id":"dc502e2c-d81c-4f0e-ad86-dd11d1368677","sequence":89}},"item":{"itemId":"90719a5d-d2c1-46dc-ad4d-274adda02344","kind":"userMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":2,"status":"completed","recordedAt":"2026-10-08T07:30:21.338944Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: second fixture turn complete","displayText":"Respond with exactly: second fixture turn complete","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}},"emittedAtMs":1791444621347}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:19","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87},"last":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87}},"item":{"itemId":"90719a5d-d2c1-46dc-ad4d-274adda02344","kind":"userMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":1,"status":"completed","recordedAt":"2026-10-08T07:30:21.321391Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: second fixture turn complete","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}},"emittedAtMs":1791444621334}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:20","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"dc502e2c-d81c-4f0e-ad86-dd11d1368677","sequence":89},"last":{"id":"dc502e2c-d81c-4f0e-ad86-dd11d1368677","sequence":89}},"item":{"itemId":"90719a5d-d2c1-46dc-ad4d-274adda02344","kind":"userMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":2,"status":"completed","recordedAt":"2026-10-08T07:30:21.338944Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: second fixture turn complete","displayText":"Respond with exactly: second fixture turn complete","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}},"emittedAtMs":1791444621347}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:21","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"09cb4c2a-03c2-4089-ba12-8d5d31f7ea48","sequence":106},"last":{"id":"09cb4c2a-03c2-4089-ba12-8d5d31f7ea48","sequence":106}},"item":{"itemId":"09cb4c2a-03c2-4089-ba12-8d5d31f7ea48","kind":"reminderChild","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:30:21.446966Z","fallbackText":"Reminder child session","childSessionId":"cd97261a-3ea9-480f-9e54-5e59bb077da2","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6b-9869-7061-a4f3-42daa3e3a8f1"}},"emittedAtMs":1791444621455}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:21.1","item":{"itemId":"2de26c0d-26b4-4533-8810-918ee44fcd82","kind":"agentMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":1,"status":"inProgress","text":""}},"emittedAtMs":1791444623127}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:21.2","itemId":"2de26c0d-26b4-4533-8810-918ee44fcd82","field":"text","delta":"second fixture turn complete"},"emittedAtMs":1791444623127}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/muse_permission/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/muse_permission/muse_transcript.ndjson index 96d6717846b38..51d6322853257 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/muse_permission/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/muse_permission/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6d-39bb-7000-8c93-4594c98e6a11/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:32:08.30084Z","updatedAt":"2026-10-08T07:32:08.300844Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"promptUnmatched","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791444728496}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6d-39bb-7000-8c93-4594c98e6a11/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:32:08.30084Z","updatedAt":"2026-10-08T07:32:08.300844Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"promptUnmatched","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:1","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b05fb8ec-7b58-4cf7-a369-379938395230","sequence":5},"last":{"id":"b05fb8ec-7b58-4cf7-a369-379938395230","sequence":5}},"mode":"promptUnmatched","source":"approvalReconfigure","commandId":"01a11a6d-39bb-7001-923e-425cc6129ce7","clientName":"t3_code"},"emittedAtMs":1791444728501}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE."}],"displayText":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE."}],"displayText":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:2","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"6159e84a-ae1e-4fae-ae8b-49f41ca34509","sequence":16},"last":{"id":"6159e84a-ae1e-4fae-ae8b-49f41ca34509","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444728769}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","status":"accepted","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","status":"running","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:3"},"emittedAtMs":1791444728783}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:3","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18},"last":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18}},"turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"},"emittedAtMs":1791444728783}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18},"last":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18}},"item":{"itemId":"dde9573b-650f-434b-ab99-60cfc820a0a5","kind":"userMessage","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:08.769894Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}},"emittedAtMs":1791444728784}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"76c57706-1378-4167-8bbf-f76d959804e8","sequence":20},"last":{"id":"76c57706-1378-4167-8bbf-f76d959804e8","sequence":20}},"item":{"itemId":"dde9573b-650f-434b-ab99-60cfc820a0a5","kind":"userMessage","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:08.791728Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","displayText":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}},"emittedAtMs":1791444728800}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18},"last":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18}},"item":{"itemId":"dde9573b-650f-434b-ab99-60cfc820a0a5","kind":"userMessage","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:08.769894Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}},"emittedAtMs":1791444728784}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"76c57706-1378-4167-8bbf-f76d959804e8","sequence":20},"last":{"id":"76c57706-1378-4167-8bbf-f76d959804e8","sequence":20}},"item":{"itemId":"dde9573b-650f-434b-ab99-60cfc820a0a5","kind":"userMessage","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:08.791728Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","displayText":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}},"emittedAtMs":1791444728800}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:6","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"29180105-84c4-4f9e-8bfd-003392b93b73","sequence":38},"last":{"id":"29180105-84c4-4f9e-8bfd-003392b93b73","sequence":38}},"item":{"itemId":"29180105-84c4-4f9e-8bfd-003392b93b73","kind":"reminderChild","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:32:08.905989Z","fallbackText":"Reminder child session","childSessionId":"7c9485f9-26aa-4b56-8ca2-f36cb9cfb8c4","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6d-3c27-73f2-8c27-cd06a3b7dadf"}},"emittedAtMs":1791444728910}} {"type":"emit_inbound","label":"session/tokenUsage","frame":{"jsonrpc":"2.0","method":"session/tokenUsage","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:7","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b1dab1f5-3c9e-4d92-b955-841a2269c23c","sequence":54},"last":{"id":"b1dab1f5-3c9e-4d92-b955-841a2269c23c","sequence":54}},"turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","modelId":"muse-spark-1.3-contributor","usage":{"inputTokens":32618,"outputTokens":315,"cachedTokens":0,"cacheWriteTokens":0,"cacheReadTokens":0,"reasoningTokens":227},"promptTokens":32618,"totalTokens":32933,"finishReason":"tool_calls","durationMs":2684,"cumulative":{"promptTokens":32618,"outputTokens":315,"totalTokens":32933,"cost":{"usd":0.0033248,"partial":false}}},"emittedAtMs":1791444731684}} {"type":"emit_inbound","label":"session/contextUsage","frame":{"jsonrpc":"2.0","method":"session/contextUsage","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:8","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b1dab1f5-3c9e-4d92-b955-841a2269c23c","sequence":54},"last":{"id":"b1dab1f5-3c9e-4d92-b955-841a2269c23c","sequence":54}},"windowTokens":1007997,"usedTokens":32933,"pressure":"normal"},"emittedAtMs":1791444731684}} @@ -42,12 +42,12 @@ {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","status":"idle","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:23"},"emittedAtMs":1791444747386}} {"type":"emit_inbound","label":"turn/completed","frame":{"jsonrpc":"2.0","method":"turn/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:23","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"7c29ac76-7e09-48c1-a18f-f336126e27d1","sequence":120},"last":{"id":"7c29ac76-7e09-48c1-a18f-f336126e27d1","sequence":120}},"turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","terminal":"completed","durationMs":18608,"timeToFirstTokenMs":4791},"emittedAtMs":1791444747387}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:24","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"1e4afe30-d924-444c-8665-5e763f524e70","sequence":121},"last":{"id":"1e4afe30-d924-444c-8665-5e763f524e70","sequence":121}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444747394}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":5,"method":"turn/start","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED."}],"displayText":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":5,"method":"turn/start","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED."}],"displayText":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":5,"result":{"commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29","status":"accepted","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","status":"running","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:25"},"emittedAtMs":1791444747660}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:25","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128},"last":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128}},"turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"},"emittedAtMs":1791444747660}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:26","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128},"last":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128}},"item":{"itemId":"27473708-71e0-4d3c-811c-a8bae6bbaa3b","kind":"userMessage","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:27.650913Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}},"emittedAtMs":1791444747660}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:27","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a056a03-469a-4c9f-94a9-78eb815023ad","sequence":130},"last":{"id":"4a056a03-469a-4c9f-94a9-78eb815023ad","sequence":130}},"item":{"itemId":"27473708-71e0-4d3c-811c-a8bae6bbaa3b","kind":"userMessage","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:27.66745Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","displayText":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}},"emittedAtMs":1791444747676}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:26","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128},"last":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128}},"item":{"itemId":"27473708-71e0-4d3c-811c-a8bae6bbaa3b","kind":"userMessage","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:27.650913Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}},"emittedAtMs":1791444747660}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:27","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a056a03-469a-4c9f-94a9-78eb815023ad","sequence":130},"last":{"id":"4a056a03-469a-4c9f-94a9-78eb815023ad","sequence":130}},"item":{"itemId":"27473708-71e0-4d3c-811c-a8bae6bbaa3b","kind":"userMessage","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:27.66745Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","displayText":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}},"emittedAtMs":1791444747676}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:28","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"3b28955d-a87a-4acb-97e9-14cad87fd41f","sequence":148},"last":{"id":"3b28955d-a87a-4acb-97e9-14cad87fd41f","sequence":148}},"item":{"itemId":"3b28955d-a87a-4acb-97e9-14cad87fd41f","kind":"reminderChild","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:32:27.787099Z","fallbackText":"Reminder child session","childSessionId":"efd21bf1-4fd1-49a2-9c55-91b7fc099765","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6d-85ed-7b91-8d91-c4ce76b6dfef"}},"emittedAtMs":1791444747794}} {"type":"emit_inbound","label":"session/tokenUsage","frame":{"jsonrpc":"2.0","method":"session/tokenUsage","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:29","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b032c01d-eae1-437e-910c-8756aedc6084","sequence":164},"last":{"id":"b032c01d-eae1-437e-910c-8756aedc6084","sequence":164}},"turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","modelId":"muse-spark-1.3-contributor","usage":{"inputTokens":33401,"outputTokens":201,"cachedTokens":33009,"cacheWriteTokens":0,"cacheReadTokens":33009,"reasoningTokens":108},"promptTokens":33401,"totalTokens":33602,"finishReason":"tool_calls","durationMs":2522,"cumulative":{"promptTokens":99045,"outputTokens":538,"totalTokens":99583,"cacheReadTokens":65506,"cost":{"usd":0.003592512,"partial":false}}},"emittedAtMs":1791444750395}} {"type":"emit_inbound","label":"session/contextUsage","frame":{"jsonrpc":"2.0","method":"session/contextUsage","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:30","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b032c01d-eae1-437e-910c-8756aedc6084","sequence":164},"last":{"id":"b032c01d-eae1-437e-910c-8756aedc6084","sequence":164}},"windowTokens":1007997,"usedTokens":33602,"pressure":"normal"},"emittedAtMs":1791444750395}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_approval/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_approval/muse_transcript.ndjson index 4b46cb200ab61..3f098fa8f6530 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_approval/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_approval/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","path":"~/.local/share/muse/sessions/2026/10/11/01a12d1d-a1b7-7000-9697-d430c2e2afd8/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:37:59.14136Z","updatedAt":"2026-10-11T22:37:59.141364Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"promptUnmatched","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791758279294}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","path":"~/.local/share/muse/sessions/2026/10/11/01a12d1d-a1b7-7000-9697-d430c2e2afd8/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:37:59.14136Z","updatedAt":"2026-10-11T22:37:59.141364Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"promptUnmatched","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:1","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"ed95a9db-eada-4751-a7e6-22ccc9bdabd5","sequence":5},"last":{"id":"ed95a9db-eada-4751-a7e6-22ccc9bdabd5","sequence":5}},"mode":"promptUnmatched","source":"approvalReconfigure","commandId":"01a12d1d-a1b8-7000-8d6c-f1324b724cdb","clientName":"t3_code"},"emittedAtMs":1791758279297}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:2","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"4f170229-d428-4a64-9516-7a355ff3bcdb","sequence":15},"last":{"id":"4f170229-d428-4a64-9516-7a355ff3bcdb","sequence":15}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791758279531}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","status":"accepted","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","status":"running","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:3"},"emittedAtMs":1791758279541}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:3","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17},"last":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17}},"turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"},"emittedAtMs":1791758279542}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:4","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17},"last":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17}},"item":{"itemId":"a4b3de8d-842b-4065-8769-aed18e62e9fc","kind":"userMessage","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":1,"status":"completed","recordedAt":"2026-10-11T22:37:59.531477Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}},"emittedAtMs":1791758279542}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:5","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"5a63e348-5bf6-4262-b37f-d31d307ea6d8","sequence":19},"last":{"id":"5a63e348-5bf6-4262-b37f-d31d307ea6d8","sequence":19}},"item":{"itemId":"a4b3de8d-842b-4065-8769-aed18e62e9fc","kind":"userMessage","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":2,"status":"completed","recordedAt":"2026-10-11T22:37:59.545908Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","displayText":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}},"emittedAtMs":1791758279553}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:4","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17},"last":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17}},"item":{"itemId":"a4b3de8d-842b-4065-8769-aed18e62e9fc","kind":"userMessage","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":1,"status":"completed","recordedAt":"2026-10-11T22:37:59.531477Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}},"emittedAtMs":1791758279542}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:5","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"5a63e348-5bf6-4262-b37f-d31d307ea6d8","sequence":19},"last":{"id":"5a63e348-5bf6-4262-b37f-d31d307ea6d8","sequence":19}},"item":{"itemId":"a4b3de8d-842b-4065-8769-aed18e62e9fc","kind":"userMessage","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":2,"status":"completed","recordedAt":"2026-10-11T22:37:59.545908Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","displayText":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}},"emittedAtMs":1791758279553}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:6","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"d55286a9-a9e2-4d7b-be97-d44360bcca2b","sequence":37},"last":{"id":"d55286a9-a9e2-4d7b-be97-d44360bcca2b","sequence":37}},"item":{"itemId":"d55286a9-a9e2-4d7b-be97-d44360bcca2b","kind":"reminderChild","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":1,"status":"inProgress","recordedAt":"2026-10-11T22:37:59.660065Z","fallbackText":"Reminder child session","childSessionId":"0779d605-54b8-45dc-90b6-91dc58b9a52c","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a12d1d-a3d4-7712-8b98-26f3c4f9bf38"}},"emittedAtMs":1791758279666}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:6.1","item":{"itemId":"21b74b34-fe9f-457c-83f0-cf49257b5948","kind":"reasoning","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":1,"status":"inProgress","summary":[""]}},"emittedAtMs":1791758282481}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:6.2","itemId":"21b74b34-fe9f-457c-83f0-cf49257b5948","field":"summary.0","delta":"Spawning a subagent via muse_subagent_spawn to run a shell command and return its exact output, while avoiding direct command execution."},"emittedAtMs":1791758282481}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_interrupt/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_interrupt/muse_transcript.ndjson index 32d54da17d3ae..d9d5111aa4f69 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_interrupt/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_interrupt/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","path":"~/.local/share/muse/sessions/2026/10/11/01a12d28-7788-7000-a946-c407f380868e/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:49:49.235205Z","updatedAt":"2026-10-11T22:49:49.235209Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791758989388}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","path":"~/.local/share/muse/sessions/2026/10/11/01a12d28-7788-7000-a946-c407f380868e/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:49:49.235205Z","updatedAt":"2026-10-11T22:49:49.235209Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:1","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"29d4e769-78f7-48fa-90cd-3ac9f8fa04bf","sequence":5},"last":{"id":"29d4e769-78f7-48fa-90cd-3ac9f8fa04bf","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a12d28-7788-7001-a223-c10e52187cdf","clientName":"t3_code"},"emittedAtMs":1791758989391}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:2","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"660e2cfd-318a-4d2d-87bb-0b1375d79fdf","sequence":15},"last":{"id":"660e2cfd-318a-4d2d-87bb-0b1375d79fdf","sequence":15}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791758989619}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a12d28-7912-7000-993a-afd019e6ac5c","status":"accepted","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","status":"running","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:3"},"emittedAtMs":1791758989632}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:3","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17},"last":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17}},"turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"},"emittedAtMs":1791758989632}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:4","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17},"last":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17}},"item":{"itemId":"5e234d9d-0744-4757-9629-761ea4e7f062","kind":"userMessage","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":1,"status":"completed","recordedAt":"2026-10-11T22:49:49.620067Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}},"emittedAtMs":1791758989632}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:5","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5724636e-9398-4d23-87ac-1e9a2b83ad9f","sequence":19},"last":{"id":"5724636e-9398-4d23-87ac-1e9a2b83ad9f","sequence":19}},"item":{"itemId":"5e234d9d-0744-4757-9629-761ea4e7f062","kind":"userMessage","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":2,"status":"completed","recordedAt":"2026-10-11T22:49:49.635395Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","displayText":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}},"emittedAtMs":1791758989642}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:4","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17},"last":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17}},"item":{"itemId":"5e234d9d-0744-4757-9629-761ea4e7f062","kind":"userMessage","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":1,"status":"completed","recordedAt":"2026-10-11T22:49:49.620067Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}},"emittedAtMs":1791758989632}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:5","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5724636e-9398-4d23-87ac-1e9a2b83ad9f","sequence":19},"last":{"id":"5724636e-9398-4d23-87ac-1e9a2b83ad9f","sequence":19}},"item":{"itemId":"5e234d9d-0744-4757-9629-761ea4e7f062","kind":"userMessage","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":2,"status":"completed","recordedAt":"2026-10-11T22:49:49.635395Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","displayText":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}},"emittedAtMs":1791758989642}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:6","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"44afb415-d6e4-4d51-9002-4deb196d463a","sequence":36},"last":{"id":"44afb415-d6e4-4d51-9002-4deb196d463a","sequence":36}},"item":{"itemId":"44afb415-d6e4-4d51-9002-4deb196d463a","kind":"reminderChild","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":1,"status":"inProgress","recordedAt":"2026-10-11T22:49:49.743418Z","fallbackText":"Reminder child session","childSessionId":"4dd3511e-2115-4fbb-a4c4-383cbb383d63","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a12d28-7997-79d0-8a69-8ac0acf92a56"}},"emittedAtMs":1791758989750}} {"type":"emit_inbound","label":"session/tokenUsage","frame":{"jsonrpc":"2.0","method":"session/tokenUsage","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:7","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"c94f5484-20b7-4057-a736-303e97bc097c","sequence":52},"last":{"id":"c94f5484-20b7-4057-a736-303e97bc097c","sequence":52}},"turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","modelId":"muse-spark-1.3-contributor","usage":{"inputTokens":32911,"outputTokens":264,"cachedTokens":0,"cacheWriteTokens":0,"cacheReadTokens":0,"reasoningTokens":143},"promptTokens":32911,"totalTokens":33175,"finishReason":"tool_calls","durationMs":3651,"cumulative":{"promptTokens":32911,"outputTokens":264,"totalTokens":33175,"cost":{"usd":0.0033439000000000003,"partial":false}}},"emittedAtMs":1791758993485}} {"type":"emit_inbound","label":"session/contextUsage","frame":{"jsonrpc":"2.0","method":"session/contextUsage","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:8","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"c94f5484-20b7-4057-a736-303e97bc097c","sequence":52},"last":{"id":"c94f5484-20b7-4057-a736-303e97bc097c","sequence":52}},"windowTokens":1007997,"usedTokens":33175,"pressure":"normal"},"emittedAtMs":1791758993485}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/muse_workflow/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/muse_workflow/muse_transcript.ndjson index b4d34e13ca5c1..e54e2fe99240b 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/muse_workflow/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/muse_workflow/muse_transcript.ndjson @@ -8,13 +8,13 @@ {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","path":"~/.local/share/muse/sessions/2026/10/11/01a12d5d-405f-7000-89a3-5aa62af6ea23/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T23:47:28.587276Z","updatedAt":"2026-10-11T23:47:28.587281Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:2"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:1","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"0c13b14b-877c-4c5b-b05f-8ad250dfd381","sequence":5},"last":{"id":"0c13b14b-877c-4c5b-b05f-8ad250dfd381","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a12d5d-4060-7000-b6cd-aaabe26f80de","clientName":"t3_code"},"emittedAtMs":1791762448807}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:2","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"28b1f3f4-4448-4a21-a1a0-2df72ad1d326","sequence":6},"last":{"id":"28b1f3f4-4448-4a21-a1a0-2df72ad1d326","sequence":6}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791762448807}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it."}],"displayText":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it."}],"displayText":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:3","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"3f1880e1-81a0-4f21-b536-6b4fa5cf9d12","sequence":16},"last":{"id":"3f1880e1-81a0-4f21-b536-6b4fa5cf9d12","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791762449097}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","status":"accepted","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","status":"running","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:4"},"emittedAtMs":1791762449102}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:4","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18},"last":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18}},"turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"},"emittedAtMs":1791762449103}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:5","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18},"last":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18}},"item":{"itemId":"0c1ceda9-41f7-4c3e-990e-4c53873c7ef5","kind":"userMessage","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":1,"status":"completed","recordedAt":"2026-10-11T23:47:29.098117Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nUse your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}},"emittedAtMs":1791762449103}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:6","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"0411a5c8-2c8a-4c9e-bb67-25fa3cef21a3","sequence":20},"last":{"id":"0411a5c8-2c8a-4c9e-bb67-25fa3cef21a3","sequence":20}},"item":{"itemId":"0c1ceda9-41f7-4c3e-990e-4c53873c7ef5","kind":"userMessage","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":2,"status":"completed","recordedAt":"2026-10-11T23:47:29.107019Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nUse your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","displayText":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}},"emittedAtMs":1791762449131}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:5","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18},"last":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18}},"item":{"itemId":"0c1ceda9-41f7-4c3e-990e-4c53873c7ef5","kind":"userMessage","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":1,"status":"completed","recordedAt":"2026-10-11T23:47:29.098117Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nUse your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}},"emittedAtMs":1791762449103}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:6","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"0411a5c8-2c8a-4c9e-bb67-25fa3cef21a3","sequence":20},"last":{"id":"0411a5c8-2c8a-4c9e-bb67-25fa3cef21a3","sequence":20}},"item":{"itemId":"0c1ceda9-41f7-4c3e-990e-4c53873c7ef5","kind":"userMessage","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":2,"status":"completed","recordedAt":"2026-10-11T23:47:29.107019Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nUse your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","displayText":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}},"emittedAtMs":1791762449131}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:7","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"95574bfe-853f-44cc-81f6-88b05d6c8c16","sequence":38},"last":{"id":"95574bfe-853f-44cc-81f6-88b05d6c8c16","sequence":38}},"item":{"itemId":"95574bfe-853f-44cc-81f6-88b05d6c8c16","kind":"reminderChild","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":1,"status":"inProgress","recordedAt":"2026-10-11T23:47:29.328939Z","fallbackText":"Reminder child session","childSessionId":"b16dbb52-7f62-4a5a-84c2-f68d7ea22b18","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a12d5d-4375-7d72-b5b2-4b096d0df507"}},"emittedAtMs":1791762449336}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:7.1","item":{"itemId":"3ce724bc-dacf-400e-af9a-995104717cb1","kind":"reasoning","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":1,"status":"inProgress","summary":[""]}},"emittedAtMs":1791762451554}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:7.2","itemId":"3ce724bc-dacf-400e-af9a-995104717cb1","field":"summary.0","delta":"Launching a two-agent ping-pong workflow via the workflow tool while skipping skill reading for a trivial task."},"emittedAtMs":1791762451554}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/simple/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/simple/muse_transcript.ndjson index 6e5742071b430..04150de3ead9a 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/simple/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/simple/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6a-bbb5-7000-ad0b-0c9e728406e5/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:29:25.018803Z","updatedAt":"2026-10-08T07:29:25.018807Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791444565334}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6a-bbb5-7000-ad0b-0c9e728406e5/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:29:25.018803Z","updatedAt":"2026-10-08T07:29:25.018807Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:1","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"cfd043e8-8728-493d-ba28-252ef91e8a80","sequence":5},"last":{"id":"cfd043e8-8728-493d-ba28-252ef91e8a80","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a11a6a-bbb6-7000-b1a4-a01ea59676ef","clientName":"t3_code"},"emittedAtMs":1791444565340}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Respond with the following text: fixture simple ok"}],"displayText":"Respond with the following text: fixture simple ok","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Respond with the following text: fixture simple ok"}],"displayText":"Respond with the following text: fixture simple ok","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:2","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"0f64f4ea-a08c-43e1-af53-cf85cee1a11c","sequence":16},"last":{"id":"0f64f4ea-a08c-43e1-af53-cf85cee1a11c","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444565612}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","status":"accepted","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","status":"running","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:3"},"emittedAtMs":1791444565635}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:3","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18},"last":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18}},"turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"},"emittedAtMs":1791444565635}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18},"last":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18}},"item":{"itemId":"23294b54-8e67-4896-a7f3-681119e1ddbe","kind":"userMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":1,"status":"completed","recordedAt":"2026-10-08T07:29:25.627042Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with the following text: fixture simple ok","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}},"emittedAtMs":1791444565635}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"8c00aa21-7809-4cb2-89f7-b499aaa8746d","sequence":20},"last":{"id":"8c00aa21-7809-4cb2-89f7-b499aaa8746d","sequence":20}},"item":{"itemId":"23294b54-8e67-4896-a7f3-681119e1ddbe","kind":"userMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":2,"status":"completed","recordedAt":"2026-10-08T07:29:25.643029Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with the following text: fixture simple ok","displayText":"Respond with the following text: fixture simple ok","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}},"emittedAtMs":1791444565652}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18},"last":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18}},"item":{"itemId":"23294b54-8e67-4896-a7f3-681119e1ddbe","kind":"userMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":1,"status":"completed","recordedAt":"2026-10-08T07:29:25.627042Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with the following text: fixture simple ok","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}},"emittedAtMs":1791444565635}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"8c00aa21-7809-4cb2-89f7-b499aaa8746d","sequence":20},"last":{"id":"8c00aa21-7809-4cb2-89f7-b499aaa8746d","sequence":20}},"item":{"itemId":"23294b54-8e67-4896-a7f3-681119e1ddbe","kind":"userMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":2,"status":"completed","recordedAt":"2026-10-08T07:29:25.643029Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with the following text: fixture simple ok","displayText":"Respond with the following text: fixture simple ok","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}},"emittedAtMs":1791444565652}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:6","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"ed1680a5-6f99-4b0f-b9ea-d12193f0de1f","sequence":37},"last":{"id":"ed1680a5-6f99-4b0f-b9ea-d12193f0de1f","sequence":37}},"item":{"itemId":"ed1680a5-6f99-4b0f-b9ea-d12193f0de1f","kind":"reminderChild","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:29:25.781511Z","fallbackText":"Reminder child session","childSessionId":"9785bf9d-382d-4781-ab3b-3817c9e6a604","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6a-bef1-7032-974a-059b8765c487"}},"emittedAtMs":1791444565789}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:6.1","item":{"itemId":"0a68e576-f554-4700-8853-a68ad2b7179b","kind":"agentMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":1,"status":"inProgress","text":""}},"emittedAtMs":1791444567707}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:6.2","itemId":"0a68e576-f554-4700-8853-a68ad2b7179b","field":"text","delta":"fixture simple ok"},"emittedAtMs":1791444567707}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/subagent_v2/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/subagent_v2/muse_transcript.ndjson index 5d181ddd95363..e3870c572c1e0 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/subagent_v2/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/subagent_v2/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","path":"~/.local/share/muse/sessions/2026/10/11/01a12d17-75fa-7000-9157-e8365ce94492/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:31:14.73121Z","updatedAt":"2026-10-11T22:31:14.731214Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791757874894}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","path":"~/.local/share/muse/sessions/2026/10/11/01a12d17-75fa-7000-9157-e8365ce94492/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:31:14.73121Z","updatedAt":"2026-10-11T22:31:14.731214Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:1","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"94d1e1ed-1d3e-4cd5-91bf-a51394fc8a0a","sequence":5},"last":{"id":"94d1e1ed-1d3e-4cd5-91bf-a51394fc8a0a","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a12d17-75fa-7001-a940-79b5d7c648a4","clientName":"t3_code"},"emittedAtMs":1791757874898}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:2","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"1dc98410-05c3-4618-a431-3638055e20df","sequence":15},"last":{"id":"1dc98410-05c3-4618-a431-3638055e20df","sequence":15}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791757875120}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a12d17-7790-7000-967d-3f2246f38a60","status":"accepted","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","status":"running","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:3"},"emittedAtMs":1791757875131}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:3","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17},"last":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17}},"turnId":"01a12d17-7790-7000-967d-3f2246f38a60","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"},"emittedAtMs":1791757875132}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:4","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17},"last":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17}},"item":{"itemId":"95c179c8-e8f8-4629-80df-e28243a234ea","kind":"userMessage","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":1,"status":"completed","recordedAt":"2026-10-11T22:31:15.120499Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}},"emittedAtMs":1791757875132}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:5","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"dcf03486-5149-4377-b325-dea3e118628a","sequence":19},"last":{"id":"dcf03486-5149-4377-b325-dea3e118628a","sequence":19}},"item":{"itemId":"95c179c8-e8f8-4629-80df-e28243a234ea","kind":"userMessage","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":2,"status":"completed","recordedAt":"2026-10-11T22:31:15.136047Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","displayText":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}},"emittedAtMs":1791757875144}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:4","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17},"last":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17}},"item":{"itemId":"95c179c8-e8f8-4629-80df-e28243a234ea","kind":"userMessage","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":1,"status":"completed","recordedAt":"2026-10-11T22:31:15.120499Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}},"emittedAtMs":1791757875132}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:5","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"dcf03486-5149-4377-b325-dea3e118628a","sequence":19},"last":{"id":"dcf03486-5149-4377-b325-dea3e118628a","sequence":19}},"item":{"itemId":"95c179c8-e8f8-4629-80df-e28243a234ea","kind":"userMessage","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":2,"status":"completed","recordedAt":"2026-10-11T22:31:15.136047Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","displayText":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}},"emittedAtMs":1791757875144}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:6","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"599a220a-d212-4a81-a60d-7284ff290284","sequence":36},"last":{"id":"599a220a-d212-4a81-a60d-7284ff290284","sequence":36}},"item":{"itemId":"599a220a-d212-4a81-a60d-7284ff290284","kind":"reminderChild","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":1,"status":"inProgress","recordedAt":"2026-10-11T22:31:15.249949Z","fallbackText":"Reminder child session","childSessionId":"0b3f4f01-850a-43bd-af36-9b011699354f","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a12d17-7819-7212-8057-3558c2bdd46d"}},"emittedAtMs":1791757875258}} {"type":"emit_inbound","label":"session/tokenUsage","frame":{"jsonrpc":"2.0","method":"session/tokenUsage","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:7","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"9198dd8d-eede-487a-9109-a48d2563c371","sequence":51},"last":{"id":"9198dd8d-eede-487a-9109-a48d2563c371","sequence":51}},"turnId":"01a12d17-7790-7000-967d-3f2246f38a60","modelId":"muse-spark-1.3-contributor","usage":{"inputTokens":32900,"outputTokens":129,"cachedTokens":0,"cacheWriteTokens":0,"cacheReadTokens":0,"reasoningTokens":36},"promptTokens":32900,"totalTokens":33029,"finishReason":"tool_calls","durationMs":2354,"cumulative":{"promptTokens":32900,"outputTokens":129,"totalTokens":33029,"cost":{"usd":0.0033158000000000003,"partial":false}}},"emittedAtMs":1791757877764}} {"type":"emit_inbound","label":"session/contextUsage","frame":{"jsonrpc":"2.0","method":"session/contextUsage","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:8","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"9198dd8d-eede-487a-9109-a48d2563c371","sequence":51},"last":{"id":"9198dd8d-eede-487a-9109-a48d2563c371","sequence":51}},"windowTokens":1007997,"usedTokens":33029,"pressure":"normal"},"emittedAtMs":1791757877764}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt/muse_transcript.ndjson index 760f7d276c896..d7755dedeab00 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt/muse_transcript.ndjson @@ -7,14 +7,14 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6d-2d3d-7000-8178-411fdb90bc34/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:32:05.094285Z","updatedAt":"2026-10-08T07:32:05.094289Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791444725265}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6d-2d3d-7000-8178-411fdb90bc34/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:32:05.094285Z","updatedAt":"2026-10-08T07:32:05.094289Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:1","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"9865268e-0a39-43a0-89d0-251a820ec8a3","sequence":5},"last":{"id":"9865268e-0a39-43a0-89d0-251a820ec8a3","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a11a6d-2d3e-7000-b0e7-f04c53ee070b","clientName":"t3_code"},"emittedAtMs":1791444725268}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally."}],"displayText":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally."}],"displayText":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:2","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"531b0e9e-c96d-4fa5-a6dd-5cc7d4569543","sequence":16},"last":{"id":"531b0e9e-c96d-4fa5-a6dd-5cc7d4569543","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444725509}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","status":"accepted","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","startedNewTurn":true,"disposition":"started"}}} {"type":"expect_outbound","label":"turn/interrupt","frame":{"jsonrpc":"2.0","id":4,"method":"turn/interrupt","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","commandId":"01a11a6d-2f0b-7000-a1d4-359cf54e471a"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","status":"running","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:3"},"emittedAtMs":1791444725522}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:3","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18},"last":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18}},"turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"},"emittedAtMs":1791444725523}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18},"last":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18}},"item":{"itemId":"cfa989ad-2359-4da2-9fca-562855cc0ae8","kind":"userMessage","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:05.510508Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}},"emittedAtMs":1791444725523}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"5db75d92-0e52-4bce-bb81-40e254b40bc3","sequence":20},"last":{"id":"5db75d92-0e52-4bce-bb81-40e254b40bc3","sequence":20}},"item":{"itemId":"cfa989ad-2359-4da2-9fca-562855cc0ae8","kind":"userMessage","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:05.530992Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","displayText":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}},"emittedAtMs":1791444725539}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18},"last":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18}},"item":{"itemId":"cfa989ad-2359-4da2-9fca-562855cc0ae8","kind":"userMessage","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:05.510508Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}},"emittedAtMs":1791444725523}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"5db75d92-0e52-4bce-bb81-40e254b40bc3","sequence":20},"last":{"id":"5db75d92-0e52-4bce-bb81-40e254b40bc3","sequence":20}},"item":{"itemId":"cfa989ad-2359-4da2-9fca-562855cc0ae8","kind":"userMessage","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:05.530992Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","displayText":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}},"emittedAtMs":1791444725539}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:6","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"ae604001-22b9-479c-a45b-3dcfed45996c","sequence":37},"last":{"id":"ae604001-22b9-479c-a45b-3dcfed45996c","sequence":37}},"item":{"itemId":"ae604001-22b9-479c-a45b-3dcfed45996c","kind":"reminderChild","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:32:05.638142Z","fallbackText":"Reminder child session","childSessionId":"1f58196a-6bf6-42da-9499-8f53a439e6e1","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6d-2f65-70b1-bb8f-69b33bb4fc62"}},"emittedAtMs":1791444725646}} {"type":"emit_inbound","label":"response:turn/interrupt","frame":{"jsonrpc":"2.0","id":4,"result":{"commandId":"01a11a6d-2f0b-7000-a1d4-359cf54e471a","status":"accepted","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}}} {"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:7","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"ae604001-22b9-479c-a45b-3dcfed45996c","sequence":37},"last":{"id":"3962d8d1-4608-4dda-8fdc-39a1804474aa","sequence":50}},"item":{"itemId":"ae604001-22b9-479c-a45b-3dcfed45996c","kind":"reminderChild","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":2,"status":"cancelled","recordedAt":"2026-10-08T07:32:05.727236Z","fallbackText":"Reminder child session","failureReason":"main run cancelled","childSessionId":"1f58196a-6bf6-42da-9499-8f53a439e6e1","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6d-2f65-70b1-bb8f-69b33bb4fc62"}},"emittedAtMs":1791444725734}} diff --git a/apps/server/src/provider/agentContextBudget.json b/apps/server/src/provider/agentContextBudget.json index ada92682fe5ec..053bb018b0f2b 100644 --- a/apps/server/src/provider/agentContextBudget.json +++ b/apps/server/src/provider/agentContextBudget.json @@ -1,5 +1,5 @@ { - "claudeSystemAppendBytes": 5729, - "codexAdditionalContextBytes": 7459, - "mcpToolListJsonBytes": 52072 + "claudeSystemAppendBytes": 5744, + "codexAdditionalContextBytes": 7474, + "mcpToolListJsonBytes": 52053 } diff --git a/packages/provider-core/src/server/runtimeInstructions.ts b/packages/provider-core/src/server/runtimeInstructions.ts index b9240dade6f98..99033d665b5a5 100644 --- a/packages/provider-core/src/server/runtimeInstructions.ts +++ b/packages/provider-core/src/server/runtimeInstructions.ts @@ -1,6 +1,6 @@ /** Session-invariant; harnesses with a native system-prompt append can carry it once per session. */ export const PULL_REQUEST_LINKING_INSTRUCTIONS = ` -Link each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, reply on, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you. +Link each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you. `; /** Omit model and effort when the harness manages them dynamically. */ From af397af58115e3313c58175dc9e119070d9c812a Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Thu, 12 Nov 2026 17:45:17 -0800 Subject: [PATCH 23/23] feat(server): PR tools are listed only where the thread's project is on a supported forge A project with no remote, or on a host T3 has no provider for, could only get errors from the forge tools. The MCP middleware now asks PullRequestService.servesProject for the calling thread's project (cached for a minute) and hides those tools when the answer is no. The PR instruction now applies when the tools are listed, so an agent without them neither searches for them nor tells the user a tool is missing. Co-Authored-By: Claude Opus 5.5 --- apps/server/src/mcp/McpHttpServer.test.ts | 199 ++++++++++-------- apps/server/src/mcp/McpHttpServer.ts | 28 ++- apps/server/src/mcp/McpInvocationContext.ts | 9 + .../src/mcp/toolkits/pullRequests/tools.ts | 21 +- .../multi_turn/muse_transcript.ndjson | 12 +- .../muse_permission/muse_transcript.ndjson | 12 +- .../muse_transcript.ndjson | 6 +- .../muse_transcript.ndjson | 6 +- .../muse_workflow/muse_transcript.ndjson | 6 +- .../fixtures/simple/muse_transcript.ndjson | 6 +- .../subagent_v2/muse_transcript.ndjson | 6 +- .../turn_interrupt/muse_transcript.ndjson | 6 +- .../src/provider/agentContextBudget.json | 6 +- .../pullRequest/PullRequestService.test.ts | 3 + .../src/pullRequest/PullRequestService.ts | 10 + apps/server/src/server.ts | 1 + evals/mcp-tool-use/cases/pull-requests.ndjson | 1 + evals/mcp-tool-use/run.ts | 36 +++- .../src/server/runtimeInstructions.ts | 2 +- 19 files changed, 242 insertions(+), 134 deletions(-) diff --git a/apps/server/src/mcp/McpHttpServer.test.ts b/apps/server/src/mcp/McpHttpServer.test.ts index 6a67c1f450155..27664e0d7204c 100644 --- a/apps/server/src/mcp/McpHttpServer.test.ts +++ b/apps/server/src/mcp/McpHttpServer.test.ts @@ -12,6 +12,7 @@ import { OrchestratorMcpEnvironmentTarget, OrchestratorMcpFailure, PreviewTabId, + ProjectId, ProviderInstanceId, ProviderInteractionMode, RuntimeMode, @@ -1510,96 +1511,122 @@ it.effect("hides tools for links and refuses another environment while the beta ).pipe(Effect.provide(NodeHttpServer.layerTest)), ); -it.effect("lists pull request watch tools only to threads that are not delegated children", () => - Effect.scoped( - Effect.gen(function* () { - const scopeFor = ( - token: string, - subagent: boolean, - ): McpInvocationContext.McpThreadInvocationScope => ({ - environmentId, - requestNamespace: token, - thread: { - threadId: ThreadId.make(`thread-${token}`), - providerSessionId: token, - providerInstanceId: ProviderInstanceId.make("codex"), - subagent, - }, - client: undefined, - capabilities: new Set(["pull-requests"]), - issuedAt: 1, - }); - const scopes = new Map([ - ["parentToken", scopeFor("parentToken", false)], - ["childToken", scopeFor("childToken", true)], - ]); - const serverLayer = McpHttpServer.layerMcpTransport( - McpHttpServer.layerPullRequestsToolkit, - ).pipe( - Layer.provide(ServerSettings.layerTest()), - Layer.provide( - Layer.mock(McpSessionRegistry.McpSessionRegistry)({ - resolve: (token) => Effect.succeed(scopes.get(token)), - }), - ), - Layer.provide( - Layer.mergeAll( - McpToolAccessTestkit.liveThreadsLayer, - Layer.mock(ProjectService.ProjectService)({}), - Layer.mock(PullRequestReviewGuideService.PullRequestReviewGuideService)({}), - Layer.mock(PullRequestService.PullRequestService)({}), - Layer.mock(GitManager.GitManager)({}), - Layer.mock(Orchestrator.OrchestratorV2)({}), - Layer.mock(ProjectionStore.ProjectionStoreV2)({}), - NodeServices.layer, - NodeCrypto.layer, +it.effect( + "lists watch tools only to threads that are not delegated children, and forge tools only where the project has a forge", + () => + Effect.scoped( + Effect.gen(function* () { + const scopeFor = ( + token: string, + subagent: boolean, + ): McpInvocationContext.McpThreadInvocationScope => ({ + environmentId, + requestNamespace: token, + thread: { + threadId: ThreadId.make(`thread-${token}`), + providerSessionId: token, + providerInstanceId: ProviderInstanceId.make("codex"), + subagent, + }, + client: undefined, + capabilities: new Set(["pull-requests"]), + issuedAt: 1, + }); + const scopes = new Map([ + ["parentToken", scopeFor("parentToken", false)], + ["childToken", scopeFor("childToken", true)], + ["noForgeToken", scopeFor("noForgeToken", false)], + ]); + const serverLayer = McpHttpServer.layerMcpTransport( + McpHttpServer.layerPullRequestsToolkit, + ).pipe( + Layer.provide(ServerSettings.layerTest()), + Layer.provide( + Layer.mock(McpSessionRegistry.McpSessionRegistry)({ + resolve: (token) => Effect.succeed(scopes.get(token)), + }), ), - ), - ); - yield* HttpRouter.serve(serverLayer, { disableListenLog: true, disableLogger: true }).pipe( - Layer.build, - ); - const httpClient = yield* HttpClient.HttpClient; - const listedTools = (token: string) => - Effect.gen(function* () { - const headers = { - accept: "application/json, text/event-stream", - authorization: `Bearer ${token}`, - }; - const initialize = yield* httpClient.post("/mcp", { - headers, - body: HttpBody.text( - `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1.0.0"}}}`, - "application/json", - ), - }); - const listed = yield* httpClient.post("/mcp", { - headers: { - ...headers, - "mcp-session-id": initialize.headers["mcp-session-id"]!, - "mcp-protocol-version": "2025-06-18", - }, - body: HttpBody.text( - `{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}`, - "application/json", + Layer.provide( + Layer.mergeAll( + McpToolAccessTestkit.liveThreadsLayer, + Layer.mock(ProjectService.ProjectService)({}), + Layer.mock(PullRequestReviewGuideService.PullRequestReviewGuideService)({}), + Layer.mock(PullRequestService.PullRequestService)({ + servesProject: (projectId) => Effect.succeed(projectId !== "project-noForgeToken"), + }), + Layer.mock(GitManager.GitManager)({}), + Layer.mock(Orchestrator.OrchestratorV2)({}), + Layer.mock(ProjectionStore.ProjectionStoreV2)({ + getThreadShell: (threadId) => + Effect.succeed({ + projectId: ProjectId.make(threadId.replace("thread-", "project-")), + } as never), + }), + NodeServices.layer, + NodeCrypto.layer, ), + ), + ); + yield* HttpRouter.serve(serverLayer, { disableListenLog: true, disableLogger: true }).pipe( + Layer.build, + ); + const httpClient = yield* HttpClient.HttpClient; + const listedTools = (token: string) => + Effect.gen(function* () { + const headers = { + accept: "application/json, text/event-stream", + authorization: `Bearer ${token}`, + }; + const initialize = yield* httpClient.post("/mcp", { + headers, + body: HttpBody.text( + `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1.0.0"}}}`, + "application/json", + ), + }); + const listed = yield* httpClient.post("/mcp", { + headers: { + ...headers, + "mcp-session-id": initialize.headers["mcp-session-id"]!, + "mcp-protocol-version": "2025-06-18", + }, + body: HttpBody.text( + `{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}`, + "application/json", + ), + }); + const body = (yield* listed.json) as { + readonly result: { readonly tools: ReadonlyArray<{ readonly name: string }> }; + }; + return body.result.tools.map((tool) => tool.name); }); - const body = (yield* listed.json) as { - readonly result: { readonly tools: ReadonlyArray<{ readonly name: string }> }; - }; - return body.result.tools.map((tool) => tool.name); - }); - const parentTools = yield* listedTools("parentToken"); - const childTools = yield* listedTools("childToken"); - expect(parentTools).toEqual( - expect.arrayContaining(["link_pull_request", "watch_pull_request", "unwatch_pull_request"]), - ); - expect(childTools).toContain("link_pull_request"); - expect(childTools).not.toContain("watch_pull_request"); - expect(childTools).not.toContain("unwatch_pull_request"); - }), - ).pipe(Effect.provide(NodeHttpServer.layerTest)), + const parentTools = yield* listedTools("parentToken"); + const childTools = yield* listedTools("childToken"); + expect(parentTools).toEqual( + expect.arrayContaining([ + "link_pull_request", + "watch_pull_request", + "unwatch_pull_request", + ]), + ); + expect(childTools).toContain("link_pull_request"); + expect(childTools).not.toContain("watch_pull_request"); + expect(childTools).not.toContain("unwatch_pull_request"); + expect(parentTools).toEqual( + expect.arrayContaining([ + "pull_request_read", + "pull_request_review", + "pull_request_merge", + ]), + ); + const noForgeTools = yield* listedTools("noForgeToken"); + expect(noForgeTools).toEqual( + expect.arrayContaining(["link_pull_request", "watch_pull_request"]), + ); + expect(noForgeTools.filter((name) => name.startsWith("pull_request_"))).toEqual([]); + }), + ).pipe(Effect.provide(NodeHttpServer.layerTest)), ); it.effect( diff --git a/apps/server/src/mcp/McpHttpServer.ts b/apps/server/src/mcp/McpHttpServer.ts index 39f679154bcfe..f34e6bdb2f6c3 100644 --- a/apps/server/src/mcp/McpHttpServer.ts +++ b/apps/server/src/mcp/McpHttpServer.ts @@ -1,6 +1,8 @@ +import * as Cache from "effect/Cache"; import * as Cause from "effect/Cause"; import * as Clock from "effect/Clock"; import * as Context from "effect/Context"; +import * as Duration from "effect/Duration"; import * as SecureRandom from "effect/crypto/SecureRandom"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -33,6 +35,8 @@ import * as DeviceService from "../device/DeviceService.ts"; import * as HtmlRender from "../htmlRender/HtmlRender.ts"; import * as ThreadCommandExecutor from "../orchestration-v2/ThreadCommandExecutor.ts"; import * as ThreadManagementService from "../orchestration-v2/ThreadManagementService.ts"; +import * as ProjectionStore from "../orchestration-v2/ProjectionStore.ts"; +import * as PullRequestService from "../pullRequest/PullRequestService.ts"; import * as PullRequestWatchService from "../pullRequest/PullRequestWatchService.ts"; import * as ProviderRegistry from "../provider/ProviderRegistry.ts"; import * as AnalyticsService from "../telemetry/AnalyticsService.ts"; @@ -238,6 +242,24 @@ const makeMcpAuthMiddleware = Effect.gen(function* () { Effect.map((settings) => settings.linkedEnvironmentsEnabled), Effect.orElseSucceed(() => false), ); + const pullRequests = yield* Effect.serviceOption(PullRequestService.PullRequestService); + const projections = yield* Effect.serviceOption(ProjectionStore.ProjectionStoreV2); + // Every request reads it, and a remote added mid-thread shows the tools within a minute. + const forgeOfThread = yield* Cache.make({ + capacity: 1_000, + timeToLive: Duration.minutes(1), + lookup: (threadId: ThreadId): Effect.Effect => + Option.isNone(pullRequests) || Option.isNone(projections) + ? Effect.undefined + : projections.value.getThreadShell(threadId).pipe( + Effect.flatMap((thread) => + thread === null + ? Effect.undefined + : pullRequests.value.servesProject(thread.projectId), + ), + Effect.orElseSucceed(() => undefined), + ), + }); const authenticateRequest = Effect.fn("McpHttpServer.authenticateRequest")(function* ( request: HttpServerRequest.HttpServerRequest, ) { @@ -270,7 +292,11 @@ const makeMcpAuthMiddleware = Effect.gen(function* () { const limited = McpInvocationContext.withRuntimeModeCeiling(asked, runtimeModeCeiling); const linkedEnvironments = yield* linksEnabled; if (limited.client?.linked === true && !linkedEnvironments) return linkedEnvironmentsOff; - return { ...limited, linkedEnvironments }; + const forge = + limited.thread === undefined + ? undefined + : yield* Cache.get(forgeOfThread, limited.thread.threadId); + return { ...limited, linkedEnvironments, ...(forge === undefined ? {} : { forge }) }; }); // Untraced: a span here would wrap the tool call; the HTTP server span already covers it. return Effect.fnUntraced(function* (httpEffect) { diff --git a/apps/server/src/mcp/McpInvocationContext.ts b/apps/server/src/mcp/McpInvocationContext.ts index eb102be177782..582b689fc1a26 100644 --- a/apps/server/src/mcp/McpInvocationContext.ts +++ b/apps/server/src/mcp/McpInvocationContext.ts @@ -141,6 +141,8 @@ export interface McpInvocationScope { readonly client: McpClientCaller | undefined; /** False while the Linked environments beta is off here; `/mcp` reads it per request. */ readonly linkedEnvironments?: boolean; + /** False when the calling thread's project is on no forge T3 reads; `/mcp` reads it per request. */ + readonly forge?: boolean; } /** @@ -182,6 +184,13 @@ export const hiddenWhileLinksOff = (): boolean => { return scope?.linkedEnvironments !== false; }; +/** `McpSchema.EnabledWhen` for tools that act on the thread's forge, hidden where it has none. */ +export const hiddenWithoutForge = (): boolean => { + const fiber = Fiber.getCurrent(); + const scope = fiber && Context.getOrUndefined(fiber.context, McpInvocationContext); + return scope?.forge !== false; +}; + export type McpCapabilityError = C extends "preview" ? PreviewAutomationUnavailableError : McpCapabilityUnavailableError; diff --git a/apps/server/src/mcp/toolkits/pullRequests/tools.ts b/apps/server/src/mcp/toolkits/pullRequests/tools.ts index 1b5d15d45ba8d..73350d9d7b8d8 100644 --- a/apps/server/src/mcp/toolkits/pullRequests/tools.ts +++ b/apps/server/src/mcp/toolkits/pullRequests/tools.ts @@ -613,7 +613,8 @@ const ReadPullRequestTool = Tool.make("pull_request_read", { .annotate(Tool.Readonly, true) .annotate(Tool.Destructive, false) .annotate(Tool.Idempotent, true) - .annotate(Tool.OpenWorld, true); + .annotate(Tool.OpenWorld, true) + .annotate(McpSchema.EnabledWhen, McpInvocationContext.hiddenWithoutForge); const ListPullRequestsTool = Tool.make("pull_request_list", { description: "List PRs in this thread's repository, recently updated first.", @@ -633,7 +634,8 @@ const ListPullRequestsTool = Tool.make("pull_request_list", { .annotate(Tool.Readonly, true) .annotate(Tool.Destructive, false) .annotate(Tool.Idempotent, true) - .annotate(Tool.OpenWorld, true); + .annotate(Tool.OpenWorld, true) + .annotate(McpSchema.EnabledWhen, McpInvocationContext.hiddenWithoutForge); const CreatePullRequestTool = Tool.make("pull_request_create", { description: "Open a PR from this thread's pushed branch and link it, or return its open PR.", @@ -652,7 +654,8 @@ const CreatePullRequestTool = Tool.make("pull_request_create", { .annotate(Tool.Readonly, false) .annotate(Tool.Destructive, false) .annotate(Tool.Idempotent, true) - .annotate(Tool.OpenWorld, true); + .annotate(Tool.OpenWorld, true) + .annotate(McpSchema.EnabledWhen, McpInvocationContext.hiddenWithoutForge); const UpdateNames = Schema.Array(TrimmedNonEmptyString).check( Schema.isMinLength(1), @@ -682,7 +685,8 @@ const UpdatePullRequestTool = Tool.make("pull_request_update", { .annotate(Tool.Readonly, false) .annotate(Tool.Destructive, false) .annotate(Tool.Idempotent, true) - .annotate(Tool.OpenWorld, true); + .annotate(Tool.OpenWorld, true) + .annotate(McpSchema.EnabledWhen, McpInvocationContext.hiddenWithoutForge); const RespondToPullRequestTool = Tool.make("pull_request_respond", { description: @@ -701,7 +705,8 @@ const RespondToPullRequestTool = Tool.make("pull_request_respond", { .annotate(Tool.Readonly, false) .annotate(Tool.Destructive, false) .annotate(Tool.Idempotent, false) - .annotate(Tool.OpenWorld, true); + .annotate(Tool.OpenWorld, true) + .annotate(McpSchema.EnabledWhen, McpInvocationContext.hiddenWithoutForge); export const ReviewLineComment = Schema.Struct({ path: TrimmedNonEmptyString, @@ -733,7 +738,8 @@ const ReviewPullRequestTool = Tool.make("pull_request_review", { .annotate(Tool.Readonly, false) .annotate(Tool.Destructive, false) .annotate(Tool.Idempotent, false) - .annotate(Tool.OpenWorld, true); + .annotate(Tool.OpenWorld, true) + .annotate(McpSchema.EnabledWhen, McpInvocationContext.hiddenWithoutForge); const MergePullRequestTool = Tool.make("pull_request_merge", { description: "Merge a PR. Refuses if the head moved from expectedHeadSha (summary.headSha).", @@ -755,7 +761,8 @@ const MergePullRequestTool = Tool.make("pull_request_merge", { .annotate(Tool.Readonly, false) .annotate(Tool.Destructive, true) .annotate(Tool.Idempotent, false) - .annotate(Tool.OpenWorld, true); + .annotate(Tool.OpenWorld, true) + .annotate(McpSchema.EnabledWhen, McpInvocationContext.hiddenWithoutForge); export const PullRequestsToolkit = Toolkit.make( LinkPullRequestTool, diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/muse_transcript.ndjson index 10cf89bce38cd..28b6b85c382f5 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6b-707e-7000-9bb5-4079c7772ad0/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:30:11.238412Z","updatedAt":"2026-10-08T07:30:11.238416Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791444611408}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6b-707e-7000-9bb5-4079c7772ad0/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:30:11.238412Z","updatedAt":"2026-10-08T07:30:11.238416Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:1","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"37b19bd1-b212-4532-a0c9-a6677f303e26","sequence":5},"last":{"id":"37b19bd1-b212-4532-a0c9-a6677f303e26","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a11a6b-707e-7001-b2f4-23db74e60097","clientName":"t3_code"},"emittedAtMs":1791444611412}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Respond with exactly: first fixture turn complete"}],"displayText":"Respond with exactly: first fixture turn complete","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\n"},{"type":"text","text":"Respond with exactly: first fixture turn complete"}],"displayText":"Respond with exactly: first fixture turn complete","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:2","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"2c530748-943b-4467-8473-da8b04c511c3","sequence":16},"last":{"id":"2c530748-943b-4467-8473-da8b04c511c3","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444611661}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","status":"accepted","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","status":"running","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:3"},"emittedAtMs":1791444611674}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:3","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18},"last":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18}},"turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"},"emittedAtMs":1791444611675}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18},"last":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18}},"item":{"itemId":"1b470279-ee8c-4c74-a298-f37184145584","kind":"userMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":1,"status":"completed","recordedAt":"2026-10-08T07:30:11.66263Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: first fixture turn complete","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}},"emittedAtMs":1791444611675}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"31b500d6-40fc-4f4c-b097-6b7be8d77cee","sequence":20},"last":{"id":"31b500d6-40fc-4f4c-b097-6b7be8d77cee","sequence":20}},"item":{"itemId":"1b470279-ee8c-4c74-a298-f37184145584","kind":"userMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":2,"status":"completed","recordedAt":"2026-10-08T07:30:11.680942Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: first fixture turn complete","displayText":"Respond with exactly: first fixture turn complete","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}},"emittedAtMs":1791444611689}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18},"last":{"id":"2be0c9b5-9dc4-48f0-9b86-06aef4de31f3","sequence":18}},"item":{"itemId":"1b470279-ee8c-4c74-a298-f37184145584","kind":"userMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":1,"status":"completed","recordedAt":"2026-10-08T07:30:11.66263Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nRespond with exactly: first fixture turn complete","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}},"emittedAtMs":1791444611675}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"31b500d6-40fc-4f4c-b097-6b7be8d77cee","sequence":20},"last":{"id":"31b500d6-40fc-4f4c-b097-6b7be8d77cee","sequence":20}},"item":{"itemId":"1b470279-ee8c-4c74-a298-f37184145584","kind":"userMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":2,"status":"completed","recordedAt":"2026-10-08T07:30:11.680942Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nRespond with exactly: first fixture turn complete","displayText":"Respond with exactly: first fixture turn complete","commandId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4"}},"emittedAtMs":1791444611689}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:6","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"077780ea-0dc9-4d7a-879c-ee368f3adbe0","sequence":37},"last":{"id":"077780ea-0dc9-4d7a-879c-ee368f3adbe0","sequence":37}},"item":{"itemId":"077780ea-0dc9-4d7a-879c-ee368f3adbe0","kind":"reminderChild","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:30:11.790301Z","fallbackText":"Reminder child session","childSessionId":"c13379db-6761-40b4-a974-b0f1a58717aa","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6b-72ac-7972-a1df-b343b7804b38"}},"emittedAtMs":1791444611795}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:6.1","item":{"itemId":"f99b90e1-9d8b-4bf2-8e7a-e240e1cf9321","kind":"agentMessage","turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","revision":1,"status":"inProgress","text":""}},"emittedAtMs":1791444618068}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:6.2","itemId":"f99b90e1-9d8b-4bf2-8e7a-e240e1cf9321","field":"text","delta":"first fixture turn complete"},"emittedAtMs":1791444618068}} @@ -29,12 +29,12 @@ {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","status":"idle","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:16"},"emittedAtMs":1791444621046}} {"type":"emit_inbound","label":"turn/completed","frame":{"jsonrpc":"2.0","method":"turn/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:16","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"688a69c5-e353-4db9-bd8c-1beb033902ba","sequence":79},"last":{"id":"688a69c5-e353-4db9-bd8c-1beb033902ba","sequence":79}},"turnId":"01a11a6b-722c-7000-a73a-1d49a3a7f4c4","terminal":"completed","durationMs":9378,"timeToFirstTokenMs":6406},"emittedAtMs":1791444621047}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:17","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"36753b8a-26ce-4935-8127-bc9191cb328b","sequence":80},"last":{"id":"36753b8a-26ce-4935-8127-bc9191cb328b","sequence":80}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444621054}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":4,"method":"turn/start","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Respond with exactly: second fixture turn complete"}],"displayText":"Respond with exactly: second fixture turn complete","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":4,"method":"turn/start","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\n"},{"type":"text","text":"Respond with exactly: second fixture turn complete"}],"displayText":"Respond with exactly: second fixture turn complete","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":4,"result":{"commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","status":"accepted","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","status":"running","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:18"},"emittedAtMs":1791444621333}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:18","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87},"last":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87}},"turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"},"emittedAtMs":1791444621334}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:19","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87},"last":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87}},"item":{"itemId":"90719a5d-d2c1-46dc-ad4d-274adda02344","kind":"userMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":1,"status":"completed","recordedAt":"2026-10-08T07:30:21.321391Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: second fixture turn complete","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}},"emittedAtMs":1791444621334}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:20","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"dc502e2c-d81c-4f0e-ad86-dd11d1368677","sequence":89},"last":{"id":"dc502e2c-d81c-4f0e-ad86-dd11d1368677","sequence":89}},"item":{"itemId":"90719a5d-d2c1-46dc-ad4d-274adda02344","kind":"userMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":2,"status":"completed","recordedAt":"2026-10-08T07:30:21.338944Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with exactly: second fixture turn complete","displayText":"Respond with exactly: second fixture turn complete","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}},"emittedAtMs":1791444621347}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:19","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87},"last":{"id":"4aba96d5-f984-4bc0-bda4-7fb97f527686","sequence":87}},"item":{"itemId":"90719a5d-d2c1-46dc-ad4d-274adda02344","kind":"userMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":1,"status":"completed","recordedAt":"2026-10-08T07:30:21.321391Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nRespond with exactly: second fixture turn complete","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}},"emittedAtMs":1791444621334}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:20","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"dc502e2c-d81c-4f0e-ad86-dd11d1368677","sequence":89},"last":{"id":"dc502e2c-d81c-4f0e-ad86-dd11d1368677","sequence":89}},"item":{"itemId":"90719a5d-d2c1-46dc-ad4d-274adda02344","kind":"userMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":2,"status":"completed","recordedAt":"2026-10-08T07:30:21.338944Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nRespond with exactly: second fixture turn complete","displayText":"Respond with exactly: second fixture turn complete","commandId":"01a11a6b-97ec-7000-bd1b-d7afbea11045"}},"emittedAtMs":1791444621347}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:21","sourceRange":{"stream":{"kind":"session","id":"01a11a6b-707e-7000-9bb5-4079c7772ad0"},"first":{"id":"09cb4c2a-03c2-4089-ba12-8d5d31f7ea48","sequence":106},"last":{"id":"09cb4c2a-03c2-4089-ba12-8d5d31f7ea48","sequence":106}},"item":{"itemId":"09cb4c2a-03c2-4089-ba12-8d5d31f7ea48","kind":"reminderChild","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:30:21.446966Z","fallbackText":"Reminder child session","childSessionId":"cd97261a-3ea9-480f-9e54-5e59bb077da2","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6b-9869-7061-a4f3-42daa3e3a8f1"}},"emittedAtMs":1791444621455}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:21.1","item":{"itemId":"2de26c0d-26b4-4533-8810-918ee44fcd82","kind":"agentMessage","turnId":"01a11a6b-97ec-7000-bd1b-d7afbea11045","revision":1,"status":"inProgress","text":""}},"emittedAtMs":1791444623127}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a11a6b-707e-7000-9bb5-4079c7772ad0","viewCursor":"v:01a11a6b-707e-7000-9bb5-4079c7772ad0:21.2","itemId":"2de26c0d-26b4-4533-8810-918ee44fcd82","field":"text","delta":"second fixture turn complete"},"emittedAtMs":1791444623127}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/muse_permission/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/muse_permission/muse_transcript.ndjson index 51d6322853257..94a525ca25a6e 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/muse_permission/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/muse_permission/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6d-39bb-7000-8c93-4594c98e6a11/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:32:08.30084Z","updatedAt":"2026-10-08T07:32:08.300844Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"promptUnmatched","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791444728496}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6d-39bb-7000-8c93-4594c98e6a11/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:32:08.30084Z","updatedAt":"2026-10-08T07:32:08.300844Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"promptUnmatched","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:1","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b05fb8ec-7b58-4cf7-a369-379938395230","sequence":5},"last":{"id":"b05fb8ec-7b58-4cf7-a369-379938395230","sequence":5}},"mode":"promptUnmatched","source":"approvalReconfigure","commandId":"01a11a6d-39bb-7001-923e-425cc6129ce7","clientName":"t3_code"},"emittedAtMs":1791444728501}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE."}],"displayText":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\n"},{"type":"text","text":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE."}],"displayText":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:2","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"6159e84a-ae1e-4fae-ae8b-49f41ca34509","sequence":16},"last":{"id":"6159e84a-ae1e-4fae-ae8b-49f41ca34509","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444728769}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","status":"accepted","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","status":"running","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:3"},"emittedAtMs":1791444728783}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:3","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18},"last":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18}},"turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"},"emittedAtMs":1791444728783}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18},"last":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18}},"item":{"itemId":"dde9573b-650f-434b-ab99-60cfc820a0a5","kind":"userMessage","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:08.769894Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}},"emittedAtMs":1791444728784}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"76c57706-1378-4167-8bbf-f76d959804e8","sequence":20},"last":{"id":"76c57706-1378-4167-8bbf-f76d959804e8","sequence":20}},"item":{"itemId":"dde9573b-650f-434b-ab99-60cfc820a0a5","kind":"userMessage","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:08.791728Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","displayText":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}},"emittedAtMs":1791444728800}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18},"last":{"id":"09218c3a-88fd-4bc8-ab45-d1aa69bea95a","sequence":18}},"item":{"itemId":"dde9573b-650f-434b-ab99-60cfc820a0a5","kind":"userMessage","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:08.769894Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nRun the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}},"emittedAtMs":1791444728784}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"76c57706-1378-4167-8bbf-f76d959804e8","sequence":20},"last":{"id":"76c57706-1378-4167-8bbf-f76d959804e8","sequence":20}},"item":{"itemId":"dde9573b-650f-434b-ab99-60cfc820a0a5","kind":"userMessage","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:08.791728Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nRun the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","displayText":"Run the shell command `touch muse-approved.txt` with your shell tool, then reply DONE.","commandId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6"}},"emittedAtMs":1791444728800}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:6","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"29180105-84c4-4f9e-8bfd-003392b93b73","sequence":38},"last":{"id":"29180105-84c4-4f9e-8bfd-003392b93b73","sequence":38}},"item":{"itemId":"29180105-84c4-4f9e-8bfd-003392b93b73","kind":"reminderChild","turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:32:08.905989Z","fallbackText":"Reminder child session","childSessionId":"7c9485f9-26aa-4b56-8ca2-f36cb9cfb8c4","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6d-3c27-73f2-8c27-cd06a3b7dadf"}},"emittedAtMs":1791444728910}} {"type":"emit_inbound","label":"session/tokenUsage","frame":{"jsonrpc":"2.0","method":"session/tokenUsage","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:7","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b1dab1f5-3c9e-4d92-b955-841a2269c23c","sequence":54},"last":{"id":"b1dab1f5-3c9e-4d92-b955-841a2269c23c","sequence":54}},"turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","modelId":"muse-spark-1.3-contributor","usage":{"inputTokens":32618,"outputTokens":315,"cachedTokens":0,"cacheWriteTokens":0,"cacheReadTokens":0,"reasoningTokens":227},"promptTokens":32618,"totalTokens":32933,"finishReason":"tool_calls","durationMs":2684,"cumulative":{"promptTokens":32618,"outputTokens":315,"totalTokens":32933,"cost":{"usd":0.0033248,"partial":false}}},"emittedAtMs":1791444731684}} {"type":"emit_inbound","label":"session/contextUsage","frame":{"jsonrpc":"2.0","method":"session/contextUsage","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:8","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b1dab1f5-3c9e-4d92-b955-841a2269c23c","sequence":54},"last":{"id":"b1dab1f5-3c9e-4d92-b955-841a2269c23c","sequence":54}},"windowTokens":1007997,"usedTokens":32933,"pressure":"normal"},"emittedAtMs":1791444731684}} @@ -42,12 +42,12 @@ {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","status":"idle","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:23"},"emittedAtMs":1791444747386}} {"type":"emit_inbound","label":"turn/completed","frame":{"jsonrpc":"2.0","method":"turn/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:23","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"7c29ac76-7e09-48c1-a18f-f336126e27d1","sequence":120},"last":{"id":"7c29ac76-7e09-48c1-a18f-f336126e27d1","sequence":120}},"turnId":"01a11a6d-3b9f-7000-b6ad-ab05e6b973b6","terminal":"completed","durationMs":18608,"timeToFirstTokenMs":4791},"emittedAtMs":1791444747387}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:24","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"1e4afe30-d924-444c-8665-5e763f524e70","sequence":121},"last":{"id":"1e4afe30-d924-444c-8665-5e763f524e70","sequence":121}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444747394}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":5,"method":"turn/start","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED."}],"displayText":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":5,"method":"turn/start","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\n"},{"type":"text","text":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED."}],"displayText":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":5,"result":{"commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29","status":"accepted","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","status":"running","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:25"},"emittedAtMs":1791444747660}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:25","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128},"last":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128}},"turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"},"emittedAtMs":1791444747660}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:26","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128},"last":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128}},"item":{"itemId":"27473708-71e0-4d3c-811c-a8bae6bbaa3b","kind":"userMessage","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:27.650913Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}},"emittedAtMs":1791444747660}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:27","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a056a03-469a-4c9f-94a9-78eb815023ad","sequence":130},"last":{"id":"4a056a03-469a-4c9f-94a9-78eb815023ad","sequence":130}},"item":{"itemId":"27473708-71e0-4d3c-811c-a8bae6bbaa3b","kind":"userMessage","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:27.66745Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRun the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","displayText":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}},"emittedAtMs":1791444747676}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:26","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128},"last":{"id":"4a1cf90d-7457-448d-a2b5-d82108636b3b","sequence":128}},"item":{"itemId":"27473708-71e0-4d3c-811c-a8bae6bbaa3b","kind":"userMessage","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:27.650913Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nRun the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}},"emittedAtMs":1791444747660}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:27","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"4a056a03-469a-4c9f-94a9-78eb815023ad","sequence":130},"last":{"id":"4a056a03-469a-4c9f-94a9-78eb815023ad","sequence":130}},"item":{"itemId":"27473708-71e0-4d3c-811c-a8bae6bbaa3b","kind":"userMessage","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:27.66745Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nRun the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","displayText":"Run the shell command `touch muse-declined.txt` with your shell tool once. If it is rejected, do not retry; reply REJECTED.","commandId":"01a11a6d-8566-7000-8ad1-6269ac187a29"}},"emittedAtMs":1791444747676}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:28","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"3b28955d-a87a-4acb-97e9-14cad87fd41f","sequence":148},"last":{"id":"3b28955d-a87a-4acb-97e9-14cad87fd41f","sequence":148}},"item":{"itemId":"3b28955d-a87a-4acb-97e9-14cad87fd41f","kind":"reminderChild","turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:32:27.787099Z","fallbackText":"Reminder child session","childSessionId":"efd21bf1-4fd1-49a2-9c55-91b7fc099765","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6d-85ed-7b91-8d91-c4ce76b6dfef"}},"emittedAtMs":1791444747794}} {"type":"emit_inbound","label":"session/tokenUsage","frame":{"jsonrpc":"2.0","method":"session/tokenUsage","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:29","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b032c01d-eae1-437e-910c-8756aedc6084","sequence":164},"last":{"id":"b032c01d-eae1-437e-910c-8756aedc6084","sequence":164}},"turnId":"01a11a6d-8566-7000-8ad1-6269ac187a29","modelId":"muse-spark-1.3-contributor","usage":{"inputTokens":33401,"outputTokens":201,"cachedTokens":33009,"cacheWriteTokens":0,"cacheReadTokens":33009,"reasoningTokens":108},"promptTokens":33401,"totalTokens":33602,"finishReason":"tool_calls","durationMs":2522,"cumulative":{"promptTokens":99045,"outputTokens":538,"totalTokens":99583,"cacheReadTokens":65506,"cost":{"usd":0.003592512,"partial":false}}},"emittedAtMs":1791444750395}} {"type":"emit_inbound","label":"session/contextUsage","frame":{"jsonrpc":"2.0","method":"session/contextUsage","params":{"sessionId":"01a11a6d-39bb-7000-8c93-4594c98e6a11","viewCursor":"v:01a11a6d-39bb-7000-8c93-4594c98e6a11:30","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-39bb-7000-8c93-4594c98e6a11"},"first":{"id":"b032c01d-eae1-437e-910c-8756aedc6084","sequence":164},"last":{"id":"b032c01d-eae1-437e-910c-8756aedc6084","sequence":164}},"windowTokens":1007997,"usedTokens":33602,"pressure":"normal"},"emittedAtMs":1791444750395}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_approval/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_approval/muse_transcript.ndjson index 3f098fa8f6530..b602a51dff03d 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_approval/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_approval/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","path":"~/.local/share/muse/sessions/2026/10/11/01a12d1d-a1b7-7000-9697-d430c2e2afd8/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:37:59.14136Z","updatedAt":"2026-10-11T22:37:59.141364Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"promptUnmatched","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791758279294}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","path":"~/.local/share/muse/sessions/2026/10/11/01a12d1d-a1b7-7000-9697-d430c2e2afd8/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:37:59.14136Z","updatedAt":"2026-10-11T22:37:59.141364Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"promptUnmatched","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:1","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"ed95a9db-eada-4751-a7e6-22ccc9bdabd5","sequence":5},"last":{"id":"ed95a9db-eada-4751-a7e6-22ccc9bdabd5","sequence":5}},"mode":"promptUnmatched","source":"approvalReconfigure","commandId":"01a12d1d-a1b8-7000-8d6c-f1324b724cdb","clientName":"t3_code"},"emittedAtMs":1791758279297}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\n"},{"type":"text","text":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:2","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"4f170229-d428-4a64-9516-7a355ff3bcdb","sequence":15},"last":{"id":"4f170229-d428-4a64-9516-7a355ff3bcdb","sequence":15}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791758279531}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","status":"accepted","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","status":"running","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:3"},"emittedAtMs":1791758279541}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:3","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17},"last":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17}},"turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"},"emittedAtMs":1791758279542}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:4","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17},"last":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17}},"item":{"itemId":"a4b3de8d-842b-4065-8769-aed18e62e9fc","kind":"userMessage","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":1,"status":"completed","recordedAt":"2026-10-11T22:37:59.531477Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}},"emittedAtMs":1791758279542}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:5","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"5a63e348-5bf6-4262-b37f-d31d307ea6d8","sequence":19},"last":{"id":"5a63e348-5bf6-4262-b37f-d31d307ea6d8","sequence":19}},"item":{"itemId":"a4b3de8d-842b-4065-8769-aed18e62e9fc","kind":"userMessage","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":2,"status":"completed","recordedAt":"2026-10-11T22:37:59.545908Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","displayText":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}},"emittedAtMs":1791758279553}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:4","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17},"last":{"id":"429e8ecf-d532-4b14-a303-b9f832c36a51","sequence":17}},"item":{"itemId":"a4b3de8d-842b-4065-8769-aed18e62e9fc","kind":"userMessage","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":1,"status":"completed","recordedAt":"2026-10-11T22:37:59.531477Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nDo not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}},"emittedAtMs":1791758279542}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:5","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"5a63e348-5bf6-4262-b37f-d31d307ea6d8","sequence":19},"last":{"id":"5a63e348-5bf6-4262-b37f-d31d307ea6d8","sequence":19}},"item":{"itemId":"a4b3de8d-842b-4065-8769-aed18e62e9fc","kind":"userMessage","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":2,"status":"completed","recordedAt":"2026-10-11T22:37:59.545908Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nDo not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","displayText":"Do not run any commands yourself. Spawn one subagent whose only task is to run this exact shell command: printf 'subagent approval fixture' > subagent-approval.txt and then reply with exactly: Written. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d1d-a348-7000-ae97-9d27b5f80bce"}},"emittedAtMs":1791758279553}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:6","sourceRange":{"stream":{"kind":"session","id":"01a12d1d-a1b7-7000-9697-d430c2e2afd8"},"first":{"id":"d55286a9-a9e2-4d7b-be97-d44360bcca2b","sequence":37},"last":{"id":"d55286a9-a9e2-4d7b-be97-d44360bcca2b","sequence":37}},"item":{"itemId":"d55286a9-a9e2-4d7b-be97-d44360bcca2b","kind":"reminderChild","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":1,"status":"inProgress","recordedAt":"2026-10-11T22:37:59.660065Z","fallbackText":"Reminder child session","childSessionId":"0779d605-54b8-45dc-90b6-91dc58b9a52c","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a12d1d-a3d4-7712-8b98-26f3c4f9bf38"}},"emittedAtMs":1791758279666}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:6.1","item":{"itemId":"21b74b34-fe9f-457c-83f0-cf49257b5948","kind":"reasoning","turnId":"01a12d1d-a348-7000-ae97-9d27b5f80bce","revision":1,"status":"inProgress","summary":[""]}},"emittedAtMs":1791758282481}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a12d1d-a1b7-7000-9697-d430c2e2afd8","viewCursor":"v:01a12d1d-a1b7-7000-9697-d430c2e2afd8:6.2","itemId":"21b74b34-fe9f-457c-83f0-cf49257b5948","field":"summary.0","delta":"Spawning a subagent via muse_subagent_spawn to run a shell command and return its exact output, while avoiding direct command execution."},"emittedAtMs":1791758282481}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_interrupt/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_interrupt/muse_transcript.ndjson index d9d5111aa4f69..d50e22967dad4 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_interrupt/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_interrupt/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","path":"~/.local/share/muse/sessions/2026/10/11/01a12d28-7788-7000-a946-c407f380868e/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:49:49.235205Z","updatedAt":"2026-10-11T22:49:49.235209Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791758989388}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","path":"~/.local/share/muse/sessions/2026/10/11/01a12d28-7788-7000-a946-c407f380868e/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:49:49.235205Z","updatedAt":"2026-10-11T22:49:49.235209Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:1","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"29d4e769-78f7-48fa-90cd-3ac9f8fa04bf","sequence":5},"last":{"id":"29d4e769-78f7-48fa-90cd-3ac9f8fa04bf","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a12d28-7788-7001-a223-c10e52187cdf","clientName":"t3_code"},"emittedAtMs":1791758989391}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\n"},{"type":"text","text":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:2","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"660e2cfd-318a-4d2d-87bb-0b1375d79fdf","sequence":15},"last":{"id":"660e2cfd-318a-4d2d-87bb-0b1375d79fdf","sequence":15}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791758989619}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a12d28-7912-7000-993a-afd019e6ac5c","status":"accepted","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","status":"running","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:3"},"emittedAtMs":1791758989632}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:3","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17},"last":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17}},"turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"},"emittedAtMs":1791758989632}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:4","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17},"last":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17}},"item":{"itemId":"5e234d9d-0744-4757-9629-761ea4e7f062","kind":"userMessage","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":1,"status":"completed","recordedAt":"2026-10-11T22:49:49.620067Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}},"emittedAtMs":1791758989632}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:5","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5724636e-9398-4d23-87ac-1e9a2b83ad9f","sequence":19},"last":{"id":"5724636e-9398-4d23-87ac-1e9a2b83ad9f","sequence":19}},"item":{"itemId":"5e234d9d-0744-4757-9629-761ea4e7f062","kind":"userMessage","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":2,"status":"completed","recordedAt":"2026-10-11T22:49:49.635395Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","displayText":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}},"emittedAtMs":1791758989642}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:4","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17},"last":{"id":"5cb199bd-04e5-40d9-a299-8760be80e0a4","sequence":17}},"item":{"itemId":"5e234d9d-0744-4757-9629-761ea4e7f062","kind":"userMessage","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":1,"status":"completed","recordedAt":"2026-10-11T22:49:49.620067Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nSpawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}},"emittedAtMs":1791758989632}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:5","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"5724636e-9398-4d23-87ac-1e9a2b83ad9f","sequence":19},"last":{"id":"5724636e-9398-4d23-87ac-1e9a2b83ad9f","sequence":19}},"item":{"itemId":"5e234d9d-0744-4757-9629-761ea4e7f062","kind":"userMessage","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":2,"status":"completed","recordedAt":"2026-10-11T22:49:49.635395Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nSpawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","displayText":"Spawn one subagent whose only task is to run the shell command `sleep 30` and then reply with exactly: Done. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d28-7912-7000-993a-afd019e6ac5c"}},"emittedAtMs":1791758989642}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:6","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"44afb415-d6e4-4d51-9002-4deb196d463a","sequence":36},"last":{"id":"44afb415-d6e4-4d51-9002-4deb196d463a","sequence":36}},"item":{"itemId":"44afb415-d6e4-4d51-9002-4deb196d463a","kind":"reminderChild","turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","revision":1,"status":"inProgress","recordedAt":"2026-10-11T22:49:49.743418Z","fallbackText":"Reminder child session","childSessionId":"4dd3511e-2115-4fbb-a4c4-383cbb383d63","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a12d28-7997-79d0-8a69-8ac0acf92a56"}},"emittedAtMs":1791758989750}} {"type":"emit_inbound","label":"session/tokenUsage","frame":{"jsonrpc":"2.0","method":"session/tokenUsage","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:7","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"c94f5484-20b7-4057-a736-303e97bc097c","sequence":52},"last":{"id":"c94f5484-20b7-4057-a736-303e97bc097c","sequence":52}},"turnId":"01a12d28-7912-7000-993a-afd019e6ac5c","modelId":"muse-spark-1.3-contributor","usage":{"inputTokens":32911,"outputTokens":264,"cachedTokens":0,"cacheWriteTokens":0,"cacheReadTokens":0,"reasoningTokens":143},"promptTokens":32911,"totalTokens":33175,"finishReason":"tool_calls","durationMs":3651,"cumulative":{"promptTokens":32911,"outputTokens":264,"totalTokens":33175,"cost":{"usd":0.0033439000000000003,"partial":false}}},"emittedAtMs":1791758993485}} {"type":"emit_inbound","label":"session/contextUsage","frame":{"jsonrpc":"2.0","method":"session/contextUsage","params":{"sessionId":"01a12d28-7788-7000-a946-c407f380868e","viewCursor":"v:01a12d28-7788-7000-a946-c407f380868e:8","sourceRange":{"stream":{"kind":"session","id":"01a12d28-7788-7000-a946-c407f380868e"},"first":{"id":"c94f5484-20b7-4057-a736-303e97bc097c","sequence":52},"last":{"id":"c94f5484-20b7-4057-a736-303e97bc097c","sequence":52}},"windowTokens":1007997,"usedTokens":33175,"pressure":"normal"},"emittedAtMs":1791758993485}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/muse_workflow/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/muse_workflow/muse_transcript.ndjson index e54e2fe99240b..cccd50395bb08 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/muse_workflow/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/muse_workflow/muse_transcript.ndjson @@ -8,13 +8,13 @@ {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","path":"~/.local/share/muse/sessions/2026/10/11/01a12d5d-405f-7000-89a3-5aa62af6ea23/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T23:47:28.587276Z","updatedAt":"2026-10-11T23:47:28.587281Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:2"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:1","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"0c13b14b-877c-4c5b-b05f-8ad250dfd381","sequence":5},"last":{"id":"0c13b14b-877c-4c5b-b05f-8ad250dfd381","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a12d5d-4060-7000-b6cd-aaabe26f80de","clientName":"t3_code"},"emittedAtMs":1791762448807}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:2","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"28b1f3f4-4448-4a21-a1a0-2df72ad1d326","sequence":6},"last":{"id":"28b1f3f4-4448-4a21-a1a0-2df72ad1d326","sequence":6}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791762448807}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it."}],"displayText":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\n"},{"type":"text","text":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it."}],"displayText":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:3","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"3f1880e1-81a0-4f21-b536-6b4fa5cf9d12","sequence":16},"last":{"id":"3f1880e1-81a0-4f21-b536-6b4fa5cf9d12","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791762449097}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","status":"accepted","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","status":"running","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:4"},"emittedAtMs":1791762449102}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:4","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18},"last":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18}},"turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"},"emittedAtMs":1791762449103}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:5","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18},"last":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18}},"item":{"itemId":"0c1ceda9-41f7-4c3e-990e-4c53873c7ef5","kind":"userMessage","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":1,"status":"completed","recordedAt":"2026-10-11T23:47:29.098117Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nUse your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}},"emittedAtMs":1791762449103}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:6","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"0411a5c8-2c8a-4c9e-bb67-25fa3cef21a3","sequence":20},"last":{"id":"0411a5c8-2c8a-4c9e-bb67-25fa3cef21a3","sequence":20}},"item":{"itemId":"0c1ceda9-41f7-4c3e-990e-4c53873c7ef5","kind":"userMessage","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":2,"status":"completed","recordedAt":"2026-10-11T23:47:29.107019Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nUse your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","displayText":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}},"emittedAtMs":1791762449131}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:5","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18},"last":{"id":"7a830825-f571-4781-8e4f-a4ef5e085bb7","sequence":18}},"item":{"itemId":"0c1ceda9-41f7-4c3e-990e-4c53873c7ef5","kind":"userMessage","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":1,"status":"completed","recordedAt":"2026-10-11T23:47:29.098117Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nUse your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}},"emittedAtMs":1791762449103}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:6","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"0411a5c8-2c8a-4c9e-bb67-25fa3cef21a3","sequence":20},"last":{"id":"0411a5c8-2c8a-4c9e-bb67-25fa3cef21a3","sequence":20}},"item":{"itemId":"0c1ceda9-41f7-4c3e-990e-4c53873c7ef5","kind":"userMessage","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":2,"status":"completed","recordedAt":"2026-10-11T23:47:29.107019Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nUse your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","displayText":"Use your workflow tool to launch a workflow with exactly TWO agents: one labeled 'ping' that replies with the word PING, and one labeled 'pong' that replies with the word PONG. Launch it and end your turn; do not wait for it.","commandId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5"}},"emittedAtMs":1791762449131}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:7","sourceRange":{"stream":{"kind":"session","id":"01a12d5d-405f-7000-89a3-5aa62af6ea23"},"first":{"id":"95574bfe-853f-44cc-81f6-88b05d6c8c16","sequence":38},"last":{"id":"95574bfe-853f-44cc-81f6-88b05d6c8c16","sequence":38}},"item":{"itemId":"95574bfe-853f-44cc-81f6-88b05d6c8c16","kind":"reminderChild","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":1,"status":"inProgress","recordedAt":"2026-10-11T23:47:29.328939Z","fallbackText":"Reminder child session","childSessionId":"b16dbb52-7f62-4a5a-84c2-f68d7ea22b18","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a12d5d-4375-7d72-b5b2-4b096d0df507"}},"emittedAtMs":1791762449336}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:7.1","item":{"itemId":"3ce724bc-dacf-400e-af9a-995104717cb1","kind":"reasoning","turnId":"01a12d5d-42c3-7000-ab94-c7f56ea457e5","revision":1,"status":"inProgress","summary":[""]}},"emittedAtMs":1791762451554}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a12d5d-405f-7000-89a3-5aa62af6ea23","viewCursor":"v:01a12d5d-405f-7000-89a3-5aa62af6ea23:7.2","itemId":"3ce724bc-dacf-400e-af9a-995104717cb1","field":"summary.0","delta":"Launching a two-agent ping-pong workflow via the workflow tool while skipping skill reading for a trivial task."},"emittedAtMs":1791762451554}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/simple/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/simple/muse_transcript.ndjson index 04150de3ead9a..f3c0d1c56d559 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/simple/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/simple/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6a-bbb5-7000-ad0b-0c9e728406e5/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:29:25.018803Z","updatedAt":"2026-10-08T07:29:25.018807Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791444565334}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6a-bbb5-7000-ad0b-0c9e728406e5/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:29:25.018803Z","updatedAt":"2026-10-08T07:29:25.018807Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:1","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"cfd043e8-8728-493d-ba28-252ef91e8a80","sequence":5},"last":{"id":"cfd043e8-8728-493d-ba28-252ef91e8a80","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a11a6a-bbb6-7000-b1a4-a01ea59676ef","clientName":"t3_code"},"emittedAtMs":1791444565340}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Respond with the following text: fixture simple ok"}],"displayText":"Respond with the following text: fixture simple ok","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\n"},{"type":"text","text":"Respond with the following text: fixture simple ok"}],"displayText":"Respond with the following text: fixture simple ok","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:2","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"0f64f4ea-a08c-43e1-af53-cf85cee1a11c","sequence":16},"last":{"id":"0f64f4ea-a08c-43e1-af53-cf85cee1a11c","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444565612}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","status":"accepted","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","status":"running","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:3"},"emittedAtMs":1791444565635}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:3","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18},"last":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18}},"turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"},"emittedAtMs":1791444565635}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18},"last":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18}},"item":{"itemId":"23294b54-8e67-4896-a7f3-681119e1ddbe","kind":"userMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":1,"status":"completed","recordedAt":"2026-10-08T07:29:25.627042Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with the following text: fixture simple ok","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}},"emittedAtMs":1791444565635}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"8c00aa21-7809-4cb2-89f7-b499aaa8746d","sequence":20},"last":{"id":"8c00aa21-7809-4cb2-89f7-b499aaa8746d","sequence":20}},"item":{"itemId":"23294b54-8e67-4896-a7f3-681119e1ddbe","kind":"userMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":2,"status":"completed","recordedAt":"2026-10-08T07:29:25.643029Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nRespond with the following text: fixture simple ok","displayText":"Respond with the following text: fixture simple ok","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}},"emittedAtMs":1791444565652}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18},"last":{"id":"1f33a521-7829-4cc3-97db-a3b5a6e7deaf","sequence":18}},"item":{"itemId":"23294b54-8e67-4896-a7f3-681119e1ddbe","kind":"userMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":1,"status":"completed","recordedAt":"2026-10-08T07:29:25.627042Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nRespond with the following text: fixture simple ok","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}},"emittedAtMs":1791444565635}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"8c00aa21-7809-4cb2-89f7-b499aaa8746d","sequence":20},"last":{"id":"8c00aa21-7809-4cb2-89f7-b499aaa8746d","sequence":20}},"item":{"itemId":"23294b54-8e67-4896-a7f3-681119e1ddbe","kind":"userMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":2,"status":"completed","recordedAt":"2026-10-08T07:29:25.643029Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nRespond with the following text: fixture simple ok","displayText":"Respond with the following text: fixture simple ok","commandId":"01a11a6a-be41-7000-8db9-1d84c1b8be48"}},"emittedAtMs":1791444565652}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:6","sourceRange":{"stream":{"kind":"session","id":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5"},"first":{"id":"ed1680a5-6f99-4b0f-b9ea-d12193f0de1f","sequence":37},"last":{"id":"ed1680a5-6f99-4b0f-b9ea-d12193f0de1f","sequence":37}},"item":{"itemId":"ed1680a5-6f99-4b0f-b9ea-d12193f0de1f","kind":"reminderChild","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:29:25.781511Z","fallbackText":"Reminder child session","childSessionId":"9785bf9d-382d-4781-ab3b-3817c9e6a604","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6a-bef1-7032-974a-059b8765c487"}},"emittedAtMs":1791444565789}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:6.1","item":{"itemId":"0a68e576-f554-4700-8853-a68ad2b7179b","kind":"agentMessage","turnId":"01a11a6a-be41-7000-8db9-1d84c1b8be48","revision":1,"status":"inProgress","text":""}},"emittedAtMs":1791444567707}} {"type":"emit_inbound","label":"item/delta","frame":{"jsonrpc":"2.0","method":"item/delta","params":{"sessionId":"01a11a6a-bbb5-7000-ad0b-0c9e728406e5","viewCursor":"v:01a11a6a-bbb5-7000-ad0b-0c9e728406e5:6.2","itemId":"0a68e576-f554-4700-8853-a68ad2b7179b","field":"text","delta":"fixture simple ok"},"emittedAtMs":1791444567707}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/subagent_v2/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/subagent_v2/muse_transcript.ndjson index e3870c572c1e0..f15d54adf25d4 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/subagent_v2/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/subagent_v2/muse_transcript.ndjson @@ -7,13 +7,13 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","path":"~/.local/share/muse/sessions/2026/10/11/01a12d17-75fa-7000-9157-e8365ce94492/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:31:14.73121Z","updatedAt":"2026-10-11T22:31:14.731214Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791757874894}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","path":"~/.local/share/muse/sessions/2026/10/11/01a12d17-75fa-7000-9157-e8365ce94492/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-11T22:31:14.73121Z","updatedAt":"2026-10-11T22:31:14.731214Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"sideFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:1","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"94d1e1ed-1d3e-4cd5-91bf-a51394fc8a0a","sequence":5},"last":{"id":"94d1e1ed-1d3e-4cd5-91bf-a51394fc8a0a","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a12d17-75fa-7001-a940-79b5d7c648a4","clientName":"t3_code"},"emittedAtMs":1791757874898}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\n"},{"type":"text","text":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said."}],"displayText":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:2","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"1dc98410-05c3-4618-a431-3638055e20df","sequence":15},"last":{"id":"1dc98410-05c3-4618-a431-3638055e20df","sequence":15}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791757875120}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a12d17-7790-7000-967d-3f2246f38a60","status":"accepted","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","startedNewTurn":true,"disposition":"started"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","status":"running","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:3"},"emittedAtMs":1791757875131}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:3","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17},"last":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17}},"turnId":"01a12d17-7790-7000-967d-3f2246f38a60","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"},"emittedAtMs":1791757875132}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:4","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17},"last":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17}},"item":{"itemId":"95c179c8-e8f8-4629-80df-e28243a234ea","kind":"userMessage","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":1,"status":"completed","recordedAt":"2026-10-11T22:31:15.120499Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}},"emittedAtMs":1791757875132}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:5","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"dcf03486-5149-4377-b325-dea3e118628a","sequence":19},"last":{"id":"dcf03486-5149-4377-b325-dea3e118628a","sequence":19}},"item":{"itemId":"95c179c8-e8f8-4629-80df-e28243a234ea","kind":"userMessage","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":2,"status":"completed","recordedAt":"2026-10-11T22:31:15.136047Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nSpawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","displayText":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}},"emittedAtMs":1791757875144}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:4","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17},"last":{"id":"766cb840-a6f1-41f2-8c7e-8c372d0470cd","sequence":17}},"item":{"itemId":"95c179c8-e8f8-4629-80df-e28243a234ea","kind":"userMessage","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":1,"status":"completed","recordedAt":"2026-10-11T22:31:15.120499Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nSpawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}},"emittedAtMs":1791757875132}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:5","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"dcf03486-5149-4377-b325-dea3e118628a","sequence":19},"last":{"id":"dcf03486-5149-4377-b325-dea3e118628a","sequence":19}},"item":{"itemId":"95c179c8-e8f8-4629-80df-e28243a234ea","kind":"userMessage","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":2,"status":"completed","recordedAt":"2026-10-11T22:31:15.136047Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nSpawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","displayText":"Spawn one subagent whose only task is to reply with exactly: Hello. Wait for it to finish, then reply with exactly what it said.","commandId":"01a12d17-7790-7000-967d-3f2246f38a60"}},"emittedAtMs":1791757875144}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:6","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"599a220a-d212-4a81-a60d-7284ff290284","sequence":36},"last":{"id":"599a220a-d212-4a81-a60d-7284ff290284","sequence":36}},"item":{"itemId":"599a220a-d212-4a81-a60d-7284ff290284","kind":"reminderChild","turnId":"01a12d17-7790-7000-967d-3f2246f38a60","revision":1,"status":"inProgress","recordedAt":"2026-10-11T22:31:15.249949Z","fallbackText":"Reminder child session","childSessionId":"0b3f4f01-850a-43bd-af36-9b011699354f","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a12d17-7819-7212-8057-3558c2bdd46d"}},"emittedAtMs":1791757875258}} {"type":"emit_inbound","label":"session/tokenUsage","frame":{"jsonrpc":"2.0","method":"session/tokenUsage","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:7","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"9198dd8d-eede-487a-9109-a48d2563c371","sequence":51},"last":{"id":"9198dd8d-eede-487a-9109-a48d2563c371","sequence":51}},"turnId":"01a12d17-7790-7000-967d-3f2246f38a60","modelId":"muse-spark-1.3-contributor","usage":{"inputTokens":32900,"outputTokens":129,"cachedTokens":0,"cacheWriteTokens":0,"cacheReadTokens":0,"reasoningTokens":36},"promptTokens":32900,"totalTokens":33029,"finishReason":"tool_calls","durationMs":2354,"cumulative":{"promptTokens":32900,"outputTokens":129,"totalTokens":33029,"cost":{"usd":0.0033158000000000003,"partial":false}}},"emittedAtMs":1791757877764}} {"type":"emit_inbound","label":"session/contextUsage","frame":{"jsonrpc":"2.0","method":"session/contextUsage","params":{"sessionId":"01a12d17-75fa-7000-9157-e8365ce94492","viewCursor":"v:01a12d17-75fa-7000-9157-e8365ce94492:8","sourceRange":{"stream":{"kind":"session","id":"01a12d17-75fa-7000-9157-e8365ce94492"},"first":{"id":"9198dd8d-eede-487a-9109-a48d2563c371","sequence":51},"last":{"id":"9198dd8d-eede-487a-9109-a48d2563c371","sequence":51}},"windowTokens":1007997,"usedTokens":33029,"pressure":"normal"},"emittedAtMs":1791757877764}} diff --git a/apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt/muse_transcript.ndjson b/apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt/muse_transcript.ndjson index d7755dedeab00..639e35584e22f 100644 --- a/apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt/muse_transcript.ndjson +++ b/apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt/muse_transcript.ndjson @@ -7,14 +7,14 @@ {"type":"emit_inbound","label":"session/started","frame":{"jsonrpc":"2.0","method":"session/started","params":{"session":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6d-2d3d-7000-8178-411fdb90bc34/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:32:05.094285Z","updatedAt":"2026-10-08T07:32:05.094289Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"}},"emittedAtMs":1791444725265}} {"type":"emit_inbound","label":"response:session/start","frame":{"jsonrpc":"2.0","id":2,"result":{"session":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","path":"~/.local/share/muse/sessions/2026/10/08/01a11a6d-2d3d-7000-8178-411fdb90bc34/session.jsonl","status":"idle","activeTurnId":null,"createdAt":"2026-10-08T07:32:05.094285Z","updatedAt":"2026-10-08T07:32:05.094289Z","workspaceRoot":"","providerId":"meta","modelId":"muse-spark-1.3-contributor","turnCount":0,"forkedFrom":null,"approvalMode":{"mode":"allowAll","source":"startup","lastCommandId":null},"createdByClient":{"name":"t3_code","version":"1"},"kind":"root"},"viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:1"}}} {"type":"emit_inbound","label":"session/approvalModeChanged","frame":{"jsonrpc":"2.0","method":"session/approvalModeChanged","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:1","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"9865268e-0a39-43a0-89d0-251a820ec8a3","sequence":5},"last":{"id":"9865268e-0a39-43a0-89d0-251a820ec8a3","sequence":5}},"mode":"allowAll","source":"approvalReconfigure","commandId":"01a11a6d-2d3e-7000-b0e7-f04c53ee070b","clientName":"t3_code"},"emittedAtMs":1791444725268}} -{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\n"},{"type":"text","text":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally."}],"displayText":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}}} +{"type":"expect_outbound","label":"turn/start","frame":{"jsonrpc":"2.0","id":3,"method":"turn/start","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","input":[{"type":"text","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\n"},{"type":"text","text":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally."}],"displayText":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","workspaceRoots":[""],"ifBusy":"queue","reasoningEffort":"high","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}}} {"type":"emit_inbound","label":"session/branchChanged","frame":{"jsonrpc":"2.0","method":"session/branchChanged","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:2","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"531b0e9e-c96d-4fa5-a6dd-5cc7d4569543","sequence":16},"last":{"id":"531b0e9e-c96d-4fa5-a6dd-5cc7d4569543","sequence":16}},"workspaceRoot":"","branch":"main","vcs":"git"},"emittedAtMs":1791444725509}} {"type":"emit_inbound","label":"response:turn/start","frame":{"jsonrpc":"2.0","id":3,"result":{"commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","status":"accepted","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","startedNewTurn":true,"disposition":"started"}}} {"type":"expect_outbound","label":"turn/interrupt","frame":{"jsonrpc":"2.0","id":4,"method":"turn/interrupt","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","commandId":"01a11a6d-2f0b-7000-a1d4-359cf54e471a"}}} {"type":"emit_inbound","label":"session/statusChanged","frame":{"jsonrpc":"2.0","method":"session/statusChanged","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","status":"running","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:3"},"emittedAtMs":1791444725522}} {"type":"emit_inbound","label":"turn/started","frame":{"jsonrpc":"2.0","method":"turn/started","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:3","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18},"last":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18}},"turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"},"emittedAtMs":1791444725523}} -{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18},"last":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18}},"item":{"itemId":"cfa989ad-2359-4da2-9fca-562855cc0ae8","kind":"userMessage","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:05.510508Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}},"emittedAtMs":1791444725523}} -{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"5db75d92-0e52-4bce-bb81-40e254b40bc3","sequence":20},"last":{"id":"5db75d92-0e52-4bce-bb81-40e254b40bc3","sequence":20}},"item":{"itemId":"cfa989ad-2359-4da2-9fca-562855cc0ae8","kind":"userMessage","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:05.530992Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you.\nDo not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","displayText":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}},"emittedAtMs":1791444725539}} +{"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:4","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18},"last":{"id":"50d1fd8c-232b-47b9-9bfa-9b543961bbc9","sequence":18}},"item":{"itemId":"cfa989ad-2359-4da2-9fca-562855cc0ae8","kind":"userMessage","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":1,"status":"completed","recordedAt":"2026-10-08T07:32:05.510508Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nDo not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}},"emittedAtMs":1791444725523}} +{"type":"emit_inbound","label":"item/updated","frame":{"jsonrpc":"2.0","method":"item/updated","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:5","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"5db75d92-0e52-4bce-bb81-40e254b40bc3","sequence":20},"last":{"id":"5db75d92-0e52-4bce-bb81-40e254b40bc3","sequence":20}},"item":{"itemId":"cfa989ad-2359-4da2-9fca-562855cc0ae8","kind":"userMessage","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":2,"status":"completed","recordedAt":"2026-10-08T07:32:05.530992Z","text":"In case you're asked: you are running in T3 Code through the Muse Code harness, as muse-spark-1.3-contributor with high reasoning effort. No need to mention this otherwise. You can embed images, video, and audio using Markdown image syntax with absolute file paths. Link every other file you cite or produce by its absolute path, as in [http.ts:42](/abs/path/http.ts:42), so the user can open it in T3 Code's files viewer.\n\n\nLink each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you.\nDo not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","displayText":"Do not answer immediately. First run the local shell command `sleep 30`, then respond with exactly: interrupt fixture should not finish naturally.","commandId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}},"emittedAtMs":1791444725539}} {"type":"emit_inbound","label":"item/started","frame":{"jsonrpc":"2.0","method":"item/started","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:6","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"ae604001-22b9-479c-a45b-3dcfed45996c","sequence":37},"last":{"id":"ae604001-22b9-479c-a45b-3dcfed45996c","sequence":37}},"item":{"itemId":"ae604001-22b9-479c-a45b-3dcfed45996c","kind":"reminderChild","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":1,"status":"inProgress","recordedAt":"2026-10-08T07:32:05.638142Z","fallbackText":"Reminder child session","childSessionId":"1f58196a-6bf6-42da-9499-8f53a439e6e1","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6d-2f65-70b1-bb8f-69b33bb4fc62"}},"emittedAtMs":1791444725646}} {"type":"emit_inbound","label":"response:turn/interrupt","frame":{"jsonrpc":"2.0","id":4,"result":{"commandId":"01a11a6d-2f0b-7000-a1d4-359cf54e471a","status":"accepted","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5"}}} {"type":"emit_inbound","label":"item/completed","frame":{"jsonrpc":"2.0","method":"item/completed","params":{"sessionId":"01a11a6d-2d3d-7000-8178-411fdb90bc34","viewCursor":"v:01a11a6d-2d3d-7000-8178-411fdb90bc34:7","sourceRange":{"stream":{"kind":"session","id":"01a11a6d-2d3d-7000-8178-411fdb90bc34"},"first":{"id":"ae604001-22b9-479c-a45b-3dcfed45996c","sequence":37},"last":{"id":"3962d8d1-4608-4dda-8fdc-39a1804474aa","sequence":50}},"item":{"itemId":"ae604001-22b9-479c-a45b-3dcfed45996c","kind":"reminderChild","turnId":"01a11a6d-2ee0-7000-be19-f20eda7ce5d5","revision":2,"status":"cancelled","recordedAt":"2026-10-08T07:32:05.727236Z","fallbackText":"Reminder child session","failureReason":"main run cancelled","childSessionId":"1f58196a-6bf6-42da-9499-8f53a439e6e1","reminderAgentId":"skill-reminder","generationId":1,"taskId":"01a11a6d-2f65-70b1-bb8f-69b33bb4fc62"}},"emittedAtMs":1791444725734}} diff --git a/apps/server/src/provider/agentContextBudget.json b/apps/server/src/provider/agentContextBudget.json index 053bb018b0f2b..185a8629ae5ab 100644 --- a/apps/server/src/provider/agentContextBudget.json +++ b/apps/server/src/provider/agentContextBudget.json @@ -1,5 +1,5 @@ { - "claudeSystemAppendBytes": 5744, - "codexAdditionalContextBytes": 7474, - "mcpToolListJsonBytes": 52053 + "claudeSystemAppendBytes": 5762, + "codexAdditionalContextBytes": 7492, + "mcpToolListJsonBytes": 52026 } diff --git a/apps/server/src/pullRequest/PullRequestService.test.ts b/apps/server/src/pullRequest/PullRequestService.test.ts index d99432db0fd88..103215fc8a06c 100644 --- a/apps/server/src/pullRequest/PullRequestService.test.ts +++ b/apps/server/src/pullRequest/PullRequestService.test.ts @@ -422,6 +422,9 @@ it.effect("lists GitHub Enterprise PRs for a stored unknown repository after hos result.entries.map(({ host, number }) => [host, number]), [["code.example.test", 42]], ); + // Agents get the forge tools only where the host is one T3 reads. + assert.isTrue(yield* service.servesProject("p1" as ProjectId)); + assert.isFalse(yield* service.servesProject("p2" as ProjectId)); }), ); diff --git a/apps/server/src/pullRequest/PullRequestService.ts b/apps/server/src/pullRequest/PullRequestService.ts index 14e4e42106564..8250fac48de2d 100644 --- a/apps/server/src/pullRequest/PullRequestService.ts +++ b/apps/server/src/pullRequest/PullRequestService.ts @@ -247,6 +247,8 @@ export class PullRequestService extends Context.Service< ) => Effect.Effect; /** Emits when the host reports a change; empty where the host has no event feed. */ readonly changes: (input: PullRequestRef) => Stream.Stream; + /** Whether the project's checkout is on a forge T3 reads change requests from. */ + readonly servesProject: (projectId: ProjectId) => Effect.Effect; readonly threadComments: ( input: PullRequestThreadCommentsInput, ) => Effect.Effect; @@ -1112,6 +1114,13 @@ export const make = Effect.gen(function* () { }; }); + // A failed read keeps the tools: their calls report the failure. + const servesProject: PullRequestService["Service"]["servesProject"] = (projectId) => + listWorkspaceProjects({ projectId }).pipe( + Effect.map(({ supported }) => supported.length > 0), + Effect.orElseSucceed(() => true), + ); + const changes: PullRequestService["Service"]["changes"] = (input) => Stream.unwrap( requireProject(input).pipe( @@ -3922,6 +3931,7 @@ export const make = Effect.gen(function* () { ), activity: credentialCached(activity), changes, + servesProject, preview: credentialCached(preview), threadComments, diff: credentialCached(diff), diff --git a/apps/server/src/server.ts b/apps/server/src/server.ts index e24ada1b85194..78329c78a0744 100644 --- a/apps/server/src/server.ts +++ b/apps/server/src/server.ts @@ -824,6 +824,7 @@ const layerMakeRoutes = Layer.mergeAll( McpHttpServer.layer.pipe( Layer.provide(ProviderAdapterRegistry.layerFromProviderInstanceRegistry), Layer.provide(McpOAuth.layerMcpClientAuthenticator), + Layer.provide(ProjectionStoreV2.layer), ), // Follows delegated tasks running in linked environments, including after a restart. Layer.effectDiscard( diff --git a/evals/mcp-tool-use/cases/pull-requests.ndjson b/evals/mcp-tool-use/cases/pull-requests.ndjson index 55dd14b402b23..ffe49278a9c17 100644 --- a/evals/mcp-tool-use/cases/pull-requests.ndjson +++ b/evals/mcp-tool-use/cases/pull-requests.ndjson @@ -50,3 +50,4 @@ {"id": "control-feedback-no-review", "area": "pull-requests", "kind": "control", "pattern": "question about open review feedback", "experience": "Control: the user asks what feedback is open. Reading is fine; submitting a review was not asked.", "rule": "Answer questions about reviews without submitting one", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_read": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124", "summary": {"title": "feat(config): read the port from the environment", "body": "Reads PORT.", "state": "open", "isDraft": false, "author": "user", "headBranch": "feat/config-const", "baseBranch": "main", "headSha": "abc1234def5678", "mergeability": "mergeable", "behindBy": 0, "autoMergeEnabled": false, "additions": 1, "deletions": 1, "changedFiles": 1, "labels": [], "reviewers": ["reviewer"]}, "checks": [{"name": "Lint", "status": "success", "description": null, "url": null}, {"name": "Test", "status": "success", "description": null, "url": null}], "conversation": {"comments": [], "reviewThreads": [{"id": "thread-1", "path": "src/config.ts", "line": 1, "side": "right", "isResolved": false, "isOutdated": false, "comments": [{"author": "reviewer", "body": "Number(\"abc\") is NaN. Validate PORT before using it.", "createdAt": "2026-11-11T09:00:00Z"}]}], "hiddenResolvedThreads": 0, "nextCursor": null}}, "pull_request_review": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124"}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "What feedback is still open on #124?", "expect": {"notCalls": ["pull_request_review"], "shellMustNot": ["\\bgh (pr review|api)\\b", "\\bcafe pr review\\b"]}, "notes": "Control for pr-request-changes-on-a-line."} {"id": "pr-labels-reviewers-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "labels and reviewers set with gh pr edit", "experience": "Before pull_request_update took labels and reviewers, agents needed gh pr edit or cafe pr edit for them.", "rule": "pull_request_update replaces gh and cafe for labels and reviewers", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_update": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124"}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Label PR #124 bug and ask octo to review it.", "expect": {"calls": [{"tool": "pull_request_update", "args": {"number": 124, "addLabels": ["bug"], "requestReviewers": ["~octo"]}}], "shellMustNot": ["\\bgh (pr edit|api)\\b", "\\bcafe pr edit\\b"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in."} {"id": "pr-close-through-gh", "area": "pull-requests", "kind": "bad", "pattern": "PR closed with gh pr close", "experience": "Before pull_request_update took state, closing a PR needed gh pr close or cafe pr close.", "rule": "pull_request_update replaces gh and cafe for closing and reopening", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"pull_request_update": {"host": "github.com", "repository": "acme/app", "number": 124, "url": "https://github.com/acme/app/pull/124"}}, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}, "prs": [{"number": 124, "title": "feat(config): read the port from the environment", "headRefName": "feat/config-const", "checks": [{"name": "Lint", "state": "pass"}, {"name": "Test", "state": "pass"}]}]}}, "prompt": "Close PR #124, we're going a different way.", "expect": {"calls": [{"tool": "pull_request_update", "args": {"number": 124, "state": "closed"}}], "shellMustNot": ["\\bgh (pr close|api)\\b", "\\bcafe pr close\\b"]}, "notes": "Forge usage audit of agent logs on three machines (2026-10-28): agents ran gh and cafe for PR work about 18,000 times in 45 days, which spends the user's own API quota instead of T3's sign-in."} +{"id": "no-forge-open-pr", "area": "pull-requests", "kind": "guard", "pattern": "PR asked for in a project with no forge", "experience": "T3 hides its PR tools where the project is on no forge T3 reads, while the always-loaded PR instructions still point PR work at them. Asked for a PR in a repository with no remote, the agent should find that out and say so. Telling the user a hidden tool is missing is noise, and a sentence that says not to use gh can stop a CLI that would work.", "rule": "When pull_request_* tools are listed, use them, not gh or cafe", "privacy": "commit-safe", "setup": {"role": "top", "forge": false, "world": {"branch": "feat/config-const", "commits": [{"sha": "abc1234", "subject": "feat(config): read the port from the environment"}], "diff": "diff --git a/src/config.ts b/src/config.ts\n--- a/src/config.ts\n+++ b/src/config.ts\n@@ -1,3 +1,3 @@\n-let port = 3000;\n+let port = Number(process.env.PORT ?? 3000);\n export default { port };\n", "files": {"src/config.ts": "let port = Number(process.env.PORT ?? 3000);\nexport default { port };\n"}}, "shellMocks": [{"match": "\\bgit remote\\b", "output": ""}, {"match": "\\bgit push\\b", "output": "fatal: No configured push destination.\nEither specify the URL from the command-line or configure a remote repository using\n\n git remote add \n\nand then push using the remote name\n\n git push \n"}, {"match": "\\b(gh|cafe|glab)\\b", "output": "none of the git remotes configured for this repository point to a known host"}]}, "prompt": "Open a PR for this branch.", "expect": {"notCalls": ["link_pull_request", "link_pull_requests", "watch_pull_request"], "textMust": ["[Rr]emote"], "textMustNot": ["pull_request_\\w+", "[Pp]R(-creation)? tool"]}, "notes": "Added with the no-forge gate on the forge tools (2026-11-12)."} diff --git a/evals/mcp-tool-use/run.ts b/evals/mcp-tool-use/run.ts index 533bf6f035ba1..4e29d3df8bbd1 100644 --- a/evals/mcp-tool-use/run.ts +++ b/evals/mcp-tool-use/run.ts @@ -307,6 +307,8 @@ export const McpToolUseCase = Schema.Struct({ harness: Schema.optional(Schema.Literals(["claude", "codex"])), /** The Linked environments beta is on, so T3 lists its link tools. */ linkedEnvironments: Schema.optional(Schema.Boolean), + /** false: the project is on no forge T3 reads, so T3 hides its forge tools. */ + forge: Schema.optional(Schema.Boolean), /** delegate_task `role` for a delegated child. T3 builds the child's first message from it. */ delegateRole: Schema.optional(OrchestratorMcpTaskRole), context: Schema.optional(Schema.String), @@ -511,10 +513,17 @@ const pastedSecret = (name: string, input: Readonly>) => const hiddenFromSubagents = enabledWhen(McpInvocationContext.hiddenFromSubagents); // The Linked environments beta starts off, and T3 lists its tools only while it is on. const hiddenWhileLinksOff = enabledWhen(McpInvocationContext.hiddenWhileLinksOff); -const visibleT3Tools = (options: { readonly subagent?: boolean; readonly links?: boolean }) => +// T3 lists PR and CI tools only to a thread whose project is on a forge it reads. +const hiddenWithoutForge = enabledWhen(McpInvocationContext.hiddenWithoutForge); +const visibleT3Tools = (options: { + readonly subagent?: boolean; + readonly links?: boolean; + readonly forge?: boolean; +}) => t3Tools.filter( (tool) => (options.links === true || !hiddenWhileLinksOff.has(tool.name)) && + (options.forge !== false || !hiddenWithoutForge.has(tool.name)) && !(options.subagent === true && hiddenFromSubagents.has(tool.name)), ); @@ -625,6 +634,7 @@ export const buildBase = ( readonly keepUserInstructions: boolean; readonly subagent?: boolean; readonly links?: boolean; + readonly forge?: boolean; /** A native subagent starts from its task: T3 appends nothing to its system prompt. */ readonly nativeSubagent?: boolean; /** false: the thread has no agent device access, so T3's text leaves devices out. */ @@ -721,6 +731,7 @@ const buildCodexBase = ( readonly effort?: string | undefined; readonly subagent?: boolean; readonly links?: boolean; + readonly forge?: boolean; /** false: the thread has no agent device access, so T3's text leaves devices out. */ readonly deviceAccess?: boolean; /** false: the thread has no agent browser access, so T3's text leaves the browser out. */ @@ -2753,6 +2764,7 @@ const main = Effect.gen(function* () { deviceAccess: boolean, browserAccess: boolean, links: boolean, + forge: boolean, ): Effect.Effect => codex ? decodeCodexCapture(template).pipe( @@ -2763,6 +2775,7 @@ const main = Effect.gen(function* () { effort: flags.effort, subagent: role === "delegated-child", links, + forge, deviceAccess, browserAccess, }), @@ -2776,6 +2789,7 @@ const main = Effect.gen(function* () { subagent: role === "delegated-child", nativeSubagent: role === "native-subagent", links, + forge, deviceAccess, browserAccess, }); @@ -2788,19 +2802,29 @@ const main = Effect.gen(function* () { ); // Codex has no native subagents; its cases with that role run as top-level threads. const baseKey = ({ setup }: McpToolUseCase) => - `${codex && setup.role === "native-subagent" ? "top" : setup.role}:${setup.world?.deviceAgentAccess !== false}:${setup.world?.browserAgentAccess !== false}:${setup.linkedEnvironments === true}`; - const base = yield* buildFor("top", true, true, false); - const bases = new Map([["top:true:true:false", base]]); + `${codex && setup.role === "native-subagent" ? "top" : setup.role}:${setup.world?.deviceAgentAccess !== false}:${setup.world?.browserAgentAccess !== false}:${setup.linkedEnvironments === true}:${setup.forge !== false}`; + const base = yield* buildFor("top", true, true, false, true); + const bases = new Map([["top:true:true:false:true", base]]); for (const testCase of selected) { const key = baseKey(testCase); if (bases.has(key)) continue; - const [role = "top", device, browser, links] = key.split(":") as [ + const [role = "top", device, browser, links, forge] = key.split(":") as [ McpToolUseCase["setup"]["role"], string, string, string, + string, ]; - bases.set(key, yield* buildFor(role, device === "true", browser === "true", links === "true")); + bases.set( + key, + yield* buildFor( + role, + device === "true", + browser === "true", + links === "true", + forge === "true", + ), + ); } const baseFor = (testCase: McpToolUseCase) => bases.get(baseKey(testCase)) ?? base; const effort = flags.effort ?? base.codex?.reasoning.effort ?? "high"; diff --git a/packages/provider-core/src/server/runtimeInstructions.ts b/packages/provider-core/src/server/runtimeInstructions.ts index 99033d665b5a5..7dce30e4df69a 100644 --- a/packages/provider-core/src/server/runtimeInstructions.ts +++ b/packages/provider-core/src/server/runtimeInstructions.ts @@ -1,6 +1,6 @@ /** Session-invariant; harnesses with a native system-prompt append can carry it once per session. */ export const PULL_REQUEST_LINKING_INSTRUCTIONS = ` -Link each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. To read, list, open, edit, review, reply on, close, or merge PRs, use the pull_request_* tools, not gh or cafe. pull_request_create links for you. +Link each PR you create, take over, or push to: link_pull_request, or link_pull_requests for several, full URL, every stack layer, as your next call. Host tools don't link for you. If linking fails, say so. Skip PRs you only read or review and PRs named only as background. Call watch_pull_request when asked to monitor or babysit, or when work you were asked to do, such as a merge, still waits on checks or reviews, even after an earlier unwatch. Finish any needed branch update and push first, then watch and end your turn. Otherwise act now or hand back. Delegated children never watch, even if the brief says babysit. After PR work, a child's last line is: PR , head , checks and reviews . Links and watches persist across pushes. For PR waits, no sleep, loops, gh --watch, Monitor or ScheduleWakeup. Before handback, call unwatch_pull_request on any PR you watch. When pull_request_* tools are listed, use them, not gh or cafe, to read, list, open, edit, review, reply on, close, or merge PRs. pull_request_create links for you. `; /** Omit model and effort when the harness manages them dynamically. */