mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 05:02:11 +00:00
docs: add OpenCode API endpoints for HITL
This commit is contained in:
parent
3a7c4fde3d
commit
cf809e757c
1 changed files with 64 additions and 18 deletions
|
|
@ -17,25 +17,46 @@ Comparison of how each coding agent handles interactive permission and question
|
||||||
|
|
||||||
OpenCode is the only agent with a fully interactive bidirectional HITL protocol. It emits events that require explicit responses via dedicated API endpoints.
|
OpenCode is the only agent with a fully interactive bidirectional HITL protocol. It emits events that require explicit responses via dedicated API endpoints.
|
||||||
|
|
||||||
|
### API Endpoints
|
||||||
|
|
||||||
|
| Method | Endpoint | Description |
|
||||||
|
|--------|----------|-------------|
|
||||||
|
| GET | `/question` | List pending question requests |
|
||||||
|
| POST | `/question/{requestID}/reply` | Answer a question |
|
||||||
|
| POST | `/question/{requestID}/reject` | Reject a question |
|
||||||
|
| GET | `/permission` | List pending permission requests |
|
||||||
|
| POST | `/permission/{requestID}/reply` | Respond to permission |
|
||||||
|
|
||||||
### Permission Requests
|
### Permission Requests
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
interface PermissionRequest {
|
interface PermissionRequest {
|
||||||
id: string;
|
id: string; // Pattern: ^per.*
|
||||||
sessionID: string;
|
sessionID: string; // Pattern: ^ses.*
|
||||||
permission: string; // e.g., "file:write"
|
permission: string; // e.g., "file:write"
|
||||||
patterns: string[]; // Affected paths
|
patterns: string[]; // Affected paths
|
||||||
metadata: Record<string, unknown>;
|
metadata: Record<string, unknown>;
|
||||||
always: string[]; // "Always allow" options
|
always: string[]; // "Always allow" options
|
||||||
tool?: { messageID: string; callID: string };
|
tool?: { messageID: string; callID: string };
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Responding:**
|
**API: Reply to Permission**
|
||||||
|
```
|
||||||
|
POST /permission/{requestID}/reply
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"reply": "once" | "always" | "reject",
|
||||||
|
"message": "optional reason"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**SDK Usage:**
|
||||||
```typescript
|
```typescript
|
||||||
await clientV2.permission.reply({
|
await client.permission.reply({
|
||||||
requestID: requestId,
|
path: { requestID: "per_abc123" },
|
||||||
reply: "once" | "always" | "reject"
|
body: { reply: "once" }
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -43,8 +64,8 @@ await clientV2.permission.reply({
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
interface QuestionRequest {
|
interface QuestionRequest {
|
||||||
id: string;
|
id: string; // Pattern: ^que.*
|
||||||
sessionID: string;
|
sessionID: string; // Pattern: ^ses.*
|
||||||
questions: Array<{
|
questions: Array<{
|
||||||
header?: string;
|
header?: string;
|
||||||
question: string;
|
question: string;
|
||||||
|
|
@ -53,26 +74,51 @@ interface QuestionRequest {
|
||||||
}>;
|
}>;
|
||||||
tool?: { messageID: string; callID: string };
|
tool?: { messageID: string; callID: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Answer type: array of selected option labels
|
||||||
|
type QuestionAnswer = string[];
|
||||||
```
|
```
|
||||||
|
|
||||||
**Responding:**
|
**API: Reply to Question**
|
||||||
|
```
|
||||||
|
POST /question/{requestID}/reply
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"answers": [["Option A"], ["Option B", "Option C"]]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Each element in `answers` corresponds to a question (in order). Each answer is an array of selected option labels.
|
||||||
|
|
||||||
|
**API: Reject Question**
|
||||||
|
```
|
||||||
|
POST /question/{requestID}/reject
|
||||||
|
```
|
||||||
|
|
||||||
|
**SDK Usage:**
|
||||||
```typescript
|
```typescript
|
||||||
// Reply with selected options
|
// Reply with answers
|
||||||
await clientV2.question.reply({
|
await client.question.reply({
|
||||||
requestID: requestId,
|
path: { requestID: "que_abc123" },
|
||||||
answers: [["selected option"]] // Array of selected labels per question
|
body: { answers: [["Yes"]] }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Or reject
|
// Or reject
|
||||||
await clientV2.question.reject({ requestID: requestId });
|
await client.question.reject({
|
||||||
|
path: { requestID: "que_abc123" }
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Event Types
|
### SSE Event Types
|
||||||
|
|
||||||
| Event | Description |
|
| Event | Description |
|
||||||
|-------|-------------|
|
|-------|-------------|
|
||||||
| `permission.asked` | Agent requesting permission for an action |
|
| `permission.asked` | Agent requesting permission for an action |
|
||||||
|
| `permission.replied` | Permission response recorded |
|
||||||
| `question.asked` | Agent asking user a question with options |
|
| `question.asked` | Agent asking user a question with options |
|
||||||
|
| `question.replied` | Question answered |
|
||||||
|
| `question.rejected` | Question rejected by user |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue