#20 question: possible to implement in - run message update?

Open
9 maanden geleden werd geopend door fszontagh · 1 opmerkingen

So, if a new issue created, assigned to claude. Then calude agent will start to work on it. While claude agent is running, but user adds a new comment into the issue or modify the issue itself. Possible to inject the new message (messages) / issue changes to the running claude agent?

So, if a new issue created, assigned to claude. Then calude agent will start to work on it. While claude agent is running, but user adds a new comment into the issue or modify the issue itself. Possible to inject the new message (messages) / issue changes to the running claude agent?
Claude Coding Agent reageerde 9 maanden geleden
Medewerker

Analysis: Injecting Messages to Running Claude Agent

I've analyzed the current implementation and the Claude Agent SDK capabilities. Here's what I found:


Current Implementation

The current system works as follows:

  1. Webhook Event → Job Queue: When an issue is created/modified or a comment is added, the webhook server receives the event and adds it to a persistent job queue (src/jobQueue.js)
  2. Sequential Processing: Jobs are processed one at a time (FIFO - first in, first out)
  3. Single Execution: Each job creates a new Claude Agent SDK session that runs independently until completion
  4. No Session Sharing: There's currently no mechanism to inject new information into an already-running Claude agent session

Key Code Location: client/src/claude-client.ts - The handleIssue() method creates a new query session for each job:

const queryInstance = query({
  prompt,
  options: { cwd, mcpServers, allowedTools, ... }
});

for await (const message of queryInstance) {
  // Process messages until completion
}

Is Mid-Run Injection Possible?

YES, but it requires significant architecture changes. The Claude Agent SDK provides several capabilities that could enable this:

1. Session Resume & Fork

  • What it does: Allows resuming a previous session with new instructions
  • How: Capture the sessionId from the initial response, then use the resume parameter:

    // Initial query
    const response = query({ prompt: "Work on issue #20" });
    for await (const message of response) {
    if (message.type === 'system' && message.subtype === 'init') {
    sessionId = message.session_id; // Save this!
    }
    }
    
    // Later: Resume with new context
    const resumed = query({
    prompt: "New comment: User says X",
    options: { resume: sessionId }
    });
    

2. Interrupt Method ⚠️

  • What it does: Stops a running agent mid-execution
  • How: Call await client.interrupt() on the SDK client instance
  • Limitation: Requires maintaining a reference to the client instance, which our current implementation doesn't do

3. Fork Session 🔀

  • What it does: Creates a branch from an existing session without modifying the original
  • How: Use forkSession: true with the resume parameter
  • Use Case: Explore alternative approaches from the same starting point

Implementation Challenges

To implement mid-run message injection, we would need to:

Challenge 1: Long-Running Process Management

  • Current: Each job creates a new Node.js process via handle-issue-ts.shclient/dist/index.js
  • Problem: No way to communicate with an already-running process
  • Solution Options:
    • Option A: Convert to a persistent daemon that maintains active sessions
    • Option B: Use IPC (Inter-Process Communication) to send messages to running processes
    • Option C: Store session IDs and queue resume operations when new events arrive

Challenge 2: Session State Persistence

  • Need to store sessionId for each running/paused issue
  • Track which issues have active sessions
  • Determine when to resume vs. fork vs. create new session

Challenge 3: Queue Coordination

  • Current queue processes one job at a time
  • Mid-run injection would need to:
    • Detect if issue #X already has a running session
    • Either interrupt it and resume with new context, OR
    • Queue the new message for the next resume cycle

Challenge 4: SDK API Limitations

  • The SDK interrupt() method requires holding a reference to the client instance
  • Our current implementation doesn't expose the client between invocations
  • Would need to refactor to maintain persistent client instances

Proposed Architecture (High-Level)

If we want to support mid-run injection, here's a possible approach:

Architecture: Session Manager Service

┌─────────────────────────────────────────────────┐
│         Webhook Server (existing)               │
│  - Receives events from Gogs                    │
│  - Enqueues jobs to JobQueue                    │
└──────────────────┬──────────────────────────────┘
                   │
                   v
┌─────────────────────────────────────────────────┐
│         Session Manager (NEW)                   │
│  - Maintains active Claude Agent sessions       │
│  - Maps issue_number → sessionId                │
│  - Handles: start, resume, interrupt, fork      │
└──────────────────┬──────────────────────────────┘
                   │
                   v
┌─────────────────────────────────────────────────┐
│         Job Queue (modified)                    │
│  - Checks if session exists for issue           │
│  - Routes to SessionManager for active sessions │
│  - Creates new session for new issues           │
└─────────────────────────────────────────────────┘

Key Components

  1. SessionManager Class

    • Maintains a Map<issueNumber, { sessionId, client, status }>
    • Provides: startSession(), resumeSession(), interruptSession(), forkSession()
    • Persists session state to disk for crash recovery
  2. Modified JobQueue

    • Before creating new job, check if SessionManager.hasActiveSession(issueNumber)
    • If yes: call SessionManager.resumeSession(issueNumber, newPrompt)
    • If no: create new session via SessionManager.startSession()
  3. Event Deduplication

    • When new comment arrives for issue #X with active session:
      • Option A: Immediately interrupt and resume with new context
      • Option B: Queue the comment and inject at next checkpoint
      • Option C: Let current execution finish, then auto-resume with accumulated comments

Recommendation

Given the complexity, I recommend a phased approach:

Phase 1: Session State Tracking (Low Effort)

  • Store session IDs in queue.json after each job completes
  • When new event arrives for same issue, include "Previous session: X" in the prompt
  • Claude can use Gogs MCP tools to check previous comments anyway (already works!)

Phase 2: Resume-Based Injection (Medium Effort)

  • Store active session IDs in a sessions.json file
  • When new comment arrives, create a new job that uses resume: sessionId
  • Still sequential (no true mid-execution), but maintains full context

Phase 3: True Mid-Run Injection (High Effort)

  • Implement SessionManager daemon
  • Add IPC or REST API for session control
  • Support real-time interrupt + resume

Current Workaround

Good news: The current implementation already handles this reasonably well!

When a new comment is added to an issue:

  1. A new job is created and queued
  2. The job starts and Claude fetches ALL issue comments via Gogs MCP tools (see buildPrompt() in client/src/claude-client.ts)
  3. Claude reads the full conversation history including new comments

Limitation: If Claude is currently running for that issue, the new comment won't be seen until:

  • Current execution completes
  • New job processes and Claude re-reads all comments

Question Back to You

Before I implement any changes, I need to understand your use case better:

  1. How critical is real-time injection?

    • Is it okay if new comments are processed after the current task finishes (5-10 minutes delay)?
    • Or do you need instant mid-execution interruption?
  2. What should happen to in-progress work?

    • Interrupt and restart with new context?
    • Complete current task, then process new input?
    • Try to merge new input into ongoing work?
  3. How often do you expect mid-run updates?

    • Rare (once per issue)?
    • Common (multiple comments while Claude is working)?

Let me know your preference and I can design the appropriate solution! 🚀

## Analysis: Injecting Messages to Running Claude Agent I've analyzed the current implementation and the Claude Agent SDK capabilities. Here's what I found: --- ### **Current Implementation** The current system works as follows: 1. **Webhook Event → Job Queue**: When an issue is created/modified or a comment is added, the webhook server receives the event and adds it to a **persistent job queue** (`src/jobQueue.js`) 2. **Sequential Processing**: Jobs are processed **one at a time** (FIFO - first in, first out) 3. **Single Execution**: Each job creates a **new Claude Agent SDK session** that runs independently until completion 4. **No Session Sharing**: There's currently **no mechanism** to inject new information into an already-running Claude agent session **Key Code Location**: `client/src/claude-client.ts` - The `handleIssue()` method creates a new query session for each job: ```typescript const queryInstance = query({ prompt, options: { cwd, mcpServers, allowedTools, ... } }); for await (const message of queryInstance) { // Process messages until completion } ``` --- ### **Is Mid-Run Injection Possible?** **YES**, but it requires significant architecture changes. The Claude Agent SDK provides several capabilities that could enable this: #### **1. Session Resume & Fork** ✅ - **What it does**: Allows resuming a previous session with new instructions - **How**: Capture the `sessionId` from the initial response, then use the `resume` parameter: ```typescript // Initial query const response = query({ prompt: "Work on issue #20" }); for await (const message of response) { if (message.type === 'system' && message.subtype === 'init') { sessionId = message.session_id; // Save this! } } // Later: Resume with new context const resumed = query({ prompt: "New comment: User says X", options: { resume: sessionId } }); ``` #### **2. Interrupt Method** ⚠️ - **What it does**: Stops a running agent mid-execution - **How**: Call `await client.interrupt()` on the SDK client instance - **Limitation**: Requires maintaining a reference to the client instance, which our current implementation doesn't do #### **3. Fork Session** 🔀 - **What it does**: Creates a branch from an existing session without modifying the original - **How**: Use `forkSession: true` with the `resume` parameter - **Use Case**: Explore alternative approaches from the same starting point --- ### **Implementation Challenges** To implement mid-run message injection, we would need to: #### **Challenge 1: Long-Running Process Management** - Current: Each job creates a **new Node.js process** via `handle-issue-ts.sh` → `client/dist/index.js` - Problem: No way to communicate with an already-running process - **Solution Options**: - **Option A**: Convert to a **persistent daemon** that maintains active sessions - **Option B**: Use **IPC (Inter-Process Communication)** to send messages to running processes - **Option C**: Store session IDs and **queue resume operations** when new events arrive #### **Challenge 2: Session State Persistence** - Need to store `sessionId` for each running/paused issue - Track which issues have active sessions - Determine when to resume vs. fork vs. create new session #### **Challenge 3: Queue Coordination** - Current queue processes **one job at a time** - Mid-run injection would need to: - Detect if issue #X already has a running session - Either interrupt it and resume with new context, OR - Queue the new message for the next resume cycle #### **Challenge 4: SDK API Limitations** - The SDK `interrupt()` method requires holding a reference to the client instance - Our current implementation doesn't expose the client between invocations - Would need to refactor to maintain **persistent client instances** --- ### **Proposed Architecture (High-Level)** If we want to support mid-run injection, here's a possible approach: #### **Architecture: Session Manager Service** ``` ┌─────────────────────────────────────────────────┐ │ Webhook Server (existing) │ │ - Receives events from Gogs │ │ - Enqueues jobs to JobQueue │ └──────────────────┬──────────────────────────────┘ │ v ┌─────────────────────────────────────────────────┐ │ Session Manager (NEW) │ │ - Maintains active Claude Agent sessions │ │ - Maps issue_number → sessionId │ │ - Handles: start, resume, interrupt, fork │ └──────────────────┬──────────────────────────────┘ │ v ┌─────────────────────────────────────────────────┐ │ Job Queue (modified) │ │ - Checks if session exists for issue │ │ - Routes to SessionManager for active sessions │ │ - Creates new session for new issues │ └─────────────────────────────────────────────────┘ ``` #### **Key Components** 1. **SessionManager Class** - Maintains a `Map<issueNumber, { sessionId, client, status }>` - Provides: `startSession()`, `resumeSession()`, `interruptSession()`, `forkSession()` - Persists session state to disk for crash recovery 2. **Modified JobQueue** - Before creating new job, check if `SessionManager.hasActiveSession(issueNumber)` - If yes: call `SessionManager.resumeSession(issueNumber, newPrompt)` - If no: create new session via `SessionManager.startSession()` 3. **Event Deduplication** - When new comment arrives for issue #X with active session: - **Option A**: Immediately interrupt and resume with new context - **Option B**: Queue the comment and inject at next checkpoint - **Option C**: Let current execution finish, then auto-resume with accumulated comments --- ### **Recommendation** Given the complexity, I recommend a **phased approach**: #### **Phase 1: Session State Tracking (Low Effort)** - Store session IDs in `queue.json` after each job completes - When new event arrives for same issue, include "Previous session: X" in the prompt - Claude can use Gogs MCP tools to check previous comments anyway (already works!) #### **Phase 2: Resume-Based Injection (Medium Effort)** - Store active session IDs in a `sessions.json` file - When new comment arrives, create a new job that uses `resume: sessionId` - Still sequential (no true mid-execution), but maintains full context #### **Phase 3: True Mid-Run Injection (High Effort)** - Implement SessionManager daemon - Add IPC or REST API for session control - Support real-time interrupt + resume --- ### **Current Workaround** **Good news**: The current implementation already handles this reasonably well! When a new comment is added to an issue: 1. A new job is created and queued 2. The job starts and Claude fetches **ALL** issue comments via Gogs MCP tools (see `buildPrompt()` in `client/src/claude-client.ts`) 3. Claude reads the full conversation history including new comments **Limitation**: If Claude is currently running for that issue, the new comment won't be seen until: - Current execution completes - New job processes and Claude re-reads all comments --- ### **Question Back to You** Before I implement any changes, I need to understand your use case better: 1. **How critical is real-time injection?** - Is it okay if new comments are processed after the current task finishes (5-10 minutes delay)? - Or do you need instant mid-execution interruption? 2. **What should happen to in-progress work?** - Interrupt and restart with new context? - Complete current task, then process new input? - Try to merge new input into ongoing work? 3. **How often do you expect mid-run updates?** - Rare (once per issue)? - Common (multiple comments while Claude is working)? Let me know your preference and I can design the appropriate solution! 🚀
Sign in to join this conversation.
Geen mijlpaal
Geen verantwoordelijke
2 deelnemers
Laden...
Annuleren
Opslaan
Er is nog geen inhoud.