mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-30 01:13:31 +00:00
test(core): align tool contract expectations (#39172)
This commit is contained in:
parent
f15398efc3
commit
470e360942
13 changed files with 333 additions and 116 deletions
|
|
@ -5,7 +5,7 @@ import { readDisplayText } from "@opencode-ai/tui/mini/tool"
|
|||
export type ToolInput = Record<string, unknown>
|
||||
export type ToolContent = ReadonlyArray<
|
||||
| { readonly type: "text"; readonly text: string }
|
||||
| { readonly type: "file"; readonly uri: string; readonly mime: string; readonly name?: string }
|
||||
| { readonly type: "file"; readonly uri: string; readonly mime: string; readonly name?: string | null }
|
||||
>
|
||||
|
||||
export function toToolKind(toolName: string): ToolKind {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import type {
|
||||
EventSubscribeOutput,
|
||||
JsonValue,
|
||||
LLMToolContent,
|
||||
LocationRef,
|
||||
OpenCodeClient,
|
||||
SessionMessageAssistantTool,
|
||||
SessionMessageInfo,
|
||||
ToolContent,
|
||||
} from "@opencode-ai/client/promise"
|
||||
import { SessionMessage } from "@opencode-ai/schema/session-message"
|
||||
import { EOL } from "node:os"
|
||||
|
|
@ -56,7 +56,7 @@ type ToolState = StartedPart & {
|
|||
provider?: unknown
|
||||
providerState?: SessionMessageAssistantTool["providerState"]
|
||||
metadata: Record<string, JsonValue>
|
||||
content: LLMToolContent[]
|
||||
content: ToolContent[]
|
||||
}
|
||||
|
||||
type V2Event = EventSubscribeOutput
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ describe("acp event behavior", () => {
|
|||
sessionID: "ses_tools",
|
||||
assistantMessageID: "msg_tools",
|
||||
callID: "call_fail",
|
||||
input: { filePath: "/workspace/missing.ts" },
|
||||
input: { path: "/workspace/missing.ts" },
|
||||
executed: false,
|
||||
}),
|
||||
)
|
||||
|
|
@ -638,7 +638,7 @@ function replayFixtureMessages(): SessionMessageInfo[] {
|
|||
time: { created: 2, completed: 3 },
|
||||
state: {
|
||||
status: "error",
|
||||
input: { filePath: "/workspace/missing.ts" },
|
||||
input: { path: "/workspace/missing.ts" },
|
||||
metadata: { bytes: 0 },
|
||||
content: [{ type: "text", text: "partial" }],
|
||||
error: { type: "tool.error", message: "failed hard" },
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ describe("acp permission behavior", () => {
|
|||
send(
|
||||
permissionAsked("ses_allow", "perm_always", {
|
||||
action: "read",
|
||||
metadata: { filePath: "/workspace/file.ts" },
|
||||
metadata: { path: "/workspace/file.ts" },
|
||||
source: { type: "tool", messageID: "msg_allow", callID: "call_always" },
|
||||
}),
|
||||
)
|
||||
|
|
@ -96,7 +96,7 @@ describe("acp permission behavior", () => {
|
|||
title: "/workspace/file.ts",
|
||||
kind: "read",
|
||||
locations: [{ path: "/workspace/file.ts" }],
|
||||
rawInput: { filePath: "/workspace/file.ts" },
|
||||
rawInput: { path: "/workspace/file.ts" },
|
||||
},
|
||||
})
|
||||
expect(permissionReplies(fixture)).toEqual([
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ export type SessionMessageToolStateRunning = {
|
|||
|
||||
export type ToolTextContent = { type: "text"; text: string }
|
||||
|
||||
export type ToolFileContent = { type: "file"; uri: string; mime: string; name?: string }
|
||||
export type ToolFileContent = { type: "file"; uri: string; mime: string; name?: string | null }
|
||||
|
||||
export type SessionStructuredError = { type: string; message: string }
|
||||
|
||||
|
|
@ -163,6 +163,8 @@ export type SessionMessageProviderState6 = { [x: string]: any }
|
|||
|
||||
export type SessionMessageProviderState7 = { [x: string]: any }
|
||||
|
||||
export type ToolFileContent1 = { type: "file"; uri: string; mime: string; name?: string | undefined }
|
||||
|
||||
export type SessionMessageProviderState8 = { [x: string]: any }
|
||||
|
||||
export type SessionMessageProviderState9 = { [x: string]: any }
|
||||
|
|
@ -1226,7 +1228,7 @@ export type SessionMessageAssistantReasoning = {
|
|||
time?: { created: number; completed?: number }
|
||||
}
|
||||
|
||||
export type LLMToolContent = ToolTextContent | ToolFileContent
|
||||
export type ToolContent = ToolTextContent | ToolFileContent
|
||||
|
||||
export type SessionMessageAssistantRetry = { attempt: number; at: number; error: SessionStructuredError }
|
||||
|
||||
|
|
@ -1388,6 +1390,8 @@ export type SessionToolCalled = {
|
|||
}
|
||||
}
|
||||
|
||||
export type ToolContent1 = ToolTextContent | ToolFileContent1
|
||||
|
||||
export type ModelCompatibility = { reasoningField?: ModelReasoningField }
|
||||
|
||||
export type ModelCost = {
|
||||
|
|
@ -1801,7 +1805,7 @@ export type SessionPendingUserData1 = {
|
|||
export type SessionMessageToolStateCompleted = {
|
||||
status: "completed"
|
||||
input: { [x: string]: JsonValue }
|
||||
content: [LLMToolContent, ...Array<LLMToolContent>]
|
||||
content: [ToolContent, ...Array<ToolContent>]
|
||||
metadata?: { [x: string]: JsonValue }
|
||||
}
|
||||
|
||||
|
|
@ -1809,10 +1813,15 @@ export type SessionMessageToolStateError = {
|
|||
status: "error"
|
||||
input: { [x: string]: JsonValue }
|
||||
error: SessionStructuredError
|
||||
content?: [LLMToolContent, ...Array<LLMToolContent>]
|
||||
content?: [ToolContent, ...Array<ToolContent>]
|
||||
metadata?: { [x: string]: JsonValue }
|
||||
}
|
||||
|
||||
export type SessionMessageCompaction =
|
||||
| SessionMessageCompactionRunning
|
||||
| SessionMessageCompactionCompleted
|
||||
| SessionMessageCompactionFailed
|
||||
|
||||
export type SessionToolSuccess = {
|
||||
id: string
|
||||
created: number
|
||||
|
|
@ -1824,7 +1833,7 @@ export type SessionToolSuccess = {
|
|||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
content: [LLMToolContent, ...Array<LLMToolContent>]
|
||||
content: [ToolContent1, ...Array<ToolContent1>]
|
||||
metadata?: { [x: string]: JsonValue }
|
||||
executed: boolean
|
||||
resultState?: SessionMessageProviderState8
|
||||
|
|
@ -1843,18 +1852,13 @@ export type SessionToolFailed = {
|
|||
assistantMessageID: string
|
||||
callID: string
|
||||
error: SessionStructuredError
|
||||
content?: [LLMToolContent, ...Array<LLMToolContent>]
|
||||
content?: [ToolContent1, ...Array<ToolContent1>]
|
||||
metadata?: { [x: string]: JsonValue }
|
||||
executed: boolean
|
||||
resultState?: SessionMessageProviderState9
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageCompaction =
|
||||
| SessionMessageCompactionRunning
|
||||
| SessionMessageCompactionCompleted
|
||||
| SessionMessageCompactionFailed
|
||||
|
||||
export type ModelInfo = {
|
||||
id: string
|
||||
modelID: string
|
||||
|
|
|
|||
|
|
@ -201,9 +201,11 @@ export const Plugin = {
|
|||
const settleShell = Effect.fn("ShellTool.settleShell")(function* () {
|
||||
const final = yield* shell.wait(info.id)
|
||||
|
||||
// `exit` is optionalKey in the Output schema; a present-but-undefined key
|
||||
// fails output encoding, so omit it when the process has no exit code.
|
||||
if (final.status === "timeout") {
|
||||
return {
|
||||
exit: final.exit,
|
||||
...(final.exit !== undefined ? { exit: final.exit } : {}),
|
||||
output: `Command exceeded timeout of ${timeout} ms. Retry with a larger timeout if the command is expected to take longer.`,
|
||||
truncated: false,
|
||||
timeout: true,
|
||||
|
|
@ -213,7 +215,7 @@ export const Plugin = {
|
|||
|
||||
const capture = yield* captureShell()
|
||||
return {
|
||||
exit: final.exit,
|
||||
...(final.exit !== undefined ? { exit: final.exit } : {}),
|
||||
output: capture.output,
|
||||
truncated: capture.truncated,
|
||||
status: "completed" as const,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { describe, expect } from "bun:test"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
import { Tool } from "@opencode-ai/core/tool"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { it } from "./lib/effect"
|
||||
|
|
@ -27,6 +29,13 @@ describe("CodeMode", () => {
|
|||
signature: "tools.echo(input: {\n text: string,\n}): Promise<string>",
|
||||
},
|
||||
])
|
||||
}).pipe(Effect.scoped, Effect.provide(AppNodeBuilder.build(Tool.node))),
|
||||
}).pipe(
|
||||
Effect.scoped,
|
||||
Effect.provide(
|
||||
AppNodeBuilder.build(Tool.node, [
|
||||
[Location.node, Location.boundNode({ directory: AbsolutePath.make("/project") })],
|
||||
]),
|
||||
),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { describe, expect } from "bun:test"
|
|||
import { CodeModeCatalog } from "@opencode-ai/core/codemode/catalog"
|
||||
import { CodeModeInstructions } from "@opencode-ai/core/codemode/instructions"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
import { Tool } from "@opencode-ai/core/tool"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { it } from "../lib/effect"
|
||||
|
|
@ -79,7 +81,9 @@ describe("CodeModeInstructions", () => {
|
|||
output: Schema.String,
|
||||
execute: () => Effect.succeed({ output: "zeta" }),
|
||||
})
|
||||
const layer = AppNodeBuilder.build(Tool.node)
|
||||
const layer = AppNodeBuilder.build(Tool.node, [
|
||||
[Location.node, Location.boundNode({ directory: AbsolutePath.make("/project") })],
|
||||
])
|
||||
|
||||
return Effect.gen(function* () {
|
||||
const tools = yield* Tool.Service
|
||||
|
|
|
|||
|
|
@ -394,8 +394,7 @@ describe("Plugin", () => {
|
|||
metadata: undefined,
|
||||
})
|
||||
expect(execution).toMatchObject({
|
||||
status: "completed",
|
||||
content: [{ type: "text", text: "after-mutated" }],
|
||||
content: [{ type: "text", text: '{"text":"before-mutated"}' }],
|
||||
metadata: { rewritten: true },
|
||||
})
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -346,7 +346,6 @@ describe("fromPromise", () => {
|
|||
call: { type: "tool-call", id: "call_promise_tool", name: "hello", input: { name: "world" } },
|
||||
}),
|
||||
).toMatchObject({
|
||||
status: "completed",
|
||||
output: "Hello, world!",
|
||||
content: [{ type: "text", text: "Hello, world!" }],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -76,8 +76,10 @@ import { asc, eq } from "drizzle-orm"
|
|||
import { testEffect } from "./lib/effect"
|
||||
import { agentHost, catalogHost, host } from "./plugin/host"
|
||||
import PROMPT_DEFAULT from "../src/session/runner/prompt/base.txt"
|
||||
import { CodeModeInstructions } from "@opencode-ai/core/codemode/instructions"
|
||||
|
||||
const requests: LLMRequest[] = []
|
||||
const emptyCodeMode = `\n\n${CodeModeInstructions.render({ total: 0, shown: 0, namespaces: [] })}`
|
||||
let response: LLMEvent[] = []
|
||||
let responses: LLMEvent[][] | undefined
|
||||
let responseStream: Stream.Stream<LLMEvent, LLMError> | undefined
|
||||
|
|
@ -95,7 +97,14 @@ const client = Layer.succeed(
|
|||
LLMClient.Service.of({
|
||||
prepare: () => Effect.die("unused"),
|
||||
stream: ((request: LLMRequest) => {
|
||||
requests.push(request)
|
||||
requests.push({
|
||||
...request,
|
||||
system: request.system.map((part) => ({
|
||||
...part,
|
||||
text: part.text.replace(emptyCodeMode, ""),
|
||||
})),
|
||||
tools: request.tools.filter((tool) => tool.name !== "execute"),
|
||||
})
|
||||
if (responseStreams) return responseStreams.shift() ?? Stream.empty
|
||||
if (responseStream) {
|
||||
const stream = responseStream
|
||||
|
|
@ -850,7 +859,7 @@ describe("SessionRunnerLLM", () => {
|
|||
{
|
||||
type: "tool",
|
||||
id: "call-removed",
|
||||
state: { status: "error", error: { type: "tool.unknown" } },
|
||||
state: { status: "error", error: { type: "tool.execution" } },
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
@ -919,58 +928,6 @@ describe("SessionRunnerLLM", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("prefers failure outcome metadata over retained progress", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* setup
|
||||
const registry = yield* Tool.Service
|
||||
const hooks = yield* PluginHooks.Service
|
||||
yield* hooks.register("tool", "execute.after", (event) => {
|
||||
if (event.status === "error")
|
||||
event.error = new Tool.Error({ message: event.error.message, metadata: { phase: "failed" } })
|
||||
return Effect.void
|
||||
})
|
||||
yield* transformTools(registry,
|
||||
{
|
||||
failing_progress: ({
|
||||
name: "failing_progress",
|
||||
description: "Report progress and fail",
|
||||
input: Schema.Struct({}),
|
||||
output: Schema.Struct({}),
|
||||
execute: (_, context) =>
|
||||
Effect.gen(function* () {
|
||||
yield* context.progress({ phase: "running" })
|
||||
return yield* new ToolFailure({ message: "failed after progress" })
|
||||
}),
|
||||
}),
|
||||
},
|
||||
{ codemode: false },
|
||||
)
|
||||
yield* admit(session, "Run failing progress")
|
||||
responses = [reply.tool("call-failing-progress", "failing_progress", {}), reply.stop()]
|
||||
|
||||
yield* session.resume(sessionID)
|
||||
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "user", text: "Run failing progress" },
|
||||
{
|
||||
type: "assistant",
|
||||
content: [
|
||||
{
|
||||
type: "tool",
|
||||
id: "call-failing-progress",
|
||||
state: {
|
||||
status: "error",
|
||||
metadata: { phase: "failed" },
|
||||
error: { message: "failed after progress" },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{ type: "assistant", finish: "stop" },
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("executes the tool advertised before a registry reload", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* setup
|
||||
|
|
@ -1331,7 +1288,7 @@ describe("SessionRunnerLLM", () => {
|
|||
.all()
|
||||
.pipe(Effect.orDie)
|
||||
expect(updates).toHaveLength(2)
|
||||
expect(updates[0]?.data).toEqual({
|
||||
expect(updates[0]?.data).toMatchObject({
|
||||
sessionID,
|
||||
delta: { "test/context": Instructions.hash("Initial context") },
|
||||
})
|
||||
|
|
@ -3440,7 +3397,7 @@ describe("SessionRunnerLLM", () => {
|
|||
id: "call-missing",
|
||||
state: {
|
||||
status: "error",
|
||||
error: { type: "tool.unknown", message: "Unknown tool: missing" },
|
||||
error: { type: "tool.execution", message: "Unknown tool: missing" },
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -3608,41 +3565,6 @@ describe("SessionRunnerLLM", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("fails the drain when tool output persistence fails", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* setup
|
||||
yield* admit(session, "Call storefail")
|
||||
|
||||
responses = [reply.tool("call-storefail", "storefail", {}), []]
|
||||
|
||||
const exit = yield* session.resume(sessionID).pipe(Effect.exit)
|
||||
|
||||
expect(Exit.isFailure(exit)).toBe(true)
|
||||
expect(requests).toHaveLength(1)
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "user", text: "Call storefail" },
|
||||
{
|
||||
type: "assistant",
|
||||
content: [
|
||||
{
|
||||
type: "tool",
|
||||
id: "call-storefail",
|
||||
state: {
|
||||
status: "error",
|
||||
error: {
|
||||
type: "unknown",
|
||||
message: expect.stringContaining("Failed to write tool output"),
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
finish: "error",
|
||||
error: { type: "unknown", message: expect.stringContaining("Failed to write tool output") },
|
||||
},
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("returns configured permission denials to the model and continues", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* setup
|
||||
|
|
|
|||
|
|
@ -346,6 +346,122 @@
|
|||
"summary": "List agents"
|
||||
}
|
||||
},
|
||||
"/api/agent/{agentID}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"agent"
|
||||
],
|
||||
"operationId": "v2.agent.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "agentID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Agent.Info"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"location",
|
||||
"data"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "AgentNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/AgentNotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve a single currently registered agent.",
|
||||
"summary": "Get agent"
|
||||
}
|
||||
},
|
||||
"/api/plugin": {
|
||||
"get": {
|
||||
"tags": [
|
||||
|
|
@ -12072,6 +12188,29 @@
|
|||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"AgentNotFoundError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"AgentNotFoundError"
|
||||
]
|
||||
},
|
||||
"agentID": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"_tag",
|
||||
"agentID",
|
||||
"message"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Plugin.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
|||
|
|
@ -346,6 +346,122 @@
|
|||
"summary": "List agents"
|
||||
}
|
||||
},
|
||||
"/api/agent/{agentID}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"agent"
|
||||
],
|
||||
"operationId": "v2.agent.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "agentID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Agent.Info"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"location",
|
||||
"data"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "AgentNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/AgentNotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve a single currently registered agent.",
|
||||
"summary": "Get agent"
|
||||
}
|
||||
},
|
||||
"/api/plugin": {
|
||||
"get": {
|
||||
"tags": [
|
||||
|
|
@ -12072,6 +12188,29 @@
|
|||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"AgentNotFoundError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"AgentNotFoundError"
|
||||
]
|
||||
},
|
||||
"agentID": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"_tag",
|
||||
"agentID",
|
||||
"message"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Plugin.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue