Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
124 commits
Select commit Hold shift + click to select a range
fab485d
...
ariane-emory Nov 27, 2025
dfdbe55
feat
ariane-emory Nov 27, 2025
fdf2b4a
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Nov 27, 2025
b2fb226
...
ariane-emory Nov 27, 2025
50be3d3
fix: close interjection modal properly after the user's interjection …
ariane-emory Nov 27, 2025
5a71038
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Nov 28, 2025
5aa49aa
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Nov 28, 2025
a2d26f4
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Nov 28, 2025
6bc520f
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Nov 29, 2025
3c1d95f
Update Nix flake.lock and hashes
actions-user Nov 29, 2025
56075ff
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Nov 29, 2025
4032d35
Merge upstream/dev - resolved conflicts
ariane-emory Nov 29, 2025
aa1ee9a
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Nov 30, 2025
57667dc
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Nov 30, 2025
5c538fb
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Nov 30, 2025
11caca4
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Nov 30, 2025
8573a8d
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 1, 2025
641508e
chore: format code
actions-user Dec 1, 2025
b77e813
Update Nix flake.lock and hashes
actions-user Dec 1, 2025
636a833
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 1, 2025
f2c2837
Merge upstream/dev into feat/interjections
ariane-emory Dec 1, 2025
2268a99
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 2, 2025
32ee819
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 2, 2025
eb3ed9f
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 2, 2025
19e7205
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 2, 2025
1b4bbb1
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 3, 2025
5ee1fa3
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 3, 2025
61bf738
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 3, 2025
e8e9e1e
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 3, 2025
be56e4d
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 4, 2025
4383177
Merge upstream/dev into feat/interjections
ariane-emory Dec 8, 2025
b59e867
Fix TypeScript error: remove cacheKey from FileContents interface usage
ariane-emory Dec 8, 2025
4092279
fix: revert damaged file
ariane-emory Dec 8, 2025
3da4ec6
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 9, 2025
fcac478
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 9, 2025
999f60d
Merge branch 'dev' into feat/interjections
ariane-emory Dec 9, 2025
eefc767
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 10, 2025
7299e87
Merge branch 'dev' into feat/interjections
ariane-emory Dec 10, 2025
fe1f157
Merge branch 'dev' into feat/interjections
ariane-emory Dec 10, 2025
6f248a6
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 10, 2025
f1a8ef5
Merge branch 'dev' into feat/interjections
ariane-emory Dec 10, 2025
c5fb377
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 10, 2025
2bd7aff
Fix type error: useKittyKeyboard should be boolean
ariane-emory Dec 10, 2025
af9fd2f
Merge remote-tracking branch 'upstream/dev' into feat/interjections
ariane-emory Dec 10, 2025
50f2e61
fix: uncorrupt
ariane-emory Dec 11, 2025
467ad1b
Merge branch 'dev' into feat/interjections
ariane-emory Dec 11, 2025
1f94591
Merge branch 'dev' into feat/interjections
ariane-emory Dec 11, 2025
7e73a45
Merge branch 'dev' into repair/feat/interjections
ariane-emory Dec 13, 2025
0315bc9
feat: add interject option to TUI permission prompts
ariane-emory Dec 13, 2025
603f794
tidy: whitespace
ariane-emory Dec 13, 2025
03b08df
Merge dev into feat/interjections
ariane-emory Dec 17, 2025
5b6c2c0
Fix TypeScript syntax error in permission respond function
ariane-emory Dec 17, 2025
95cad32
Merge branch 'dev' into feat/interjections
ariane-emory Dec 17, 2025
031b66a
Merge branch 'dev' into feat/interjections
ariane-emory Dec 18, 2025
a650f5b
Merge branch 'dev' into feat/interjections
ariane-emory Dec 19, 2025
bd93d63
Merge branch 'dev' into feat/interjections
ariane-emory Dec 19, 2025
29c84f3
Merge branch 'dev' into feat/interjections
ariane-emory Dec 20, 2025
124b2b2
Merge branch 'dev' into feat/interjections
ariane-emory Dec 20, 2025
b3a7014
Merge branch 'dev' into feat/interjections
ariane-emory Dec 21, 2025
c89f854
Merge branch 'dev' into feat/interjections
ariane-emory Dec 21, 2025
956e9ba
Merge dev into feat/interjections
ariane-emory Dec 22, 2025
d28593e
Merge branch 'dev' into feat/interjections
ariane-emory Dec 23, 2025
27fb607
Merge branch 'dev' into feat/interjections
ariane-emory Dec 23, 2025
74992f4
Merge branch 'dev' into feat/interjections
ariane-emory Dec 23, 2025
baef977
Merge branch 'dev' into feat/interjections
ariane-emory Dec 23, 2025
70e18e5
Merge branch 'feat/interjections' of github.com:ariane-emory/opencode…
ariane-emory Dec 23, 2025
b58a448
Merge branch 'dev' into feat/interjections
ariane-emory Dec 23, 2025
026120e
Merge branch 'dev' into feat/interjections
ariane-emory Dec 23, 2025
d4303c0
Merge branch 'dev' into feat/interjections
ariane-emory Dec 23, 2025
6da70b1
Merge branch 'dev' into feat/interjections
ariane-emory Dec 24, 2025
62ad0f7
Merge branch 'dev' into feat/interjections
ariane-emory Dec 24, 2025
42180a1
Merge branch 'dev' into feat/interjections
ariane-emory Dec 24, 2025
b0e920f
Merge branch 'dev' into feat/interjections
ariane-emory Dec 24, 2025
eb906e9
Merge branch 'dev' into feat/interjections
ariane-emory Dec 25, 2025
306250d
Merge branch 'dev' into feat/interjections
ariane-emory Dec 25, 2025
7b909bc
Merge branch 'dev' into feat/interjections
ariane-emory Dec 25, 2025
8a6ac52
Merge branch 'dev' into feat/interjections
ariane-emory Dec 26, 2025
2e9ae29
Merge branch 'dev' into feat/interjections
ariane-emory Dec 27, 2025
a870ebb
Merge branch 'dev' into feat/interjections
ariane-emory Dec 27, 2025
0e6da61
Merge remote-tracking branch 'origin/dev' into feat/interjections
ariane-emory Dec 27, 2025
1f2c70a
Merge branch 'dev' into feat/interjections
ariane-emory Dec 28, 2025
097b0b6
Merge branch 'dev' into feat/interjections
ariane-emory Dec 28, 2025
0d0fc71
Merge branch 'dev' into feat/interjections
ariane-emory Dec 28, 2025
044dc67
Merge branch 'dev' into feat/interjections
ariane-emory Dec 29, 2025
e94113b
Merge branch 'dev' into feat/interjections
ariane-emory Dec 29, 2025
019b31a
Merge branch 'dev' into feat/interjections
ariane-emory Dec 29, 2025
37b8d84
Fix merge conflicts: add DialogPrompt import and remove unsupported u…
ariane-emory Dec 29, 2025
d3c253e
Revert: preserve pre-existing errors from dev and feat/interjections …
ariane-emory Dec 29, 2025
9f71eee
Fix missing DialogPrompt import in feat/interjections branch
ariane-emory Dec 29, 2025
0577d47
Merge branch 'dev' into feat/interjections
ariane-emory Dec 29, 2025
b6cef80
Merge branch 'dev' into feat/interjections
ariane-emory Dec 29, 2025
db4e3c1
Merge branch 'dev' into feat/interjections
ariane-emory Dec 30, 2025
5dc79bd
Merge branch 'dev' into feat/interjections
ariane-emory Dec 30, 2025
496a8f8
Merge branch 'dev' into feat/interjections
ariane-emory Dec 30, 2025
614a9a2
Merge branch 'dev' into feat/interjections
ariane-emory Dec 30, 2025
dd25976
Merge branch 'feat/interjections' of github.com:ariane-emory/opencode…
ariane-emory Dec 30, 2025
c70cdf7
Merge branch 'dev' into feat/interjections
ariane-emory Dec 30, 2025
438f0cd
Merge branch 'dev' into feat/interjections
ariane-emory Dec 30, 2025
e6ef4b1
Merge branch 'dev' into feat/interjections
ariane-emory Dec 31, 2025
e2b0edb
Merge branch 'dev' into feat/interjections
ariane-emory Jan 1, 2026
3800a6e
Merge branch 'dev' into feat/interjections
ariane-emory Jan 1, 2026
ebb3547
Merge dev into feat/interjections
ariane-emory Jan 1, 2026
2e682fb
Merge dev into feat/interjections
ariane-emory Jan 2, 2026
541714b
Merge dev into feat/interjections
ariane-emory Jan 3, 2026
d86fbc9
Merge branch 'dev' into feat/interjections
ariane-emory Jan 3, 2026
1edbd37
Merge branch 'dev' into feat/interjections
ariane-emory Jan 4, 2026
54748a2
Merge branch 'dev' into feat/interjections
ariane-emory Jan 4, 2026
f7066dd
Merge branch 'dev' into feat/interjections
ariane-emory Jan 4, 2026
8d47e32
Merge branch 'dev' into feat/interjections
ariane-emory Jan 5, 2026
a4f11a4
Merge branch 'dev' into feat/interjections
ariane-emory Jan 5, 2026
ae2bb35
Merge branch 'dev' into feat/interjections
ariane-emory Jan 5, 2026
daef542
Merge branch 'dev' into feat/interjections
ariane-emory Jan 6, 2026
13b384d
Merge branch 'dev' into feat/interjections
ariane-emory Jan 6, 2026
3946e25
Merge branch 'feat/interjections' of github.com:ariane-emory/opencode…
ariane-emory Jan 6, 2026
ac4993a
Merge branch 'dev' into feat/interjections
ariane-emory Jan 6, 2026
60149e9
Merge branch 'dev' into feat/interjections
ariane-emory Jan 6, 2026
0cc0a55
Merge branch 'dev' into feat/interjections
ariane-emory Jan 6, 2026
c883823
Merge branch 'dev' into feat/interjections
ariane-emory Jan 6, 2026
7fde978
Merge branch 'dev' into feat/interjections
ariane-emory Jan 7, 2026
6519a77
Merge branch 'dev' into feat/interjections
ariane-emory Jan 7, 2026
7aae0c0
Merge branch 'dev' into feat/interjections
ariane-emory Jan 7, 2026
617e74a
Merge branch 'dev' into feat/interjections
ariane-emory Jan 7, 2026
5ffcba9
Merge branch 'dev' into feat/interjections
ariane-emory Jan 8, 2026
dbf80b3
Merge branch 'dev' into feat/interjections
ariane-emory Jan 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import { TodoItem } from "../../component/todo-item"
import { DialogMessage } from "./dialog-message"
import type { PromptInfo } from "../../component/prompt/history"
import { DialogConfirm } from "@tui/ui/dialog-confirm"
import { DialogPrompt } from "@tui/ui/dialog-prompt"
import { DialogTimeline } from "./dialog-timeline"
import { DialogForkFromTimeline } from "./dialog-fork-from-timeline"
import { DialogSessionRename } from "../../component/dialog-session-rename"
Expand All @@ -73,6 +74,7 @@ import { PermissionPrompt } from "./permission"
import { QuestionPrompt } from "./question"
import { DialogExportOptions } from "../../ui/dialog-export-options"
import { formatTranscript } from "../../util/transcript"
import { iife } from "@/util/iife"

addDefaultParsers(parsers.parsers)

Expand Down Expand Up @@ -254,6 +256,49 @@ export function Session() {
dialog.clear()
}

useKeyboard(async (evt) => {
if (dialog.stack.length > 0) return

const first = permissions()[0]
if (first) {
if (evt.ctrl || evt.meta) return

// Handle interject with "i" key - opens prompt for user suggestion
if (evt.name === "i") {
const interjection = await DialogPrompt.show(dialog, "Interject", {
placeholder: "Enter your suggestion...",
description: () => (
<text fg={theme.textMuted}>
Provide a suggestion or correction for the model to consider
</text>
),
})
if (interjection !== null && interjection.trim()) {
sdk.client.permission.reply({
requestID: first.id,
reply: "interject",
interjection: interjection.trim(),
})
}
return
}

const response = iife(() => {
if (evt.name === "return") return "once"
if (evt.name === "a") return "always"
if (evt.name === "d") return "reject"
if (evt.name === "escape") return "reject"
return
})
if (response) {
sdk.client.permission.reply({
requestID: first.id,
reply: response,
})
}
}
})

function toBottom() {
setTimeout(() => {
if (scroll) scroll.scrollTo(scroll.scrollHeight)
Expand Down
2 changes: 2 additions & 0 deletions packages/opencode/src/cli/cmd/tui/ui/dialog-prompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export function DialogPrompt(props: DialogPromptProps) {
useKeyboard((evt) => {
if (evt.name === "return") {
props.onConfirm?.(textarea.plainText)
dialog.clear()
}
})

Expand All @@ -45,6 +46,7 @@ export function DialogPrompt(props: DialogPromptProps) {
<textarea
onSubmit={() => {
props.onConfirm?.(textarea.plainText)
dialog.clear()
}}
height={3}
keyBindings={[{ name: "return", action: "submit" }]}
Expand Down
24 changes: 20 additions & 4 deletions packages/opencode/src/permission/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export namespace Permission {
sessionID: z.string(),
permissionID: z.string(),
response: z.string(),
interjection: z.string().optional(),
}),
),
}
Expand Down Expand Up @@ -152,10 +153,10 @@ export namespace Permission {
})
}

export const Response = z.enum(["once", "always", "reject"])
export const Response = z.enum(["once", "always", "reject", "interject"])
export type Response = z.infer<typeof Response>

export function respond(input: { sessionID: Info["sessionID"]; permissionID: Info["id"]; response: Response }) {
export function respond(input: {sessionID: Info["sessionID"]; permissionID: Info["id"]; response: Response; interjection?: string}) {
log.info("response", input)
const { pending, approved } = state()
const match = pending[input.sessionID]?.[input.permissionID]
Expand All @@ -165,9 +166,23 @@ export namespace Permission {
sessionID: input.sessionID,
permissionID: input.permissionID,
response: input.response,
interjection: input.interjection,
})
if (input.response === "reject") {
match.reject(new RejectedError(input.sessionID, input.permissionID, match.info.callID, match.info.metadata))
if (input.response === "reject" || input.response === "interject") {
const reason =
input.response === "interject" && input.interjection
? `The user rejected this action and suggests: ${input.interjection}`
: undefined
match.reject(
new RejectedError(
input.sessionID,
input.permissionID,
match.info.callID,
match.info.metadata,
reason,
input.response === "interject",
),
)
return
}
match.resolve()
Expand Down Expand Up @@ -199,6 +214,7 @@ export namespace Permission {
public readonly toolCallID?: string,
public readonly metadata?: Record<string, any>,
public readonly reason?: string,
public readonly isInterjection: boolean = false,
) {
super(
reason !== undefined
Expand Down
20 changes: 17 additions & 3 deletions packages/opencode/src/permission/next.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export namespace PermissionNext {

export type Request = z.infer<typeof Request>

export const Reply = z.enum(["once", "always", "reject"])
export const Reply = z.enum(["once", "always", "reject", "interject"])
export type Reply = z.infer<typeof Reply>

export const Approval = z.object({
Expand All @@ -90,6 +90,7 @@ export namespace PermissionNext {
sessionID: z.string(),
requestID: z.string(),
reply: Reply,
interjection: z.string().optional(),
}),
),
}
Expand Down Expand Up @@ -149,6 +150,7 @@ export namespace PermissionNext {
z.object({
requestID: Identifier.schema("permission"),
reply: Reply,
interjection: z.string().optional(),
message: z.string().optional(),
}),
async (input) => {
Expand All @@ -160,7 +162,12 @@ export namespace PermissionNext {
sessionID: existing.info.sessionID,
requestID: existing.info.id,
reply: input.reply,
interjection: input.interjection,
})
if (input.reply === "interject") {
existing.reject(new RejectedError(true, input.interjection))
return
}
if (input.reply === "reject") {
existing.reject(input.message ? new CorrectedError(input.message) : new RejectedError())
// Reject all other pending permissions for this session
Expand Down Expand Up @@ -242,8 +249,15 @@ export namespace PermissionNext {

/** User rejected without message - halts execution */
export class RejectedError extends Error {
constructor() {
super(`The user rejected permission to use this specific tool call.`)
public readonly isInterjection: boolean
public readonly interjection?: string
constructor(isInterjection = false, interjection?: string) {
const message = isInterjection && interjection
? `The user interjected with a suggestion: ${interjection}`
: `The user rejected permission to use this specific tool call. You may try again with different parameters.`
super(message)
this.isInterjection = isInterjection
this.interjection = interjection
}
}

Expand Down
16 changes: 13 additions & 3 deletions packages/opencode/src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1625,12 +1625,21 @@ export namespace Server {
permissionID: z.string(),
}),
),
validator("json", z.object({ response: PermissionNext.Reply })),
validator(
"json",
z.object({
response: PermissionNext.Reply,
interjection: z.string().optional(),
message: z.string().optional(),
}),
),
async (c) => {
const params = c.req.valid("param")
const json = c.req.valid("json")
PermissionNext.reply({
requestID: params.permissionID,
reply: c.req.valid("json").response,
reply: json.response,
interjection: json.interjection,
})
return c.json(true)
},
Expand Down Expand Up @@ -1659,13 +1668,14 @@ export namespace Server {
requestID: z.string(),
}),
),
validator("json", z.object({ reply: PermissionNext.Reply, message: z.string().optional() })),
validator("json", z.object({ reply: PermissionNext.Reply, interjection: z.string().optional(), message: z.string().optional() })),
async (c) => {
const params = c.req.valid("param")
const json = c.req.valid("json")
await PermissionNext.reply({
requestID: params.requestID,
reply: json.reply,
interjection: json.interjection,
message: json.message,
})
return c.json(true)
Expand Down
11 changes: 7 additions & 4 deletions packages/opencode/src/session/processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,13 @@ export namespace SessionProcessor {
},
})

if (
value.error instanceof PermissionNext.RejectedError ||
value.error instanceof Question.RejectedError
) {
if (value.error instanceof PermissionNext.RejectedError) {
// Only block processing for actual denials, not interjections
// Interjections contain user suggestions and should allow model to continue
if (!value.error.isInterjection) {
blocked = shouldBreak
}
} else if (value.error instanceof Question.RejectedError) {
blocked = shouldBreak
}
delete toolcalls[value.toolCallId]
Expand Down
4 changes: 3 additions & 1 deletion packages/sdk/js/src/gen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ export type EventPermissionReplied = {
sessionID: string
permissionID: string
response: string
interjection?: string
}
}

Expand Down Expand Up @@ -2877,7 +2878,8 @@ export type SessionUnrevertResponse = SessionUnrevertResponses[keyof SessionUnre

export type PostSessionIdPermissionsPermissionIdData = {
body?: {
response: "once" | "always" | "reject"
response: "once" | "always" | "reject" | "interject"
interjection?: string
}
path: {
id: string
Expand Down
8 changes: 6 additions & 2 deletions packages/sdk/js/src/v2/gen/sdk.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1699,7 +1699,8 @@ export class Permission extends HeyApiClient {
sessionID: string
permissionID: string
directory?: string
response?: "once" | "always" | "reject"
response?: "once" | "always" | "reject" | "interject"
interjection?: string
},
options?: Options<never, ThrowOnError>,
) {
Expand All @@ -1712,6 +1713,7 @@ export class Permission extends HeyApiClient {
{ in: "path", key: "permissionID" },
{ in: "query", key: "directory" },
{ in: "body", key: "response" },
{ in: "body", key: "interjection" },
],
},
],
Expand All @@ -1737,7 +1739,8 @@ export class Permission extends HeyApiClient {
parameters: {
requestID: string
directory?: string
reply?: "once" | "always" | "reject"
reply?: "once" | "always" | "reject" | "interject"
interjection?: string
message?: string
},
options?: Options<never, ThrowOnError>,
Expand All @@ -1750,6 +1753,7 @@ export class Permission extends HeyApiClient {
{ in: "path", key: "requestID" },
{ in: "query", key: "directory" },
{ in: "body", key: "reply" },
{ in: "body", key: "interjection" },
{ in: "body", key: "message" },
],
},
Expand Down
12 changes: 8 additions & 4 deletions packages/sdk/js/src/v2/gen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,9 @@ export type EventPermissionReplied = {
properties: {
sessionID: string
requestID: string
reply: "once" | "always" | "reject"
reply: "once" | "always" | "reject" | "interject"
interjection?: string
message?: string
}
}

Expand Down Expand Up @@ -3528,7 +3530,8 @@ export type SessionUnrevertResponse = SessionUnrevertResponses[keyof SessionUnre

export type PermissionRespondData = {
body?: {
response: "once" | "always" | "reject"
response: "once" | "always" | "reject" | "interject"
interjection?: string
}
path: {
sessionID: string
Expand Down Expand Up @@ -3564,8 +3567,9 @@ export type PermissionRespondResponse = PermissionRespondResponses[keyof Permiss

export type PermissionReplyData = {
body?: {
reply: "once" | "always" | "reject"
message?: string
reply: "once" | "always" | "reject" | "interject"
interjection?: string
message?: string
}
path: {
requestID: string
Expand Down
5 changes: 4 additions & 1 deletion packages/sdk/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -3022,7 +3022,10 @@
"properties": {
"response": {
"type": "string",
"enum": ["once", "always", "reject"]
"enum": ["once", "always", "reject", "interject"]
},
"interjection": {
"type": "string"
}
},
"required": ["response"]
Expand Down