Bug: noReply pattern broken in 1.0.69+ (agent loop refactor regression) #2931

Closed
opened 2026-02-16 17:37:52 -05:00 by yindo · 3 comments
Owner

Originally created by @wolfie82 on GitHub (Nov 17, 2025).

Originally assigned to: @rekram1-node on GitHub.

Bug: noReply pattern broken in 1.0.69+ (agent loop refactor regression)

Summary

The noReply: true option for client.session.prompt() is broken in OpenCode 1.0.69 and later. Tools that use this pattern to silently insert context into the session now hang indefinitely with status "queued".

Version Information

Expected Behavior (1.0.68 and earlier)

When a plugin calls client.session.prompt({ noReply: true, ... }), the context should be inserted into the session without triggering an AI response, and the function should return immediately with the created user message.

// Inside a tool handler
await client.session.prompt({
  path: { id: sessionID },
  body: {
    noReply: true, // Should skip AI inference and return immediately
    parts: [{ type: "text", text: "Context to insert..." }],
  },
});

// Tool returns confirmation
return "✓ Context inserted successfully";

Result in 1.0.68: Context inserted, tool returns immediately, agent continues normally.

Actual Behavior (1.0.69+)

The same code now causes the tool to hang indefinitely with status "queued" in the TUI. The tool never completes.

Result in 1.0.69+: Tool hangs, session becomes unresponsive.

Root Cause Analysis

In 1.0.68, the prompt() function had an early return for noReply:

// packages/opencode/src/session/prompt.ts (1.0.68)
export async function prompt(input: PromptInput): Promise<MessageV2.WithParts> {
  // ... setup code ...
  const userMsg = await createUserMessage(input);
  await Session.touch(input.sessionID);

  // Early return for context-only messages (no AI inference)
  if (input.noReply) {
    return userMsg; // ✅ Returns immediately
  }

  // ... continue with agent loop ...
}

In 1.0.69, this early return was removed during the agent loop refactor:

// packages/opencode/src/session/prompt.ts (1.0.69+)
export const prompt = fn(PromptInput, async (input) => {
  const session = await Session.get(input.sessionID);
  await SessionRevert.cleanup(session);

  await createUserMessage(input); // Note: changed to not return userMsg
  await Session.touch(input.sessionID);

  return loop(input.sessionID); // ❌ Always enters loop, even with noReply: true
});

The Problem: The loop waits for an assistant message with a finish reason, but when noReply: true, no assistant message is ever created. The loop runs forever, waiting for a response that will never come.

Proposed Fix

Restore the noReply early return in packages/opencode/src/session/prompt.ts:

export const prompt = fn(PromptInput, async (input) => {
  const session = await Session.get(input.sessionID);
  await SessionRevert.cleanup(session);

  const userMsg = await createUserMessage(input); // Capture return value
  await Session.touch(input.sessionID);

  // Early return for context-only messages (no AI inference)
  if (input.noReply) {
    return userMsg; // ✅ Return immediately, skip agent loop
  }

  return loop(input.sessionID);
});

Steps to Reproduce

  1. Create a plugin with a tool that uses noReply (see test plugin example below)
  2. Use OpenCode 1.0.69+ and call the tool
  3. Expected: Tool returns immediately with confirmation message
  4. Actual: Tool hangs indefinitely with status "queued"

Test Plugin

// .opencode/plugin/test-noreply.ts
import { type Plugin, tool } from "@opencode-ai/plugin";

export const TestNoReplyPlugin: Plugin = async ({ client }) => {
  return {
    tool: {
      test_noreply: tool({
        description: "Test noReply pattern",
        args: {
          message: tool.schema.string(),
        },
        async execute(args, ctx) {
          // Insert context using noReply
          await client.session.prompt({
            path: { id: ctx.sessionID },
            body: {
              noReply: true,
              parts: [{ type: "text", text: `Context: ${args.message}` }],
            },
          });

          return "✓ Context inserted";
        },
      }),
    },
  };
};

Impact

This regression affects plugins that inject context into sessions for:

  • Background information that needs to persist across tool output compaction
  • Multi-step workflows where context must survive between tool calls
  • Any tool requiring persistent context in the conversation history

References

Originally created by @wolfie82 on GitHub (Nov 17, 2025). Originally assigned to: @rekram1-node on GitHub. # Bug: `noReply` pattern broken in 1.0.69+ (agent loop refactor regression) ## Summary The `noReply: true` option for `client.session.prompt()` is broken in OpenCode 1.0.69 and later. Tools that use this pattern to silently insert context into the session now hang indefinitely with status "queued". ## Version Information - **Working**: OpenCode <= 1.0.68 ([`8ba48ed7`](https://github.com/sst/opencode/commit/8ba48ed7)) - **Broken**: OpenCode >= 1.0.69 ([`de50234a`](https://github.com/sst/opencode/commit/de50234a)) - **Root Cause**: Commit [`a1214fff`](https://github.com/sst/opencode/commit/a1214fff) - "Refactor agent loop" (#4412) ## Expected Behavior (1.0.68 and earlier) When a plugin calls `client.session.prompt({ noReply: true, ... })`, the context should be inserted into the session **without triggering an AI response**, and the function should return immediately with the created user message. ```typescript // Inside a tool handler await client.session.prompt({ path: { id: sessionID }, body: { noReply: true, // Should skip AI inference and return immediately parts: [{ type: "text", text: "Context to insert..." }], }, }); // Tool returns confirmation return "✓ Context inserted successfully"; ``` **Result in 1.0.68**: ✅ Context inserted, tool returns immediately, agent continues normally. ## Actual Behavior (1.0.69+) The same code now causes the tool to hang indefinitely with status "queued" in the TUI. The tool never completes. **Result in 1.0.69+**: ❌ Tool hangs, session becomes unresponsive. ## Root Cause Analysis In **1.0.68**, the `prompt()` function had an early return for `noReply`: ```typescript // packages/opencode/src/session/prompt.ts (1.0.68) export async function prompt(input: PromptInput): Promise<MessageV2.WithParts> { // ... setup code ... const userMsg = await createUserMessage(input); await Session.touch(input.sessionID); // Early return for context-only messages (no AI inference) if (input.noReply) { return userMsg; // ✅ Returns immediately } // ... continue with agent loop ... } ``` In **1.0.69**, this early return was **removed** during the agent loop refactor: ```typescript // packages/opencode/src/session/prompt.ts (1.0.69+) export const prompt = fn(PromptInput, async (input) => { const session = await Session.get(input.sessionID); await SessionRevert.cleanup(session); await createUserMessage(input); // Note: changed to not return userMsg await Session.touch(input.sessionID); return loop(input.sessionID); // ❌ Always enters loop, even with noReply: true }); ``` **The Problem**: The loop waits for an assistant message with a finish reason, but when `noReply: true`, no assistant message is ever created. The loop runs forever, waiting for a response that will never come. ## Proposed Fix Restore the `noReply` early return in `packages/opencode/src/session/prompt.ts`: ```typescript export const prompt = fn(PromptInput, async (input) => { const session = await Session.get(input.sessionID); await SessionRevert.cleanup(session); const userMsg = await createUserMessage(input); // Capture return value await Session.touch(input.sessionID); // Early return for context-only messages (no AI inference) if (input.noReply) { return userMsg; // ✅ Return immediately, skip agent loop } return loop(input.sessionID); }); ``` ## Steps to Reproduce 1. Create a plugin with a tool that uses `noReply` (see test plugin example below) 2. Use OpenCode 1.0.69+ and call the tool 3. **Expected**: Tool returns immediately with confirmation message 4. **Actual**: Tool hangs indefinitely with status "queued" ### Test Plugin ```typescript // .opencode/plugin/test-noreply.ts import { type Plugin, tool } from "@opencode-ai/plugin"; export const TestNoReplyPlugin: Plugin = async ({ client }) => { return { tool: { test_noreply: tool({ description: "Test noReply pattern", args: { message: tool.schema.string(), }, async execute(args, ctx) { // Insert context using noReply await client.session.prompt({ path: { id: ctx.sessionID }, body: { noReply: true, parts: [{ type: "text", text: `Context: ${args.message}` }], }, }); return "✓ Context inserted"; }, }), }, }; }; ``` ## Impact This regression affects plugins that inject context into sessions for: - Background information that needs to persist across tool output compaction - Multi-step workflows where context must survive between tool calls - Any tool requiring persistent context in the conversation history ## References - **Breaking Commit**: [`a1214fff`](https://github.com/sst/opencode/commit/a1214fff) - "Refactor agent loop" ([#4412](https://github.com/sst/opencode/pull/4412)) (Nov 17, 2025) - **Affected File**: [`packages/opencode/src/session/prompt.ts`](https://github.com/sst/opencode/blob/main/packages/opencode/src/session/prompt.ts) - **Diff**: [Compare 1.0.68...1.0.69](https://github.com/sst/opencode/compare/v1.0.68...v1.0.69) - **Working Version**: Git tag [`v1.0.68`](https://github.com/sst/opencode/releases/tag/v1.0.68) (commit [`8ba48ed7`](https://github.com/sst/opencode/commit/8ba48ed7)) - **Broken Version**: Git tag [`v1.0.69`](https://github.com/sst/opencode/releases/tag/v1.0.69) (commit [`de50234a`](https://github.com/sst/opencode/commit/de50234a))
yindo closed this issue 2026-02-16 17:37:52 -05:00
Author
Owner

@omaclaren commented on GitHub (Nov 17, 2025):

FYI: This issue broke opencode-skills (https://github.com/malhashemi/opencode-skills) for me

@omaclaren commented on GitHub (Nov 17, 2025): FYI: This issue broke opencode-skills (https://github.com/malhashemi/opencode-skills) for me
Author
Owner

@rekram1-node commented on GitHub (Nov 17, 2025):

fixed

will release

@rekram1-node commented on GitHub (Nov 17, 2025): [fixed](https://github.com/sst/opencode/issues/4431#issuecomment-3544757452) will release
Author
Owner

@omaclaren commented on GitHub (Nov 17, 2025):

can verify opencode-skills works again with this fix :-)

@omaclaren commented on GitHub (Nov 17, 2025): can verify opencode-skills works again with this fix :-)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#2931