Skip to content

Commit 308f0ea

Browse files
dcramercodexclaude
authored
ref(chat): Rename agent execution boundary to run vocabulary (#755)
Hard cutover of the executor boundary from reply/respond vocabulary to the run/slice vocabulary that `specs/terminology.md` canonicalizes. This is the fourth slice of the #746 series (after #750#752), ported from the original #748 branch onto the reworked outcome model: - `generateAssistantReply` → `executeAgentRun`, `respond.ts` → `agent-run.ts`, `respond-helpers.ts` → `agent-run-helpers.ts` - `ReplyRequestContext` → `AgentRunRequest` (group interfaces follow suit), `ReplySteeringMessage` → `AgentRunSteeringMessage` - `AssistantReply` → `AgentRunResult`; the `AgentRunOutcome` completed variant carries `result` instead of `reply` - The `AssistantReplyRequestContext` compat alias and the type re-export layer on the executor module are deleted; consumers import `AgentRunResult` from `@/chat/services/turn-result` directly - Test fixture follows: `respondAgentRunner` → `realAgentRunner`, `flattenReplyRequestForTest` → `flattenAgentRunRequestForTest` No behavior change — the diff is renames plus spec-reference updates. `reply` stays reserved for destination-visible messages owned by delivery and reply-policy layers (`specs/terminology.md` now says this explicitly), which is why `reply-executor.ts` and its locals keep their names. The module stays at the chat root because it composes tools, plugins, MCP, sandbox, and capabilities, which `runtime/` modules may not depend on under the dependency-cruiser rules. Review order: `specs/terminology.md` for the vocabulary rule, then `src/chat/agent-run.ts` and `runtime/agent-run-outcome.ts` for the boundary surface; the rest is mechanical rename fallout. Refs #746 Co-authored-by: GPT-5.5 Codex <noreply@openai.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent a3e5077 commit 308f0ea

74 files changed

Lines changed: 605 additions & 633 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/junior-evals/src/behavior-harness.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import {
4040
scheduleSessionCompletedPluginTasks,
4141
} from "@/chat/plugins/task-runner";
4242
import type { PluginTaskQueueMessage } from "@/chat/plugins/task-message";
43-
import { generateAssistantReply } from "@/chat/respond";
43+
import { executeAgentRun } from "@/chat/agent-run";
4444
import { completedAgentRun } from "@/chat/runtime/agent-run-outcome";
4545
import type { AgentRunner } from "@/chat/runtime/agent-runner";
4646
import { resumeAwaitingSlackContinuation } from "@/chat/runtime/agent-continue-runner";
@@ -1572,7 +1572,7 @@ function buildRuntimeServices(
15721572
delete process.env.VERCEL_OIDC_TOKEN;
15731573
}
15741574
try {
1575-
const outcome = await generateAssistantReply({
1575+
const outcome = await executeAgentRun({
15761576
...request,
15771577
policy: {
15781578
...request.policy,

packages/junior/src/app.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
import { getSlackReactionConfig, setSlackReactionConfig } from "@/chat/config";
1212
import { getDb } from "@/chat/db";
1313
import { logException } from "@/chat/logging";
14-
import { generateAssistantReply } from "@/chat/respond";
14+
import { executeAgentRun } from "@/chat/agent-run";
1515
import { normalizeSandboxEgressTracePropagationDomains } from "@/chat/sandbox/egress/tracing";
1616
import { pluginCatalogRuntime } from "@/chat/plugins/catalog-runtime";
1717
import {
@@ -585,7 +585,7 @@ export async function createApp(options?: JuniorAppOptions): Promise<Hono> {
585585

586586
const waitUntil = options?.waitUntil ?? (await defaultWaitUntil());
587587
const tracePropagation = { domains: sandboxEgressTracePropagationDomains };
588-
const agentRunner = createAgentRunner(generateAssistantReply, {
588+
const agentRunner = createAgentRunner(executeAgentRun, {
589589
tracePropagation,
590590
});
591591
const runtimeServiceOverrides = {

packages/junior/src/chat/agent-dispatch/runner.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* state, and schedules follow-up slices when a turn needs to continue.
88
*/
99
import { botConfig } from "@/chat/config";
10-
import type { AssistantReply } from "@/chat/respond";
10+
import type { AgentRunResult } from "@/chat/services/turn-result";
1111
import type { AgentRunner } from "@/chat/runtime/agent-runner";
1212
import { logException } from "@/chat/logging";
1313
import {
@@ -76,7 +76,7 @@ function buildDispatchConversationText(dispatch: DispatchRecord): string {
7676
return `[dispatched task] ${dispatch.input}`;
7777
}
7878

79-
function ensureVisibleDeliveryText(reply: AssistantReply): AssistantReply {
79+
function ensureVisibleDeliveryText(reply: AgentRunResult): AgentRunResult {
8080
if (reply.text.trim().length > 0 || !reply.files?.length) {
8181
return reply;
8282
}
@@ -377,7 +377,7 @@ export async function runAgentDispatchSlice(
377377
return;
378378
}
379379

380-
let reply = outcome.reply;
380+
let reply = outcome.result;
381381

382382
const failure =
383383
reply.diagnostics.outcome === "success"

packages/junior/src/chat/respond-helpers.ts renamed to packages/junior/src/chat/agent-run-helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Pure helper functions used by the agent reply orchestration in respond.ts.
2+
* Pure helper functions used by the agent-run orchestration in agent-run.ts.
33
*
44
* These are extracted to reduce the size of the main orchestration module and
55
* make individual helpers independently testable.
Lines changed: 47 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,8 @@ import {
114114
summarizeMessageText,
115115
toObservablePromptPart,
116116
upsertActiveSkill,
117-
} from "@/chat/respond-helpers";
118-
import {
119-
buildTurnResult,
120-
type AssistantReply,
121-
type AgentTurnDiagnostics,
122-
} from "@/chat/services/turn-result";
117+
} from "@/chat/agent-run-helpers";
118+
import { buildTurnResult } from "@/chat/services/turn-result";
123119
import {
124120
isProviderRetryError,
125121
nextProviderRetry,
@@ -161,9 +157,6 @@ import {
161157
type ConversationPrivacy,
162158
} from "@/chat/conversation-privacy";
163159

164-
// Re-export types for backward compatibility with existing consumers.
165-
export type { AssistantReply, AgentTurnDiagnostics };
166-
167160
const AGENT_ABORT_SETTLE_GRACE_MS = 5_000;
168161

169162
function sleep(ms: number): Promise<void> {
@@ -205,9 +198,9 @@ function waitForAbortSettlement(
205198
}
206199

207200
/** Carries the user-visible content and prior transcript for one agent-run slice. */
208-
export interface ReplyRequestInput {
201+
export interface AgentRunInput {
209202
messageText: string;
210-
userAttachments?: ReplyRequestAttachment[];
203+
userAttachments?: AgentRunAttachment[];
211204
inboundAttachmentCount?: number;
212205
omittedImageAttachmentCount?: number;
213206
/** Durable Pi transcript for this conversation, excluding ephemeral turn context. */
@@ -216,7 +209,7 @@ export interface ReplyRequestInput {
216209
}
217210

218211
/** Carries identity and addressing needed to route tools, auth, and delivery. */
219-
export interface ReplyRequestRouting {
212+
export interface AgentRunRouting {
220213
credentialContext?: CredentialContext;
221214
requester?: Requester;
222215
source: Source;
@@ -247,7 +240,7 @@ export interface ReplyRequestRouting {
247240
* Carries execution limits, dependency overrides, and persisted sandbox
248241
* reuse state for one run slice.
249242
*/
250-
export interface ReplyRequestPolicy {
243+
export interface AgentRunPolicy {
251244
/** Absolute wall-clock deadline for this host request, in milliseconds. */
252245
turnDeadlineAtMs?: number;
253246
authorizationFlowMode?: AuthorizationFlowMode;
@@ -268,7 +261,7 @@ export interface ReplyRequestPolicy {
268261
}
269262

270263
/** Carries durable state snapshots already loaded by the caller. */
271-
export interface ReplyRequestState {
264+
export interface AgentRunState {
272265
artifactState?: ThreadArtifactsState;
273266
pendingAuth?: ConversationPendingAuthState;
274267
}
@@ -277,7 +270,7 @@ export interface ReplyRequestState {
277270
* Carries notification-only callbacks for streaming UI and status surfaces;
278271
* their failures never affect the run.
279272
*/
280-
export interface ReplyRequestObservers {
273+
export interface AgentRunObservers {
281274
onTextDelta?: (deltaText: string) => void | Promise<void>;
282275
onAssistantMessageStart?: () => void | Promise<void>;
283276
onToolInvocation?: (invocation: {
@@ -289,13 +282,13 @@ export interface ReplyRequestObservers {
289282
}
290283

291284
/** Carries durable-worker ports that commit or update resumable run state. */
292-
export interface ReplyRequestDurability {
285+
export interface AgentRunDurability {
293286
onInputCommitted?: () => void | Promise<void>;
294287
/** Return true when the durable worker should pause at the next Pi boundary. */
295288
shouldYield?: () => boolean;
296289
drainSteeringMessages?: (
297-
accept: (messages: ReplySteeringMessage[]) => Promise<void>,
298-
) => Promise<ReplySteeringMessage[]>;
290+
accept: (messages: AgentRunSteeringMessage[]) => Promise<void>,
291+
) => Promise<AgentRunSteeringMessage[]>;
299292
recordPendingAuth?: (
300293
pendingAuth: ConversationPendingAuthState,
301294
) => void | Promise<void>;
@@ -305,33 +298,29 @@ export interface ReplyRequestDurability {
305298
) => void | Promise<void>;
306299
}
307300

308-
/** Groups the per-slice reply request by the runtime role each field serves. */
309-
export interface ReplyRequestContext {
310-
input: ReplyRequestInput;
311-
routing: ReplyRequestRouting;
312-
policy?: ReplyRequestPolicy;
313-
state?: ReplyRequestState;
314-
observers?: ReplyRequestObservers;
315-
durability?: ReplyRequestDurability;
301+
/** Groups the per-slice run request by the runtime role each field serves. */
302+
export interface AgentRunRequest {
303+
input: AgentRunInput;
304+
routing: AgentRunRouting;
305+
policy?: AgentRunPolicy;
306+
state?: AgentRunState;
307+
observers?: AgentRunObservers;
308+
durability?: AgentRunDurability;
316309
}
317310

318-
export type AssistantReplyRequestContext = ReplyRequestContext;
319-
320-
type FlatReplyRequestContext = ReplyRequestInput &
321-
ReplyRequestRouting &
322-
ReplyRequestPolicy &
323-
ReplyRequestState &
324-
ReplyRequestObservers &
325-
ReplyRequestDurability;
311+
type FlatAgentRunRequest = AgentRunInput &
312+
AgentRunRouting &
313+
AgentRunPolicy &
314+
AgentRunState &
315+
AgentRunObservers &
316+
AgentRunDurability;
326317

327318
/**
328319
* Interim shim: run internals still consume the historical flat shape
329320
* (grouped rewrite deferred to #746 Phase 5). The groups must stay
330321
* key-disjoint or later spreads silently shadow earlier fields.
331322
*/
332-
function flattenReplyRequestContext(
333-
request: ReplyRequestContext,
334-
): FlatReplyRequestContext {
323+
function flattenAgentRunRequest(request: AgentRunRequest): FlatAgentRunRequest {
335324
return {
336325
...request.input,
337326
...request.routing,
@@ -342,18 +331,18 @@ function flattenReplyRequestContext(
342331
};
343332
}
344333

345-
export interface ReplyRequestAttachment {
334+
export interface AgentRunAttachment {
346335
data?: Buffer;
347336
mediaType: string;
348337
filename?: string;
349338
promptText?: string;
350339
}
351340

352-
export interface ReplySteeringMessage {
341+
export interface AgentRunSteeringMessage {
353342
omittedImageAttachmentCount?: number;
354343
text: string;
355344
timestampMs?: number;
356-
userAttachments?: ReplyRequestAttachment[];
345+
userAttachments?: AgentRunAttachment[];
357346
}
358347

359348
let startupDiscoveryLogged = false;
@@ -370,9 +359,7 @@ const legacyStoredTextPartSchema = z
370359
})
371360
.strict();
372361

373-
type UserTurnAttachment = NonNullable<
374-
ReplyRequestInput["userAttachments"]
375-
>[number];
362+
type UserTurnAttachment = NonNullable<AgentRunInput["userAttachments"]>[number];
376363

377364
function buildOmittedImageAttachmentNotice(count: number): string {
378365
return [
@@ -406,15 +393,13 @@ function extractSliceUsage(
406393
}
407394

408395
function requesterFromContext(
409-
context: FlatReplyRequestContext,
396+
context: FlatAgentRunRequest,
410397
): Requester | undefined {
411398
return actorRequesterFromContext(context);
412399
}
413400

414401
/** Reject requester identities that do not belong to the active destination. */
415-
function assertRequesterDestinationMatch(
416-
context: FlatReplyRequestContext,
417-
): void {
402+
function assertRequesterDestinationMatch(context: FlatAgentRunRequest): void {
418403
const { destination, requester } = context;
419404
if (!requester) {
420405
return;
@@ -434,9 +419,7 @@ function assertRequesterDestinationMatch(
434419
}
435420

436421
/** Reject legacy Slack correlation fields that conflict with the destination. */
437-
function assertCorrelationDestinationMatch(
438-
context: FlatReplyRequestContext,
439-
): void {
422+
function assertCorrelationDestinationMatch(context: FlatAgentRunRequest): void {
440423
const { correlation, destination } = context;
441424
if (destination.platform !== "slack") {
442425
return;
@@ -460,7 +443,7 @@ function assertCorrelationDestinationMatch(
460443
}
461444

462445
function actorRequesterFromContext(
463-
context: FlatReplyRequestContext,
446+
context: FlatAgentRunRequest,
464447
): Requester | undefined {
465448
return createRequester(context.requester, {
466449
platform:
@@ -478,9 +461,7 @@ function actorRequesterFromContext(
478461
});
479462
}
480463

481-
function toolInvocationDestination(
482-
context: FlatReplyRequestContext,
483-
): Destination {
464+
function toolInvocationDestination(context: FlatAgentRunRequest): Destination {
484465
if (context.destination.platform !== "slack" || !context.toolChannelId) {
485466
return context.destination;
486467
}
@@ -492,7 +473,7 @@ function toolInvocationDestination(
492473
}
493474

494475
function surfaceFromContext(
495-
context: FlatReplyRequestContext,
476+
context: FlatAgentRunRequest,
496477
): AgentTurnSurface | undefined {
497478
if (context.surface) {
498479
return context.surface;
@@ -557,7 +538,7 @@ function buildRouterAttachmentBlock(attachment: UserTurnAttachment): string {
557538

558539
function buildUserTurnInput(args: {
559540
omittedImageAttachmentCount: number;
560-
userAttachments?: ReplyRequestInput["userAttachments"];
541+
userAttachments?: AgentRunInput["userAttachments"];
561542
userTurnText: string;
562543
}): {
563544
routerBlocks: string[];
@@ -622,7 +603,7 @@ function buildUserTurnInput(args: {
622603
* paths store identical durable history.
623604
*/
624605
export function buildSteeringPiMessage(
625-
message: ReplySteeringMessage,
606+
message: AgentRunSteeringMessage,
626607
): PiMessage {
627608
const { userContentParts } = buildUserTurnInput({
628609
userTurnText: buildUserTurnText(message.text),
@@ -707,10 +688,10 @@ function legacyTextPartMatchesCurrentText(
707688
}
708689

709690
/** Run a full agent turn: discover skills, execute tools, and return the assistant reply. */
710-
export async function generateAssistantReply(
711-
request: AssistantReplyRequestContext,
691+
export async function executeAgentRun(
692+
request: AgentRunRequest,
712693
): Promise<AgentRunOutcome> {
713-
const context = flattenReplyRequestContext(request);
694+
const context = flattenAgentRunRequest(request);
714695
const messageText = request.input.messageText;
715696
const conversationPrivacy = resolveConversationPrivacy({
716697
channelId: context.correlation?.channelId,
@@ -723,17 +704,13 @@ export async function generateAssistantReply(
723704
visibility: context.slackConversation?.visibility,
724705
});
725706
return runWithConversationPrivacy(conversationPrivacy ?? "private", () =>
726-
generateAssistantReplyInPrivacyContext(
727-
messageText,
728-
context,
729-
conversationPrivacy,
730-
),
707+
executeAgentRunInPrivacyContext(messageText, context, conversationPrivacy),
731708
);
732709
}
733710

734-
async function generateAssistantReplyInPrivacyContext(
711+
async function executeAgentRunInPrivacyContext(
735712
messageText: string,
736-
context: FlatReplyRequestContext,
713+
context: FlatAgentRunRequest,
737714
conversationPrivacy: ConversationPrivacy | undefined,
738715
): Promise<AgentRunOutcome> {
739716
if (!context.destination) {
@@ -1946,7 +1923,7 @@ async function generateAssistantReplyInPrivacyContext(
19461923
// ── Build turn result ────────────────────────────────────────────
19471924
return {
19481925
status: "completed",
1949-
reply: buildTurnResult({
1926+
result: buildTurnResult({
19501927
newMessages,
19511928
userInput,
19521929
replyFiles,
@@ -2099,15 +2076,15 @@ async function generateAssistantReplyInPrivacyContext(
20992076
modelId: botConfig.modelId,
21002077
},
21012078
{},
2102-
"generateAssistantReply failed",
2079+
"executeAgentRun failed",
21032080
);
21042081

21052082
// Raw exception text is diagnostics-only; the failure-response service
21062083
// owns the sanitized user-visible fallback for empty provider errors.
21072084
const message = error instanceof Error ? error.message : String(error);
21082085
return {
21092086
status: "completed",
2110-
reply: {
2087+
result: {
21112088
text: "",
21122089
...getSandboxMetadata(),
21132090
diagnostics: {

packages/junior/src/chat/app/services.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { completeObject, completeText } from "@/chat/pi/client";
2-
import { generateAssistantReply as generateAssistantReplyImpl } from "@/chat/respond";
2+
import { executeAgentRun as executeAgentRunImpl } from "@/chat/agent-run";
33
import type { SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress/tracing";
44
import {
55
getAwaitingAgentContinueRequest,
@@ -78,7 +78,7 @@ export function createJuniorRuntimeServices(
7878
overrides.replyExecutor?.contextCompactor ?? contextCompactor,
7979
agentRunner:
8080
overrides.replyExecutor?.agentRunner ??
81-
createAgentRunner(generateAssistantReplyImpl, {
81+
createAgentRunner(executeAgentRunImpl, {
8282
tracePropagation: overrides.sandbox?.tracePropagation,
8383
}),
8484
getAwaitingAgentContinueRequest:

0 commit comments

Comments
 (0)