# Copilot Queue (Pi Extension)

Queue user feedback ahead of time and let the model consume it via an `ask_user` tool.

This extension is inspired by [TaskSync](https://github.com/4regab/TaskSync)-style workflows: you preload responses, then configured providers can pull them during long runs.

## What it does

- Registers tool: `ask_user`
- Registers command: `/copilot-queue`
- Keeps a FIFO queue of responses
- Supports autopilot prompt cycling (1→2→3→1…)
- Activates queue/autopilot only on configured providers (defaults to `github-copilot`)
- Injects a provider-targeted `ask_user` loop policy into the system prompt on each new run
- Adds a hidden `ask_user` protocol reminder, and reinforces compatible provider payloads (`tool_choice: required` for OpenAI-style requests, `tool_choice: { type: "any" }` for Anthropic-style requests when thinking is not enabled) when `ask_user` is available
- While a configured provider is actively running, normal interactive input is captured into queue by default (instead of triggering a new turn)
- Interactive capture can be toggled with `/copilot-queue capture on|off` (`on` by default)
- Tracks session elapsed time, `ask_user` call count, other tool-call count, and direct-reply misses in status line
- Emits session hygiene warnings at configurable thresholds (default: 120 minutes, 50 `ask_user` calls)
- Persists state in session entries
- Shows queue/autopilot/session state in Pi status line when the current provider is configured for Copilot Queue
- Status line output follows the active Pi theme, and can be disabled with `copilotQueue.showStatusLine`

When `ask_user` is called:

1. If queue has items → returns next queued response
2. Else if autopilot is enabled and has prompts → returns next autopilot prompt (cycling)
3. Else in interactive UI for a configured provider → waits for `/copilot-queue add <message>`, `/copilot-queue done`, or `/copilot-queue stop` (optionally with timeout)
4. Else → returns fallback response (`continue` by default)

When the current model provider is not configured for Copilot Queue, queue/autopilot is bypassed, `ask_user` uses manual/fallback behavior only, and the extension status line is hidden.

## Install

### Option 1: Direct with Pi (npm or git)

Install from npm:

```bash
pi install npm:pi-copilot-queue
```

Install from git:

```bash
pi install git:github.com/ayagmar/pi-copilot-queue
```

Pinned to a specific release tag:

```bash
pi install git:github.com/ayagmar/pi-copilot-queue@v0.1.1
```

Project-local install (writes to `.pi/settings.json`):

```bash
pi install -l git:github.com/ayagmar/pi-copilot-queue
```

Install from local path:

```bash
pi install /absolute/path/to/pi-copilot-queue
```

Then reload in Pi:

```text
/reload
```

### Option 2: With [pi-extmgr](https://github.com/ayagmar/pi-extmgr) (`/extensions`)

Install extmgr once:

```bash
pi install npm:pi-extmgr
```

Then in Pi (GitHub source):

```text
/extensions install git:github.com/ayagmar/pi-copilot-queue
/reload
```

Or install the extension file directly from GitHub (`index.ts`/entrypoint path):

```text
/extensions install https://github.com/ayagmar/pi-copilot-queue/blob/master/src/index.ts
/reload
```

You can also install a local extension file directly:

```text
/extensions install /absolute/path/to/pi-copilot-queue/src/index.ts
/reload
```

## Settings

By default, Copilot Queue is active only for `github-copilot`.

You can override that in `~/.pi/agent/settings.json`:

```json
{
  "copilotQueue": {
    "providers": ["github-copilot", "openai"],
    "showStatusLine": true
  }
}
```

Single-provider shorthand also works:

```json
{
  "copilotQueue": {
    "provider": "github-copilot"
  }
}
```

Settings are global and are read from `~/.pi/agent/settings.json`.

Defaults:

- `providers = ["github-copilot"]`
- `showStatusLine = true`

Use an empty array to disable provider interception entirely:

```json
{
  "copilotQueue": {
    "providers": []
  }
}
```

Hide the extension status line while keeping provider management enabled:

```json
{
  "copilotQueue": {
    "showStatusLine": false
  }
}
```

You can also manage the global settings from inside Pi:

```text
/copilot-queue providers
/copilot-queue providers github-copilot openai
/copilot-queue providers global openai anthropic
/copilot-queue providers off
/copilot-queue providers global off
/copilot-queue settings
```

- `providers` with no arguments shows the current active list.
- Passing one or more provider names writes `~/.pi/agent/settings.json`.
- `global` is still accepted as an alias.
- `off` writes an empty global provider list.
- Tab completion covers the full command surface, including top-level commands, provider routing, session subcommands, timeout presets, and common provider names.

## Usage

### Queue messages

```text
/copilot-queue add continue with the refactor
/copilot-queue add now add tests for edge cases
/copilot-queue list
/copilot-queue clear
/copilot-queue done
/copilot-queue stop
```

### Done / stop waiting

```text
/copilot-queue done
/copilot-queue stop
```

Both commands request an explicit stop. If `ask_user` is currently waiting, it is released with `stop`. Otherwise the next `ask_user` call will immediately receive `stop`.

After an explicit stop, managed-provider runs stay in normal direct-reply mode until you queue a new message or enable autopilot. That re-arms the `ask_user` loop immediately.

### Quick settings UI

```text
/copilot-queue settings
```

The settings UI lets you adjust all current Copilot Queue settings from one place, including:

- managed providers
- busy input capture
- status line visibility
- empty-queue wait timeout
- fallback response
- warning thresholds
- autopilot on/off
- autopilot prompt add/clear

### Interactive capture while busy (configured providers only)

```text
/copilot-queue capture on
/copilot-queue capture off
```

- `on` (default): while a run is active, interactive input is queued for `ask_user`.
- `off`: keep normal steering behavior (input is not auto-queued).

### Wait timeout (for empty queue in UI mode)

```text
/copilot-queue wait-timeout 0
/copilot-queue wait-timeout 60
```

- `0` disables timeout (default): wait indefinitely.
- `>0` makes waiting `ask_user` return fallback after `<seconds>`.

### Session counters and hygiene warnings

```text
/copilot-queue session status
/copilot-queue session reset
/copilot-queue session threshold 120 50
```

- When enabled, the status line includes elapsed time + `ask_user` call count, and shows missed ask_user runs when they happen.
- `/copilot-queue session status` also reports completed managed-provider runs, runs that used `ask_user`, direct replies that skipped `ask_user`, compliance rate, other tool-call count, the last missed direct reply preview, and the non-`ask_user` tool count from that missed run.
- Warnings are advisory only (no forced stop).
- Default thresholds are `120` minutes and `50` `ask_user` calls.

### Fallback message

```text
/copilot-queue fallback continue
```

### Autopilot (cycling prompts)

```text
/copilot-queue autopilot add continue with implementation
/copilot-queue autopilot add now write tests
/copilot-queue autopilot on
/copilot-queue autopilot list
/copilot-queue autopilot off
/copilot-queue autopilot clear
```

## Recommended instruction snippet for your model

```text
When provider is managed by Copilot Queue, use the ask_user tool whenever feedback is required. Keep calling ask_user after every completed step instead of ending with a direct reply. Only stop when the user explicitly replies with stop, end, terminate, or quit.
```

## Development

```bash
pnpm install
pnpm run check
```

Release commands:

```bash
pnpm run release:patch
pnpm run release:minor
pnpm run release:major
```

Quick run:

```bash
pi -e ./src/index.ts
```
