From 0a86b5a291f4b5840593e40267b545e4011c0678 Mon Sep 17 00:00:00 2001 From: Wang Defa <1+wangdefa@noreply.gitea.bcde.io> Date: Mon, 13 Jul 2026 20:17:06 +0800 Subject: [PATCH] =?UTF-8?q?AI=E7=BD=91=E5=85=B3=E6=96=B0=E5=A2=9ETTS/?= =?UTF-8?q?=E9=87=8D=E6=8E=92/=E5=AE=A1=E6=A0=B8=E7=AB=AF=E7=82=B9,xAI?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E6=89=A9=E5=B1=95,swagger=E4=BF=AE=E7=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新端点 /ai/v1/audio/speech(xai.grok-tts)、/rerank(cohere.rerank-v4)、/moderations(OCI Guardrails) - Responses 放行 code_interpreter 与远程 mcp 工具,web_search/x_search 解除仅非流式限制 - 模型能力映射扩展:TEXT_RERANK→RERANK、TEXT_TO_AUDIO→TTS - AI 网关文档独立 docs/ai-gateway.md,字段兼容矩阵只列支持项;README 精简引用 - swagger 修缺:135 处响应注解具体化,RawMessage/联合类型统一渲染 AnyJSON,overrides 迁至 docs/.swaggo - CHANGELOG 0.4.0,版本段不再记日期;DASH_VERSION v0.4.0 --- .trellis/spec/backend/index.md | 4 +- CHANGELOG.md | 27 +- DASH_VERSION | 2 +- README.md | 202 +- docs/.swaggo | 6 + docs/ai-gateway.md | 266 ++ docs/docs.go | 3773 +++++++++++++++++++-- docs/swagger.json | 3773 +++++++++++++++++++-- docs/swagger.yaml | 2639 ++++++++++++-- internal/aiwire/anyjson.go | 5 + internal/aiwire/moderations.go | 45 + internal/aiwire/rerank.go | 28 + internal/aiwire/responses.go | 13 + internal/api/about.go | 2 +- internal/api/aiadmin.go | 27 +- internal/api/aigateway.go | 18 +- internal/api/aigateway_extras.go | 119 + internal/api/aigateway_test.go | 8 + internal/api/attachment.go | 22 +- internal/api/auth.go | 6 +- internal/api/authx.go | 24 +- internal/api/console.go | 6 +- internal/api/federation.go | 12 +- internal/api/instance.go | 18 +- internal/api/logevent.go | 12 +- internal/api/network.go | 32 +- internal/api/ociconfig.go | 18 +- internal/api/overview.go | 4 +- internal/api/proxy.go | 12 +- internal/api/region.go | 10 +- internal/api/routes_ai.go | 3 + internal/api/settings.go | 22 +- internal/api/subscription.go | 8 +- internal/api/swagger_resp.go | 176 + internal/api/systemlog.go | 3 +- internal/api/task.go | 15 +- internal/api/tenant.go | 36 +- internal/api/webconsole.go | 2 +- internal/api/webhook.go | 2 +- internal/model/models.go | 2 +- internal/oci/client.go | 6 + internal/oci/genai.go | 5 + internal/oci/genai_guard.go | 127 + internal/oci/genai_responses.go | 6 +- internal/oci/genai_speech.go | 44 + internal/service/aigateway_extras.go | 248 ++ internal/service/aigateway_extras_test.go | 164 + internal/service/aigateway_test.go | 20 + internal/service/airesponses.go | 21 +- internal/service/airesponses_test.go | 27 +- 50 files changed, 10699 insertions(+), 1371 deletions(-) create mode 100644 docs/.swaggo create mode 100644 docs/ai-gateway.md create mode 100644 internal/aiwire/anyjson.go create mode 100644 internal/aiwire/moderations.go create mode 100644 internal/aiwire/rerank.go create mode 100644 internal/api/aigateway_extras.go create mode 100644 internal/api/swagger_resp.go create mode 100644 internal/oci/genai_guard.go create mode 100644 internal/oci/genai_speech.go create mode 100644 internal/service/aigateway_extras.go create mode 100644 internal/service/aigateway_extras_test.go diff --git a/.trellis/spec/backend/index.md b/.trellis/spec/backend/index.md index 9126d81..ec00321 100644 --- a/.trellis/spec/backend/index.md +++ b/.trellis/spec/backend/index.md @@ -1,6 +1,6 @@ # Backend Development Guidelines(oci-portal 后端规范) -> Go 后端(`oci-portal/`)编码规范入口。规范提炼自 Google / Uber Go Style Guide、Effective Go 与 Go 官方模块布局指南,按本项目裁剪;条目与项目约定冲突时,以本 spec 为准。迁自 docs/开发指南.md 与根目录 AGENTS.md(2026-07)。 +> Go 后端(`oci-portal/`)编码规范入口。规范提炼自 Google / Uber Go Style Guide、Effective Go 与 Go 官方模块布局指南,按本项目裁剪;条目与项目约定冲突时,以本 spec 为准。 --- @@ -51,7 +51,7 @@ go mod tidy # 依赖有变更时 全部 HTTP 接口带 swaggo 注释(@Summary 中文/@Tags 按域/@Param/@Success/@Router;JWT 组接口标 @Security BearerAuth)。**新增或修改接口必须同步注释**,并重新生成 spec: ```bash -go tool swag init -g cmd/server/main.go -o docs --parseInternal --parseDependency +go tool swag init -g cmd/server/main.go -o docs --parseInternal --parseDependency --overridesFile docs/.swaggo ``` 生成的 `docs/` 一并提交;UI 由 `SWAGGER=1` 开启(/swagger/index.html)。同名 handler 方法(list/create/get/update/remove)分布在多个 struct 上,写注释时确认 @Router 路径与该 receiver 的真实注册一致(routes_*.go)。 diff --git a/CHANGELOG.md b/CHANGELOG.md index 09e67fd..4bfba0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,23 @@ # Changelog -格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循语义化版本。 +格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)(版本段不记日期),版本号遵循语义化版本。 -## [0.3.1] - 2026-07-13 +## [0.4.0] + +### Added + +- 文本转语音端点 `POST /ai/v1/audio/speech`:OpenAI Audio Speech 兼容,直通 OCI 兼容面(模型 `xai.grok-tts`,voice 取 xAI Grok Voice 列表 `ara`/`eve`/`leo`/`rex`/`sal`);上游必填的 `language` 缺省时自动注入 `"auto"`,xAI 专属参数平铺透传;响应为一次性完整音频(Content-Type 透传上游,缺省 audio/mpeg),不提供流式 +- 文档重排端点 `POST /ai/v1/rerank`:Jina / Cohere 通行协议,走 OCI typed 面(`cohere.rerank-v4.0-pro` / `-fast`),支持 `top_n` 与 `return_documents`,`results[].index` 指向入参 `documents` 下标 +- 内容审核端点 `POST /ai/v1/moderations`:OpenAI moderations 外壳映射 OCI Guardrails(内容审核 / PII / 提示注入),`input` 为字符串或字符串数组(单次至多 8 条),categories 用 OCI 原生维度 `overall` / `blocklist` / `prompt_injection`(任一得分 ≥0.5 判 `flagged`),PII 命中放扩展字段 `results[].pii`(不参与 flagged;实测中文人名 / 手机号识别较弱,英文正常) +- Responses 服务端工具扩展:放行 Oracle 文档化的 xAI `code_interpreter` 与远程 `mcp` 工具,并解除 `web_search` / `x_search` 仅非流式的限制——四类服务端工具非流式与流式均实测可用;`code_interpreter` 的命名容器管理与 File Search 不提供 +- 模型能力映射扩展:`TEXT_RERANK` → RERANK、`TEXT_TO_AUDIO` → TTS,渠道探测 / 同步自动发现重排与语音模型入池 + +### Changed + +- AI 网关文档独立成篇 `docs/ai-gateway.md`(端点定位、兼容边界、已知上游限制、字段兼容矩阵——矩阵只列支持项,不支持 / 忽略项以文字简述),README 精简为概览并引用;实测披露:Responses `input_file` 内容块被上游以 ZDR 形态拒绝,能力不可用 +- swagger 全面修缺:135 处响应注解从泛型 map 改为具体类型(补文档用途响应结构与泛型列表外壳),AI 网关端点请求 / 响应 schema 完整可见;`json.RawMessage` 与联合类型统一渲染为任意 JSON 值(AnyJSON),不再误显示为 byte 数组;swag overrides 配置移至 `docs/.swaggo`,生成命令加 `--overridesFile docs/.swaggo`;顺带修正网页控制台会话创建响应码(200→201)与 SAML 元数据下载(改文件响应)两处注解失真 + +## [0.3.1] ### Added @@ -16,7 +31,7 @@ - AI 网关流式假成功:上游 error / `response.failed` 事件此前被吞掉,流提前 EOF 也被伪装成正常结束,调用日志呈现 200 · 0/0 且无错误信息;现 Messages 将上游失败转为 Anthropic `error` 事件,三个流式端点日志均记录上游错误消息或「上游流提前终止,未返回终态事件」 -## [0.3.0] - 2026-07-13 +## [0.3.0] ### Added @@ -33,7 +48,7 @@ - **移除自定义审计告警规则**及其阈值、窗口和冷却匹配能力;`/api/v1/log-events/alert-rules` 与 `/api/v1/log-events/alert-rules/{ruleId}` 管理接口、`audit_alert` 通知模板不再提供,已有规则升级后不再执行 -## [0.2.0] - 2026-07-12 +## [0.2.0] ### Added @@ -60,7 +75,7 @@ - 渠道「同步模型成功但探测报错不可用」:法兰克福等区域的微调基座模型占满探测候选导致的误报(探测状态与真实可用性不符的根因) - 租户删除:告警命中清理改子查询,日志事件数万条时不再超出 SQL 绑定变量上限导致删除失败;无法解析的任务 payload 记警告跳过并保留原任务,不再永久阻断租户删除 -## [0.1.0] - 2026-07-10 +## [0.1.0] ### Added @@ -88,7 +103,7 @@ - HTTP 入口加固:显式读写超时与优雅关闭、请求体上限(面板 1MB / AI 网关 10MB)、登录字段长度上限、登录守卫条目数有界 - 出错响应脱敏:内部错误只返回固定文案 + requestId,完整原因写服务端日志;GORM SQL 日志参数化输出,不再记录实参 -## [0.0.1] - 2026-07-09 +## [0.0.1] 首个版本:自托管 OCI 多租户管理面板后端。 diff --git a/DASH_VERSION b/DASH_VERSION index 268b033..fb7a04c 100644 --- a/DASH_VERSION +++ b/DASH_VERSION @@ -1 +1 @@ -v0.3.0 +v0.4.0 diff --git a/README.md b/README.md index 39e1149..cb3c81a 100644 --- a/README.md +++ b/README.md @@ -197,206 +197,20 @@ server { ## AI 网关 -AI 网关使用面板创建的独立密钥鉴权,支持 `Authorization: Bearer sk-...` 和 `x-api-key: sk-...`。密钥可绑定渠道分组和模型白名单;全局模型黑名单会从模型列表、路由和探测候选中同时排除目标模型。 +面板内置 OpenAI / Anthropic 兼容的 GenAI 网关:独立密钥鉴权(`Authorization: Bearer sk-...` 或 `x-api-key`),支持渠道分组、加权路由、熔断探测、模型黑白名单、内容日志与调用日志。 | 端点 | 定位 | 流式 | | --- | --- | --- | -| `POST /ai/v1/responses` | OpenAI Responses,无状态主接口 | SSE;服务端工具除外 | -| `POST /ai/v1/chat/completions` | OpenAI Chat Completions,存量客户端兼容层 | SSE | +| `POST /ai/v1/responses` | OpenAI Responses,无状态主接口(xAI 服务端工具 / MCP) | SSE | +| `POST /ai/v1/chat/completions` | OpenAI Chat Completions 兼容层 | SSE | | `POST /ai/v1/messages` | Anthropic Messages 转换层 | SSE | | `POST /ai/v1/embeddings` | OpenAI Embeddings | 否 | +| `POST /ai/v1/audio/speech` | 文本转语音(xAI Voice) | 否 | +| `POST /ai/v1/rerank` | 文档重排(Cohere Rerank) | 否 | +| `POST /ai/v1/moderations` | 内容审核(OCI Guardrails) | 否 | | `GET /ai/v1/models` | 当前密钥可见的模型列表 | 否 | -兼容边界: - -- 对话请求统一转发 OCI OpenAI 兼容面,当前供给以 `xai.`、`meta.`、`openai.` 前缀模型为主;Cohere Embeddings 不受该对话模型范围影响 -- 网关不保存会话历史,客户端需要携带完整上下文;Responses 拒绝非空 `previous_response_id`、非 `null` `conversation` 和 `background:true` -- Responses 支持 xAI Grok `web_search` / `x_search` 服务端工具,但仅限非流式请求 -- Responses 的 `reasoning.effort`、Messages 的 `output_config.effort` 和 Chat Completions 的 `reasoning_effort` 会传给上游,实际档位和效果由模型决定 -- Chat Completions 只承担协议转换与兼容修复;新能力优先在 Responses 和 Messages 提供 -- 单次请求最多尝试三个渠道;可重试错误会切换渠道,流式响应建立后不会换渠道重试 - -### 已知上游限制:大 system 区流式断流 - -实测(2026-07-13)OCI 兼容面对 `instructions` 与 `tools` 合计超约 64.5KB 的**流式**请求会在发出少量事件后静默断开连接(无任何错误事件;同请求非流式正常),与模型、字符集、消息正文大小均无关——消息正文(`input`)不计入该限制。Chat Completions 与 Messages 的 system/developer 提示会转换为 `instructions`,因此 Claude Code 等自带大体量系统提示与工具定义的客户端极易触发。 - -网关侧应对: - -- Messages 与 Chat Completions 的流式请求在客户端尚未收到任何输出时遭遇上游断流,会自动降级为非流式重做,并按标准事件/chunk 序列一次推送;调用日志记 `retries=1` 与降级标记 -- Responses 直通因初始事件已转发、协议上无法透明降级,调用日志记「上游流提前终止」,客户端需自行回退非流式 -- 应急规避:将超长 system 内容移入首条 user 消息正文可绕过该限制(正文不计入),但语义有别,根治有待上游修复 - -这里提供的是兼容接口而非 OpenAI / Anthropic 协议的完整实现。OCI OpenAI 兼容面的部分行为来自实测,未见 Oracle 文档承诺,可能随上游调整。路由与鉴权定义以 [Swagger YAML](docs/swagger.yaml) 或运行时 Swagger UI 为准;无法由 OpenAPI 完整表达的兼容边界列于上方。 - -### 字段兼容矩阵 - -以下矩阵以 2026-07-13 的 [OpenAI Responses](https://developers.openai.com/api/reference/resources/responses/methods/create)、[Chat Completions](https://developers.openai.com/api/reference/resources/chat/subresources/completions/methods/create)、[Embeddings](https://developers.openai.com/api/reference/resources/embeddings/methods/create) 和 [Anthropic Messages](https://platform.claude.com/docs/en/api/messages/create) 为标准基线,并与当前实现逐项核对。 - -这是一份兼容性快照,不替代 Swagger。标准接口和 OCI 上游都可能变化,最终行为以当前版本代码与实测为准。 - -| 标记 | 含义 | -| :---: | --- | -| ✅ | 网关直接支持 | -| ➡️ | 网关原样透传;是否生效由 OCI 上游决定 | -| 🔄 | 网关进行字段或协议转换后支持 | -| ◐ | 部分支持、存在前置条件或语义降级 | -| ⚠️ | 请求可被接受,但字段会被忽略 | -| ❌ | 网关在请求到达上游前拒绝 | - -
-POST /ai/v1/responses 对比 OpenAI Responses - -Responses 是“原始 JSON 直通 + 本地门禁”。除 `store` 外,网关不会重建请求体;未知顶层字段也会保留并送往 OCI。 - -| 标准字段 | 状态 | 网关行为 | -| --- | :---: | --- | -| `model` | ◐ | 必须非空,还要通过密钥模型白名单并匹配可用渠道;随后原样透传 | -| `input` | ➡️ | 支持标准的字符串或 item 数组,原始内容透传;网关不逐项保证 OCI 能处理所有 item 类型 | -| `instructions`、`max_output_tokens` | ➡️ | 类型可解析后原样透传,不做范围或模型能力校验 | -| `temperature`、`top_p`、`parallel_tool_calls` | ➡️ | 原样透传,不做取值范围校验 | -| `text` / `text.format` / `text.verbosity` | ➡️ | 整个原始对象透传;结构化输出是否可用由 OCI 模型决定 | -| `reasoning` | ➡️ | 整个原始对象透传;`effort` 不校验档位,`summary` 等字段不会被网关删除 | -| `tool_choice` | ➡️ | 任意 JSON 原样透传,本地不校验枚举或结构 | -| `context_management`、`include`、`max_tool_calls`、`metadata`、`moderation`、`prompt` | ➡️ | 网关未建模但会保留在原始请求中,由 OCI 决定是否接受 | -| `prompt_cache_key`、`prompt_cache_retention`、`safety_identifier`、`service_tier` | ➡️ | 原样透传,不代表 OCI 一定实现 OpenAI 的对应语义 | -| `stream_options`、`top_logprobs`、`truncation`、`user` | ➡️ | 原样透传,不做本地语义校验 | -| `store` | 🔄 | 无论客户端传什么,上游请求都强制改写为 `false` | -| `previous_response_id` | ❌ | 非空即返回 400;网关不保存历史响应 | -| `conversation` | ◐ | 省略或 `null` 可通过;任何非 `null` 值返回 400 | -| `background` | ◐ | `true` 返回 400;`false`、`null` 或省略时继续透传 | -| `stream` | ◐ | 普通请求和 `function` 工具支持 SSE;含 `web_search` / `x_search` 时拒绝流式 | -| `tools[].type=function` | ➡️ | 非流式和流式均可,工具对象原样透传 | -| `tools[].type=web_search` / `x_search` | ◐ | 使用 xAI 服务端工具语义且仅支持非流式;`x_search` 不是 OpenAI 标准工具 | -| 其他标准工具类型 | ❌ | `web_search_preview`、`file_search`、`computer`、`code_interpreter`、`image_generation`、`mcp`、`shell`、`custom` 等返回 400 | -| 其他未知顶层字段 | ➡️ | 只要整个请求是合法 JSON,字段名、结构和数值都会保留 | - -响应边界: - -- 非流式成功响应不做转换,OCI JSON 原样返回;usage 解析只用于面板调用日志 -- SSE 事件逐行原样转发,不补 `data: [DONE]`,推理增量也不会被网关过滤 -- 流建立前最多切换三个渠道;流建立后中断不重试,客户端可能只收到部分事件 -- 未知模型返回 404、无渠道返回 503;上游错误会套入 OpenAI 风格错误体,不保证与标准 OpenAI 错误字段完全相同 - -实现依据:[`airesponses.go`](internal/service/airesponses.go) · [`responses.go`](internal/aiwire/responses.go) · [`aigateway.go`](internal/api/aigateway.go) - -
- -
-POST /ai/v1/chat/completions 对比 OpenAI Chat Completions - -Chat Completions 会先转换为 Responses 请求,再把 OCI Responses 响应桥接回 Chat Completions 形态。 - -| 标准字段 | 状态 | 网关行为 | -| --- | :---: | --- | -| `model` | ◐ | 必填,受密钥白名单和可用渠道限制;模型名保留到上游请求 | -| `messages` | 🔄 | 必填并转换为 Responses `input` / `instructions` | -| `system` / `developer` 消息 | ◐ | 文本按出现顺序合并为 `instructions`;块数组中的非文本内容被忽略 | -| `user` / `assistant` 文本内容 | 🔄 | 字符串及 `text` 块分别转为 `input_text` / `output_text` | -| `image_url` 内容块 | ◐ | URL 或 data URI 转为 `input_image`;`image_url.detail` 被忽略 | -| `input_audio`、`file`、`refusal` 等内容块 | ❌ | 当前消息转换器不支持,返回 400 | -| assistant `tool_calls` / `role=tool` | 🔄 | 转为 `function_call` / `function_call_output`,保留调用 ID、函数名和参数 | -| 消息 `name`、`refusal`、`audio`、旧式 `function_call` | ⚠️ | 当前消息结构未建模,静默忽略 | -| `max_completion_tokens` | 🔄 | 转为 `max_output_tokens`,优先于 `max_tokens` | -| `max_tokens` | 🔄 | 未提供 `max_completion_tokens` 时转为 `max_output_tokens` | -| `temperature`、`top_p`、`parallel_tool_calls` | ◐ | 原值写入 Responses 请求,但不校验范围或模型能力 | -| `stream` | 🔄 | OCI Responses SSE 桥接为 `chat.completion.chunk`,末尾补 `data: [DONE]`;上游断流且尚无输出时自动降级非流式重做,结果按 chunk 序列一次推送 | -| `stream_options.include_usage` | 🔄 | 控制网关在终块后追加 `choices: []` 的 usage 块 | -| `stream_options.include_obfuscation` | ⚠️ | 未建模,静默忽略 | -| `tools[].type=function` | ◐ | `name`、`description`、`parameters` 支持;`function.strict` 被忽略 | -| `tools[].type=custom` 及其他工具 | ❌ | 只接受 `function`,其他类型返回 400 | -| `tool_choice` | ◐ | 支持 `auto` / `none` / `required` 和具名 function;非法或未知值被静默忽略 | -| `response_format` | ◐ | `json_object`、`json_schema` 转为 Responses `text.format`;未知类型交给 OCI 处理 | -| `reasoning_effort` | ◐ | 转小写后映射为 `reasoning.effort`,不校验模型或档位 | -| `store` | ⚠️ / 🔄 | 客户端字段被忽略,转换后的上游请求始终使用 `store:false` | -| `stop`、`seed`、`n`、`frequency_penalty`、`presence_penalty` | ⚠️ | 静默忽略;`n` 因此恒为单个 choice | -| `logprobs`、`top_logprobs`、`logit_bias`、`user` | ⚠️ | 静默忽略 | -| `audio`、`modalities`、`prediction`、`metadata`、`moderation` | ⚠️ | 静默忽略 | -| `prompt_cache_key`、`safety_identifier`、`service_tier`、`verbosity`、`web_search_options` | ⚠️ | 静默忽略 | -| 其他未知字段 | ⚠️ | JSON 解码器不会拒绝未知字段,但转换后的上游请求不包含它们 | - -响应边界: - -- 非流式固定生成一个 `choices[0]`;文本会合并,函数调用转为 `tool_calls` -- `finish_reason` 只生成 `stop`、`tool_calls`、`length`;其他上游终止原因不保留 -- reasoning 输出、logprobs、refusal、annotations、audio、service tier 和 system fingerprint 不返回 -- usage 保留 `prompt_tokens`、`completion_tokens`、`total_tokens` 和 `prompt_tokens_details.cached_tokens` -- 已建立的流中断或上游 `response.failed` 不会转换成标准 SSE 错误事件 - -实现依据:[`chatresponses.go`](internal/service/chatresponses.go) · [`openai.go`](internal/aiwire/openai.go) · [`aigateway.go`](internal/api/aigateway.go) - -
- -
-POST /ai/v1/embeddings 对比 OpenAI Embeddings - -| 标准字段 | 状态 | 网关行为 | -| --- | :---: | --- | -| `model` | ◐ | 必填,受密钥白名单限制,并且必须存在具有 `EMBEDDING` 能力的渠道 | -| `input` 为字符串 | ✅ | 包装为单个输入后调用 OCI | -| `input` 为字符串数组 | ✅ | 按原顺序调用 OCI | -| `input` 为 token ID 数组或二维 token ID 数组 | ❌ | 只能解码字符串或字符串数组,绑定阶段返回 400 | -| 空数组 / `null` | ❌ | 本地返回 400;空字符串不在本地拒绝,由 OCI 决定 | -| `dimensions` | ◐ | 映射为 OCI 输出维度,不做范围或模型能力校验 | -| `encoding_format=float` | ✅ | 返回 float 数组;省略时行为相同 | -| `encoding_format=base64` | ❌ | 本地返回 400,不提供 base64 响应 | -| `user` | ⚠️ | 能解析但不会传给 OCI | -| 其他未知字段 | ⚠️ | 静默忽略 | - -响应使用标准的 `object:"list"`、`data[].object:"embedding"`、`index`、`model` 和可选 `usage` 外壳;向量为 `float32` 数组,不支持流式。 - -实现依据:[`embeddings.go`](internal/aiwire/embeddings.go) · [`aigateway_chat.go`](internal/service/aigateway_chat.go) · [`aigateway.go`](internal/api/aigateway.go) - -
- -
-POST /ai/v1/messages 对比 Anthropic Messages - -网关接受 `Authorization: Bearer` 或 `x-api-key`,但不会校验或使用标准 Anthropic `anthropic-version`、`anthropic-beta` 请求头。 - -| 标准字段 | 状态 | 网关行为 | -| --- | :---: | --- | -| `model` | ◐ | 用于模型与渠道选择,但空字符串不会在 handler 中按参数错误拒绝,通常最终返回模型不存在 | -| `max_tokens` | 🔄 | 可缺省(缺省或 ≤0 时按默认值 8192),转换为 `max_output_tokens` | -| `messages` | ◐ | 必须非空;角色、交替顺序和空内容不做完整校验 | -| `system` | ◐ | 支持字符串或 text 块数组;多个文本块直接拼接,`cache_control` 等附加字段被忽略 | -| `temperature`、`top_p` | ◐ | 写入 Responses 请求,不做取值范围或模型能力校验 | -| `top_k` | ⚠️ | 能解析但不会传给上游 | -| `stop_sequences` | ⚠️ | 能解析但不会传给上游;响应 `stop_sequence` 恒为 `null` | -| `stream` | 🔄 | Responses SSE 桥接为 Anthropic 事件序列;上游断流且尚无输出时自动降级非流式重做,结果按事件序列一次推送 | -| `tools` | ◐ | 每个工具都转换成 Responses `function`;自定义客户端工具可用,Anthropic 服务端工具类型不保留原语义 | -| `tool_choice` | ◐ | 支持 `auto`、`any`、`none`、具名 `tool`;`disable_parallel_tool_use` 等附加字段被忽略 | -| `metadata` | ⚠️ | 能解析但不会传给上游 | -| `thinking` | ⚠️ | 顶层 thinking 配置不会控制上游思考预算 | -| `output_config.effort` | 🔄 | 转小写后映射为 Responses `reasoning.effort` | -| `output_config` 其他子字段 | ⚠️ | 未建模,静默忽略 | -| `cache_control`、`container`、`inference_geo`、`service_tier` | ⚠️ | 标准 SDK 中存在,但当前请求结构未建模,静默忽略 | -| 其他未知顶层字段 | ⚠️ | JSON 解码器接受,但转换后的上游请求不包含它们 | - -`messages[].content`: - -| 标准内容块 | 状态 | 网关行为 | -| --- | :---: | --- | -| 字符串 / `text` | 🔄 | user 转 `input_text`,assistant 历史转 `output_text` | -| `image` | ◐ | 仅支持 `base64` 和 `url` source;缺字段或其他 source 类型返回 400 | -| `tool_use` | 🔄 | 转为 `function_call`,保留 ID、名称和输入 | -| `tool_result` | ◐ | 转为 `function_call_output`;块数组只拼接 text,`is_error` 和非文本结果丢失 | -| `thinking` / `redacted_thinking` | ⚠️ | 历史思考块被删除,不进入上游上下文 | -| `document`、服务端工具结果及其他未知块 | ❌ | 返回 400 | -| `null` / 空块数组 | ◐ | 该消息可能从上游 input 中消失,不返回参数错误 | - -响应边界: - -- 非流式只把 Responses `output_text` 转成 `text`、`function_call` 转成 `tool_use` -- `stop_reason` 只生成 `end_turn`、`tool_use`、`max_tokens`;`stop_sequence` 恒为 `null` -- reasoning 不会生成 Anthropic `thinking` / `redacted_thinking` 块,也没有 signature -- usage 只保留 `input_tokens`、`output_tokens` 和 `cache_read_input_tokens`,不提供 `cache_creation_input_tokens` -- 流式输出标准事件骨架,但不生成 `thinking_delta` 和 `signature_delta`;上游错误事件与无终态断流会转成 Anthropic `error` 事件 - -实现依据:[`anthresponses.go`](internal/service/anthresponses.go) · [`anthropic.go`](internal/aiwire/anthropic.go) · [`aigateway.go`](internal/api/aigateway.go) - -
- -`GET /ai/v1/models` 使用 OpenAI Models 列表外壳(`object`、`data[].id/object/created/owned_by`),但只返回当前渠道目录中通过分组、全局黑名单和密钥白名单筛选后的模型;网关不提供标准的单模型检索端点。 +协议兼容边界、已知上游限制与逐字段兼容矩阵见 **[AI 网关文档](docs/ai-gateway.md)**。 ## API 与配置 @@ -446,7 +260,7 @@ go vet ./... go test ./... # Handler 注释变更后重新生成唯一的对外 API 文档。 -go tool swag init -g cmd/server/main.go -o docs --parseInternal --parseDependency +go tool swag init -g cmd/server/main.go -o docs --parseInternal --parseDependency --overridesFile docs/.swaggo ``` - Go 后端规范与目录约定:[`AGENTS.md`](AGENTS.md) · [`.trellis/spec/backend/`](.trellis/spec/backend/) diff --git a/docs/.swaggo b/docs/.swaggo new file mode 100644 index 0000000..acabe31 --- /dev/null +++ b/docs/.swaggo @@ -0,0 +1,6 @@ +// swag 全局类型替换:原始 JSON 与联合类型统一渲染为 AnyJSON(任意 JSON 值), +// 避免 json.RawMessage 被误渲染成 byte 数组、联合类型暴露内部字段。 +replace encoding/json.RawMessage oci-portal/internal/aiwire.AnyJSON +replace oci-portal/internal/aiwire.RespInput oci-portal/internal/aiwire.AnyJSON +replace oci-portal/internal/aiwire.Content oci-portal/internal/aiwire.AnyJSON +replace oci-portal/internal/aiwire.StringList oci-portal/internal/aiwire.AnyJSON diff --git a/docs/ai-gateway.md b/docs/ai-gateway.md new file mode 100644 index 0000000..4456357 --- /dev/null +++ b/docs/ai-gateway.md @@ -0,0 +1,266 @@ +# AI 网关 + +> 本文是 OCI Portal AI 网关的完整使用与兼容性文档:端点定位、协议兼容边界、已知上游限制与字段兼容矩阵。 +> 路由与鉴权的机器可读定义以 [Swagger YAML](swagger.yaml) 或运行时 Swagger UI 为准;无法由 OpenAPI 表达的兼容边界以本文为准。 + +AI 网关使用面板创建的独立密钥鉴权,支持 `Authorization: Bearer sk-...` 和 `x-api-key: sk-...`。密钥可绑定渠道分组和模型白名单;全局模型黑名单会从模型列表、路由和探测候选中同时排除目标模型。 + +| 端点 | 定位 | 流式 | +| --- | --- | --- | +| `POST /ai/v1/responses` | OpenAI Responses,无状态主接口 | SSE | +| `POST /ai/v1/chat/completions` | OpenAI Chat Completions,存量客户端兼容层 | SSE | +| `POST /ai/v1/messages` | Anthropic Messages 转换层 | SSE | +| `POST /ai/v1/embeddings` | OpenAI Embeddings | 否 | +| `POST /ai/v1/audio/speech` | OpenAI Audio Speech,文本转语音(xAI Voice) | 否 | +| `POST /ai/v1/rerank` | 文档重排(Cohere Rerank,Jina 风格协议) | 否 | +| `POST /ai/v1/moderations` | 内容审核(OCI Guardrails:内容审核 / PII / 提示注入) | 否 | +| `GET /ai/v1/models` | 当前密钥可见的模型列表 | 否 | + +兼容边界: + +- 对话请求统一转发 OCI OpenAI 兼容面,当前供给以 `xai.`、`meta.`、`openai.` 前缀模型为主;Cohere Embeddings 不受该对话模型范围影响 +- 网关不保存会话历史,客户端需要携带完整上下文;Responses 拒绝非空 `previous_response_id`、非 `null` `conversation` 和 `background:true` +- Responses 支持 Oracle 文档化的 xAI 服务端工具 `web_search` / `x_search` / `code_interpreter` 与远程 `mcp` 工具(非流式与流式均可),工具参数与限制遵循 [xAI 规格](https://docs.oracle.com/en-us/iaas/Content/generative-ai/get-started-agents.htm#xai-compatible-tools);`code_interpreter` 的命名容器管理(containers API)与 File Search 不提供 +- Responses 的 `reasoning.effort`、Messages 的 `output_config.effort` 和 Chat Completions 的 `reasoning_effort` 会传给上游,实际档位和效果由模型决定 +- Chat Completions 只承担协议转换与兼容修复;新能力优先在 Responses 和 Messages 提供 +- 单次请求最多尝试三个渠道;可重试错误会切换渠道,流式响应建立后不会换渠道重试 +- Audio Speech 直通 OCI 兼容面(模型 `xai.grok-tts`,voice 取 xAI Grok Voice 列表:`ara`/`eve`/`leo`/`rex`/`sal`);上游把 `language` 当必填,缺省时网关自动注入 `"auto"`,xAI 专属参数(`output_format` 等)可平铺在请求体透传;仅单请求返回音频,不提供 WebSocket 流式 +- Rerank 走 OCI typed 面(`cohere.rerank-v4.0-pro` / `-fast`),请求 `{model, query, documents[], top_n?, return_documents?}`,响应 `results[].index` 指向入参下标;无 token 用量口径,调用日志只记时延 +- Moderations 是 OpenAI moderations 外壳映射 OCI Guardrails:`input` 为字符串或字符串数组(至多 8 条),categories 用 OCI 原生维度 `overall` / `blocklist` / `prompt_injection`(阈值 0.5 判定 `flagged`),PII 命中放扩展字段 `results[].pii`(不参与 flagged);`model` 字段接受但忽略,无模型白名单维度;实测中文人名/手机号识别较弱,英文 PII 识别正常 +- Responses 的 `input_file` 内容块(file_url / file_data)实测被上游拒绝:`File content is currently unsupported for ZDR customers`——网关强制 `store:false` 属 ZDR 形态,该能力在上游侧不可用 + +### 已知上游限制:大 system 区流式断流 + +实测(2026-07-13)OCI 兼容面对 `instructions` 与 `tools` 合计超约 64.5KB 的**流式**请求会在发出少量事件后静默断开连接(无任何错误事件;同请求非流式正常),与模型、字符集、消息正文大小均无关——消息正文(`input`)不计入该限制。Chat Completions 与 Messages 的 system/developer 提示会转换为 `instructions`,因此 Claude Code 等自带大体量系统提示与工具定义的客户端极易触发。 + +网关侧应对: + +- Messages 与 Chat Completions 的流式请求在客户端尚未收到任何输出时遭遇上游断流,会自动降级为非流式重做,并按标准事件/chunk 序列一次推送;调用日志记 `retries=1` 与降级标记 +- Responses 直通因初始事件已转发、协议上无法透明降级,调用日志记「上游流提前终止」,客户端需自行回退非流式 +- 应急规避:将超长 system 内容移入首条 user 消息正文可绕过该限制(正文不计入),但语义有别,根治有待上游修复 + +这里提供的是兼容接口而非 OpenAI / Anthropic 协议的完整实现。OCI OpenAI 兼容面的部分行为来自实测,未见 Oracle 文档承诺,可能随上游调整。路由与鉴权定义以 [Swagger YAML](swagger.yaml) 或运行时 Swagger UI 为准;无法由 OpenAPI 完整表达的兼容边界列于上方。 + +### 字段兼容矩阵 + +以下矩阵以 2026-07-13 的 [OpenAI Responses](https://developers.openai.com/api/reference/resources/responses/methods/create)、[Chat Completions](https://developers.openai.com/api/reference/resources/chat/subresources/completions/methods/create)、[Embeddings](https://developers.openai.com/api/reference/resources/embeddings/methods/create)、[Audio Speech](https://developers.openai.com/api/reference/resources/audio/methods/speech)、[Moderations](https://developers.openai.com/api/reference/resources/moderations/methods/create) 和 [Anthropic Messages](https://platform.claude.com/docs/en/api/messages/create) 为标准基线,并与当前实现逐项核对;Rerank 无 OpenAI 对应端点,基线取 [Cohere Rerank](https://docs.cohere.com/reference/rerank) 协议。 + +这是一份兼容性快照,不替代 Swagger。标准接口和 OCI 上游都可能变化,最终行为以当前版本代码与实测为准。 + +矩阵只列网关支持的字段;不支持(本地拒绝)与被忽略的字段不入表,在各端点段落末尾以文字简述。 + +| 标记 | 含义 | +| :---: | --- | +| ✅ | 网关直接支持 | +| ➡️ | 网关原样透传;是否生效由 OCI 上游决定 | +| 🔄 | 网关进行字段或协议转换后支持 | +| ◐ | 部分支持、存在前置条件或语义降级 | + +
+POST /ai/v1/responses 对比 OpenAI Responses + +Responses 是“原始 JSON 直通 + 本地门禁”。除 `store` 外,网关不会重建请求体;未知顶层字段也会保留并送往 OCI。 + +| 标准字段 | 状态 | 网关行为 | +| --- | :---: | --- | +| `model` | ◐ | 必须非空,还要通过密钥模型白名单并匹配可用渠道;随后原样透传 | +| `input` | ➡️ | 支持标准的字符串或 item 数组,原始内容透传;网关不逐项保证 OCI 能处理所有 item 类型 | +| `instructions`、`max_output_tokens` | ➡️ | 类型可解析后原样透传,不做范围或模型能力校验 | +| `temperature`、`top_p`、`parallel_tool_calls` | ➡️ | 原样透传,不做取值范围校验 | +| `text` / `text.format` / `text.verbosity` | ➡️ | 整个原始对象透传;结构化输出是否可用由 OCI 模型决定 | +| `reasoning` | ➡️ | 整个原始对象透传;`effort` 不校验档位,`summary` 等字段不会被网关删除 | +| `tool_choice` | ➡️ | 任意 JSON 原样透传,本地不校验枚举或结构 | +| `store` | 🔄 | 无论客户端传什么,上游请求都强制改写为 `false` | +| `stream` | ✅ | 普通请求、`function` 与服务端工具均支持 SSE | +| `tools[].type=function` | ➡️ | 非流式和流式均可,工具对象原样透传 | +| `tools[].type=web_search` / `x_search` / `code_interpreter` | ◐ | Oracle 文档化的 xAI 服务端工具,参数与限制遵循 xAI 规格(如 `allowed_domains` 上限 10、`container` 支持 `{"type":"auto"}`),非流式与流式均实测可用;`x_search` 不是 OpenAI 标准工具 | +| `tools[].type=mcp` | ➡️ | 远程 MCP 服务由上游直连调用(`server_url` / `require_approval` / `authorization` 等原样透传),非流式与流式均实测可用 | +| 其余标准与未知顶层字段 | ➡️ | `context_management`、`include`、`metadata`、`prompt`、`prompt_cache_key`、`service_tier`、`truncation`、`user` 等未建模字段一律保留在原始请求中,由 OCI 决定是否接受 | + +不支持(请求到达上游前返回 400):非空 `previous_response_id`、非 `null` 的 `conversation`、`background:true`——网关无状态,不保存历史响应;以及 `function` / xAI 服务端工具 / `mcp` 之外的工具类型(`web_search_preview`、`file_search`、`computer`、`image_generation`、`shell`、`custom` 等)。 + +响应边界: + +- 非流式成功响应不做转换,OCI JSON 原样返回;usage 解析只用于面板调用日志 +- SSE 事件逐行原样转发,不补 `data: [DONE]`,推理增量也不会被网关过滤 +- 流建立前最多切换三个渠道;流建立后中断不重试,客户端可能只收到部分事件 +- 未知模型返回 404、无渠道返回 503;上游错误会套入 OpenAI 风格错误体,不保证与标准 OpenAI 错误字段完全相同 + +实现依据:[`airesponses.go`](../internal/service/airesponses.go) · [`responses.go`](../internal/aiwire/responses.go) · [`aigateway.go`](../internal/api/aigateway.go) + +
+ +
+POST /ai/v1/chat/completions 对比 OpenAI Chat Completions + +Chat Completions 会先转换为 Responses 请求,再把 OCI Responses 响应桥接回 Chat Completions 形态。转换器只搬运下表字段,其余字段不进入上游请求。 + +| 标准字段 | 状态 | 网关行为 | +| --- | :---: | --- | +| `model` | ◐ | 必填,受密钥白名单和可用渠道限制;模型名保留到上游请求 | +| `messages` | 🔄 | 必填并转换为 Responses `input` / `instructions` | +| `system` / `developer` 消息 | ◐ | 文本按出现顺序合并为 `instructions`;块数组中的非文本内容被忽略 | +| `user` / `assistant` 文本内容 | 🔄 | 字符串及 `text` 块分别转为 `input_text` / `output_text` | +| `image_url` 内容块 | ◐ | URL 或 data URI 转为 `input_image`;`image_url.detail` 被忽略 | +| assistant `tool_calls` / `role=tool` | 🔄 | 转为 `function_call` / `function_call_output`,保留调用 ID、函数名和参数 | +| `max_completion_tokens` | 🔄 | 转为 `max_output_tokens`,优先于 `max_tokens` | +| `max_tokens` | 🔄 | 未提供 `max_completion_tokens` 时转为 `max_output_tokens` | +| `temperature`、`top_p`、`parallel_tool_calls` | ◐ | 原值写入 Responses 请求,但不校验范围或模型能力 | +| `stream` | 🔄 | OCI Responses SSE 桥接为 `chat.completion.chunk`,末尾补 `data: [DONE]`;上游断流且尚无输出时自动降级非流式重做,结果按 chunk 序列一次推送 | +| `stream_options.include_usage` | 🔄 | 控制网关在终块后追加 `choices: []` 的 usage 块 | +| `tools[].type=function` | ◐ | `name`、`description`、`parameters` 支持;`function.strict` 被忽略 | +| `tool_choice` | ◐ | 支持 `auto` / `none` / `required` 和具名 function;非法或未知值被静默忽略 | +| `response_format` | ◐ | `json_object`、`json_schema` 转为 Responses `text.format`;未知类型交给 OCI 处理 | +| `reasoning_effort` | ◐ | 转小写后映射为 `reasoning.effort`,不校验模型或档位 | +| `store` | 🔄 | 客户端取值被忽略,转换后的上游请求始终使用 `store:false` | + +不支持(返回 400):`input_audio`、`file`、`refusal` 等消息内容块;`function` 以外的工具类型(含 `custom`)。 + +静默忽略(转换后的上游请求不包含):消息级 `name` / `refusal` / `audio` / 旧式 `function_call`;采样与输出控制类 `stop`、`seed`、`n`(恒返回单个 choice)、`frequency_penalty`、`presence_penalty`、`logprobs`、`top_logprobs`、`logit_bias`;平台类 `user`、`audio`、`modalities`、`prediction`、`metadata`、`moderation`、`prompt_cache_key`、`safety_identifier`、`service_tier`、`verbosity`、`web_search_options`、`stream_options.include_obfuscation` 及其他未知字段。 + +响应边界: + +- 非流式固定生成一个 `choices[0]`;文本会合并,函数调用转为 `tool_calls` +- `finish_reason` 只生成 `stop`、`tool_calls`、`length`;其他上游终止原因不保留 +- reasoning 输出、logprobs、refusal、annotations、audio、service tier 和 system fingerprint 不返回 +- usage 保留 `prompt_tokens`、`completion_tokens`、`total_tokens` 和 `prompt_tokens_details.cached_tokens` +- 已建立的流中断或上游 `response.failed` 不会转换成标准 SSE 错误事件 + +实现依据:[`chatresponses.go`](../internal/service/chatresponses.go) · [`openai.go`](../internal/aiwire/openai.go) · [`aigateway.go`](../internal/api/aigateway.go) + +
+ +
+POST /ai/v1/embeddings 对比 OpenAI Embeddings + +| 标准字段 | 状态 | 网关行为 | +| --- | :---: | --- | +| `model` | ◐ | 必填,受密钥白名单限制,并且必须存在具有 `EMBEDDING` 能力的渠道 | +| `input` 为字符串 | ✅ | 包装为单个输入后调用 OCI | +| `input` 为字符串数组 | ✅ | 按原顺序调用 OCI;空字符串不在本地拒绝,由 OCI 决定 | +| `dimensions` | ◐ | 映射为 OCI 输出维度,不做范围或模型能力校验 | +| `encoding_format=float` | ✅ | 返回 float 数组;省略时行为相同 | + +不支持(返回 400):token ID 数组(一维或二维)形态的 `input`、空数组、`null`,以及 `encoding_format=base64`。静默忽略:`user` 及其他未知字段。 + +响应使用标准的 `object:"list"`、`data[].object:"embedding"`、`index`、`model` 和可选 `usage` 外壳;向量为 `float32` 数组,不支持流式。 + +实现依据:[`embeddings.go`](../internal/aiwire/embeddings.go) · [`aigateway_chat.go`](../internal/service/aigateway_chat.go) · [`aigateway.go`](../internal/api/aigateway.go) + +
+ +
+POST /ai/v1/messages 对比 Anthropic Messages + +网关接受 `Authorization: Bearer` 或 `x-api-key`,但不会校验或使用标准 Anthropic `anthropic-version`、`anthropic-beta` 请求头。 + +| 标准字段 | 状态 | 网关行为 | +| --- | :---: | --- | +| `model` | ◐ | 用于模型与渠道选择,但空字符串不会在 handler 中按参数错误拒绝,通常最终返回模型不存在 | +| `max_tokens` | 🔄 | 可缺省(缺省或 ≤0 时按默认值 8192),转换为 `max_output_tokens` | +| `messages` | ◐ | 必须非空;角色、交替顺序和空内容不做完整校验 | +| `system` | ◐ | 支持字符串或 text 块数组;多个文本块直接拼接,`cache_control` 等附加字段被忽略 | +| `temperature`、`top_p` | ◐ | 写入 Responses 请求,不做取值范围或模型能力校验 | +| `stream` | 🔄 | Responses SSE 桥接为 Anthropic 事件序列;上游断流且尚无输出时自动降级非流式重做,结果按事件序列一次推送 | +| `tools` | ◐ | 每个工具都转换成 Responses `function`;自定义客户端工具可用,Anthropic 服务端工具类型不保留原语义 | +| `tool_choice` | ◐ | 支持 `auto`、`any`、`none`、具名 `tool`;`disable_parallel_tool_use` 等附加字段被忽略 | +| `output_config.effort` | 🔄 | 转小写后映射为 Responses `reasoning.effort` | + +顶层静默忽略(能解析但不传上游):`top_k`、`stop_sequences`(响应 `stop_sequence` 恒为 `null`)、`metadata`、`thinking`(不控制上游思考预算)、`output_config` 其余子字段、`cache_control`、`container`、`inference_geo`、`service_tier` 及其他未知顶层字段。 + +`messages[].content`: + +| 标准内容块 | 状态 | 网关行为 | +| --- | :---: | --- | +| 字符串 / `text` | 🔄 | user 转 `input_text`,assistant 历史转 `output_text` | +| `image` | ◐ | 仅支持 `base64` 和 `url` source;缺字段或其他 source 类型返回 400 | +| `tool_use` | 🔄 | 转为 `function_call`,保留 ID、名称和输入 | +| `tool_result` | ◐ | 转为 `function_call_output`;块数组只拼接 text,`is_error` 和非文本结果丢失 | +| `null` / 空块数组 | ◐ | 该消息可能从上游 input 中消失,不返回参数错误 | + +不支持的内容块(返回 400):`document`、服务端工具结果及其他未知块。历史 `thinking` / `redacted_thinking` 块会被删除,不进入上游上下文。 + +响应边界: + +- 非流式只把 Responses `output_text` 转成 `text`、`function_call` 转成 `tool_use` +- `stop_reason` 只生成 `end_turn`、`tool_use`、`max_tokens`;`stop_sequence` 恒为 `null` +- reasoning 不会生成 Anthropic `thinking` / `redacted_thinking` 块,也没有 signature +- usage 只保留 `input_tokens`、`output_tokens` 和 `cache_read_input_tokens`,不提供 `cache_creation_input_tokens` +- 流式输出标准事件骨架,但不生成 `thinking_delta` 和 `signature_delta`;上游错误事件与无终态断流会转成 Anthropic `error` 事件 + +实现依据:[`anthresponses.go`](../internal/service/anthresponses.go) · [`anthropic.go`](../internal/aiwire/anthropic.go) · [`aigateway.go`](../internal/api/aigateway.go) + +
+ +
+POST /ai/v1/audio/speech 对比 OpenAI Audio Speech + +Audio Speech 与 Responses 同为“原始 JSON 直通 + 本地门禁”:除缺省注入 `language` 外不重建请求体,未知字段原样透传。 + +| 标准字段 | 状态 | 网关行为 | +| --- | :---: | --- | +| `model` | ◐ | 必填,受密钥白名单限制,并且必须存在具有 `TTS` 能力的渠道(当前上游仅 `xai.grok-tts`) | +| `input` | ◐ | 必填非空,随后原样透传 | +| `voice` | ➡️ | 原样透传;取 xAI Grok Voice 音色(`ara` / `eve` / `leo` / `rex` / `sal`),OpenAI 标准音色名不可用 | +| `response_format` | ➡️ | 原样透传;实测 `mp3` 可用,其余格式由上游决定 | +| `language`(扩展字段) | 🔄 | 上游必填;客户端缺省时网关自动注入 `"auto"` | +| `speed`、`instructions` 及其他未知字段 | ➡️ | 原样透传(含 xAI 专属参数如 `output_format`),是否生效由上游决定 | + +不支持:流式音频(`stream_format` 等流式选项无效,响应恒为一次性完整音频)与 WebSocket 语音会话。 + +响应边界: + +- 成功响应为音频字节,`Content-Type` 透传上游(缺省 `audio/mpeg`) +- 无 token 用量口径,调用日志只记时延与渠道 + +实现依据:[`genai_speech.go`](../internal/oci/genai_speech.go) · [`service/aigateway_extras.go`](../internal/service/aigateway_extras.go) · [`api/aigateway_extras.go`](../internal/api/aigateway_extras.go) + +
+ +
+POST /ai/v1/rerank 对比 Cohere Rerank + +Rerank 无 OpenAI 对应端点,协议取 Jina / Cohere 通行风格,上游走 OCI typed 面(`cohere.rerank-v4.0-pro` / `-fast`)。 + +| 字段 | 状态 | 网关行为 | +| --- | :---: | --- | +| `model` | ◐ | 必填,受密钥白名单限制,并且必须存在具有 `RERANK` 能力的渠道 | +| `query` | ✅ | 必填非空 | +| `documents` | ◐ | 必填,仅接受字符串数组;Cohere 旧版 `{"text": ...}` 对象数组形态返回 400 | +| `top_n` | ✅ | 可选,传给上游限制返回条数;缺省返回全部文档的重排结果 | +| `return_documents` | ✅ | 可选,`true` 时 `results[].document.text` 回带原文 | + +静默忽略:`max_tokens_per_doc` 等 Cohere 专属参数及其他未知字段。 + +响应边界: + +- `results[]` 按相关度降序,`index` 指向入参 `documents` 下标,`relevance_score` 为 0–1 浮点;响应 `model` 回显请求值 +- 无 token 用量口径,调用日志只记时延与渠道 + +实现依据:[`genai_guard.go`](../internal/oci/genai_guard.go) · [`rerank.go`](../internal/aiwire/rerank.go) · [`service/aigateway_extras.go`](../internal/service/aigateway_extras.go) + +
+ +
+POST /ai/v1/moderations 对比 OpenAI Moderations + +Moderations 是 OpenAI moderations 外壳映射 OCI Guardrails(内容审核 / PII / 提示注入)。上游是服务级 API,没有模型与白名单维度;渠道按分组直接挑选。 + +| 标准字段 | 状态 | 网关行为 | +| --- | :---: | --- | +| `input` 为字符串 | ✅ | 单条审核 | +| `input` 为字符串数组 | ✅ | 逐条审核,单次 1~8 条 | + +不支持(返回 400):多模态 input(图片等对象数组形态)、空字符串条目、空数组或超过 8 条的数组。静默忽略:`model`(接受任意值,不校验白名单)及其他未知字段。 + +响应边界: + +- `categories` / `category_scores` 用 OCI 原生维度 `overall` / `blocklist` / `prompt_injection`,而非 OpenAI 标准类目(`hate` / `violence` 等);任一维度得分 ≥ 0.5 判定 `flagged` +- PII 命中放扩展字段 `results[].pii`(`text` / `label` / `score` / `offset` / `length`),不参与 `flagged` 判定;实测中文人名 / 手机号识别较弱,英文 PII 识别正常 +- 响应 `model` 恒为 `oci-guardrails` + +实现依据:[`genai_guard.go`](../internal/oci/genai_guard.go) · [`moderations.go`](../internal/aiwire/moderations.go) · [`service/aigateway_extras.go`](../internal/service/aigateway_extras.go) + +
+ +`GET /ai/v1/models` 使用 OpenAI Models 列表外壳(`object`、`data[].id/object/created/owned_by`),但只返回当前渠道目录中通过分组、全局黑名单和密钥白名单筛选后的模型;网关不提供标准的单模型检索端点。 diff --git a/docs/docs.go b/docs/docs.go index d49d016..b43985c 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -15,6 +15,33 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/ai/v1/audio/speech": { + "post": { + "tags": [ + "AI 网关" + ], + "summary": "OpenAI Audio Speech 兼容端点(文本转语音)", + "parameters": [ + { + "description": "OpenAI audio speech 请求体(model/input 必填,voice 见 xAI Grok Voice 列表,language 缺省 auto;未列字段原样透传)", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.SpeechRequest" + } + } + ], + "responses": { + "200": { + "description": "音频字节(Content-Type 透传上游,默认 audio/mpeg)", + "schema": { + "type": "file" + } + } + } + } + }, "/ai/v1/chat/completions": { "post": { "tags": [ @@ -28,16 +55,15 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "type": "object" + "$ref": "#/definitions/oci-portal_internal_aiwire.ChatRequest" } } ], "responses": { "200": { - "description": "OpenAI 兼容响应(流式为 SSE,末尾 data: [DONE])", + "description": "OpenAI 兼容响应(非流式;流式为 SSE,末尾 data: [DONE])", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_aiwire.ChatResponse" } } } @@ -56,7 +82,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "type": "object" + "$ref": "#/definitions/oci-portal_internal_aiwire.EmbeddingsRequest" } } ], @@ -64,8 +90,7 @@ const docTemplate = `{ "200": { "description": "OpenAI 兼容响应", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_aiwire.EmbeddingsResponse" } } } @@ -84,16 +109,15 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "type": "object" + "$ref": "#/definitions/oci-portal_internal_aiwire.MessagesRequest" } } ], "responses": { "200": { - "description": "Anthropic 兼容响应(流式为 SSE)", + "description": "Anthropic 兼容响应(非流式;流式为 SSE 事件序列)", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_aiwire.MessagesResponse" } } } @@ -109,8 +133,61 @@ const docTemplate = `{ "200": { "description": "OpenAI 兼容 models 列表", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_aiwire.ModelList" + } + } + } + } + }, + "/ai/v1/moderations": { + "post": { + "tags": [ + "AI 网关" + ], + "summary": "内容审核端点(OCI Guardrails)", + "parameters": [ + { + "description": "审核请求体(input 为字符串或字符串数组,单次至多 8 条;model 接受但忽略)", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ModerationsRequest" + } + } + ], + "responses": { + "200": { + "description": "审核结果(categories/category_scores 为 overall/blocklist/prompt_injection,pii 为扩展字段)", + "schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ModerationsResponse" + } + } + } + } + }, + "/ai/v1/rerank": { + "post": { + "tags": [ + "AI 网关" + ], + "summary": "文档重排端点(Cohere Rerank)", + "parameters": [ + { + "description": "重排请求体(model/query/documents 必填,可选 top_n/return_documents)", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RerankRequest" + } + } + ], + "responses": { + "200": { + "description": "重排结果(results[].index 指向入参下标)", + "schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RerankResponse" } } } @@ -124,21 +201,20 @@ const docTemplate = `{ "summary": "OpenAI Responses 兼容端点", "parameters": [ { - "description": "OpenAI responses 请求体(支持 stream;web_search/x_search 服务端工具仅非流式)", + "description": "OpenAI responses 请求体(支持 stream;服务端工具 web_search/x_search/code_interpreter/mcp 含流式;未列字段原样透传上游)", "name": "body", "in": "body", "required": true, "schema": { - "type": "object" + "$ref": "#/definitions/oci-portal_internal_aiwire.RespRequest" } } ], "responses": { "200": { - "description": "OpenAI 兼容响应(流式为 SSE)", + "description": "OpenAI 兼容响应(非流式;流式为 SSE);直通仅建模常用字段,未列字段原样返回", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_aiwire.RespResponse" } } } @@ -159,8 +235,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.aboutResponse" } } } @@ -181,8 +256,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_model_AiModelBlacklist" } } } @@ -212,8 +286,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemResponse-oci-portal_internal_model_AiModelBlacklist" } } } @@ -261,8 +334,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_model_AiChannel" } } } @@ -292,8 +364,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.AiChannel" } } } @@ -384,8 +455,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.AiChannel" } } } @@ -415,8 +485,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_model_AiModelCache" } } } @@ -437,8 +506,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.pagedResponse-oci-portal_internal_model_AiCallLog" } } } @@ -459,8 +527,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_model_AiKey" } } } @@ -488,10 +555,9 @@ const docTemplate = `{ ], "responses": { "201": { - "description": "Created", + "description": "key 为明文密钥,仅本次返回", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.aiKeyCreateResponse" } } } @@ -591,8 +657,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.AiKey" } } } @@ -613,8 +678,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.pagedResponse-oci-portal_internal_model_AiContentLog" } } } @@ -635,8 +699,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_aiwire_Model" } } } @@ -657,8 +720,7 @@ const docTemplate = `{ "200": { "description": "username 与 passwordLoginDisabled", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.credentialsResponse" } } } @@ -691,10 +753,7 @@ const docTemplate = `{ "401": { "description": "当前密码错误", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.errorResponse" } } } @@ -715,8 +774,7 @@ const docTemplate = `{ "200": { "description": "items", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_model_UserIdentity" } } } @@ -749,10 +807,7 @@ const docTemplate = `{ "409": { "description": "最后一个身份不可解绑", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.errorResponse" } } } @@ -785,24 +840,19 @@ const docTemplate = `{ "200": { "description": "token 与 expiresAt", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.tokenResponse" } }, "401": { "description": "凭据错误", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.errorResponse" } }, "428": { "description": "需要两步验证码(totpRequired=true)", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.totpRequiredResponse" } } } @@ -836,8 +886,7 @@ const docTemplate = `{ "200": { "description": "providers 与 passwordLoginDisabled", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.oauthProvidersResponse" } } } @@ -868,10 +917,7 @@ const docTemplate = `{ "200": { "description": "url", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.urlResponse" } } } @@ -942,10 +988,7 @@ const docTemplate = `{ "409": { "description": "未绑定外部身份", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.errorResponse" } } } @@ -966,10 +1009,7 @@ const docTemplate = `{ "200": { "description": "新 token 与 expiresAt", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.tokenResponse" } } } @@ -990,10 +1030,7 @@ const docTemplate = `{ "200": { "description": "enabled", "schema": { - "type": "object", - "additionalProperties": { - "type": "boolean" - } + "$ref": "#/definitions/internal_api.enabledResponse" } } } @@ -1072,19 +1109,13 @@ const docTemplate = `{ "200": { "description": "secret 与 otpauthUri", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.totpSetupResponse" } }, "409": { "description": "已启用", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.errorResponse" } } } @@ -1175,8 +1206,7 @@ const docTemplate = `{ "200": { "description": "items 与 total", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.pagedResponse-oci-portal_internal_model_LogEvent" } } } @@ -1195,10 +1225,12 @@ const docTemplate = `{ "summary": "租户配置列表", "responses": { "200": { - "description": "items", + "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.ConfigSummary" + } } } } @@ -1228,8 +1260,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.OciConfig" } } } @@ -1259,8 +1290,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.OciConfig" } } } @@ -1295,10 +1325,9 @@ const docTemplate = `{ ], "responses": { "200": { - "description": "OK", + "description": "config 与 changes 字段变更对照", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.configChangesResponse" } } } @@ -1366,8 +1395,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.AuditEventsView" } } } @@ -1395,10 +1423,9 @@ const docTemplate = `{ ], "responses": { "200": { - "description": "OK", + "description": "raw 为事件原文 JSON", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.rawDetailResponse" } } } @@ -1428,8 +1455,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "type": "string" + } } } } @@ -1493,8 +1522,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.BootVolume" + } } } } @@ -1531,8 +1562,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.BootVolume" } } } @@ -1576,8 +1606,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.BootVolume" } } } @@ -1639,8 +1668,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Compartment" + } } } } @@ -1670,8 +1701,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.RegionSubscriptionView" + } } } } @@ -1701,8 +1734,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Compartment" + } } } } @@ -1766,8 +1801,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.CostItem" + } } } } @@ -1797,8 +1834,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.IdentityDomain" + } } } } @@ -1834,8 +1873,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.IdentityProviderInfo" + } } } } @@ -1878,8 +1919,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.IdentityProviderInfo" } } } @@ -1971,8 +2011,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.IdentityProviderInfo" } } } @@ -2008,8 +2047,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.IdentitySettingInfo" } } } @@ -2052,8 +2090,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.IdentitySettingInfo" } } } @@ -2083,8 +2120,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Image" + } } } } @@ -2121,8 +2160,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Image" } } } @@ -2152,8 +2190,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Instance" + } } } } @@ -2188,10 +2228,9 @@ const docTemplate = `{ ], "responses": { "201": { - "description": "Created", + "description": "部分成功仍 201,errors 为逐台失败信息", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.createInstancesResponse" } } } @@ -2228,8 +2267,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Instance" } } } @@ -2273,8 +2311,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Instance" } } } @@ -2352,8 +2389,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Instance" } } } @@ -2390,8 +2426,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.BootVolumeAttachment" + } } } } @@ -2435,8 +2473,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.BootVolumeAttachment" } } } @@ -2482,8 +2519,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.publicIpResponse" } } } @@ -2520,8 +2556,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.ConsoleConnection" + } } } } @@ -2565,8 +2603,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.ConsoleConnection" } } } @@ -2609,11 +2646,10 @@ const docTemplate = `{ } ], "responses": { - "200": { - "description": "sessionId 与 wsPath", + "201": { + "description": "sessionId 与 type", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.webConsoleSessionResponse" } } } @@ -2659,8 +2695,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.ipv6AddressResponse" } } } @@ -2738,8 +2773,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.BootVolumeAttachment" } } } @@ -2776,8 +2810,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.InstanceTraffic" } } } @@ -2814,8 +2847,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Vnic" + } } } } @@ -2859,8 +2894,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Vnic" } } } @@ -2897,8 +2931,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.VolumeAttachment" + } } } } @@ -2942,8 +2978,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.VolumeAttachment" } } } @@ -2973,8 +3008,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.LimitValue" + } } } } @@ -3004,8 +3041,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.LimitService" + } } } } @@ -3035,8 +3074,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.RelayView" } } } @@ -3064,8 +3102,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.RelayView" } } } @@ -3120,8 +3157,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.logWebhookStatusResponse" } } } @@ -3149,8 +3185,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.LogWebhookInfo" } } } @@ -3211,8 +3246,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.NotificationRecipients" } } } @@ -3255,8 +3289,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.NotificationRecipients" } } } @@ -3292,8 +3325,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.PasswordPolicyInfo" + } } } } @@ -3345,8 +3380,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.PasswordPolicyInfo" } } } @@ -3376,8 +3410,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.RegionSubscriptionView" + } } } } @@ -3414,8 +3450,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.RegionSubscriptionView" + } } } } @@ -3449,10 +3487,9 @@ const docTemplate = `{ ], "responses": { "200": { - "description": "OK", + "description": "SAML 元数据 XML(附件下载)", "schema": { - "type": "object", - "additionalProperties": true + "type": "file" } } } @@ -3482,8 +3519,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.SecurityList" + } } } } @@ -3520,8 +3559,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.SecurityList" } } } @@ -3558,8 +3596,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.SecurityList" } } } @@ -3603,8 +3640,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.SecurityList" } } } @@ -3666,8 +3702,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.ComputeShape" + } } } } @@ -3712,8 +3750,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.SignOnRuleInfo" } } } @@ -3789,8 +3826,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.SignOnRuleInfo" + } } } } @@ -3820,8 +3859,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Subnet" + } } } } @@ -3858,8 +3899,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Subnet" } } } @@ -3896,8 +3936,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Subnet" } } } @@ -3941,8 +3980,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Subnet" } } } @@ -4004,8 +4042,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.SubscriptionInfo" + } } } } @@ -4042,8 +4082,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.SubscriptionDetail" } } } @@ -4079,8 +4118,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.TenantUser" + } } } } @@ -4123,8 +4164,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.TenantUser" } } } @@ -4167,8 +4207,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.TenantUserDetail" } } } @@ -4218,8 +4257,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.TenantUser" } } } @@ -4294,8 +4332,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.deletedApiKeysResponse" } } } @@ -4338,8 +4375,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.deletedTotpResponse" } } } @@ -4380,10 +4416,9 @@ const docTemplate = `{ ], "responses": { "200": { - "description": "OK", + "description": "一次性明文密码", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.passwordResponse" } } } @@ -4413,8 +4448,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.VCN" + } } } } @@ -4451,8 +4488,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.VCN" } } } @@ -4489,8 +4525,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.VCN" } } } @@ -4534,8 +4569,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.VCN" } } } @@ -4613,8 +4647,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.ipv6StepsResponse" } } } @@ -4642,10 +4675,9 @@ const docTemplate = `{ ], "responses": { "200": { - "description": "OK", + "description": "config 与 changes 字段变更对照", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.configChangesResponse" } } } @@ -4725,8 +4757,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.addressResponse" } } } @@ -4790,8 +4821,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.BlockVolume" + } } } } @@ -4812,8 +4845,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.Overview" } } } @@ -4834,8 +4866,7 @@ const docTemplate = `{ "200": { "description": "items", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_service_ProxyView" } } } @@ -4865,8 +4896,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.ProxyView" } } } @@ -4898,8 +4928,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.ImportResult" } } } @@ -4938,8 +4967,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.ProxyView" } } } @@ -4994,8 +5022,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.ProxyView" } } } @@ -5034,8 +5061,7 @@ const docTemplate = `{ "200": { "description": "usedBy", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.usedByResponse" } } } @@ -5056,8 +5082,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.RegionInfo" + } } } } @@ -5078,8 +5106,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_service_NotifyChannelView" } } } @@ -5118,8 +5145,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_service_NotifyChannelView" } } } @@ -5167,8 +5193,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.NotifyEventsView" } } } @@ -5198,8 +5223,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.NotifyEventsView" } } } @@ -5220,8 +5244,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_service_NotifyTemplateView" } } } @@ -5365,8 +5388,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.SecuritySettings" } } } @@ -5396,8 +5418,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.SecuritySettings" } } } @@ -5418,8 +5439,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.TaskSettingsView" } } } @@ -5449,8 +5469,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.TaskSettingsView" } } } @@ -5471,8 +5490,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.TelegramView" } } } @@ -5502,8 +5520,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.TelegramView" } } } @@ -5542,8 +5559,7 @@ const docTemplate = `{ "200": { "description": "items 与 total", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.pagedResponse-oci-portal_internal_model_SystemLog" } } } @@ -5566,8 +5582,7 @@ const docTemplate = `{ "schema": { "type": "array", "items": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.Task" } } } @@ -5598,8 +5613,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.Task" } } } @@ -5629,8 +5643,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.Task" } } } @@ -5667,8 +5680,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.Task" } } } @@ -5723,8 +5735,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.TaskLog" + } } } } @@ -5754,15 +5768,13 @@ const docTemplate = `{ "202": { "description": "Accepted", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.triggerResponse" } }, "409": { "description": "任务正在执行中", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.errorResponse" } } } @@ -5799,10 +5811,7 @@ const docTemplate = `{ "403": { "description": "时间戳超窗或证书源非 Oracle 域", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.errorResponse" } }, "404": { @@ -5813,6 +5822,77 @@ const docTemplate = `{ } }, "definitions": { + "internal_api.aboutResources": { + "type": "object", + "properties": { + "cpuAvgPercent": { + "type": "number" + }, + "dbBytes": { + "type": "integer" + }, + "dbEngine": { + "type": "string" + }, + "goroutines": { + "type": "integer" + }, + "memHeapBytes": { + "type": "integer" + }, + "memSysBytes": { + "type": "integer" + }, + "numCpu": { + "type": "integer" + } + } + }, + "internal_api.aboutResponse": { + "type": "object", + "properties": { + "buildTime": { + "type": "string" + }, + "goVersion": { + "type": "string" + }, + "platform": { + "type": "string" + }, + "resources": { + "$ref": "#/definitions/internal_api.aboutResources" + }, + "startedAt": { + "type": "string" + }, + "uptimeSeconds": { + "type": "integer" + }, + "version": { + "type": "string" + } + } + }, + "internal_api.addressResponse": { + "type": "object", + "properties": { + "address": { + "type": "string" + } + } + }, + "internal_api.aiKeyCreateResponse": { + "type": "object", + "properties": { + "item": { + "$ref": "#/definitions/oci-portal_internal_model.AiKey" + }, + "key": { + "type": "string" + } + } + }, "internal_api.attachBootVolumeRequest": { "type": "object", "required": [ @@ -5871,6 +5951,17 @@ const docTemplate = `{ } } }, + "internal_api.configChangesResponse": { + "type": "object", + "properties": { + "changes": { + "$ref": "#/definitions/oci-portal_internal_service.Changes" + }, + "config": { + "$ref": "#/definitions/oci-portal_internal_model.OciConfig" + } + } + }, "internal_api.createConsoleConnectionRequest": { "type": "object", "required": [ @@ -6001,6 +6092,23 @@ const docTemplate = `{ } } }, + "internal_api.createInstancesResponse": { + "type": "object", + "properties": { + "errors": { + "type": "array", + "items": { + "type": "string" + } + }, + "instances": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Instance" + } + } + } + }, "internal_api.createSecurityListRequest": { "type": "object", "required": [ @@ -6077,10 +6185,7 @@ const docTemplate = `{ "type": "string" }, "payload": { - "type": "array", - "items": { - "type": "integer" - } + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" }, "type": { "type": "string" @@ -6148,6 +6253,33 @@ const docTemplate = `{ } } }, + "internal_api.credentialsResponse": { + "type": "object", + "properties": { + "passwordLoginDisabled": { + "type": "boolean" + }, + "username": { + "type": "string" + } + } + }, + "internal_api.deletedApiKeysResponse": { + "type": "object", + "properties": { + "deletedApiKeys": { + "type": "integer" + } + } + }, + "internal_api.deletedTotpResponse": { + "type": "object", + "properties": { + "deletedTotpDevices": { + "type": "integer" + } + } + }, "internal_api.enableIPv6Request": { "type": "object", "properties": { @@ -6156,6 +6288,22 @@ const docTemplate = `{ } } }, + "internal_api.enabledResponse": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "internal_api.errorResponse": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + }, "internal_api.importRequest": { "type": "object", "required": [ @@ -6219,6 +6367,143 @@ const docTemplate = `{ } } }, + "internal_api.ipv6AddressResponse": { + "type": "object", + "properties": { + "ipv6Address": { + "type": "string" + } + } + }, + "internal_api.ipv6StepsResponse": { + "type": "object", + "properties": { + "steps": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.IPv6Step" + } + } + } + }, + "internal_api.itemResponse-oci-portal_internal_model_AiModelBlacklist": { + "type": "object", + "properties": { + "item": { + "$ref": "#/definitions/oci-portal_internal_model.AiModelBlacklist" + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_aiwire_Model": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.Model" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_model_AiChannel": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.AiChannel" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_model_AiKey": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.AiKey" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_model_AiModelBlacklist": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.AiModelBlacklist" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_model_AiModelCache": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.AiModelCache" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_model_UserIdentity": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.UserIdentity" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_service_NotifyChannelView": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.NotifyChannelView" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_service_NotifyTemplateView": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.NotifyTemplateView" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_service_ProxyView": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.ProxyView" + } + } + } + }, + "internal_api.logWebhookStatusResponse": { + "type": "object", + "properties": { + "exists": { + "type": "boolean" + }, + "webhook": { + "$ref": "#/definitions/oci-portal_internal_service.LogWebhookInfo" + } + } + }, "internal_api.loginRequest": { "type": "object", "required": [ @@ -6242,6 +6527,100 @@ const docTemplate = `{ } } }, + "internal_api.oauthProvidersResponse": { + "type": "object", + "properties": { + "passwordLoginDisabled": { + "type": "boolean" + }, + "providers": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.ProviderInfo" + } + } + } + }, + "internal_api.pagedResponse-oci-portal_internal_model_AiCallLog": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.AiCallLog" + } + }, + "total": { + "type": "integer" + } + } + }, + "internal_api.pagedResponse-oci-portal_internal_model_AiContentLog": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.AiContentLog" + } + }, + "total": { + "type": "integer" + } + } + }, + "internal_api.pagedResponse-oci-portal_internal_model_LogEvent": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.LogEvent" + } + }, + "total": { + "type": "integer" + } + } + }, + "internal_api.pagedResponse-oci-portal_internal_model_SystemLog": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.SystemLog" + } + }, + "total": { + "type": "integer" + } + } + }, + "internal_api.passwordResponse": { + "type": "object", + "properties": { + "password": { + "type": "string" + } + } + }, + "internal_api.publicIpResponse": { + "type": "object", + "properties": { + "publicIp": { + "type": "string" + } + } + }, + "internal_api.rawDetailResponse": { + "type": "object", + "properties": { + "raw": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + } + } + }, "internal_api.renameRequest": { "type": "object", "required": [ @@ -6267,6 +6646,47 @@ const docTemplate = `{ } } }, + "internal_api.tokenResponse": { + "type": "object", + "properties": { + "expiresAt": { + "type": "string" + }, + "token": { + "type": "string" + } + } + }, + "internal_api.totpRequiredResponse": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "totpRequired": { + "type": "boolean" + } + } + }, + "internal_api.totpSetupResponse": { + "type": "object", + "properties": { + "otpauthUri": { + "type": "string" + }, + "secret": { + "type": "string" + } + } + }, + "internal_api.triggerResponse": { + "type": "object", + "properties": { + "triggered": { + "type": "boolean" + } + } + }, "internal_api.updateBootVolumeRequest": { "type": "object", "properties": { @@ -6376,10 +6796,7 @@ const docTemplate = `{ "type": "string" }, "payload": { - "type": "array", - "items": { - "type": "integer" - } + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" }, "status": { "type": "string" @@ -6423,6 +6840,1927 @@ const docTemplate = `{ } } }, + "internal_api.urlResponse": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + } + }, + "internal_api.usedByResponse": { + "type": "object", + "properties": { + "usedBy": { + "type": "integer" + } + } + }, + "internal_api.webConsoleSessionResponse": { + "type": "object", + "properties": { + "sessionId": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.AnthBlock": { + "type": "object", + "properties": { + "content": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "id": { + "description": "tool_use", + "type": "string" + }, + "input": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "is_error": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "source": { + "description": "image", + "allOf": [ + { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + } + ] + }, + "text": { + "type": "string" + }, + "tool_use_id": { + "description": "tool_result", + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.AnthContent": { + "type": "object", + "properties": { + "blocks": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthBlock" + } + }, + "text": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.AnthMessage": { + "type": "object", + "properties": { + "content": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthContent" + }, + "role": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.AnthOutputConfig": { + "type": "object", + "properties": { + "effort": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.AnthTool": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "input_schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "name": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.AnthUsage": { + "type": "object", + "properties": { + "cache_read_input_tokens": { + "description": "CacheReadInputTokens 是缓存命中读取数;OCI 隐式缓存无「写入」计数,cache_creation 恒缺", + "type": "integer" + }, + "input_tokens": { + "type": "integer" + }, + "output_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.AnyJSON": { + "type": "object" + }, + "oci-portal_internal_aiwire.ChatMessage": { + "type": "object", + "properties": { + "content": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "role": { + "type": "string" + }, + "tool_call_id": { + "type": "string" + }, + "tool_calls": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ToolCall" + } + } + } + }, + "oci-portal_internal_aiwire.ChatRequest": { + "type": "object", + "properties": { + "max_completion_tokens": { + "type": "integer" + }, + "max_tokens": { + "type": "integer" + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ChatMessage" + } + }, + "model": { + "type": "string" + }, + "parallel_tool_calls": { + "type": "boolean" + }, + "reasoning_effort": { + "type": "string" + }, + "response_format": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ResponseFormat" + }, + "stream": { + "type": "boolean" + }, + "stream_options": { + "$ref": "#/definitions/oci-portal_internal_aiwire.StreamOptions" + }, + "temperature": { + "type": "number" + }, + "tool_choice": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "tools": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.Tool" + } + }, + "top_p": { + "type": "number" + } + } + }, + "oci-portal_internal_aiwire.ChatResponse": { + "type": "object", + "properties": { + "choices": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.Choice" + } + }, + "created": { + "type": "integer" + }, + "id": { + "type": "string" + }, + "model": { + "type": "string" + }, + "object": { + "type": "string" + }, + "usage": { + "$ref": "#/definitions/oci-portal_internal_aiwire.Usage" + } + } + }, + "oci-portal_internal_aiwire.Choice": { + "type": "object", + "properties": { + "finish_reason": { + "type": "string" + }, + "index": { + "type": "integer" + }, + "message": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ChatMessage" + } + } + }, + "oci-portal_internal_aiwire.EmbedUsage": { + "type": "object", + "properties": { + "prompt_tokens": { + "type": "integer" + }, + "total_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.Embedding": { + "type": "object", + "properties": { + "embedding": { + "type": "array", + "items": { + "type": "number" + } + }, + "index": { + "type": "integer" + }, + "object": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.EmbeddingsRequest": { + "type": "object", + "properties": { + "dimensions": { + "type": "integer" + }, + "encoding_format": { + "type": "string" + }, + "input": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "model": { + "type": "string" + }, + "user": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.EmbeddingsResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.Embedding" + } + }, + "model": { + "type": "string" + }, + "object": { + "type": "string" + }, + "usage": { + "$ref": "#/definitions/oci-portal_internal_aiwire.EmbedUsage" + } + } + }, + "oci-portal_internal_aiwire.FunctionCall": { + "type": "object", + "properties": { + "arguments": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.FunctionDef": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "parameters": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + } + } + }, + "oci-portal_internal_aiwire.MessagesRequest": { + "type": "object", + "properties": { + "max_tokens": { + "type": "integer" + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthMessage" + } + }, + "metadata": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "model": { + "type": "string" + }, + "output_config": { + "description": "OutputConfig 是 Anthropic 官方输出控制(effort 等);网关映射 effort 到 OCI reasoningEffort。", + "allOf": [ + { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthOutputConfig" + } + ] + }, + "stop_sequences": { + "type": "array", + "items": { + "type": "string" + } + }, + "stream": { + "type": "boolean" + }, + "system": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "temperature": { + "type": "number" + }, + "thinking": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "tool_choice": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "tools": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthTool" + } + }, + "top_k": { + "type": "integer" + }, + "top_p": { + "type": "number" + } + } + }, + "oci-portal_internal_aiwire.MessagesResponse": { + "type": "object", + "properties": { + "content": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthBlock" + } + }, + "id": { + "type": "string" + }, + "model": { + "type": "string" + }, + "role": { + "type": "string" + }, + "stop_reason": { + "type": "string" + }, + "stop_sequence": { + "type": "string" + }, + "type": { + "type": "string" + }, + "usage": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthUsage" + } + } + }, + "oci-portal_internal_aiwire.Model": { + "type": "object", + "properties": { + "created": { + "type": "integer" + }, + "id": { + "type": "string" + }, + "object": { + "type": "string" + }, + "owned_by": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.ModelList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.Model" + } + }, + "object": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.ModerationPii": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "length": { + "type": "integer" + }, + "offset": { + "type": "integer" + }, + "score": { + "type": "number" + }, + "text": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.ModerationResult": { + "type": "object", + "properties": { + "categories": { + "type": "object", + "additionalProperties": { + "type": "boolean" + } + }, + "category_scores": { + "type": "object", + "additionalProperties": { + "type": "number", + "format": "float64" + } + }, + "flagged": { + "type": "boolean" + }, + "pii": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ModerationPii" + } + } + } + }, + "oci-portal_internal_aiwire.ModerationsRequest": { + "type": "object", + "properties": { + "input": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "model": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.ModerationsResponse": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "model": { + "type": "string" + }, + "results": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ModerationResult" + } + } + } + }, + "oci-portal_internal_aiwire.PromptTokensDetails": { + "type": "object", + "properties": { + "cached_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.RerankDocument": { + "type": "object", + "properties": { + "text": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.RerankRequest": { + "type": "object", + "properties": { + "documents": { + "type": "array", + "items": { + "type": "string" + } + }, + "model": { + "type": "string" + }, + "query": { + "type": "string" + }, + "return_documents": { + "type": "boolean" + }, + "top_n": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.RerankResponse": { + "type": "object", + "properties": { + "model": { + "type": "string" + }, + "results": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RerankResult" + } + } + } + }, + "oci-portal_internal_aiwire.RerankResult": { + "type": "object", + "properties": { + "document": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RerankDocument" + }, + "index": { + "type": "integer" + }, + "relevance_score": { + "type": "number" + } + } + }, + "oci-portal_internal_aiwire.RespError": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.RespInDetails": { + "type": "object", + "properties": { + "cached_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.RespOutDetails": { + "type": "object", + "properties": { + "reasoning_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.RespReasoning": { + "type": "object", + "properties": { + "effort": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.RespRequest": { + "type": "object", + "properties": { + "background": { + "type": "boolean" + }, + "conversation": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "input": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "instructions": { + "type": "string" + }, + "max_output_tokens": { + "type": "integer" + }, + "model": { + "type": "string" + }, + "parallel_tool_calls": { + "type": "boolean" + }, + "previous_response_id": { + "type": "string" + }, + "reasoning": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespReasoning" + }, + "store": { + "type": "boolean" + }, + "stream": { + "type": "boolean" + }, + "temperature": { + "type": "number" + }, + "text": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespText" + }, + "tool_choice": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "tools": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespTool" + } + }, + "top_p": { + "type": "number" + } + } + }, + "oci-portal_internal_aiwire.RespResponse": { + "type": "object", + "properties": { + "created_at": { + "type": "integer" + }, + "error": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespError" + }, + "id": { + "type": "string" + }, + "model": { + "type": "string" + }, + "object": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "status": { + "type": "string" + }, + "usage": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespUsage" + } + } + }, + "oci-portal_internal_aiwire.RespText": { + "type": "object", + "properties": { + "format": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespTextFormat" + } + } + }, + "oci-portal_internal_aiwire.RespTextFormat": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "strict": { + "type": "boolean" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.RespTool": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "parameters": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "strict": { + "type": "boolean" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.RespUsage": { + "type": "object", + "properties": { + "input_tokens": { + "type": "integer" + }, + "input_tokens_details": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespInDetails" + }, + "output_tokens": { + "type": "integer" + }, + "output_tokens_details": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespOutDetails" + }, + "total_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.ResponseFormat": { + "type": "object", + "properties": { + "json_schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.SpeechRequest": { + "type": "object", + "properties": { + "input": { + "type": "string" + }, + "language": { + "type": "string" + }, + "model": { + "type": "string" + }, + "response_format": { + "type": "string" + }, + "voice": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.StreamOptions": { + "type": "object", + "properties": { + "include_usage": { + "type": "boolean" + } + } + }, + "oci-portal_internal_aiwire.Tool": { + "type": "object", + "properties": { + "function": { + "$ref": "#/definitions/oci-portal_internal_aiwire.FunctionDef" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.ToolCall": { + "type": "object", + "properties": { + "function": { + "$ref": "#/definitions/oci-portal_internal_aiwire.FunctionCall" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.Usage": { + "type": "object", + "properties": { + "completion_tokens": { + "type": "integer" + }, + "prompt_tokens": { + "type": "integer" + }, + "prompt_tokens_details": { + "description": "PromptTokensDetails 携带缓存命中细分;OCI 为隐式 prompt 缓存,只有读取计数", + "allOf": [ + { + "$ref": "#/definitions/oci-portal_internal_aiwire.PromptTokensDetails" + } + ] + }, + "total_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_model.AiCallLog": { + "type": "object", + "properties": { + "cachedTokens": { + "description": "CachedTokens 是输入中缓存命中(读取)的部分;OCI 隐式缓存无写入计数", + "type": "integer" + }, + "channelId": { + "type": "integer" + }, + "channelName": { + "type": "string" + }, + "clientIp": { + "description": "ClientIP 是网关调用方来源 IP(尊重「真实 IP 头」安全设置,与系统日志同源)", + "type": "string" + }, + "completionTokens": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "endpoint": { + "description": "openai / anthropic", + "type": "string" + }, + "errMsg": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "keyId": { + "type": "integer" + }, + "keyName": { + "type": "string" + }, + "latencyMs": { + "type": "integer" + }, + "model": { + "type": "string" + }, + "promptTokens": { + "type": "integer" + }, + "retries": { + "type": "integer" + }, + "status": { + "type": "integer" + }, + "stream": { + "type": "boolean" + }, + "totalTokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_model.AiChannel": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "disabledUntil": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "failCount": { + "description": "FailCount 连续失败计数;达阈值后 DisabledUntil 指数退避熔断,成功/探测通过复位", + "type": "integer" + }, + "group": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "lastProbeAt": { + "type": "string" + }, + "name": { + "type": "string" + }, + "ociConfigId": { + "type": "integer" + }, + "priority": { + "type": "integer" + }, + "probeError": { + "type": "string" + }, + "probeStatus": { + "description": "ok / no_service / no_quota / error", + "type": "string" + }, + "region": { + "type": "string" + }, + "updatedAt": { + "type": "string" + }, + "weight": { + "type": "integer" + } + } + }, + "oci-portal_internal_model.AiContentLog": { + "type": "object", + "properties": { + "callLogId": { + "description": "CallLogID 关联同次调用的 AiCallLog,调用日志详情据此反查正文", + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "keyId": { + "type": "integer" + }, + "keyName": { + "type": "string" + }, + "model": { + "type": "string" + }, + "requestBody": { + "description": "RequestBody / ResponseBody 是截断后的正文 JSON;\n64KB 截断恰在 MySQL TEXT 上限(65535B)边界,size 上探一档 → MEDIUMTEXT", + "type": "string" + }, + "responseBody": { + "type": "string" + }, + "stream": { + "type": "boolean" + } + } + }, + "oci-portal_internal_model.AiKey": { + "type": "object", + "properties": { + "contentLogUntil": { + "description": "ContentLogUntil 是内容日志开启截止时间;nil = 永关(默认,红线),\n开启必须限时,到期自动停写", + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "group": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "lastUsedAt": { + "type": "string" + }, + "models": { + "description": "Models 是模型白名单(精确匹配模型名);空 = 不限,非空时网关仅放行列表内模型", + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": "string" + }, + "tail": { + "type": "string" + } + } + }, + "oci-portal_internal_model.AiModelBlacklist": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + } + }, + "oci-portal_internal_model.AiModelCache": { + "type": "object", + "properties": { + "capability": { + "type": "string" + }, + "channelId": { + "type": "integer" + }, + "deprecatedAt": { + "description": "DeprecatedAt 是 OCI 宣布的模型弃用时间;nil 表示未宣布。\n弃用后仍可调用,直到 RetiredAt(按需推理退役,同步层已剔除过期项)。", + "type": "string" + }, + "modelOcid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "retiredAt": { + "type": "string" + }, + "syncedAt": { + "type": "string" + }, + "vendor": { + "type": "string" + } + } + }, + "oci-portal_internal_model.LogEvent": { + "type": "object", + "properties": { + "eventTime": { + "type": "string" + }, + "eventType": { + "description": "异步解析回填,如 com.oraclecloud.ComputeApi.TerminateInstance", + "type": "string" + }, + "id": { + "type": "integer" + }, + "messageId": { + "description": "幂等键(X-OCI-NS-MessageId)", + "type": "string" + }, + "ociConfigId": { + "description": "经 secret 反查归属租户", + "type": "integer" + }, + "payload": { + "description": "防御上限 256KB 超 MySQL TEXT(64KB),size 上探一档 → MEDIUMTEXT;PG/SQLite 仍为 text", + "type": "string" + }, + "processed": { + "type": "boolean" + }, + "receivedAt": { + "type": "string" + }, + "source": { + "type": "string" + }, + "sourceIp": { + "description": "异步解析回填,Audit 事件的发起方 IP", + "type": "string" + }, + "truncated": { + "type": "boolean" + } + } + }, + "oci-portal_internal_model.OciConfig": { + "type": "object", + "properties": { + "accountType": { + "type": "string" + }, + "alias": { + "type": "string" + }, + "aliveStatus": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "fingerprint": { + "type": "string" + }, + "group": { + "description": "Group 是面板内的自定义分组标签,空串表示未分组;\n列名避开 SQL 保留字 GROUP", + "type": "string" + }, + "homeRegionKey": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "lastError": { + "type": "string" + }, + "lastVerifiedAt": { + "type": "string" + }, + "multiCompartment": { + "type": "boolean" + }, + "multiRegion": { + "description": "多区域 / 多区间支持:开启后订阅区域与 compartment 列表入库缓存,\n供筛选器免实时调 OCI;未开启的租户筛选器锁定主区域 / 根区间。", + "type": "boolean" + }, + "paymentModel": { + "type": "string" + }, + "promotionAmount": { + "type": "number" + }, + "promotionExpires": { + "type": "string" + }, + "promotionStatus": { + "type": "string" + }, + "proxyId": { + "description": "ProxyID 关联出站代理,nil 表示直连;该租户全部 SDK 调用经此代理", + "type": "integer" + }, + "region": { + "type": "string" + }, + "subscriptionId": { + "type": "string" + }, + "subscriptionTier": { + "type": "string" + }, + "tenancyName": { + "type": "string" + }, + "tenancyOcid": { + "type": "string" + }, + "updatedAt": { + "type": "string" + }, + "userOcid": { + "type": "string" + } + } + }, + "oci-portal_internal_model.SystemLog": { + "type": "object", + "properties": { + "clientIp": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "durationMs": { + "type": "integer" + }, + "errMsg": { + "description": "ErrMsg 仅失败请求(\u003e=400)存响应的 error 文案,便于免翻服务端日志定位原因", + "type": "string" + }, + "id": { + "type": "integer" + }, + "method": { + "type": "string" + }, + "path": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "userAgent": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "oci-portal_internal_model.Task": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "cronExpr": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "lastError": { + "type": "string" + }, + "lastRunAt": { + "type": "string" + }, + "name": { + "type": "string" + }, + "payload": { + "type": "string" + }, + "runCount": { + "type": "integer" + }, + "status": { + "type": "string" + }, + "type": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "oci-portal_internal_model.TaskLog": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "durationMs": { + "type": "integer" + }, + "id": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + }, + "taskId": { + "type": "integer" + } + } + }, + "oci-portal_internal_model.UserIdentity": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "display": { + "description": "展示名:邮箱 / GitHub login", + "type": "string" + }, + "id": { + "type": "integer" + }, + "provider": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.AuditEvent": { + "type": "object", + "properties": { + "compartmentName": { + "type": "string" + }, + "eventId": { + "type": "string" + }, + "eventName": { + "type": "string" + }, + "eventTime": { + "type": "string" + }, + "ipAddress": { + "type": "string" + }, + "principalName": { + "type": "string" + }, + "raw": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "requestAction": { + "type": "string" + }, + "requestPath": { + "type": "string" + }, + "resourceName": { + "type": "string" + }, + "source": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.BlockVolume": { + "type": "object", + "properties": { + "availabilityDomain": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "id": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + }, + "sizeInGBs": { + "type": "integer" + }, + "timeCreated": { + "type": "string" + }, + "vpusPerGB": { + "type": "integer" + } + } + }, + "oci-portal_internal_oci.BootVolume": { + "type": "object", + "properties": { + "attachedInstanceId": { + "type": "string" + }, + "attachedInstanceName": { + "type": "string" + }, + "availabilityDomain": { + "type": "string" + }, + "compartmentId": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "id": { + "type": "string" + }, + "imageId": { + "type": "string" + }, + "imageName": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + }, + "sizeInGBs": { + "type": "integer" + }, + "timeCreated": { + "type": "string" + }, + "vpusPerGB": { + "type": "integer" + } + } + }, + "oci-portal_internal_oci.BootVolumeAttachment": { + "type": "object", + "properties": { + "availabilityDomain": { + "type": "string" + }, + "bootVolumeId": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "id": { + "type": "string" + }, + "instanceId": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.Compartment": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + }, + "name": { + "type": "string" + }, + "parentId": { + "type": "string" + }, + "timeCreated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.ComputeShape": { + "type": "object", + "properties": { + "billingType": { + "description": "ALWAYS_FREE / LIMITED_FREE / PAID", + "type": "string" + }, + "gpus": { + "type": "integer" + }, + "isFlexible": { + "type": "boolean" + }, + "memoryInGBs": { + "type": "number" + }, + "memoryMaxGBs": { + "type": "number" + }, + "memoryMinGBs": { + "type": "number" + }, + "name": { + "type": "string" + }, + "ocpus": { + "type": "number" + }, + "ocpusMax": { + "type": "number" + }, + "ocpusMin": { + "type": "number" + }, + "processorDescription": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.ConsoleConnection": { + "type": "object", + "properties": { + "connectionString": { + "description": "串口控制台 SSH 命令", + "type": "string" + }, + "id": { + "type": "string" + }, + "instanceId": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + }, + "vncConnectionString": { + "description": "VNC over SSH 隧道命令", + "type": "string" + } + } + }, + "oci-portal_internal_oci.CostItem": { + "type": "object", + "properties": { + "computedAmount": { + "type": "number" + }, + "computedQuantity": { + "type": "number" + }, + "currency": { + "type": "string" + }, + "groupValue": { + "type": "string" + }, + "timeStart": { + "type": "string" + }, + "unit": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.IPv6Step": { + "type": "object", + "properties": { + "detail": { + "type": "string" + }, + "status": { + "description": "done / skipped / failed", + "type": "string" + }, + "step": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.IdentityDomain": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "homeRegion": { + "type": "string" + }, + "id": { + "type": "string" + }, + "licenseType": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.IdentityProviderInfo": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "jitEnabled": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "partnerProviderId": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.IdentitySettingInfo": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "primaryEmailRequired": { + "description": "用户需要提供主电子邮件地址:开启后创建用户 / JIT 预配必须带邮箱", + "type": "boolean" + } + } + }, + "oci-portal_internal_oci.Image": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "id": { + "type": "string" + }, + "operatingSystem": { + "type": "string" + }, + "operatingSystemVersion": { + "type": "string" + }, + "sizeInMBs": { + "type": "integer" + }, + "timeCreated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.Instance": { + "type": "object", + "properties": { + "availabilityDomain": { + "type": "string" + }, + "compartmentId": { + "type": "string" + }, + "definedTags": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": {} + } + }, + "displayName": { + "type": "string" + }, + "freeformTags": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "imageId": { + "type": "string" + }, + "ipv6Addresses": { + "type": "array", + "items": { + "type": "string" + } + }, + "lifecycleState": { + "type": "string" + }, + "memoryInGBs": { + "type": "number" + }, + "ocpus": { + "type": "number" + }, + "privateIp": { + "type": "string" + }, + "publicIp": { + "type": "string" + }, + "region": { + "type": "string" + }, + "shape": { + "type": "string" + }, + "subnetId": { + "type": "string" + }, + "timeCreated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.InstanceTraffic": { + "type": "object", + "properties": { + "inboundBytes": { + "type": "number" + }, + "instanceId": { + "type": "string" + }, + "outboundBytes": { + "type": "number" + }, + "vnics": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.VnicTraffic" + } + } + } + }, + "oci-portal_internal_oci.LimitService": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.LimitValue": { + "type": "object", + "properties": { + "availabilityDomain": { + "type": "string" + }, + "available": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "scopeType": { + "type": "string" + }, + "used": { + "type": "integer" + }, + "value": { + "type": "integer" + } + } + }, + "oci-portal_internal_oci.NotificationRecipients": { + "type": "object", + "properties": { + "recipients": { + "type": "array", + "items": { + "type": "string" + } + }, + "testModeEnabled": { + "type": "boolean" + } + } + }, + "oci-portal_internal_oci.PasswordPolicyInfo": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "minLength": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "numPasswordsInHistory": { + "type": "integer" + }, + "passwordExpiresAfter": { + "type": "integer" + }, + "passwordStrength": { + "type": "string" + }, + "priority": { + "type": "integer" + } + } + }, + "oci-portal_internal_oci.PromotionInfo": { + "type": "object", + "properties": { + "amount": { + "type": "number" + }, + "currencyUnit": { + "type": "string" + }, + "duration": { + "type": "integer" + }, + "durationUnit": { + "type": "string" + }, + "isIntentToPay": { + "type": "boolean" + }, + "status": { + "type": "string" + }, + "timeExpired": { + "type": "string" + }, + "timeStarted": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.RegionInfo": { + "type": "object", + "properties": { + "alias": { + "type": "string" + }, + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.RelayResource": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "state": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.SecurityList": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "egressRules": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.SecurityRule" + } + }, + "id": { + "type": "string" + }, + "ingressRules": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.SecurityRule" + } + }, + "lifecycleState": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "vcnId": { + "type": "string" + } + } + }, "oci-portal_internal_oci.SecurityRule": { "type": "object", "properties": { @@ -6456,6 +8794,379 @@ const docTemplate = `{ } } }, + "oci-portal_internal_oci.SignOnRuleInfo": { + "type": "object", + "properties": { + "authenticationFactor": { + "type": "string" + }, + "builtIn": { + "type": "boolean" + }, + "conditionAttribute": { + "type": "string" + }, + "conditionValue": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "sequence": { + "type": "integer" + } + } + }, + "oci-portal_internal_oci.Subnet": { + "type": "object", + "properties": { + "availabilityDomain": { + "type": "string" + }, + "cidrBlock": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "dnsLabel": { + "type": "string" + }, + "id": { + "type": "string" + }, + "ipv6CidrBlock": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + }, + "prohibitPublicIp": { + "type": "boolean" + }, + "routeTableId": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "vcnId": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.SubscriptionDetail": { + "type": "object", + "properties": { + "classicSubscriptionId": { + "type": "string" + }, + "cloudAmountCurrency": { + "type": "string" + }, + "csiNumber": { + "type": "string" + }, + "customerCountryCode": { + "type": "string" + }, + "endDate": { + "type": "string" + }, + "id": { + "type": "string" + }, + "isGovernmentSubscription": { + "type": "boolean" + }, + "lifecycleState": { + "type": "string" + }, + "paymentModel": { + "type": "string" + }, + "programType": { + "type": "string" + }, + "promotions": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.PromotionInfo" + } + }, + "regionAssignment": { + "type": "string" + }, + "serviceName": { + "type": "string" + }, + "startDate": { + "type": "string" + }, + "subscriptionTier": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "timeUpdated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.SubscriptionInfo": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "serviceName": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "timeUpdated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.TenantUser": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "email": { + "type": "string" + }, + "emailVerified": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "isCurrentUser": { + "type": "boolean" + }, + "lastLoginTime": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + }, + "mfaActivated": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "timeCreated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.TenantUserDetail": { + "type": "object", + "properties": { + "familyName": { + "type": "string" + }, + "givenName": { + "type": "string" + }, + "inAdminGroup": { + "type": "boolean" + }, + "inDomain": { + "type": "boolean" + }, + "isDomainAdmin": { + "type": "boolean" + } + } + }, + "oci-portal_internal_oci.TrafficPoint": { + "type": "object", + "properties": { + "bytes": { + "type": "number" + }, + "timestamp": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.VCN": { + "type": "object", + "properties": { + "cidrBlocks": { + "type": "array", + "items": { + "type": "string" + } + }, + "compartmentId": { + "type": "string" + }, + "defaultRouteTableId": { + "type": "string" + }, + "defaultSecurityListId": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "dnsLabel": { + "type": "string" + }, + "id": { + "type": "string" + }, + "ipv6CidrBlocks": { + "type": "array", + "items": { + "type": "string" + } + }, + "lifecycleState": { + "type": "string" + }, + "timeCreated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.Vnic": { + "type": "object", + "properties": { + "attachmentId": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "ipv6Addresses": { + "type": "array", + "items": { + "type": "string" + } + }, + "isPrimary": { + "type": "boolean" + }, + "lifecycleState": { + "type": "string" + }, + "privateIp": { + "type": "string" + }, + "publicIp": { + "type": "string" + }, + "subnetId": { + "type": "string" + }, + "subnetName": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "vnicId": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.VnicTraffic": { + "type": "object", + "properties": { + "inbound": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.TrafficPoint" + } + }, + "inboundBytes": { + "type": "number" + }, + "outbound": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.TrafficPoint" + } + }, + "outboundBytes": { + "type": "number" + }, + "vnicId": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.VolumeAttachment": { + "type": "object", + "properties": { + "availabilityDomain": { + "type": "string" + }, + "device": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "id": { + "type": "string" + }, + "instanceId": { + "type": "string" + }, + "isReadOnly": { + "type": "boolean" + }, + "lifecycleState": { + "type": "string" + }, + "volumeId": { + "type": "string" + }, + "volumeName": { + "description": "卷本身的名称(attachment 名是自动生成的)", + "type": "string" + } + } + }, + "oci-portal_internal_service.AuditEventsView": { + "type": "object", + "properties": { + "cursor": { + "type": "string" + }, + "exhausted": { + "type": "boolean" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.AuditEvent" + } + } + } + }, + "oci-portal_internal_service.Changes": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, "oci-portal_internal_service.ChannelInput": { "type": "object", "properties": { @@ -6482,6 +9193,150 @@ const docTemplate = `{ } } }, + "oci-portal_internal_service.ConfigSummary": { + "type": "object", + "properties": { + "accountType": { + "type": "string" + }, + "alias": { + "type": "string" + }, + "aliveStatus": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "group": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "lastError": { + "type": "string" + }, + "lastVerifiedAt": { + "type": "string" + }, + "multiCompartment": { + "type": "boolean" + }, + "multiRegion": { + "type": "boolean" + }, + "proxyId": { + "type": "integer" + }, + "proxyName": { + "description": "ProxyName 由 List 按关联填充,供表格代理列 hover 展示", + "type": "string" + }, + "region": { + "type": "string" + }, + "tenancyName": { + "type": "string" + }, + "tenancyOcid": { + "type": "string" + } + } + }, + "oci-portal_internal_service.ImportFail": { + "type": "object", + "properties": { + "line": { + "type": "string" + }, + "lineNo": { + "type": "integer" + }, + "reason": { + "type": "string" + } + } + }, + "oci-portal_internal_service.ImportResult": { + "type": "object", + "properties": { + "created": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.ProxyView" + } + }, + "failed": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.ImportFail" + } + } + } + }, + "oci-portal_internal_service.LogWebhookInfo": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "path": { + "type": "string" + }, + "secret": { + "type": "string" + } + } + }, + "oci-portal_internal_service.NotifyChannelView": { + "type": "object", + "properties": { + "bodyTemplate": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "from": { + "type": "string" + }, + "host": { + "description": "smtp", + "type": "string" + }, + "port": { + "type": "integer" + }, + "secretSet": { + "description": "密文字段状态(ntfy token / bark device key / smtp password)", + "type": "boolean" + }, + "secretTail": { + "type": "string" + }, + "server": { + "description": "ntfy / bark 共用 Server", + "type": "string" + }, + "to": { + "type": "string" + }, + "topic": { + "type": "string" + }, + "type": { + "type": "string" + }, + "url": { + "description": "webhook", + "type": "string" + }, + "username": { + "type": "string" + } + } + }, "oci-portal_internal_service.NotifyEventsView": { "type": "object", "properties": { @@ -6523,6 +9378,30 @@ const docTemplate = `{ } } }, + "oci-portal_internal_service.NotifyTemplateView": { + "type": "object", + "properties": { + "defaultTemplate": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "label": { + "type": "string" + }, + "template": { + "description": "Template 是自定义模板;空串表示未自定义(按默认发送)", + "type": "string" + }, + "vars": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "oci-portal_internal_service.OAuthProvidersView": { "type": "object", "properties": { @@ -6555,6 +9434,128 @@ const docTemplate = `{ } } }, + "oci-portal_internal_service.Overview": { + "type": "object", + "properties": { + "check": { + "$ref": "#/definitions/oci-portal_internal_service.OverviewCheck" + }, + "cost": { + "$ref": "#/definitions/oci-portal_internal_service.OverviewCost" + }, + "tasks": { + "$ref": "#/definitions/oci-portal_internal_service.OverviewTasks" + }, + "tenants": { + "$ref": "#/definitions/oci-portal_internal_service.OverviewTenants" + } + } + }, + "oci-portal_internal_service.OverviewCheck": { + "type": "object", + "properties": { + "coveredConfigs": { + "type": "integer" + }, + "hasActiveTask": { + "type": "boolean" + }, + "instanceCount": { + "type": "integer" + }, + "lastCheckedAt": { + "type": "string" + }, + "totalConfigs": { + "type": "integer" + } + } + }, + "oci-portal_internal_service.OverviewCost": { + "type": "object", + "properties": { + "coveredConfigs": { + "type": "integer" + }, + "currency": { + "type": "string" + }, + "days": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.OverviewCostDay" + } + }, + "hasActiveTask": { + "type": "boolean" + }, + "total": { + "type": "number" + } + } + }, + "oci-portal_internal_service.OverviewCostDay": { + "type": "object", + "properties": { + "amount": { + "type": "number" + }, + "day": { + "type": "string" + } + } + }, + "oci-portal_internal_service.OverviewTasks": { + "type": "object", + "properties": { + "active": { + "type": "integer" + }, + "cost": { + "type": "integer" + }, + "healthCheck": { + "type": "integer" + }, + "snatch": { + "type": "integer" + }, + "total": { + "type": "integer" + } + } + }, + "oci-portal_internal_service.OverviewTenants": { + "type": "object", + "properties": { + "alive": { + "type": "integer" + }, + "byType": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "dead": { + "type": "integer" + }, + "total": { + "type": "integer" + } + } + }, + "oci-portal_internal_service.ProviderInfo": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "provider": { + "type": "string" + } + } + }, "oci-portal_internal_service.ProxyInput": { "type": "object", "required": [ @@ -6583,6 +9584,101 @@ const docTemplate = `{ } } }, + "oci-portal_internal_service.ProxyView": { + "type": "object", + "properties": { + "city": { + "type": "string" + }, + "country": { + "description": "Country / City 为出口实测地区;GeoAt 空串表示尚未探测(前端显示「检测中」)", + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "geoAt": { + "type": "string" + }, + "host": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "passwordSet": { + "type": "boolean" + }, + "port": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "usedBy": { + "description": "UsedBy 为关联此代理的租户数,前端据此提示删除约束", + "type": "integer" + }, + "username": { + "type": "string" + } + } + }, + "oci-portal_internal_service.RegionSubscriptionView": { + "type": "object", + "properties": { + "alias": { + "type": "string" + }, + "isHomeRegion": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "oci-portal_internal_service.RelayView": { + "type": "object", + "properties": { + "connector": { + "$ref": "#/definitions/oci-portal_internal_oci.RelayResource" + }, + "endpoint": { + "type": "string" + }, + "events": { + "type": "array", + "items": { + "type": "string" + } + }, + "policy": { + "$ref": "#/definitions/oci-portal_internal_oci.RelayResource" + }, + "ready": { + "type": "boolean" + }, + "subscription": { + "$ref": "#/definitions/oci-portal_internal_oci.RelayResource" + }, + "topic": { + "$ref": "#/definitions/oci-portal_internal_oci.RelayResource" + }, + "webhook": { + "$ref": "#/definitions/oci-portal_internal_service.LogWebhookInfo" + } + } + }, "oci-portal_internal_service.SecuritySettings": { "type": "object", "properties": { @@ -6618,6 +9714,23 @@ const docTemplate = `{ } } }, + "oci-portal_internal_service.TelegramView": { + "type": "object", + "properties": { + "chatId": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "tokenSet": { + "type": "boolean" + }, + "tokenTail": { + "type": "string" + } + } + }, "oci-portal_internal_service.UpdateCredentialsInput": { "type": "object", "required": [ diff --git a/docs/swagger.json b/docs/swagger.json index 1c98a76..9c2e24d 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -8,6 +8,33 @@ }, "basePath": "/", "paths": { + "/ai/v1/audio/speech": { + "post": { + "tags": [ + "AI 网关" + ], + "summary": "OpenAI Audio Speech 兼容端点(文本转语音)", + "parameters": [ + { + "description": "OpenAI audio speech 请求体(model/input 必填,voice 见 xAI Grok Voice 列表,language 缺省 auto;未列字段原样透传)", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.SpeechRequest" + } + } + ], + "responses": { + "200": { + "description": "音频字节(Content-Type 透传上游,默认 audio/mpeg)", + "schema": { + "type": "file" + } + } + } + } + }, "/ai/v1/chat/completions": { "post": { "tags": [ @@ -21,16 +48,15 @@ "in": "body", "required": true, "schema": { - "type": "object" + "$ref": "#/definitions/oci-portal_internal_aiwire.ChatRequest" } } ], "responses": { "200": { - "description": "OpenAI 兼容响应(流式为 SSE,末尾 data: [DONE])", + "description": "OpenAI 兼容响应(非流式;流式为 SSE,末尾 data: [DONE])", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_aiwire.ChatResponse" } } } @@ -49,7 +75,7 @@ "in": "body", "required": true, "schema": { - "type": "object" + "$ref": "#/definitions/oci-portal_internal_aiwire.EmbeddingsRequest" } } ], @@ -57,8 +83,7 @@ "200": { "description": "OpenAI 兼容响应", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_aiwire.EmbeddingsResponse" } } } @@ -77,16 +102,15 @@ "in": "body", "required": true, "schema": { - "type": "object" + "$ref": "#/definitions/oci-portal_internal_aiwire.MessagesRequest" } } ], "responses": { "200": { - "description": "Anthropic 兼容响应(流式为 SSE)", + "description": "Anthropic 兼容响应(非流式;流式为 SSE 事件序列)", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_aiwire.MessagesResponse" } } } @@ -102,8 +126,61 @@ "200": { "description": "OpenAI 兼容 models 列表", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_aiwire.ModelList" + } + } + } + } + }, + "/ai/v1/moderations": { + "post": { + "tags": [ + "AI 网关" + ], + "summary": "内容审核端点(OCI Guardrails)", + "parameters": [ + { + "description": "审核请求体(input 为字符串或字符串数组,单次至多 8 条;model 接受但忽略)", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ModerationsRequest" + } + } + ], + "responses": { + "200": { + "description": "审核结果(categories/category_scores 为 overall/blocklist/prompt_injection,pii 为扩展字段)", + "schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ModerationsResponse" + } + } + } + } + }, + "/ai/v1/rerank": { + "post": { + "tags": [ + "AI 网关" + ], + "summary": "文档重排端点(Cohere Rerank)", + "parameters": [ + { + "description": "重排请求体(model/query/documents 必填,可选 top_n/return_documents)", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RerankRequest" + } + } + ], + "responses": { + "200": { + "description": "重排结果(results[].index 指向入参下标)", + "schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RerankResponse" } } } @@ -117,21 +194,20 @@ "summary": "OpenAI Responses 兼容端点", "parameters": [ { - "description": "OpenAI responses 请求体(支持 stream;web_search/x_search 服务端工具仅非流式)", + "description": "OpenAI responses 请求体(支持 stream;服务端工具 web_search/x_search/code_interpreter/mcp 含流式;未列字段原样透传上游)", "name": "body", "in": "body", "required": true, "schema": { - "type": "object" + "$ref": "#/definitions/oci-portal_internal_aiwire.RespRequest" } } ], "responses": { "200": { - "description": "OpenAI 兼容响应(流式为 SSE)", + "description": "OpenAI 兼容响应(非流式;流式为 SSE);直通仅建模常用字段,未列字段原样返回", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_aiwire.RespResponse" } } } @@ -152,8 +228,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.aboutResponse" } } } @@ -174,8 +249,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_model_AiModelBlacklist" } } } @@ -205,8 +279,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemResponse-oci-portal_internal_model_AiModelBlacklist" } } } @@ -254,8 +327,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_model_AiChannel" } } } @@ -285,8 +357,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.AiChannel" } } } @@ -377,8 +448,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.AiChannel" } } } @@ -408,8 +478,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_model_AiModelCache" } } } @@ -430,8 +499,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.pagedResponse-oci-portal_internal_model_AiCallLog" } } } @@ -452,8 +520,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_model_AiKey" } } } @@ -481,10 +548,9 @@ ], "responses": { "201": { - "description": "Created", + "description": "key 为明文密钥,仅本次返回", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.aiKeyCreateResponse" } } } @@ -584,8 +650,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.AiKey" } } } @@ -606,8 +671,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.pagedResponse-oci-portal_internal_model_AiContentLog" } } } @@ -628,8 +692,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_aiwire_Model" } } } @@ -650,8 +713,7 @@ "200": { "description": "username 与 passwordLoginDisabled", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.credentialsResponse" } } } @@ -684,10 +746,7 @@ "401": { "description": "当前密码错误", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.errorResponse" } } } @@ -708,8 +767,7 @@ "200": { "description": "items", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_model_UserIdentity" } } } @@ -742,10 +800,7 @@ "409": { "description": "最后一个身份不可解绑", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.errorResponse" } } } @@ -778,24 +833,19 @@ "200": { "description": "token 与 expiresAt", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.tokenResponse" } }, "401": { "description": "凭据错误", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.errorResponse" } }, "428": { "description": "需要两步验证码(totpRequired=true)", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.totpRequiredResponse" } } } @@ -829,8 +879,7 @@ "200": { "description": "providers 与 passwordLoginDisabled", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.oauthProvidersResponse" } } } @@ -861,10 +910,7 @@ "200": { "description": "url", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.urlResponse" } } } @@ -935,10 +981,7 @@ "409": { "description": "未绑定外部身份", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.errorResponse" } } } @@ -959,10 +1002,7 @@ "200": { "description": "新 token 与 expiresAt", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.tokenResponse" } } } @@ -983,10 +1023,7 @@ "200": { "description": "enabled", "schema": { - "type": "object", - "additionalProperties": { - "type": "boolean" - } + "$ref": "#/definitions/internal_api.enabledResponse" } } } @@ -1065,19 +1102,13 @@ "200": { "description": "secret 与 otpauthUri", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.totpSetupResponse" } }, "409": { "description": "已启用", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.errorResponse" } } } @@ -1168,8 +1199,7 @@ "200": { "description": "items 与 total", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.pagedResponse-oci-portal_internal_model_LogEvent" } } } @@ -1188,10 +1218,12 @@ "summary": "租户配置列表", "responses": { "200": { - "description": "items", + "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.ConfigSummary" + } } } } @@ -1221,8 +1253,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.OciConfig" } } } @@ -1252,8 +1283,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.OciConfig" } } } @@ -1288,10 +1318,9 @@ ], "responses": { "200": { - "description": "OK", + "description": "config 与 changes 字段变更对照", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.configChangesResponse" } } } @@ -1359,8 +1388,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.AuditEventsView" } } } @@ -1388,10 +1416,9 @@ ], "responses": { "200": { - "description": "OK", + "description": "raw 为事件原文 JSON", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.rawDetailResponse" } } } @@ -1421,8 +1448,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "type": "string" + } } } } @@ -1486,8 +1515,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.BootVolume" + } } } } @@ -1524,8 +1555,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.BootVolume" } } } @@ -1569,8 +1599,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.BootVolume" } } } @@ -1632,8 +1661,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Compartment" + } } } } @@ -1663,8 +1694,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.RegionSubscriptionView" + } } } } @@ -1694,8 +1727,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Compartment" + } } } } @@ -1759,8 +1794,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.CostItem" + } } } } @@ -1790,8 +1827,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.IdentityDomain" + } } } } @@ -1827,8 +1866,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.IdentityProviderInfo" + } } } } @@ -1871,8 +1912,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.IdentityProviderInfo" } } } @@ -1964,8 +2004,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.IdentityProviderInfo" } } } @@ -2001,8 +2040,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.IdentitySettingInfo" } } } @@ -2045,8 +2083,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.IdentitySettingInfo" } } } @@ -2076,8 +2113,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Image" + } } } } @@ -2114,8 +2153,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Image" } } } @@ -2145,8 +2183,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Instance" + } } } } @@ -2181,10 +2221,9 @@ ], "responses": { "201": { - "description": "Created", + "description": "部分成功仍 201,errors 为逐台失败信息", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.createInstancesResponse" } } } @@ -2221,8 +2260,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Instance" } } } @@ -2266,8 +2304,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Instance" } } } @@ -2345,8 +2382,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Instance" } } } @@ -2383,8 +2419,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.BootVolumeAttachment" + } } } } @@ -2428,8 +2466,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.BootVolumeAttachment" } } } @@ -2475,8 +2512,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.publicIpResponse" } } } @@ -2513,8 +2549,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.ConsoleConnection" + } } } } @@ -2558,8 +2596,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.ConsoleConnection" } } } @@ -2602,11 +2639,10 @@ } ], "responses": { - "200": { - "description": "sessionId 与 wsPath", + "201": { + "description": "sessionId 与 type", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.webConsoleSessionResponse" } } } @@ -2652,8 +2688,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.ipv6AddressResponse" } } } @@ -2731,8 +2766,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.BootVolumeAttachment" } } } @@ -2769,8 +2803,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.InstanceTraffic" } } } @@ -2807,8 +2840,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Vnic" + } } } } @@ -2852,8 +2887,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Vnic" } } } @@ -2890,8 +2924,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.VolumeAttachment" + } } } } @@ -2935,8 +2971,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.VolumeAttachment" } } } @@ -2966,8 +3001,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.LimitValue" + } } } } @@ -2997,8 +3034,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.LimitService" + } } } } @@ -3028,8 +3067,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.RelayView" } } } @@ -3057,8 +3095,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.RelayView" } } } @@ -3113,8 +3150,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.logWebhookStatusResponse" } } } @@ -3142,8 +3178,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.LogWebhookInfo" } } } @@ -3204,8 +3239,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.NotificationRecipients" } } } @@ -3248,8 +3282,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.NotificationRecipients" } } } @@ -3285,8 +3318,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.PasswordPolicyInfo" + } } } } @@ -3338,8 +3373,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.PasswordPolicyInfo" } } } @@ -3369,8 +3403,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.RegionSubscriptionView" + } } } } @@ -3407,8 +3443,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.RegionSubscriptionView" + } } } } @@ -3442,10 +3480,9 @@ ], "responses": { "200": { - "description": "OK", + "description": "SAML 元数据 XML(附件下载)", "schema": { - "type": "object", - "additionalProperties": true + "type": "file" } } } @@ -3475,8 +3512,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.SecurityList" + } } } } @@ -3513,8 +3552,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.SecurityList" } } } @@ -3551,8 +3589,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.SecurityList" } } } @@ -3596,8 +3633,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.SecurityList" } } } @@ -3659,8 +3695,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.ComputeShape" + } } } } @@ -3705,8 +3743,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.SignOnRuleInfo" } } } @@ -3782,8 +3819,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.SignOnRuleInfo" + } } } } @@ -3813,8 +3852,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Subnet" + } } } } @@ -3851,8 +3892,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Subnet" } } } @@ -3889,8 +3929,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Subnet" } } } @@ -3934,8 +3973,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.Subnet" } } } @@ -3997,8 +4035,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.SubscriptionInfo" + } } } } @@ -4035,8 +4075,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.SubscriptionDetail" } } } @@ -4072,8 +4111,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.TenantUser" + } } } } @@ -4116,8 +4157,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.TenantUser" } } } @@ -4160,8 +4200,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.TenantUserDetail" } } } @@ -4211,8 +4250,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.TenantUser" } } } @@ -4287,8 +4325,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.deletedApiKeysResponse" } } } @@ -4331,8 +4368,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.deletedTotpResponse" } } } @@ -4373,10 +4409,9 @@ ], "responses": { "200": { - "description": "OK", + "description": "一次性明文密码", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.passwordResponse" } } } @@ -4406,8 +4441,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.VCN" + } } } } @@ -4444,8 +4481,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.VCN" } } } @@ -4482,8 +4518,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.VCN" } } } @@ -4527,8 +4562,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_oci.VCN" } } } @@ -4606,8 +4640,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.ipv6StepsResponse" } } } @@ -4635,10 +4668,9 @@ ], "responses": { "200": { - "description": "OK", + "description": "config 与 changes 字段变更对照", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.configChangesResponse" } } } @@ -4718,8 +4750,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.addressResponse" } } } @@ -4783,8 +4814,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.BlockVolume" + } } } } @@ -4805,8 +4838,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.Overview" } } } @@ -4827,8 +4859,7 @@ "200": { "description": "items", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_service_ProxyView" } } } @@ -4858,8 +4889,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.ProxyView" } } } @@ -4891,8 +4921,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.ImportResult" } } } @@ -4931,8 +4960,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.ProxyView" } } } @@ -4987,8 +5015,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.ProxyView" } } } @@ -5027,8 +5054,7 @@ "200": { "description": "usedBy", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.usedByResponse" } } } @@ -5049,8 +5075,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.RegionInfo" + } } } } @@ -5071,8 +5099,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_service_NotifyChannelView" } } } @@ -5111,8 +5138,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_service_NotifyChannelView" } } } @@ -5160,8 +5186,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.NotifyEventsView" } } } @@ -5191,8 +5216,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.NotifyEventsView" } } } @@ -5213,8 +5237,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.itemsResponse-oci-portal_internal_service_NotifyTemplateView" } } } @@ -5358,8 +5381,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.SecuritySettings" } } } @@ -5389,8 +5411,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.SecuritySettings" } } } @@ -5411,8 +5432,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.TaskSettingsView" } } } @@ -5442,8 +5462,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.TaskSettingsView" } } } @@ -5464,8 +5483,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.TelegramView" } } } @@ -5495,8 +5513,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_service.TelegramView" } } } @@ -5535,8 +5552,7 @@ "200": { "description": "items 与 total", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.pagedResponse-oci-portal_internal_model_SystemLog" } } } @@ -5559,8 +5575,7 @@ "schema": { "type": "array", "items": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.Task" } } } @@ -5591,8 +5606,7 @@ "201": { "description": "Created", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.Task" } } } @@ -5622,8 +5636,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.Task" } } } @@ -5660,8 +5673,7 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/oci-portal_internal_model.Task" } } } @@ -5716,8 +5728,10 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.TaskLog" + } } } } @@ -5747,15 +5761,13 @@ "202": { "description": "Accepted", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.triggerResponse" } }, "409": { "description": "任务正在执行中", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/internal_api.errorResponse" } } } @@ -5792,10 +5804,7 @@ "403": { "description": "时间戳超窗或证书源非 Oracle 域", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/internal_api.errorResponse" } }, "404": { @@ -5806,6 +5815,77 @@ } }, "definitions": { + "internal_api.aboutResources": { + "type": "object", + "properties": { + "cpuAvgPercent": { + "type": "number" + }, + "dbBytes": { + "type": "integer" + }, + "dbEngine": { + "type": "string" + }, + "goroutines": { + "type": "integer" + }, + "memHeapBytes": { + "type": "integer" + }, + "memSysBytes": { + "type": "integer" + }, + "numCpu": { + "type": "integer" + } + } + }, + "internal_api.aboutResponse": { + "type": "object", + "properties": { + "buildTime": { + "type": "string" + }, + "goVersion": { + "type": "string" + }, + "platform": { + "type": "string" + }, + "resources": { + "$ref": "#/definitions/internal_api.aboutResources" + }, + "startedAt": { + "type": "string" + }, + "uptimeSeconds": { + "type": "integer" + }, + "version": { + "type": "string" + } + } + }, + "internal_api.addressResponse": { + "type": "object", + "properties": { + "address": { + "type": "string" + } + } + }, + "internal_api.aiKeyCreateResponse": { + "type": "object", + "properties": { + "item": { + "$ref": "#/definitions/oci-portal_internal_model.AiKey" + }, + "key": { + "type": "string" + } + } + }, "internal_api.attachBootVolumeRequest": { "type": "object", "required": [ @@ -5864,6 +5944,17 @@ } } }, + "internal_api.configChangesResponse": { + "type": "object", + "properties": { + "changes": { + "$ref": "#/definitions/oci-portal_internal_service.Changes" + }, + "config": { + "$ref": "#/definitions/oci-portal_internal_model.OciConfig" + } + } + }, "internal_api.createConsoleConnectionRequest": { "type": "object", "required": [ @@ -5994,6 +6085,23 @@ } } }, + "internal_api.createInstancesResponse": { + "type": "object", + "properties": { + "errors": { + "type": "array", + "items": { + "type": "string" + } + }, + "instances": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.Instance" + } + } + } + }, "internal_api.createSecurityListRequest": { "type": "object", "required": [ @@ -6070,10 +6178,7 @@ "type": "string" }, "payload": { - "type": "array", - "items": { - "type": "integer" - } + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" }, "type": { "type": "string" @@ -6141,6 +6246,33 @@ } } }, + "internal_api.credentialsResponse": { + "type": "object", + "properties": { + "passwordLoginDisabled": { + "type": "boolean" + }, + "username": { + "type": "string" + } + } + }, + "internal_api.deletedApiKeysResponse": { + "type": "object", + "properties": { + "deletedApiKeys": { + "type": "integer" + } + } + }, + "internal_api.deletedTotpResponse": { + "type": "object", + "properties": { + "deletedTotpDevices": { + "type": "integer" + } + } + }, "internal_api.enableIPv6Request": { "type": "object", "properties": { @@ -6149,6 +6281,22 @@ } } }, + "internal_api.enabledResponse": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "internal_api.errorResponse": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + }, "internal_api.importRequest": { "type": "object", "required": [ @@ -6212,6 +6360,143 @@ } } }, + "internal_api.ipv6AddressResponse": { + "type": "object", + "properties": { + "ipv6Address": { + "type": "string" + } + } + }, + "internal_api.ipv6StepsResponse": { + "type": "object", + "properties": { + "steps": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.IPv6Step" + } + } + } + }, + "internal_api.itemResponse-oci-portal_internal_model_AiModelBlacklist": { + "type": "object", + "properties": { + "item": { + "$ref": "#/definitions/oci-portal_internal_model.AiModelBlacklist" + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_aiwire_Model": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.Model" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_model_AiChannel": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.AiChannel" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_model_AiKey": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.AiKey" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_model_AiModelBlacklist": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.AiModelBlacklist" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_model_AiModelCache": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.AiModelCache" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_model_UserIdentity": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.UserIdentity" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_service_NotifyChannelView": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.NotifyChannelView" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_service_NotifyTemplateView": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.NotifyTemplateView" + } + } + } + }, + "internal_api.itemsResponse-oci-portal_internal_service_ProxyView": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.ProxyView" + } + } + } + }, + "internal_api.logWebhookStatusResponse": { + "type": "object", + "properties": { + "exists": { + "type": "boolean" + }, + "webhook": { + "$ref": "#/definitions/oci-portal_internal_service.LogWebhookInfo" + } + } + }, "internal_api.loginRequest": { "type": "object", "required": [ @@ -6235,6 +6520,100 @@ } } }, + "internal_api.oauthProvidersResponse": { + "type": "object", + "properties": { + "passwordLoginDisabled": { + "type": "boolean" + }, + "providers": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.ProviderInfo" + } + } + } + }, + "internal_api.pagedResponse-oci-portal_internal_model_AiCallLog": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.AiCallLog" + } + }, + "total": { + "type": "integer" + } + } + }, + "internal_api.pagedResponse-oci-portal_internal_model_AiContentLog": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.AiContentLog" + } + }, + "total": { + "type": "integer" + } + } + }, + "internal_api.pagedResponse-oci-portal_internal_model_LogEvent": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.LogEvent" + } + }, + "total": { + "type": "integer" + } + } + }, + "internal_api.pagedResponse-oci-portal_internal_model_SystemLog": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_model.SystemLog" + } + }, + "total": { + "type": "integer" + } + } + }, + "internal_api.passwordResponse": { + "type": "object", + "properties": { + "password": { + "type": "string" + } + } + }, + "internal_api.publicIpResponse": { + "type": "object", + "properties": { + "publicIp": { + "type": "string" + } + } + }, + "internal_api.rawDetailResponse": { + "type": "object", + "properties": { + "raw": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + } + } + }, "internal_api.renameRequest": { "type": "object", "required": [ @@ -6260,6 +6639,47 @@ } } }, + "internal_api.tokenResponse": { + "type": "object", + "properties": { + "expiresAt": { + "type": "string" + }, + "token": { + "type": "string" + } + } + }, + "internal_api.totpRequiredResponse": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "totpRequired": { + "type": "boolean" + } + } + }, + "internal_api.totpSetupResponse": { + "type": "object", + "properties": { + "otpauthUri": { + "type": "string" + }, + "secret": { + "type": "string" + } + } + }, + "internal_api.triggerResponse": { + "type": "object", + "properties": { + "triggered": { + "type": "boolean" + } + } + }, "internal_api.updateBootVolumeRequest": { "type": "object", "properties": { @@ -6369,10 +6789,7 @@ "type": "string" }, "payload": { - "type": "array", - "items": { - "type": "integer" - } + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" }, "status": { "type": "string" @@ -6416,6 +6833,1927 @@ } } }, + "internal_api.urlResponse": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + } + }, + "internal_api.usedByResponse": { + "type": "object", + "properties": { + "usedBy": { + "type": "integer" + } + } + }, + "internal_api.webConsoleSessionResponse": { + "type": "object", + "properties": { + "sessionId": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.AnthBlock": { + "type": "object", + "properties": { + "content": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "id": { + "description": "tool_use", + "type": "string" + }, + "input": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "is_error": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "source": { + "description": "image", + "allOf": [ + { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + } + ] + }, + "text": { + "type": "string" + }, + "tool_use_id": { + "description": "tool_result", + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.AnthContent": { + "type": "object", + "properties": { + "blocks": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthBlock" + } + }, + "text": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.AnthMessage": { + "type": "object", + "properties": { + "content": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthContent" + }, + "role": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.AnthOutputConfig": { + "type": "object", + "properties": { + "effort": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.AnthTool": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "input_schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "name": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.AnthUsage": { + "type": "object", + "properties": { + "cache_read_input_tokens": { + "description": "CacheReadInputTokens 是缓存命中读取数;OCI 隐式缓存无「写入」计数,cache_creation 恒缺", + "type": "integer" + }, + "input_tokens": { + "type": "integer" + }, + "output_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.AnyJSON": { + "type": "object" + }, + "oci-portal_internal_aiwire.ChatMessage": { + "type": "object", + "properties": { + "content": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "role": { + "type": "string" + }, + "tool_call_id": { + "type": "string" + }, + "tool_calls": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ToolCall" + } + } + } + }, + "oci-portal_internal_aiwire.ChatRequest": { + "type": "object", + "properties": { + "max_completion_tokens": { + "type": "integer" + }, + "max_tokens": { + "type": "integer" + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ChatMessage" + } + }, + "model": { + "type": "string" + }, + "parallel_tool_calls": { + "type": "boolean" + }, + "reasoning_effort": { + "type": "string" + }, + "response_format": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ResponseFormat" + }, + "stream": { + "type": "boolean" + }, + "stream_options": { + "$ref": "#/definitions/oci-portal_internal_aiwire.StreamOptions" + }, + "temperature": { + "type": "number" + }, + "tool_choice": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "tools": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.Tool" + } + }, + "top_p": { + "type": "number" + } + } + }, + "oci-portal_internal_aiwire.ChatResponse": { + "type": "object", + "properties": { + "choices": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.Choice" + } + }, + "created": { + "type": "integer" + }, + "id": { + "type": "string" + }, + "model": { + "type": "string" + }, + "object": { + "type": "string" + }, + "usage": { + "$ref": "#/definitions/oci-portal_internal_aiwire.Usage" + } + } + }, + "oci-portal_internal_aiwire.Choice": { + "type": "object", + "properties": { + "finish_reason": { + "type": "string" + }, + "index": { + "type": "integer" + }, + "message": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ChatMessage" + } + } + }, + "oci-portal_internal_aiwire.EmbedUsage": { + "type": "object", + "properties": { + "prompt_tokens": { + "type": "integer" + }, + "total_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.Embedding": { + "type": "object", + "properties": { + "embedding": { + "type": "array", + "items": { + "type": "number" + } + }, + "index": { + "type": "integer" + }, + "object": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.EmbeddingsRequest": { + "type": "object", + "properties": { + "dimensions": { + "type": "integer" + }, + "encoding_format": { + "type": "string" + }, + "input": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "model": { + "type": "string" + }, + "user": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.EmbeddingsResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.Embedding" + } + }, + "model": { + "type": "string" + }, + "object": { + "type": "string" + }, + "usage": { + "$ref": "#/definitions/oci-portal_internal_aiwire.EmbedUsage" + } + } + }, + "oci-portal_internal_aiwire.FunctionCall": { + "type": "object", + "properties": { + "arguments": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.FunctionDef": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "parameters": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + } + } + }, + "oci-portal_internal_aiwire.MessagesRequest": { + "type": "object", + "properties": { + "max_tokens": { + "type": "integer" + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthMessage" + } + }, + "metadata": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "model": { + "type": "string" + }, + "output_config": { + "description": "OutputConfig 是 Anthropic 官方输出控制(effort 等);网关映射 effort 到 OCI reasoningEffort。", + "allOf": [ + { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthOutputConfig" + } + ] + }, + "stop_sequences": { + "type": "array", + "items": { + "type": "string" + } + }, + "stream": { + "type": "boolean" + }, + "system": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "temperature": { + "type": "number" + }, + "thinking": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "tool_choice": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "tools": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthTool" + } + }, + "top_k": { + "type": "integer" + }, + "top_p": { + "type": "number" + } + } + }, + "oci-portal_internal_aiwire.MessagesResponse": { + "type": "object", + "properties": { + "content": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthBlock" + } + }, + "id": { + "type": "string" + }, + "model": { + "type": "string" + }, + "role": { + "type": "string" + }, + "stop_reason": { + "type": "string" + }, + "stop_sequence": { + "type": "string" + }, + "type": { + "type": "string" + }, + "usage": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnthUsage" + } + } + }, + "oci-portal_internal_aiwire.Model": { + "type": "object", + "properties": { + "created": { + "type": "integer" + }, + "id": { + "type": "string" + }, + "object": { + "type": "string" + }, + "owned_by": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.ModelList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.Model" + } + }, + "object": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.ModerationPii": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "length": { + "type": "integer" + }, + "offset": { + "type": "integer" + }, + "score": { + "type": "number" + }, + "text": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.ModerationResult": { + "type": "object", + "properties": { + "categories": { + "type": "object", + "additionalProperties": { + "type": "boolean" + } + }, + "category_scores": { + "type": "object", + "additionalProperties": { + "type": "number", + "format": "float64" + } + }, + "flagged": { + "type": "boolean" + }, + "pii": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ModerationPii" + } + } + } + }, + "oci-portal_internal_aiwire.ModerationsRequest": { + "type": "object", + "properties": { + "input": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "model": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.ModerationsResponse": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "model": { + "type": "string" + }, + "results": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.ModerationResult" + } + } + } + }, + "oci-portal_internal_aiwire.PromptTokensDetails": { + "type": "object", + "properties": { + "cached_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.RerankDocument": { + "type": "object", + "properties": { + "text": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.RerankRequest": { + "type": "object", + "properties": { + "documents": { + "type": "array", + "items": { + "type": "string" + } + }, + "model": { + "type": "string" + }, + "query": { + "type": "string" + }, + "return_documents": { + "type": "boolean" + }, + "top_n": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.RerankResponse": { + "type": "object", + "properties": { + "model": { + "type": "string" + }, + "results": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RerankResult" + } + } + } + }, + "oci-portal_internal_aiwire.RerankResult": { + "type": "object", + "properties": { + "document": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RerankDocument" + }, + "index": { + "type": "integer" + }, + "relevance_score": { + "type": "number" + } + } + }, + "oci-portal_internal_aiwire.RespError": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.RespInDetails": { + "type": "object", + "properties": { + "cached_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.RespOutDetails": { + "type": "object", + "properties": { + "reasoning_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.RespReasoning": { + "type": "object", + "properties": { + "effort": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.RespRequest": { + "type": "object", + "properties": { + "background": { + "type": "boolean" + }, + "conversation": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "input": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "instructions": { + "type": "string" + }, + "max_output_tokens": { + "type": "integer" + }, + "model": { + "type": "string" + }, + "parallel_tool_calls": { + "type": "boolean" + }, + "previous_response_id": { + "type": "string" + }, + "reasoning": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespReasoning" + }, + "store": { + "type": "boolean" + }, + "stream": { + "type": "boolean" + }, + "temperature": { + "type": "number" + }, + "text": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespText" + }, + "tool_choice": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "tools": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespTool" + } + }, + "top_p": { + "type": "number" + } + } + }, + "oci-portal_internal_aiwire.RespResponse": { + "type": "object", + "properties": { + "created_at": { + "type": "integer" + }, + "error": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespError" + }, + "id": { + "type": "string" + }, + "model": { + "type": "string" + }, + "object": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "status": { + "type": "string" + }, + "usage": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespUsage" + } + } + }, + "oci-portal_internal_aiwire.RespText": { + "type": "object", + "properties": { + "format": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespTextFormat" + } + } + }, + "oci-portal_internal_aiwire.RespTextFormat": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "strict": { + "type": "boolean" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.RespTool": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "parameters": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "strict": { + "type": "boolean" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.RespUsage": { + "type": "object", + "properties": { + "input_tokens": { + "type": "integer" + }, + "input_tokens_details": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespInDetails" + }, + "output_tokens": { + "type": "integer" + }, + "output_tokens_details": { + "$ref": "#/definitions/oci-portal_internal_aiwire.RespOutDetails" + }, + "total_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_aiwire.ResponseFormat": { + "type": "object", + "properties": { + "json_schema": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.SpeechRequest": { + "type": "object", + "properties": { + "input": { + "type": "string" + }, + "language": { + "type": "string" + }, + "model": { + "type": "string" + }, + "response_format": { + "type": "string" + }, + "voice": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.StreamOptions": { + "type": "object", + "properties": { + "include_usage": { + "type": "boolean" + } + } + }, + "oci-portal_internal_aiwire.Tool": { + "type": "object", + "properties": { + "function": { + "$ref": "#/definitions/oci-portal_internal_aiwire.FunctionDef" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.ToolCall": { + "type": "object", + "properties": { + "function": { + "$ref": "#/definitions/oci-portal_internal_aiwire.FunctionCall" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_aiwire.Usage": { + "type": "object", + "properties": { + "completion_tokens": { + "type": "integer" + }, + "prompt_tokens": { + "type": "integer" + }, + "prompt_tokens_details": { + "description": "PromptTokensDetails 携带缓存命中细分;OCI 为隐式 prompt 缓存,只有读取计数", + "allOf": [ + { + "$ref": "#/definitions/oci-portal_internal_aiwire.PromptTokensDetails" + } + ] + }, + "total_tokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_model.AiCallLog": { + "type": "object", + "properties": { + "cachedTokens": { + "description": "CachedTokens 是输入中缓存命中(读取)的部分;OCI 隐式缓存无写入计数", + "type": "integer" + }, + "channelId": { + "type": "integer" + }, + "channelName": { + "type": "string" + }, + "clientIp": { + "description": "ClientIP 是网关调用方来源 IP(尊重「真实 IP 头」安全设置,与系统日志同源)", + "type": "string" + }, + "completionTokens": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "endpoint": { + "description": "openai / anthropic", + "type": "string" + }, + "errMsg": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "keyId": { + "type": "integer" + }, + "keyName": { + "type": "string" + }, + "latencyMs": { + "type": "integer" + }, + "model": { + "type": "string" + }, + "promptTokens": { + "type": "integer" + }, + "retries": { + "type": "integer" + }, + "status": { + "type": "integer" + }, + "stream": { + "type": "boolean" + }, + "totalTokens": { + "type": "integer" + } + } + }, + "oci-portal_internal_model.AiChannel": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "disabledUntil": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "failCount": { + "description": "FailCount 连续失败计数;达阈值后 DisabledUntil 指数退避熔断,成功/探测通过复位", + "type": "integer" + }, + "group": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "lastProbeAt": { + "type": "string" + }, + "name": { + "type": "string" + }, + "ociConfigId": { + "type": "integer" + }, + "priority": { + "type": "integer" + }, + "probeError": { + "type": "string" + }, + "probeStatus": { + "description": "ok / no_service / no_quota / error", + "type": "string" + }, + "region": { + "type": "string" + }, + "updatedAt": { + "type": "string" + }, + "weight": { + "type": "integer" + } + } + }, + "oci-portal_internal_model.AiContentLog": { + "type": "object", + "properties": { + "callLogId": { + "description": "CallLogID 关联同次调用的 AiCallLog,调用日志详情据此反查正文", + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "keyId": { + "type": "integer" + }, + "keyName": { + "type": "string" + }, + "model": { + "type": "string" + }, + "requestBody": { + "description": "RequestBody / ResponseBody 是截断后的正文 JSON;\n64KB 截断恰在 MySQL TEXT 上限(65535B)边界,size 上探一档 → MEDIUMTEXT", + "type": "string" + }, + "responseBody": { + "type": "string" + }, + "stream": { + "type": "boolean" + } + } + }, + "oci-portal_internal_model.AiKey": { + "type": "object", + "properties": { + "contentLogUntil": { + "description": "ContentLogUntil 是内容日志开启截止时间;nil = 永关(默认,红线),\n开启必须限时,到期自动停写", + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "group": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "lastUsedAt": { + "type": "string" + }, + "models": { + "description": "Models 是模型白名单(精确匹配模型名);空 = 不限,非空时网关仅放行列表内模型", + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": "string" + }, + "tail": { + "type": "string" + } + } + }, + "oci-portal_internal_model.AiModelBlacklist": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + } + }, + "oci-portal_internal_model.AiModelCache": { + "type": "object", + "properties": { + "capability": { + "type": "string" + }, + "channelId": { + "type": "integer" + }, + "deprecatedAt": { + "description": "DeprecatedAt 是 OCI 宣布的模型弃用时间;nil 表示未宣布。\n弃用后仍可调用,直到 RetiredAt(按需推理退役,同步层已剔除过期项)。", + "type": "string" + }, + "modelOcid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "retiredAt": { + "type": "string" + }, + "syncedAt": { + "type": "string" + }, + "vendor": { + "type": "string" + } + } + }, + "oci-portal_internal_model.LogEvent": { + "type": "object", + "properties": { + "eventTime": { + "type": "string" + }, + "eventType": { + "description": "异步解析回填,如 com.oraclecloud.ComputeApi.TerminateInstance", + "type": "string" + }, + "id": { + "type": "integer" + }, + "messageId": { + "description": "幂等键(X-OCI-NS-MessageId)", + "type": "string" + }, + "ociConfigId": { + "description": "经 secret 反查归属租户", + "type": "integer" + }, + "payload": { + "description": "防御上限 256KB 超 MySQL TEXT(64KB),size 上探一档 → MEDIUMTEXT;PG/SQLite 仍为 text", + "type": "string" + }, + "processed": { + "type": "boolean" + }, + "receivedAt": { + "type": "string" + }, + "source": { + "type": "string" + }, + "sourceIp": { + "description": "异步解析回填,Audit 事件的发起方 IP", + "type": "string" + }, + "truncated": { + "type": "boolean" + } + } + }, + "oci-portal_internal_model.OciConfig": { + "type": "object", + "properties": { + "accountType": { + "type": "string" + }, + "alias": { + "type": "string" + }, + "aliveStatus": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "fingerprint": { + "type": "string" + }, + "group": { + "description": "Group 是面板内的自定义分组标签,空串表示未分组;\n列名避开 SQL 保留字 GROUP", + "type": "string" + }, + "homeRegionKey": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "lastError": { + "type": "string" + }, + "lastVerifiedAt": { + "type": "string" + }, + "multiCompartment": { + "type": "boolean" + }, + "multiRegion": { + "description": "多区域 / 多区间支持:开启后订阅区域与 compartment 列表入库缓存,\n供筛选器免实时调 OCI;未开启的租户筛选器锁定主区域 / 根区间。", + "type": "boolean" + }, + "paymentModel": { + "type": "string" + }, + "promotionAmount": { + "type": "number" + }, + "promotionExpires": { + "type": "string" + }, + "promotionStatus": { + "type": "string" + }, + "proxyId": { + "description": "ProxyID 关联出站代理,nil 表示直连;该租户全部 SDK 调用经此代理", + "type": "integer" + }, + "region": { + "type": "string" + }, + "subscriptionId": { + "type": "string" + }, + "subscriptionTier": { + "type": "string" + }, + "tenancyName": { + "type": "string" + }, + "tenancyOcid": { + "type": "string" + }, + "updatedAt": { + "type": "string" + }, + "userOcid": { + "type": "string" + } + } + }, + "oci-portal_internal_model.SystemLog": { + "type": "object", + "properties": { + "clientIp": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "durationMs": { + "type": "integer" + }, + "errMsg": { + "description": "ErrMsg 仅失败请求(\u003e=400)存响应的 error 文案,便于免翻服务端日志定位原因", + "type": "string" + }, + "id": { + "type": "integer" + }, + "method": { + "type": "string" + }, + "path": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "userAgent": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "oci-portal_internal_model.Task": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "cronExpr": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "lastError": { + "type": "string" + }, + "lastRunAt": { + "type": "string" + }, + "name": { + "type": "string" + }, + "payload": { + "type": "string" + }, + "runCount": { + "type": "integer" + }, + "status": { + "type": "string" + }, + "type": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "oci-portal_internal_model.TaskLog": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "durationMs": { + "type": "integer" + }, + "id": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + }, + "taskId": { + "type": "integer" + } + } + }, + "oci-portal_internal_model.UserIdentity": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "display": { + "description": "展示名:邮箱 / GitHub login", + "type": "string" + }, + "id": { + "type": "integer" + }, + "provider": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.AuditEvent": { + "type": "object", + "properties": { + "compartmentName": { + "type": "string" + }, + "eventId": { + "type": "string" + }, + "eventName": { + "type": "string" + }, + "eventTime": { + "type": "string" + }, + "ipAddress": { + "type": "string" + }, + "principalName": { + "type": "string" + }, + "raw": { + "$ref": "#/definitions/oci-portal_internal_aiwire.AnyJSON" + }, + "requestAction": { + "type": "string" + }, + "requestPath": { + "type": "string" + }, + "resourceName": { + "type": "string" + }, + "source": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.BlockVolume": { + "type": "object", + "properties": { + "availabilityDomain": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "id": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + }, + "sizeInGBs": { + "type": "integer" + }, + "timeCreated": { + "type": "string" + }, + "vpusPerGB": { + "type": "integer" + } + } + }, + "oci-portal_internal_oci.BootVolume": { + "type": "object", + "properties": { + "attachedInstanceId": { + "type": "string" + }, + "attachedInstanceName": { + "type": "string" + }, + "availabilityDomain": { + "type": "string" + }, + "compartmentId": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "id": { + "type": "string" + }, + "imageId": { + "type": "string" + }, + "imageName": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + }, + "sizeInGBs": { + "type": "integer" + }, + "timeCreated": { + "type": "string" + }, + "vpusPerGB": { + "type": "integer" + } + } + }, + "oci-portal_internal_oci.BootVolumeAttachment": { + "type": "object", + "properties": { + "availabilityDomain": { + "type": "string" + }, + "bootVolumeId": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "id": { + "type": "string" + }, + "instanceId": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.Compartment": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + }, + "name": { + "type": "string" + }, + "parentId": { + "type": "string" + }, + "timeCreated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.ComputeShape": { + "type": "object", + "properties": { + "billingType": { + "description": "ALWAYS_FREE / LIMITED_FREE / PAID", + "type": "string" + }, + "gpus": { + "type": "integer" + }, + "isFlexible": { + "type": "boolean" + }, + "memoryInGBs": { + "type": "number" + }, + "memoryMaxGBs": { + "type": "number" + }, + "memoryMinGBs": { + "type": "number" + }, + "name": { + "type": "string" + }, + "ocpus": { + "type": "number" + }, + "ocpusMax": { + "type": "number" + }, + "ocpusMin": { + "type": "number" + }, + "processorDescription": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.ConsoleConnection": { + "type": "object", + "properties": { + "connectionString": { + "description": "串口控制台 SSH 命令", + "type": "string" + }, + "id": { + "type": "string" + }, + "instanceId": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + }, + "vncConnectionString": { + "description": "VNC over SSH 隧道命令", + "type": "string" + } + } + }, + "oci-portal_internal_oci.CostItem": { + "type": "object", + "properties": { + "computedAmount": { + "type": "number" + }, + "computedQuantity": { + "type": "number" + }, + "currency": { + "type": "string" + }, + "groupValue": { + "type": "string" + }, + "timeStart": { + "type": "string" + }, + "unit": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.IPv6Step": { + "type": "object", + "properties": { + "detail": { + "type": "string" + }, + "status": { + "description": "done / skipped / failed", + "type": "string" + }, + "step": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.IdentityDomain": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "homeRegion": { + "type": "string" + }, + "id": { + "type": "string" + }, + "licenseType": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.IdentityProviderInfo": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "jitEnabled": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "partnerProviderId": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.IdentitySettingInfo": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "primaryEmailRequired": { + "description": "用户需要提供主电子邮件地址:开启后创建用户 / JIT 预配必须带邮箱", + "type": "boolean" + } + } + }, + "oci-portal_internal_oci.Image": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "id": { + "type": "string" + }, + "operatingSystem": { + "type": "string" + }, + "operatingSystemVersion": { + "type": "string" + }, + "sizeInMBs": { + "type": "integer" + }, + "timeCreated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.Instance": { + "type": "object", + "properties": { + "availabilityDomain": { + "type": "string" + }, + "compartmentId": { + "type": "string" + }, + "definedTags": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": {} + } + }, + "displayName": { + "type": "string" + }, + "freeformTags": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "imageId": { + "type": "string" + }, + "ipv6Addresses": { + "type": "array", + "items": { + "type": "string" + } + }, + "lifecycleState": { + "type": "string" + }, + "memoryInGBs": { + "type": "number" + }, + "ocpus": { + "type": "number" + }, + "privateIp": { + "type": "string" + }, + "publicIp": { + "type": "string" + }, + "region": { + "type": "string" + }, + "shape": { + "type": "string" + }, + "subnetId": { + "type": "string" + }, + "timeCreated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.InstanceTraffic": { + "type": "object", + "properties": { + "inboundBytes": { + "type": "number" + }, + "instanceId": { + "type": "string" + }, + "outboundBytes": { + "type": "number" + }, + "vnics": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.VnicTraffic" + } + } + } + }, + "oci-portal_internal_oci.LimitService": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.LimitValue": { + "type": "object", + "properties": { + "availabilityDomain": { + "type": "string" + }, + "available": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "scopeType": { + "type": "string" + }, + "used": { + "type": "integer" + }, + "value": { + "type": "integer" + } + } + }, + "oci-portal_internal_oci.NotificationRecipients": { + "type": "object", + "properties": { + "recipients": { + "type": "array", + "items": { + "type": "string" + } + }, + "testModeEnabled": { + "type": "boolean" + } + } + }, + "oci-portal_internal_oci.PasswordPolicyInfo": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "minLength": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "numPasswordsInHistory": { + "type": "integer" + }, + "passwordExpiresAfter": { + "type": "integer" + }, + "passwordStrength": { + "type": "string" + }, + "priority": { + "type": "integer" + } + } + }, + "oci-portal_internal_oci.PromotionInfo": { + "type": "object", + "properties": { + "amount": { + "type": "number" + }, + "currencyUnit": { + "type": "string" + }, + "duration": { + "type": "integer" + }, + "durationUnit": { + "type": "string" + }, + "isIntentToPay": { + "type": "boolean" + }, + "status": { + "type": "string" + }, + "timeExpired": { + "type": "string" + }, + "timeStarted": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.RegionInfo": { + "type": "object", + "properties": { + "alias": { + "type": "string" + }, + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.RelayResource": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "state": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.SecurityList": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "egressRules": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.SecurityRule" + } + }, + "id": { + "type": "string" + }, + "ingressRules": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.SecurityRule" + } + }, + "lifecycleState": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "vcnId": { + "type": "string" + } + } + }, "oci-portal_internal_oci.SecurityRule": { "type": "object", "properties": { @@ -6449,6 +8787,379 @@ } } }, + "oci-portal_internal_oci.SignOnRuleInfo": { + "type": "object", + "properties": { + "authenticationFactor": { + "type": "string" + }, + "builtIn": { + "type": "boolean" + }, + "conditionAttribute": { + "type": "string" + }, + "conditionValue": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "sequence": { + "type": "integer" + } + } + }, + "oci-portal_internal_oci.Subnet": { + "type": "object", + "properties": { + "availabilityDomain": { + "type": "string" + }, + "cidrBlock": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "dnsLabel": { + "type": "string" + }, + "id": { + "type": "string" + }, + "ipv6CidrBlock": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + }, + "prohibitPublicIp": { + "type": "boolean" + }, + "routeTableId": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "vcnId": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.SubscriptionDetail": { + "type": "object", + "properties": { + "classicSubscriptionId": { + "type": "string" + }, + "cloudAmountCurrency": { + "type": "string" + }, + "csiNumber": { + "type": "string" + }, + "customerCountryCode": { + "type": "string" + }, + "endDate": { + "type": "string" + }, + "id": { + "type": "string" + }, + "isGovernmentSubscription": { + "type": "boolean" + }, + "lifecycleState": { + "type": "string" + }, + "paymentModel": { + "type": "string" + }, + "programType": { + "type": "string" + }, + "promotions": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.PromotionInfo" + } + }, + "regionAssignment": { + "type": "string" + }, + "serviceName": { + "type": "string" + }, + "startDate": { + "type": "string" + }, + "subscriptionTier": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "timeUpdated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.SubscriptionInfo": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "serviceName": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "timeUpdated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.TenantUser": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "email": { + "type": "string" + }, + "emailVerified": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "isCurrentUser": { + "type": "boolean" + }, + "lastLoginTime": { + "type": "string" + }, + "lifecycleState": { + "type": "string" + }, + "mfaActivated": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "timeCreated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.TenantUserDetail": { + "type": "object", + "properties": { + "familyName": { + "type": "string" + }, + "givenName": { + "type": "string" + }, + "inAdminGroup": { + "type": "boolean" + }, + "inDomain": { + "type": "boolean" + }, + "isDomainAdmin": { + "type": "boolean" + } + } + }, + "oci-portal_internal_oci.TrafficPoint": { + "type": "object", + "properties": { + "bytes": { + "type": "number" + }, + "timestamp": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.VCN": { + "type": "object", + "properties": { + "cidrBlocks": { + "type": "array", + "items": { + "type": "string" + } + }, + "compartmentId": { + "type": "string" + }, + "defaultRouteTableId": { + "type": "string" + }, + "defaultSecurityListId": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "dnsLabel": { + "type": "string" + }, + "id": { + "type": "string" + }, + "ipv6CidrBlocks": { + "type": "array", + "items": { + "type": "string" + } + }, + "lifecycleState": { + "type": "string" + }, + "timeCreated": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.Vnic": { + "type": "object", + "properties": { + "attachmentId": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "ipv6Addresses": { + "type": "array", + "items": { + "type": "string" + } + }, + "isPrimary": { + "type": "boolean" + }, + "lifecycleState": { + "type": "string" + }, + "privateIp": { + "type": "string" + }, + "publicIp": { + "type": "string" + }, + "subnetId": { + "type": "string" + }, + "subnetName": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "vnicId": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.VnicTraffic": { + "type": "object", + "properties": { + "inbound": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.TrafficPoint" + } + }, + "inboundBytes": { + "type": "number" + }, + "outbound": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.TrafficPoint" + } + }, + "outboundBytes": { + "type": "number" + }, + "vnicId": { + "type": "string" + } + } + }, + "oci-portal_internal_oci.VolumeAttachment": { + "type": "object", + "properties": { + "availabilityDomain": { + "type": "string" + }, + "device": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "id": { + "type": "string" + }, + "instanceId": { + "type": "string" + }, + "isReadOnly": { + "type": "boolean" + }, + "lifecycleState": { + "type": "string" + }, + "volumeId": { + "type": "string" + }, + "volumeName": { + "description": "卷本身的名称(attachment 名是自动生成的)", + "type": "string" + } + } + }, + "oci-portal_internal_service.AuditEventsView": { + "type": "object", + "properties": { + "cursor": { + "type": "string" + }, + "exhausted": { + "type": "boolean" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_oci.AuditEvent" + } + } + } + }, + "oci-portal_internal_service.Changes": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, "oci-portal_internal_service.ChannelInput": { "type": "object", "properties": { @@ -6475,6 +9186,150 @@ } } }, + "oci-portal_internal_service.ConfigSummary": { + "type": "object", + "properties": { + "accountType": { + "type": "string" + }, + "alias": { + "type": "string" + }, + "aliveStatus": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "group": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "lastError": { + "type": "string" + }, + "lastVerifiedAt": { + "type": "string" + }, + "multiCompartment": { + "type": "boolean" + }, + "multiRegion": { + "type": "boolean" + }, + "proxyId": { + "type": "integer" + }, + "proxyName": { + "description": "ProxyName 由 List 按关联填充,供表格代理列 hover 展示", + "type": "string" + }, + "region": { + "type": "string" + }, + "tenancyName": { + "type": "string" + }, + "tenancyOcid": { + "type": "string" + } + } + }, + "oci-portal_internal_service.ImportFail": { + "type": "object", + "properties": { + "line": { + "type": "string" + }, + "lineNo": { + "type": "integer" + }, + "reason": { + "type": "string" + } + } + }, + "oci-portal_internal_service.ImportResult": { + "type": "object", + "properties": { + "created": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.ProxyView" + } + }, + "failed": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.ImportFail" + } + } + } + }, + "oci-portal_internal_service.LogWebhookInfo": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "path": { + "type": "string" + }, + "secret": { + "type": "string" + } + } + }, + "oci-portal_internal_service.NotifyChannelView": { + "type": "object", + "properties": { + "bodyTemplate": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "from": { + "type": "string" + }, + "host": { + "description": "smtp", + "type": "string" + }, + "port": { + "type": "integer" + }, + "secretSet": { + "description": "密文字段状态(ntfy token / bark device key / smtp password)", + "type": "boolean" + }, + "secretTail": { + "type": "string" + }, + "server": { + "description": "ntfy / bark 共用 Server", + "type": "string" + }, + "to": { + "type": "string" + }, + "topic": { + "type": "string" + }, + "type": { + "type": "string" + }, + "url": { + "description": "webhook", + "type": "string" + }, + "username": { + "type": "string" + } + } + }, "oci-portal_internal_service.NotifyEventsView": { "type": "object", "properties": { @@ -6516,6 +9371,30 @@ } } }, + "oci-portal_internal_service.NotifyTemplateView": { + "type": "object", + "properties": { + "defaultTemplate": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "label": { + "type": "string" + }, + "template": { + "description": "Template 是自定义模板;空串表示未自定义(按默认发送)", + "type": "string" + }, + "vars": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "oci-portal_internal_service.OAuthProvidersView": { "type": "object", "properties": { @@ -6548,6 +9427,128 @@ } } }, + "oci-portal_internal_service.Overview": { + "type": "object", + "properties": { + "check": { + "$ref": "#/definitions/oci-portal_internal_service.OverviewCheck" + }, + "cost": { + "$ref": "#/definitions/oci-portal_internal_service.OverviewCost" + }, + "tasks": { + "$ref": "#/definitions/oci-portal_internal_service.OverviewTasks" + }, + "tenants": { + "$ref": "#/definitions/oci-portal_internal_service.OverviewTenants" + } + } + }, + "oci-portal_internal_service.OverviewCheck": { + "type": "object", + "properties": { + "coveredConfigs": { + "type": "integer" + }, + "hasActiveTask": { + "type": "boolean" + }, + "instanceCount": { + "type": "integer" + }, + "lastCheckedAt": { + "type": "string" + }, + "totalConfigs": { + "type": "integer" + } + } + }, + "oci-portal_internal_service.OverviewCost": { + "type": "object", + "properties": { + "coveredConfigs": { + "type": "integer" + }, + "currency": { + "type": "string" + }, + "days": { + "type": "array", + "items": { + "$ref": "#/definitions/oci-portal_internal_service.OverviewCostDay" + } + }, + "hasActiveTask": { + "type": "boolean" + }, + "total": { + "type": "number" + } + } + }, + "oci-portal_internal_service.OverviewCostDay": { + "type": "object", + "properties": { + "amount": { + "type": "number" + }, + "day": { + "type": "string" + } + } + }, + "oci-portal_internal_service.OverviewTasks": { + "type": "object", + "properties": { + "active": { + "type": "integer" + }, + "cost": { + "type": "integer" + }, + "healthCheck": { + "type": "integer" + }, + "snatch": { + "type": "integer" + }, + "total": { + "type": "integer" + } + } + }, + "oci-portal_internal_service.OverviewTenants": { + "type": "object", + "properties": { + "alive": { + "type": "integer" + }, + "byType": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "dead": { + "type": "integer" + }, + "total": { + "type": "integer" + } + } + }, + "oci-portal_internal_service.ProviderInfo": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "provider": { + "type": "string" + } + } + }, "oci-portal_internal_service.ProxyInput": { "type": "object", "required": [ @@ -6576,6 +9577,101 @@ } } }, + "oci-portal_internal_service.ProxyView": { + "type": "object", + "properties": { + "city": { + "type": "string" + }, + "country": { + "description": "Country / City 为出口实测地区;GeoAt 空串表示尚未探测(前端显示「检测中」)", + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "geoAt": { + "type": "string" + }, + "host": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "passwordSet": { + "type": "boolean" + }, + "port": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "usedBy": { + "description": "UsedBy 为关联此代理的租户数,前端据此提示删除约束", + "type": "integer" + }, + "username": { + "type": "string" + } + } + }, + "oci-portal_internal_service.RegionSubscriptionView": { + "type": "object", + "properties": { + "alias": { + "type": "string" + }, + "isHomeRegion": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "oci-portal_internal_service.RelayView": { + "type": "object", + "properties": { + "connector": { + "$ref": "#/definitions/oci-portal_internal_oci.RelayResource" + }, + "endpoint": { + "type": "string" + }, + "events": { + "type": "array", + "items": { + "type": "string" + } + }, + "policy": { + "$ref": "#/definitions/oci-portal_internal_oci.RelayResource" + }, + "ready": { + "type": "boolean" + }, + "subscription": { + "$ref": "#/definitions/oci-portal_internal_oci.RelayResource" + }, + "topic": { + "$ref": "#/definitions/oci-portal_internal_oci.RelayResource" + }, + "webhook": { + "$ref": "#/definitions/oci-portal_internal_service.LogWebhookInfo" + } + } + }, "oci-portal_internal_service.SecuritySettings": { "type": "object", "properties": { @@ -6611,6 +9707,23 @@ } } }, + "oci-portal_internal_service.TelegramView": { + "type": "object", + "properties": { + "chatId": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "tokenSet": { + "type": "boolean" + }, + "tokenTail": { + "type": "string" + } + } + }, "oci-portal_internal_service.UpdateCredentialsInput": { "type": "object", "required": [ diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 636a6c5..51f46d9 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,5 +1,51 @@ basePath: / definitions: + internal_api.aboutResources: + properties: + cpuAvgPercent: + type: number + dbBytes: + type: integer + dbEngine: + type: string + goroutines: + type: integer + memHeapBytes: + type: integer + memSysBytes: + type: integer + numCpu: + type: integer + type: object + internal_api.aboutResponse: + properties: + buildTime: + type: string + goVersion: + type: string + platform: + type: string + resources: + $ref: '#/definitions/internal_api.aboutResources' + startedAt: + type: string + uptimeSeconds: + type: integer + version: + type: string + type: object + internal_api.addressResponse: + properties: + address: + type: string + type: object + internal_api.aiKeyCreateResponse: + properties: + item: + $ref: '#/definitions/oci-portal_internal_model.AiKey' + key: + type: string + type: object internal_api.attachBootVolumeRequest: properties: bootVolumeId: @@ -38,6 +84,13 @@ definitions: required: - volumeId type: object + internal_api.configChangesResponse: + properties: + changes: + $ref: '#/definitions/oci-portal_internal_service.Changes' + config: + $ref: '#/definitions/oci-portal_internal_model.OciConfig' + type: object internal_api.createConsoleConnectionRequest: properties: region: @@ -126,6 +179,17 @@ definitions: - displayName - shape type: object + internal_api.createInstancesResponse: + properties: + errors: + items: + type: string + type: array + instances: + items: + $ref: '#/definitions/oci-portal_internal_oci.Instance' + type: array + type: object internal_api.createSecurityListRequest: properties: displayName: @@ -174,9 +238,7 @@ definitions: name: type: string payload: - items: - type: integer - type: array + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' type: type: string required: @@ -226,11 +288,38 @@ definitions: - cidrBlock - displayName type: object + internal_api.credentialsResponse: + properties: + passwordLoginDisabled: + type: boolean + username: + type: string + type: object + internal_api.deletedApiKeysResponse: + properties: + deletedApiKeys: + type: integer + type: object + internal_api.deletedTotpResponse: + properties: + deletedTotpDevices: + type: integer + type: object internal_api.enableIPv6Request: properties: region: type: string type: object + internal_api.enabledResponse: + properties: + enabled: + type: boolean + type: object + internal_api.errorResponse: + properties: + error: + type: string + type: object internal_api.importRequest: properties: alias: @@ -274,6 +363,93 @@ definitions: required: - action type: object + internal_api.ipv6AddressResponse: + properties: + ipv6Address: + type: string + type: object + internal_api.ipv6StepsResponse: + properties: + steps: + items: + $ref: '#/definitions/oci-portal_internal_oci.IPv6Step' + type: array + type: object + internal_api.itemResponse-oci-portal_internal_model_AiModelBlacklist: + properties: + item: + $ref: '#/definitions/oci-portal_internal_model.AiModelBlacklist' + type: object + internal_api.itemsResponse-oci-portal_internal_aiwire_Model: + properties: + items: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.Model' + type: array + type: object + internal_api.itemsResponse-oci-portal_internal_model_AiChannel: + properties: + items: + items: + $ref: '#/definitions/oci-portal_internal_model.AiChannel' + type: array + type: object + internal_api.itemsResponse-oci-portal_internal_model_AiKey: + properties: + items: + items: + $ref: '#/definitions/oci-portal_internal_model.AiKey' + type: array + type: object + internal_api.itemsResponse-oci-portal_internal_model_AiModelBlacklist: + properties: + items: + items: + $ref: '#/definitions/oci-portal_internal_model.AiModelBlacklist' + type: array + type: object + internal_api.itemsResponse-oci-portal_internal_model_AiModelCache: + properties: + items: + items: + $ref: '#/definitions/oci-portal_internal_model.AiModelCache' + type: array + type: object + internal_api.itemsResponse-oci-portal_internal_model_UserIdentity: + properties: + items: + items: + $ref: '#/definitions/oci-portal_internal_model.UserIdentity' + type: array + type: object + internal_api.itemsResponse-oci-portal_internal_service_NotifyChannelView: + properties: + items: + items: + $ref: '#/definitions/oci-portal_internal_service.NotifyChannelView' + type: array + type: object + internal_api.itemsResponse-oci-portal_internal_service_NotifyTemplateView: + properties: + items: + items: + $ref: '#/definitions/oci-portal_internal_service.NotifyTemplateView' + type: array + type: object + internal_api.itemsResponse-oci-portal_internal_service_ProxyView: + properties: + items: + items: + $ref: '#/definitions/oci-portal_internal_service.ProxyView' + type: array + type: object + internal_api.logWebhookStatusResponse: + properties: + exists: + type: boolean + webhook: + $ref: '#/definitions/oci-portal_internal_service.LogWebhookInfo' + type: object internal_api.loginRequest: properties: password: @@ -291,6 +467,66 @@ definitions: - password - username type: object + internal_api.oauthProvidersResponse: + properties: + passwordLoginDisabled: + type: boolean + providers: + items: + $ref: '#/definitions/oci-portal_internal_service.ProviderInfo' + type: array + type: object + internal_api.pagedResponse-oci-portal_internal_model_AiCallLog: + properties: + items: + items: + $ref: '#/definitions/oci-portal_internal_model.AiCallLog' + type: array + total: + type: integer + type: object + internal_api.pagedResponse-oci-portal_internal_model_AiContentLog: + properties: + items: + items: + $ref: '#/definitions/oci-portal_internal_model.AiContentLog' + type: array + total: + type: integer + type: object + internal_api.pagedResponse-oci-portal_internal_model_LogEvent: + properties: + items: + items: + $ref: '#/definitions/oci-portal_internal_model.LogEvent' + type: array + total: + type: integer + type: object + internal_api.pagedResponse-oci-portal_internal_model_SystemLog: + properties: + items: + items: + $ref: '#/definitions/oci-portal_internal_model.SystemLog' + type: array + total: + type: integer + type: object + internal_api.passwordResponse: + properties: + password: + type: string + type: object + internal_api.publicIpResponse: + properties: + publicIp: + type: string + type: object + internal_api.rawDetailResponse: + properties: + raw: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + type: object internal_api.renameRequest: properties: displayName: @@ -307,6 +543,32 @@ definitions: required: - regionKey type: object + internal_api.tokenResponse: + properties: + expiresAt: + type: string + token: + type: string + type: object + internal_api.totpRequiredResponse: + properties: + error: + type: string + totpRequired: + type: boolean + type: object + internal_api.totpSetupResponse: + properties: + otpauthUri: + type: string + secret: + type: string + type: object + internal_api.triggerResponse: + properties: + triggered: + type: boolean + type: object internal_api.updateBootVolumeRequest: properties: displayName: @@ -379,9 +641,7 @@ definitions: name: type: string payload: - items: - type: integer - type: array + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' status: type: string type: object @@ -409,6 +669,1277 @@ definitions: grantDomainAdmin: type: boolean type: object + internal_api.urlResponse: + properties: + url: + type: string + type: object + internal_api.usedByResponse: + properties: + usedBy: + type: integer + type: object + internal_api.webConsoleSessionResponse: + properties: + sessionId: + type: string + type: + type: string + type: object + oci-portal_internal_aiwire.AnthBlock: + properties: + content: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + id: + description: tool_use + type: string + input: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + is_error: + type: boolean + name: + type: string + source: + allOf: + - $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + description: image + text: + type: string + tool_use_id: + description: tool_result + type: string + type: + type: string + type: object + oci-portal_internal_aiwire.AnthContent: + properties: + blocks: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.AnthBlock' + type: array + text: + type: string + type: object + oci-portal_internal_aiwire.AnthMessage: + properties: + content: + $ref: '#/definitions/oci-portal_internal_aiwire.AnthContent' + role: + type: string + type: object + oci-portal_internal_aiwire.AnthOutputConfig: + properties: + effort: + type: string + type: object + oci-portal_internal_aiwire.AnthTool: + properties: + description: + type: string + input_schema: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + name: + type: string + type: object + oci-portal_internal_aiwire.AnthUsage: + properties: + cache_read_input_tokens: + description: CacheReadInputTokens 是缓存命中读取数;OCI 隐式缓存无「写入」计数,cache_creation + 恒缺 + type: integer + input_tokens: + type: integer + output_tokens: + type: integer + type: object + oci-portal_internal_aiwire.AnyJSON: + type: object + oci-portal_internal_aiwire.ChatMessage: + properties: + content: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + role: + type: string + tool_call_id: + type: string + tool_calls: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.ToolCall' + type: array + type: object + oci-portal_internal_aiwire.ChatRequest: + properties: + max_completion_tokens: + type: integer + max_tokens: + type: integer + messages: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.ChatMessage' + type: array + model: + type: string + parallel_tool_calls: + type: boolean + reasoning_effort: + type: string + response_format: + $ref: '#/definitions/oci-portal_internal_aiwire.ResponseFormat' + stream: + type: boolean + stream_options: + $ref: '#/definitions/oci-portal_internal_aiwire.StreamOptions' + temperature: + type: number + tool_choice: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + tools: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.Tool' + type: array + top_p: + type: number + type: object + oci-portal_internal_aiwire.ChatResponse: + properties: + choices: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.Choice' + type: array + created: + type: integer + id: + type: string + model: + type: string + object: + type: string + usage: + $ref: '#/definitions/oci-portal_internal_aiwire.Usage' + type: object + oci-portal_internal_aiwire.Choice: + properties: + finish_reason: + type: string + index: + type: integer + message: + $ref: '#/definitions/oci-portal_internal_aiwire.ChatMessage' + type: object + oci-portal_internal_aiwire.EmbedUsage: + properties: + prompt_tokens: + type: integer + total_tokens: + type: integer + type: object + oci-portal_internal_aiwire.Embedding: + properties: + embedding: + items: + type: number + type: array + index: + type: integer + object: + type: string + type: object + oci-portal_internal_aiwire.EmbeddingsRequest: + properties: + dimensions: + type: integer + encoding_format: + type: string + input: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + model: + type: string + user: + type: string + type: object + oci-portal_internal_aiwire.EmbeddingsResponse: + properties: + data: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.Embedding' + type: array + model: + type: string + object: + type: string + usage: + $ref: '#/definitions/oci-portal_internal_aiwire.EmbedUsage' + type: object + oci-portal_internal_aiwire.FunctionCall: + properties: + arguments: + type: string + name: + type: string + type: object + oci-portal_internal_aiwire.FunctionDef: + properties: + description: + type: string + name: + type: string + parameters: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + type: object + oci-portal_internal_aiwire.MessagesRequest: + properties: + max_tokens: + type: integer + messages: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.AnthMessage' + type: array + metadata: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + model: + type: string + output_config: + allOf: + - $ref: '#/definitions/oci-portal_internal_aiwire.AnthOutputConfig' + description: OutputConfig 是 Anthropic 官方输出控制(effort 等);网关映射 effort 到 OCI reasoningEffort。 + stop_sequences: + items: + type: string + type: array + stream: + type: boolean + system: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + temperature: + type: number + thinking: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + tool_choice: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + tools: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.AnthTool' + type: array + top_k: + type: integer + top_p: + type: number + type: object + oci-portal_internal_aiwire.MessagesResponse: + properties: + content: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.AnthBlock' + type: array + id: + type: string + model: + type: string + role: + type: string + stop_reason: + type: string + stop_sequence: + type: string + type: + type: string + usage: + $ref: '#/definitions/oci-portal_internal_aiwire.AnthUsage' + type: object + oci-portal_internal_aiwire.Model: + properties: + created: + type: integer + id: + type: string + object: + type: string + owned_by: + type: string + type: object + oci-portal_internal_aiwire.ModelList: + properties: + data: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.Model' + type: array + object: + type: string + type: object + oci-portal_internal_aiwire.ModerationPii: + properties: + label: + type: string + length: + type: integer + offset: + type: integer + score: + type: number + text: + type: string + type: object + oci-portal_internal_aiwire.ModerationResult: + properties: + categories: + additionalProperties: + type: boolean + type: object + category_scores: + additionalProperties: + format: float64 + type: number + type: object + flagged: + type: boolean + pii: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.ModerationPii' + type: array + type: object + oci-portal_internal_aiwire.ModerationsRequest: + properties: + input: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + model: + type: string + type: object + oci-portal_internal_aiwire.ModerationsResponse: + properties: + id: + type: string + model: + type: string + results: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.ModerationResult' + type: array + type: object + oci-portal_internal_aiwire.PromptTokensDetails: + properties: + cached_tokens: + type: integer + type: object + oci-portal_internal_aiwire.RerankDocument: + properties: + text: + type: string + type: object + oci-portal_internal_aiwire.RerankRequest: + properties: + documents: + items: + type: string + type: array + model: + type: string + query: + type: string + return_documents: + type: boolean + top_n: + type: integer + type: object + oci-portal_internal_aiwire.RerankResponse: + properties: + model: + type: string + results: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.RerankResult' + type: array + type: object + oci-portal_internal_aiwire.RerankResult: + properties: + document: + $ref: '#/definitions/oci-portal_internal_aiwire.RerankDocument' + index: + type: integer + relevance_score: + type: number + type: object + oci-portal_internal_aiwire.RespError: + properties: + code: + type: string + message: + type: string + type: object + oci-portal_internal_aiwire.RespInDetails: + properties: + cached_tokens: + type: integer + type: object + oci-portal_internal_aiwire.RespOutDetails: + properties: + reasoning_tokens: + type: integer + type: object + oci-portal_internal_aiwire.RespReasoning: + properties: + effort: + type: string + type: object + oci-portal_internal_aiwire.RespRequest: + properties: + background: + type: boolean + conversation: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + input: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + instructions: + type: string + max_output_tokens: + type: integer + model: + type: string + parallel_tool_calls: + type: boolean + previous_response_id: + type: string + reasoning: + $ref: '#/definitions/oci-portal_internal_aiwire.RespReasoning' + store: + type: boolean + stream: + type: boolean + temperature: + type: number + text: + $ref: '#/definitions/oci-portal_internal_aiwire.RespText' + tool_choice: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + tools: + items: + $ref: '#/definitions/oci-portal_internal_aiwire.RespTool' + type: array + top_p: + type: number + type: object + oci-portal_internal_aiwire.RespResponse: + properties: + created_at: + type: integer + error: + $ref: '#/definitions/oci-portal_internal_aiwire.RespError' + id: + type: string + model: + type: string + object: + type: string + output: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + status: + type: string + usage: + $ref: '#/definitions/oci-portal_internal_aiwire.RespUsage' + type: object + oci-portal_internal_aiwire.RespText: + properties: + format: + $ref: '#/definitions/oci-portal_internal_aiwire.RespTextFormat' + type: object + oci-portal_internal_aiwire.RespTextFormat: + properties: + name: + type: string + schema: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + strict: + type: boolean + type: + type: string + type: object + oci-portal_internal_aiwire.RespTool: + properties: + description: + type: string + name: + type: string + parameters: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + strict: + type: boolean + type: + type: string + type: object + oci-portal_internal_aiwire.RespUsage: + properties: + input_tokens: + type: integer + input_tokens_details: + $ref: '#/definitions/oci-portal_internal_aiwire.RespInDetails' + output_tokens: + type: integer + output_tokens_details: + $ref: '#/definitions/oci-portal_internal_aiwire.RespOutDetails' + total_tokens: + type: integer + type: object + oci-portal_internal_aiwire.ResponseFormat: + properties: + json_schema: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + type: + type: string + type: object + oci-portal_internal_aiwire.SpeechRequest: + properties: + input: + type: string + language: + type: string + model: + type: string + response_format: + type: string + voice: + type: string + type: object + oci-portal_internal_aiwire.StreamOptions: + properties: + include_usage: + type: boolean + type: object + oci-portal_internal_aiwire.Tool: + properties: + function: + $ref: '#/definitions/oci-portal_internal_aiwire.FunctionDef' + type: + type: string + type: object + oci-portal_internal_aiwire.ToolCall: + properties: + function: + $ref: '#/definitions/oci-portal_internal_aiwire.FunctionCall' + id: + type: string + type: + type: string + type: object + oci-portal_internal_aiwire.Usage: + properties: + completion_tokens: + type: integer + prompt_tokens: + type: integer + prompt_tokens_details: + allOf: + - $ref: '#/definitions/oci-portal_internal_aiwire.PromptTokensDetails' + description: PromptTokensDetails 携带缓存命中细分;OCI 为隐式 prompt 缓存,只有读取计数 + total_tokens: + type: integer + type: object + oci-portal_internal_model.AiCallLog: + properties: + cachedTokens: + description: CachedTokens 是输入中缓存命中(读取)的部分;OCI 隐式缓存无写入计数 + type: integer + channelId: + type: integer + channelName: + type: string + clientIp: + description: ClientIP 是网关调用方来源 IP(尊重「真实 IP 头」安全设置,与系统日志同源) + type: string + completionTokens: + type: integer + createdAt: + type: string + endpoint: + description: openai / anthropic + type: string + errMsg: + type: string + id: + type: integer + keyId: + type: integer + keyName: + type: string + latencyMs: + type: integer + model: + type: string + promptTokens: + type: integer + retries: + type: integer + status: + type: integer + stream: + type: boolean + totalTokens: + type: integer + type: object + oci-portal_internal_model.AiChannel: + properties: + createdAt: + type: string + disabledUntil: + type: string + enabled: + type: boolean + failCount: + description: FailCount 连续失败计数;达阈值后 DisabledUntil 指数退避熔断,成功/探测通过复位 + type: integer + group: + type: string + id: + type: integer + lastProbeAt: + type: string + name: + type: string + ociConfigId: + type: integer + priority: + type: integer + probeError: + type: string + probeStatus: + description: ok / no_service / no_quota / error + type: string + region: + type: string + updatedAt: + type: string + weight: + type: integer + type: object + oci-portal_internal_model.AiContentLog: + properties: + callLogId: + description: CallLogID 关联同次调用的 AiCallLog,调用日志详情据此反查正文 + type: integer + createdAt: + type: string + endpoint: + type: string + id: + type: integer + keyId: + type: integer + keyName: + type: string + model: + type: string + requestBody: + description: |- + RequestBody / ResponseBody 是截断后的正文 JSON; + 64KB 截断恰在 MySQL TEXT 上限(65535B)边界,size 上探一档 → MEDIUMTEXT + type: string + responseBody: + type: string + stream: + type: boolean + type: object + oci-portal_internal_model.AiKey: + properties: + contentLogUntil: + description: |- + ContentLogUntil 是内容日志开启截止时间;nil = 永关(默认,红线), + 开启必须限时,到期自动停写 + type: string + createdAt: + type: string + enabled: + type: boolean + group: + type: string + id: + type: integer + lastUsedAt: + type: string + models: + description: Models 是模型白名单(精确匹配模型名);空 = 不限,非空时网关仅放行列表内模型 + items: + type: string + type: array + name: + type: string + tail: + type: string + type: object + oci-portal_internal_model.AiModelBlacklist: + properties: + createdAt: + type: string + id: + type: integer + name: + type: string + type: object + oci-portal_internal_model.AiModelCache: + properties: + capability: + type: string + channelId: + type: integer + deprecatedAt: + description: |- + DeprecatedAt 是 OCI 宣布的模型弃用时间;nil 表示未宣布。 + 弃用后仍可调用,直到 RetiredAt(按需推理退役,同步层已剔除过期项)。 + type: string + modelOcid: + type: string + name: + type: string + retiredAt: + type: string + syncedAt: + type: string + vendor: + type: string + type: object + oci-portal_internal_model.LogEvent: + properties: + eventTime: + type: string + eventType: + description: 异步解析回填,如 com.oraclecloud.ComputeApi.TerminateInstance + type: string + id: + type: integer + messageId: + description: 幂等键(X-OCI-NS-MessageId) + type: string + ociConfigId: + description: 经 secret 反查归属租户 + type: integer + payload: + description: 防御上限 256KB 超 MySQL TEXT(64KB),size 上探一档 → MEDIUMTEXT;PG/SQLite + 仍为 text + type: string + processed: + type: boolean + receivedAt: + type: string + source: + type: string + sourceIp: + description: 异步解析回填,Audit 事件的发起方 IP + type: string + truncated: + type: boolean + type: object + oci-portal_internal_model.OciConfig: + properties: + accountType: + type: string + alias: + type: string + aliveStatus: + type: string + createdAt: + type: string + fingerprint: + type: string + group: + description: |- + Group 是面板内的自定义分组标签,空串表示未分组; + 列名避开 SQL 保留字 GROUP + type: string + homeRegionKey: + type: string + id: + type: integer + lastError: + type: string + lastVerifiedAt: + type: string + multiCompartment: + type: boolean + multiRegion: + description: |- + 多区域 / 多区间支持:开启后订阅区域与 compartment 列表入库缓存, + 供筛选器免实时调 OCI;未开启的租户筛选器锁定主区域 / 根区间。 + type: boolean + paymentModel: + type: string + promotionAmount: + type: number + promotionExpires: + type: string + promotionStatus: + type: string + proxyId: + description: ProxyID 关联出站代理,nil 表示直连;该租户全部 SDK 调用经此代理 + type: integer + region: + type: string + subscriptionId: + type: string + subscriptionTier: + type: string + tenancyName: + type: string + tenancyOcid: + type: string + updatedAt: + type: string + userOcid: + type: string + type: object + oci-portal_internal_model.SystemLog: + properties: + clientIp: + type: string + createdAt: + type: string + durationMs: + type: integer + errMsg: + description: ErrMsg 仅失败请求(>=400)存响应的 error 文案,便于免翻服务端日志定位原因 + type: string + id: + type: integer + method: + type: string + path: + type: string + status: + type: integer + userAgent: + type: string + username: + type: string + type: object + oci-portal_internal_model.Task: + properties: + createdAt: + type: string + cronExpr: + type: string + id: + type: integer + lastError: + type: string + lastRunAt: + type: string + name: + type: string + payload: + type: string + runCount: + type: integer + status: + type: string + type: + type: string + updatedAt: + type: string + type: object + oci-portal_internal_model.TaskLog: + properties: + createdAt: + type: string + durationMs: + type: integer + id: + type: integer + message: + type: string + success: + type: boolean + taskId: + type: integer + type: object + oci-portal_internal_model.UserIdentity: + properties: + createdAt: + type: string + display: + description: 展示名:邮箱 / GitHub login + type: string + id: + type: integer + provider: + type: string + type: object + oci-portal_internal_oci.AuditEvent: + properties: + compartmentName: + type: string + eventId: + type: string + eventName: + type: string + eventTime: + type: string + ipAddress: + type: string + principalName: + type: string + raw: + $ref: '#/definitions/oci-portal_internal_aiwire.AnyJSON' + requestAction: + type: string + requestPath: + type: string + resourceName: + type: string + source: + type: string + status: + type: string + type: object + oci-portal_internal_oci.BlockVolume: + properties: + availabilityDomain: + type: string + displayName: + type: string + id: + type: string + lifecycleState: + type: string + sizeInGBs: + type: integer + timeCreated: + type: string + vpusPerGB: + type: integer + type: object + oci-portal_internal_oci.BootVolume: + properties: + attachedInstanceId: + type: string + attachedInstanceName: + type: string + availabilityDomain: + type: string + compartmentId: + type: string + displayName: + type: string + id: + type: string + imageId: + type: string + imageName: + type: string + lifecycleState: + type: string + sizeInGBs: + type: integer + timeCreated: + type: string + vpusPerGB: + type: integer + type: object + oci-portal_internal_oci.BootVolumeAttachment: + properties: + availabilityDomain: + type: string + bootVolumeId: + type: string + displayName: + type: string + id: + type: string + instanceId: + type: string + lifecycleState: + type: string + type: object + oci-portal_internal_oci.Compartment: + properties: + description: + type: string + id: + type: string + lifecycleState: + type: string + name: + type: string + parentId: + type: string + timeCreated: + type: string + type: object + oci-portal_internal_oci.ComputeShape: + properties: + billingType: + description: ALWAYS_FREE / LIMITED_FREE / PAID + type: string + gpus: + type: integer + isFlexible: + type: boolean + memoryInGBs: + type: number + memoryMaxGBs: + type: number + memoryMinGBs: + type: number + name: + type: string + ocpus: + type: number + ocpusMax: + type: number + ocpusMin: + type: number + processorDescription: + type: string + type: object + oci-portal_internal_oci.ConsoleConnection: + properties: + connectionString: + description: 串口控制台 SSH 命令 + type: string + id: + type: string + instanceId: + type: string + lifecycleState: + type: string + vncConnectionString: + description: VNC over SSH 隧道命令 + type: string + type: object + oci-portal_internal_oci.CostItem: + properties: + computedAmount: + type: number + computedQuantity: + type: number + currency: + type: string + groupValue: + type: string + timeStart: + type: string + unit: + type: string + type: object + oci-portal_internal_oci.IPv6Step: + properties: + detail: + type: string + status: + description: done / skipped / failed + type: string + step: + type: string + type: object + oci-portal_internal_oci.IdentityDomain: + properties: + displayName: + type: string + homeRegion: + type: string + id: + type: string + licenseType: + type: string + type: + type: string + type: object + oci-portal_internal_oci.IdentityProviderInfo: + properties: + enabled: + type: boolean + id: + type: string + jitEnabled: + type: boolean + name: + type: string + partnerProviderId: + type: string + timeCreated: + type: string + type: + type: string + type: object + oci-portal_internal_oci.IdentitySettingInfo: + properties: + id: + type: string + primaryEmailRequired: + description: 用户需要提供主电子邮件地址:开启后创建用户 / JIT 预配必须带邮箱 + type: boolean + type: object + oci-portal_internal_oci.Image: + properties: + displayName: + type: string + id: + type: string + operatingSystem: + type: string + operatingSystemVersion: + type: string + sizeInMBs: + type: integer + timeCreated: + type: string + type: object + oci-portal_internal_oci.Instance: + properties: + availabilityDomain: + type: string + compartmentId: + type: string + definedTags: + additionalProperties: + additionalProperties: {} + type: object + type: object + displayName: + type: string + freeformTags: + additionalProperties: + type: string + type: object + id: + type: string + imageId: + type: string + ipv6Addresses: + items: + type: string + type: array + lifecycleState: + type: string + memoryInGBs: + type: number + ocpus: + type: number + privateIp: + type: string + publicIp: + type: string + region: + type: string + shape: + type: string + subnetId: + type: string + timeCreated: + type: string + type: object + oci-portal_internal_oci.InstanceTraffic: + properties: + inboundBytes: + type: number + instanceId: + type: string + outboundBytes: + type: number + vnics: + items: + $ref: '#/definitions/oci-portal_internal_oci.VnicTraffic' + type: array + type: object + oci-portal_internal_oci.LimitService: + properties: + description: + type: string + name: + type: string + type: object + oci-portal_internal_oci.LimitValue: + properties: + availabilityDomain: + type: string + available: + type: integer + name: + type: string + scopeType: + type: string + used: + type: integer + value: + type: integer + type: object + oci-portal_internal_oci.NotificationRecipients: + properties: + recipients: + items: + type: string + type: array + testModeEnabled: + type: boolean + type: object + oci-portal_internal_oci.PasswordPolicyInfo: + properties: + id: + type: string + minLength: + type: integer + name: + type: string + numPasswordsInHistory: + type: integer + passwordExpiresAfter: + type: integer + passwordStrength: + type: string + priority: + type: integer + type: object + oci-portal_internal_oci.PromotionInfo: + properties: + amount: + type: number + currencyUnit: + type: string + duration: + type: integer + durationUnit: + type: string + isIntentToPay: + type: boolean + status: + type: string + timeExpired: + type: string + timeStarted: + type: string + type: object + oci-portal_internal_oci.RegionInfo: + properties: + alias: + type: string + key: + type: string + name: + type: string + type: object + oci-portal_internal_oci.RelayResource: + properties: + id: + type: string + state: + type: string + type: object + oci-portal_internal_oci.SecurityList: + properties: + displayName: + type: string + egressRules: + items: + $ref: '#/definitions/oci-portal_internal_oci.SecurityRule' + type: array + id: + type: string + ingressRules: + items: + $ref: '#/definitions/oci-portal_internal_oci.SecurityRule' + type: array + lifecycleState: + type: string + timeCreated: + type: string + vcnId: + type: string + type: object oci-portal_internal_oci.SecurityRule: properties: description: @@ -431,6 +1962,251 @@ definitions: source: type: string type: object + oci-portal_internal_oci.SignOnRuleInfo: + properties: + authenticationFactor: + type: string + builtIn: + type: boolean + conditionAttribute: + type: string + conditionValue: + type: string + id: + type: string + name: + type: string + sequence: + type: integer + type: object + oci-portal_internal_oci.Subnet: + properties: + availabilityDomain: + type: string + cidrBlock: + type: string + displayName: + type: string + dnsLabel: + type: string + id: + type: string + ipv6CidrBlock: + type: string + lifecycleState: + type: string + prohibitPublicIp: + type: boolean + routeTableId: + type: string + timeCreated: + type: string + vcnId: + type: string + type: object + oci-portal_internal_oci.SubscriptionDetail: + properties: + classicSubscriptionId: + type: string + cloudAmountCurrency: + type: string + csiNumber: + type: string + customerCountryCode: + type: string + endDate: + type: string + id: + type: string + isGovernmentSubscription: + type: boolean + lifecycleState: + type: string + paymentModel: + type: string + programType: + type: string + promotions: + items: + $ref: '#/definitions/oci-portal_internal_oci.PromotionInfo' + type: array + regionAssignment: + type: string + serviceName: + type: string + startDate: + type: string + subscriptionTier: + type: string + timeCreated: + type: string + timeUpdated: + type: string + type: object + oci-portal_internal_oci.SubscriptionInfo: + properties: + id: + type: string + serviceName: + type: string + timeCreated: + type: string + timeUpdated: + type: string + type: object + oci-portal_internal_oci.TenantUser: + properties: + description: + type: string + email: + type: string + emailVerified: + type: boolean + id: + type: string + isCurrentUser: + type: boolean + lastLoginTime: + type: string + lifecycleState: + type: string + mfaActivated: + type: boolean + name: + type: string + timeCreated: + type: string + type: object + oci-portal_internal_oci.TenantUserDetail: + properties: + familyName: + type: string + givenName: + type: string + inAdminGroup: + type: boolean + inDomain: + type: boolean + isDomainAdmin: + type: boolean + type: object + oci-portal_internal_oci.TrafficPoint: + properties: + bytes: + type: number + timestamp: + type: string + type: object + oci-portal_internal_oci.VCN: + properties: + cidrBlocks: + items: + type: string + type: array + compartmentId: + type: string + defaultRouteTableId: + type: string + defaultSecurityListId: + type: string + displayName: + type: string + dnsLabel: + type: string + id: + type: string + ipv6CidrBlocks: + items: + type: string + type: array + lifecycleState: + type: string + timeCreated: + type: string + type: object + oci-portal_internal_oci.Vnic: + properties: + attachmentId: + type: string + displayName: + type: string + ipv6Addresses: + items: + type: string + type: array + isPrimary: + type: boolean + lifecycleState: + type: string + privateIp: + type: string + publicIp: + type: string + subnetId: + type: string + subnetName: + type: string + timeCreated: + type: string + vnicId: + type: string + type: object + oci-portal_internal_oci.VnicTraffic: + properties: + inbound: + items: + $ref: '#/definitions/oci-portal_internal_oci.TrafficPoint' + type: array + inboundBytes: + type: number + outbound: + items: + $ref: '#/definitions/oci-portal_internal_oci.TrafficPoint' + type: array + outboundBytes: + type: number + vnicId: + type: string + type: object + oci-portal_internal_oci.VolumeAttachment: + properties: + availabilityDomain: + type: string + device: + type: string + displayName: + type: string + id: + type: string + instanceId: + type: string + isReadOnly: + type: boolean + lifecycleState: + type: string + volumeId: + type: string + volumeName: + description: 卷本身的名称(attachment 名是自动生成的) + type: string + type: object + oci-portal_internal_service.AuditEventsView: + properties: + cursor: + type: string + exhausted: + type: boolean + items: + items: + $ref: '#/definitions/oci-portal_internal_oci.AuditEvent' + type: array + type: object + oci-portal_internal_service.Changes: + additionalProperties: + items: + type: string + type: array + type: object oci-portal_internal_service.ChannelInput: properties: enabled: @@ -448,6 +2224,102 @@ definitions: weight: type: integer type: object + oci-portal_internal_service.ConfigSummary: + properties: + accountType: + type: string + alias: + type: string + aliveStatus: + type: string + createdAt: + type: string + group: + type: string + id: + type: integer + lastError: + type: string + lastVerifiedAt: + type: string + multiCompartment: + type: boolean + multiRegion: + type: boolean + proxyId: + type: integer + proxyName: + description: ProxyName 由 List 按关联填充,供表格代理列 hover 展示 + type: string + region: + type: string + tenancyName: + type: string + tenancyOcid: + type: string + type: object + oci-portal_internal_service.ImportFail: + properties: + line: + type: string + lineNo: + type: integer + reason: + type: string + type: object + oci-portal_internal_service.ImportResult: + properties: + created: + items: + $ref: '#/definitions/oci-portal_internal_service.ProxyView' + type: array + failed: + items: + $ref: '#/definitions/oci-portal_internal_service.ImportFail' + type: array + type: object + oci-portal_internal_service.LogWebhookInfo: + properties: + createdAt: + type: string + path: + type: string + secret: + type: string + type: object + oci-portal_internal_service.NotifyChannelView: + properties: + bodyTemplate: + type: string + enabled: + type: boolean + from: + type: string + host: + description: smtp + type: string + port: + type: integer + secretSet: + description: 密文字段状态(ntfy token / bark device key / smtp password) + type: boolean + secretTail: + type: string + server: + description: ntfy / bark 共用 Server + type: string + to: + type: string + topic: + type: string + type: + type: string + url: + description: webhook + type: string + username: + type: string + type: object oci-portal_internal_service.NotifyEventsView: properties: logEventIdentity: @@ -475,6 +2347,22 @@ definitions: tenantDead: type: boolean type: object + oci-portal_internal_service.NotifyTemplateView: + properties: + defaultTemplate: + type: string + kind: + type: string + label: + type: string + template: + description: Template 是自定义模板;空串表示未自定义(按默认发送) + type: string + vars: + items: + type: string + type: array + type: object oci-portal_internal_service.OAuthProvidersView: properties: githubClientId: @@ -496,6 +2384,85 @@ definitions: oidcSecretSet: type: boolean type: object + oci-portal_internal_service.Overview: + properties: + check: + $ref: '#/definitions/oci-portal_internal_service.OverviewCheck' + cost: + $ref: '#/definitions/oci-portal_internal_service.OverviewCost' + tasks: + $ref: '#/definitions/oci-portal_internal_service.OverviewTasks' + tenants: + $ref: '#/definitions/oci-portal_internal_service.OverviewTenants' + type: object + oci-portal_internal_service.OverviewCheck: + properties: + coveredConfigs: + type: integer + hasActiveTask: + type: boolean + instanceCount: + type: integer + lastCheckedAt: + type: string + totalConfigs: + type: integer + type: object + oci-portal_internal_service.OverviewCost: + properties: + coveredConfigs: + type: integer + currency: + type: string + days: + items: + $ref: '#/definitions/oci-portal_internal_service.OverviewCostDay' + type: array + hasActiveTask: + type: boolean + total: + type: number + type: object + oci-portal_internal_service.OverviewCostDay: + properties: + amount: + type: number + day: + type: string + type: object + oci-portal_internal_service.OverviewTasks: + properties: + active: + type: integer + cost: + type: integer + healthCheck: + type: integer + snatch: + type: integer + total: + type: integer + type: object + oci-portal_internal_service.OverviewTenants: + properties: + alive: + type: integer + byType: + additionalProperties: + type: integer + type: object + dead: + type: integer + total: + type: integer + type: object + oci-portal_internal_service.ProviderInfo: + properties: + displayName: + type: string + provider: + type: string + type: object oci-portal_internal_service.ProxyInput: properties: host: @@ -515,6 +2482,69 @@ definitions: - port - type type: object + oci-portal_internal_service.ProxyView: + properties: + city: + type: string + country: + description: Country / City 为出口实测地区;GeoAt 空串表示尚未探测(前端显示「检测中」) + type: string + createdAt: + type: string + geoAt: + type: string + host: + type: string + id: + type: integer + name: + type: string + passwordSet: + type: boolean + port: + type: integer + type: + type: string + usedBy: + description: UsedBy 为关联此代理的租户数,前端据此提示删除约束 + type: integer + username: + type: string + type: object + oci-portal_internal_service.RegionSubscriptionView: + properties: + alias: + type: string + isHomeRegion: + type: boolean + key: + type: string + name: + type: string + status: + type: string + type: object + oci-portal_internal_service.RelayView: + properties: + connector: + $ref: '#/definitions/oci-portal_internal_oci.RelayResource' + endpoint: + type: string + events: + items: + type: string + type: array + policy: + $ref: '#/definitions/oci-portal_internal_oci.RelayResource' + ready: + type: boolean + subscription: + $ref: '#/definitions/oci-portal_internal_oci.RelayResource' + topic: + $ref: '#/definitions/oci-portal_internal_oci.RelayResource' + webhook: + $ref: '#/definitions/oci-portal_internal_service.LogWebhookInfo' + type: object oci-portal_internal_service.SecuritySettings: properties: appUrl: @@ -539,6 +2569,17 @@ definitions: snatchAuthFailLimit: type: integer type: object + oci-portal_internal_service.TelegramView: + properties: + chatId: + type: string + enabled: + type: boolean + tokenSet: + type: boolean + tokenTail: + type: string + type: object oci-portal_internal_service.UpdateCredentialsInput: properties: currentPassword: @@ -578,6 +2619,24 @@ info: title: OCI Portal API version: 0.0.1 paths: + /ai/v1/audio/speech: + post: + parameters: + - description: OpenAI audio speech 请求体(model/input 必填,voice 见 xAI Grok Voice + 列表,language 缺省 auto;未列字段原样透传) + in: body + name: body + required: true + schema: + $ref: '#/definitions/oci-portal_internal_aiwire.SpeechRequest' + responses: + "200": + description: 音频字节(Content-Type 透传上游,默认 audio/mpeg) + schema: + type: file + summary: OpenAI Audio Speech 兼容端点(文本转语音) + tags: + - AI 网关 /ai/v1/chat/completions: post: parameters: @@ -586,13 +2645,12 @@ paths: name: body required: true schema: - type: object + $ref: '#/definitions/oci-portal_internal_aiwire.ChatRequest' responses: "200": - description: 'OpenAI 兼容响应(流式为 SSE,末尾 data: [DONE])' + description: 'OpenAI 兼容响应(非流式;流式为 SSE,末尾 data: [DONE])' schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_aiwire.ChatResponse' summary: OpenAI Chat Completions 兼容端点 tags: - AI 网关 @@ -604,13 +2662,12 @@ paths: name: body required: true schema: - type: object + $ref: '#/definitions/oci-portal_internal_aiwire.EmbeddingsRequest' responses: "200": description: OpenAI 兼容响应 schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_aiwire.EmbeddingsResponse' summary: OpenAI 兼容向量嵌入 tags: - AI 网关 @@ -623,13 +2680,12 @@ paths: name: body required: true schema: - type: object + $ref: '#/definitions/oci-portal_internal_aiwire.MessagesRequest' responses: "200": - description: Anthropic 兼容响应(流式为 SSE) + description: Anthropic 兼容响应(非流式;流式为 SSE 事件序列) schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_aiwire.MessagesResponse' summary: Anthropic Messages 兼容端点 tags: - AI 网关 @@ -639,26 +2695,60 @@ paths: "200": description: OpenAI 兼容 models 列表 schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_aiwire.ModelList' summary: 可用模型列表 tags: - AI 网关 + /ai/v1/moderations: + post: + parameters: + - description: 审核请求体(input 为字符串或字符串数组,单次至多 8 条;model 接受但忽略) + in: body + name: body + required: true + schema: + $ref: '#/definitions/oci-portal_internal_aiwire.ModerationsRequest' + responses: + "200": + description: 审核结果(categories/category_scores 为 overall/blocklist/prompt_injection,pii + 为扩展字段) + schema: + $ref: '#/definitions/oci-portal_internal_aiwire.ModerationsResponse' + summary: 内容审核端点(OCI Guardrails) + tags: + - AI 网关 + /ai/v1/rerank: + post: + parameters: + - description: 重排请求体(model/query/documents 必填,可选 top_n/return_documents) + in: body + name: body + required: true + schema: + $ref: '#/definitions/oci-portal_internal_aiwire.RerankRequest' + responses: + "200": + description: 重排结果(results[].index 指向入参下标) + schema: + $ref: '#/definitions/oci-portal_internal_aiwire.RerankResponse' + summary: 文档重排端点(Cohere Rerank) + tags: + - AI 网关 /ai/v1/responses: post: parameters: - - description: OpenAI responses 请求体(支持 stream;web_search/x_search 服务端工具仅非流式) + - description: OpenAI responses 请求体(支持 stream;服务端工具 web_search/x_search/code_interpreter/mcp + 含流式;未列字段原样透传上游) in: body name: body required: true schema: - type: object + $ref: '#/definitions/oci-portal_internal_aiwire.RespRequest' responses: "200": - description: OpenAI 兼容响应(流式为 SSE) + description: OpenAI 兼容响应(非流式;流式为 SSE);直通仅建模常用字段,未列字段原样返回 schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_aiwire.RespResponse' summary: OpenAI Responses 兼容端点 tags: - AI 网关 @@ -668,8 +2758,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.aboutResponse' security: - BearerAuth: [] summary: 返回构建、运行时长与资源占用信息,「设置 · 关于」页展示 @@ -681,8 +2770,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.itemsResponse-oci-portal_internal_model_AiModelBlacklist' security: - BearerAuth: [] summary: 模型黑名单列表 @@ -700,8 +2788,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.itemResponse-oci-portal_internal_model_AiModelBlacklist' security: - BearerAuth: [] summary: 添加模型黑名单 @@ -729,8 +2816,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.itemsResponse-oci-portal_internal_model_AiChannel' security: - BearerAuth: [] summary: '---- 渠道 ----' @@ -748,8 +2834,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_model.AiChannel' security: - BearerAuth: [] summary: 创建 AI 渠道 @@ -804,8 +2889,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_model.AiChannel' security: - BearerAuth: [] summary: 触发探测:服务可见性 + 模型同步 + 配额试调,返回更新后的渠道 @@ -823,8 +2907,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.itemsResponse-oci-portal_internal_model_AiModelCache' security: - BearerAuth: [] summary: 同步渠道模型缓存 @@ -836,8 +2919,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.pagedResponse-oci-portal_internal_model_AiCallLog' security: - BearerAuth: [] summary: 分页查询内容日志 @@ -849,8 +2931,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.itemsResponse-oci-portal_internal_model_AiKey' security: - BearerAuth: [] summary: '---- 密钥 ----' @@ -866,10 +2947,9 @@ paths: type: object responses: "201": - description: Created + description: key 为明文密钥,仅本次返回 schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.aiKeyCreateResponse' security: - BearerAuth: [] summary: 生成密钥 @@ -930,8 +3010,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_model.AiKey' security: - BearerAuth: [] summary: 设置密钥内容日志窗口 @@ -943,8 +3022,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.pagedResponse-oci-portal_internal_model_AiContentLog' security: - BearerAuth: [] summary: AI 调用日志列表 @@ -956,8 +3034,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.itemsResponse-oci-portal_internal_aiwire_Model' security: - BearerAuth: [] summary: '---- 聚合模型与调用日志 ----' @@ -969,8 +3046,7 @@ paths: "200": description: username 与 passwordLoginDisabled schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.credentialsResponse' security: - BearerAuth: [] summary: 登录凭据摘要 @@ -990,9 +3066,7 @@ paths: "401": description: 当前密码错误 schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/internal_api.errorResponse' security: - BearerAuth: [] summary: 修改登录凭据 @@ -1004,8 +3078,7 @@ paths: "200": description: items schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.itemsResponse-oci-portal_internal_model_UserIdentity' security: - BearerAuth: [] summary: 已绑定外部身份 @@ -1025,9 +3098,7 @@ paths: "409": description: 最后一个身份不可解绑 schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/internal_api.errorResponse' security: - BearerAuth: [] summary: 解绑外部身份 @@ -1050,19 +3121,15 @@ paths: "200": description: token 与 expiresAt schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.tokenResponse' "401": description: 凭据错误 schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/internal_api.errorResponse' "428": description: 需要两步验证码(totpRequired=true) schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.totpRequiredResponse' summary: 登录 tags: - 认证 @@ -1092,9 +3159,7 @@ paths: "200": description: url schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/internal_api.urlResponse' summary: 外部登录授权跳转 tags: - 认证 @@ -1128,8 +3193,7 @@ paths: "200": description: providers 与 passwordLoginDisabled schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.oauthProvidersResponse' summary: 外部登录 provider 列表 tags: - 认证 @@ -1148,9 +3212,7 @@ paths: "409": description: 未绑定外部身份 schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/internal_api.errorResponse' security: - BearerAuth: [] summary: 密码登录开关 @@ -1162,9 +3224,7 @@ paths: "200": description: 新 token 与 expiresAt schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/internal_api.tokenResponse' security: - BearerAuth: [] summary: 撤销全部会话 @@ -1176,9 +3236,7 @@ paths: "200": description: enabled schema: - additionalProperties: - type: boolean - type: object + $ref: '#/definitions/internal_api.enabledResponse' security: - BearerAuth: [] summary: 两步验证状态 @@ -1224,15 +3282,11 @@ paths: "200": description: secret 与 otpauthUri schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/internal_api.totpSetupResponse' "409": description: 已启用 schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/internal_api.errorResponse' security: - BearerAuth: [] summary: 发起两步验证设置 @@ -1288,8 +3342,7 @@ paths: "200": description: items 与 total schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.pagedResponse-oci-portal_internal_model_LogEvent' security: - BearerAuth: [] summary: 回传日志事件列表 @@ -1299,10 +3352,11 @@ paths: get: responses: "200": - description: items + description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_service.ConfigSummary' + type: array security: - BearerAuth: [] summary: 租户配置列表 @@ -1320,8 +3374,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_model.OciConfig' security: - BearerAuth: [] summary: 导入租户配置 @@ -1355,8 +3408,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_model.OciConfig' security: - BearerAuth: [] summary: 租户配置详情 @@ -1377,10 +3429,9 @@ paths: type: object responses: "200": - description: OK + description: config 与 changes 字段变更对照 schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.configChangesResponse' security: - BearerAuth: [] summary: 更新租户配置 @@ -1406,8 +3457,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.AuditEventsView' security: - BearerAuth: [] summary: 批式懒加载查询租户 OCI 审计事件 @@ -1423,10 +3473,9 @@ paths: type: integer responses: "200": - description: OK + description: raw 为事件原文 JSON schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.rawDetailResponse' security: - BearerAuth: [] summary: 按 eventId 取回原始事件 JSON:缓存命中秒开, @@ -1444,8 +3493,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + type: string + type: array security: - BearerAuth: [] summary: 可用域列表 @@ -1484,8 +3534,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.BootVolume' + type: array security: - BearerAuth: [] summary: 引导卷列表 @@ -1528,8 +3579,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.BootVolume' security: - BearerAuth: [] summary: 引导卷详情 @@ -1557,8 +3607,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.BootVolume' security: - BearerAuth: [] summary: 更新引导卷 @@ -1576,8 +3625,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.Compartment' + type: array security: - BearerAuth: [] summary: 返回筛选器用区间列表:未开多区间支持返回空数组 @@ -1595,8 +3645,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_service.RegionSubscriptionView' + type: array security: - BearerAuth: [] summary: 返回筛选器用区域列表:未开多区域支持只含默认区域 @@ -1614,8 +3665,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.Compartment' + type: array security: - BearerAuth: [] summary: 列出租户下全部 ACTIVE compartment @@ -1654,8 +3706,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.CostItem' + type: array security: - BearerAuth: [] summary: 配置成本快照 @@ -1673,8 +3726,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.IdentityDomain' + type: array security: - BearerAuth: [] summary: 租户身份域列表 @@ -1696,8 +3750,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.IdentityProviderInfo' + type: array security: - BearerAuth: [] summary: 身份提供商列表 @@ -1724,8 +3779,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.IdentityProviderInfo' security: - BearerAuth: [] summary: 创建身份提供商(SAML) @@ -1783,8 +3837,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.IdentityProviderInfo' security: - BearerAuth: [] summary: 激活身份提供商 @@ -1806,8 +3859,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.IdentitySettingInfo' security: - BearerAuth: [] summary: 身份域设置 @@ -1834,8 +3886,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.IdentitySettingInfo' security: - BearerAuth: [] summary: 更新身份域设置 @@ -1853,8 +3904,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.Image' + type: array security: - BearerAuth: [] summary: 镜像列表 @@ -1877,8 +3929,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.Image' security: - BearerAuth: [] summary: 镜像详情 @@ -1896,8 +3947,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.Instance' + type: array security: - BearerAuth: [] summary: 实例列表 @@ -1918,10 +3970,9 @@ paths: $ref: '#/definitions/internal_api.createInstanceRequest' responses: "201": - description: Created + description: 部分成功仍 201,errors 为逐台失败信息 schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.createInstancesResponse' security: - BearerAuth: [] summary: 创建实例 @@ -1964,8 +4015,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.Instance' security: - BearerAuth: [] summary: 实例详情 @@ -1993,8 +4043,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.Instance' security: - BearerAuth: [] summary: 更新实例 @@ -2023,8 +4072,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.Instance' security: - BearerAuth: [] summary: 实例电源操作(启停/重启) @@ -2047,8 +4095,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.BootVolumeAttachment' + type: array security: - BearerAuth: [] summary: 引导卷附件列表 @@ -2076,8 +4125,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.BootVolumeAttachment' security: - BearerAuth: [] summary: 附加引导卷 @@ -2106,8 +4154,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.publicIpResponse' security: - BearerAuth: [] summary: '---- 实例 IP ----' @@ -2130,8 +4177,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.ConsoleConnection' + type: array security: - BearerAuth: [] summary: 实例控制台连接列表 @@ -2159,8 +4207,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.ConsoleConnection' security: - BearerAuth: [] summary: 创建实例控制台连接 @@ -2186,11 +4233,10 @@ paths: schema: type: object responses: - "200": - description: sessionId 与 wsPath + "201": + description: sessionId 与 type schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.webConsoleSessionResponse' security: - BearerAuth: [] summary: 创建网页控制台会话 @@ -2239,8 +4285,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.ipv6AddressResponse' security: - BearerAuth: [] summary: 实例添加 IPv6 地址 @@ -2269,8 +4314,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.BootVolumeAttachment' security: - BearerAuth: [] summary: 更换实例引导卷 @@ -2293,8 +4337,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.InstanceTraffic' security: - BearerAuth: [] summary: '---- 流量与成本 ----' @@ -2317,8 +4360,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.Vnic' + type: array security: - BearerAuth: [] summary: 实例 VNIC 列表 @@ -2346,8 +4390,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.Vnic' security: - BearerAuth: [] summary: 附加 VNIC @@ -2370,8 +4413,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.VolumeAttachment' + type: array security: - BearerAuth: [] summary: 卷附件列表 @@ -2399,8 +4443,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.VolumeAttachment' security: - BearerAuth: [] summary: 附加块存储卷 @@ -2418,8 +4461,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.LimitValue' + type: array security: - BearerAuth: [] summary: 服务限额查询 @@ -2437,8 +4481,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.LimitService' + type: array security: - BearerAuth: [] summary: 限额服务列表 @@ -2471,8 +4516,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.RelayView' security: - BearerAuth: [] summary: 查询 OCI 侧链路状态与关键事件清单 @@ -2489,8 +4533,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.RelayView' security: - BearerAuth: [] summary: 一键建立回传链路 @@ -2523,8 +4566,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.logWebhookStatusResponse' security: - BearerAuth: [] summary: 查询配置的回调地址 @@ -2541,8 +4583,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.LogWebhookInfo' security: - BearerAuth: [] summary: 生成 @@ -2564,8 +4605,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.NotificationRecipients' security: - BearerAuth: [] summary: '---- 域通知收件人与密码策略 ----' @@ -2592,8 +4632,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.NotificationRecipients' security: - BearerAuth: [] summary: 更新通知收件人 @@ -2615,8 +4654,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.PasswordPolicyInfo' + type: array security: - BearerAuth: [] summary: 密码策略列表 @@ -2649,8 +4689,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.PasswordPolicyInfo' security: - BearerAuth: [] summary: 更新密码策略 @@ -2668,8 +4707,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_service.RegionSubscriptionView' + type: array security: - BearerAuth: [] summary: 区域订阅列表 @@ -2692,8 +4732,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_service.RegionSubscriptionView' + type: array security: - BearerAuth: [] summary: 订阅新区域 @@ -2713,10 +4754,9 @@ paths: type: string responses: "200": - description: OK + description: SAML 元数据 XML(附件下载) schema: - additionalProperties: true - type: object + type: file security: - BearerAuth: [] summary: 下载 SAML 元数据 @@ -2734,8 +4774,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.SecurityList' + type: array security: - BearerAuth: [] summary: 安全列表清单 @@ -2758,8 +4799,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.SecurityList' security: - BearerAuth: [] summary: 创建安全列表 @@ -2802,8 +4842,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.SecurityList' security: - BearerAuth: [] summary: 安全列表详情 @@ -2831,8 +4870,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.SecurityList' security: - BearerAuth: [] summary: 更新安全列表 @@ -2850,8 +4888,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.ComputeShape' + type: array security: - BearerAuth: [] summary: 实例形状列表 @@ -2879,8 +4918,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.SignOnRuleInfo' security: - BearerAuth: [] summary: 创建 MFA 豁免规则 @@ -2927,8 +4965,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.SignOnRuleInfo' + type: array security: - BearerAuth: [] summary: 单点登录规则列表 @@ -2946,8 +4985,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.Subnet' + type: array security: - BearerAuth: [] summary: 子网列表 @@ -2970,8 +5010,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.Subnet' security: - BearerAuth: [] summary: 创建子网 @@ -3014,8 +5053,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.Subnet' security: - BearerAuth: [] summary: 子网详情 @@ -3043,8 +5081,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.Subnet' security: - BearerAuth: [] summary: 更新子网 @@ -3062,8 +5099,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.SubscriptionInfo' + type: array security: - BearerAuth: [] summary: 订阅列表 @@ -3086,8 +5124,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.SubscriptionDetail' security: - BearerAuth: [] summary: 订阅详情 @@ -3109,8 +5146,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.TenantUser' + type: array security: - BearerAuth: [] summary: 租户 IAM 用户列表 @@ -3137,8 +5175,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.TenantUser' security: - BearerAuth: [] summary: 创建租户 IAM 用户 @@ -3189,8 +5226,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.TenantUserDetail' security: - BearerAuth: [] summary: 租户用户详情 @@ -3222,8 +5258,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.TenantUser' security: - BearerAuth: [] summary: 更新租户 IAM 用户 @@ -3246,8 +5281,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.deletedApiKeysResponse' security: - BearerAuth: [] summary: 清除用户全部 API Key @@ -3274,8 +5308,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.deletedTotpResponse' security: - BearerAuth: [] summary: 清除用户 MFA 设备 @@ -3300,10 +5333,9 @@ paths: type: string responses: "200": - description: OK + description: 一次性明文密码 schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.passwordResponse' security: - BearerAuth: [] summary: 重置租户用户密码 @@ -3321,8 +5353,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.VCN' + type: array security: - BearerAuth: [] summary: VCN 列表 @@ -3345,8 +5378,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.VCN' security: - BearerAuth: [] summary: 创建 VCN @@ -3389,8 +5421,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.VCN' security: - BearerAuth: [] summary: VCN 详情 @@ -3418,8 +5449,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_oci.VCN' security: - BearerAuth: [] summary: 更新 VCN @@ -3448,8 +5478,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.ipv6StepsResponse' security: - BearerAuth: [] summary: VCN 启用 IPv6 @@ -3465,10 +5494,9 @@ paths: type: integer responses: "200": - description: OK + description: config 与 changes 字段变更对照 schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.configChangesResponse' security: - BearerAuth: [] summary: 验证配置连通性并刷新画像 @@ -3518,8 +5546,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.addressResponse' security: - BearerAuth: [] summary: 为指定 VNIC 添加 IPv6 @@ -3558,8 +5585,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.BlockVolume' + type: array security: - BearerAuth: [] summary: 块存储卷列表 @@ -3571,8 +5599,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.Overview' security: - BearerAuth: [] summary: 返回总览页聚合数据 @@ -3584,8 +5611,7 @@ paths: "200": description: items schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.itemsResponse-oci-portal_internal_service_ProxyView' security: - BearerAuth: [] summary: 代理列表 @@ -3603,8 +5629,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.ProxyView' security: - BearerAuth: [] summary: 创建代理 @@ -3643,8 +5668,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.ProxyView' security: - BearerAuth: [] summary: 更新代理 @@ -3662,8 +5686,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.ProxyView' security: - BearerAuth: [] summary: 手动重测代理出口地区,同步返回最新视图 @@ -3687,8 +5710,7 @@ paths: "200": description: usedBy schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.usedByResponse' security: - BearerAuth: [] summary: 设置代理关联的租户全集 @@ -3707,8 +5729,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.ImportResult' security: - BearerAuth: [] summary: 批量导入代理 @@ -3720,8 +5741,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_oci.RegionInfo' + type: array security: - BearerAuth: [] summary: 返回本地维护的完整区域表 @@ -3733,8 +5755,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.itemsResponse-oci-portal_internal_service_NotifyChannelView' security: - BearerAuth: [] summary: 返回全部通知渠道的脱敏视图 @@ -3758,8 +5779,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.itemsResponse-oci-portal_internal_service_NotifyChannelView' security: - BearerAuth: [] summary: 保存单渠道配置并返回全渠道最新视图 @@ -3787,8 +5807,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.NotifyEventsView' security: - BearerAuth: [] summary: 返回全部通知事件开关 @@ -3806,8 +5825,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.NotifyEventsView' security: - BearerAuth: [] summary: 全量保存五个事件开关并返回最新值 @@ -3819,8 +5837,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.itemsResponse-oci-portal_internal_service_NotifyTemplateView' security: - BearerAuth: [] summary: 返回全部通知模板 @@ -3906,8 +5923,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.SecuritySettings' security: - BearerAuth: [] summary: 返回安全设置 @@ -3925,8 +5941,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.SecuritySettings' security: - BearerAuth: [] summary: 保存安全设置并返回最新值 @@ -3938,8 +5953,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.TaskSettingsView' security: - BearerAuth: [] summary: 返回任务行为设置 @@ -3957,8 +5971,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.TaskSettingsView' security: - BearerAuth: [] summary: 保存任务行为设置并返回最新值 @@ -3970,8 +5983,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.TelegramView' security: - BearerAuth: [] summary: 返回脱敏后的 Telegram 配置,绝不回 token 明文 @@ -3989,8 +6001,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_service.TelegramView' security: - BearerAuth: [] summary: 保存配置并返回最新脱敏视图 @@ -4012,8 +6023,7 @@ paths: "200": description: items 与 total schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.pagedResponse-oci-portal_internal_model_SystemLog' security: - BearerAuth: [] summary: 系统操作日志列表 @@ -4026,8 +6036,7 @@ paths: description: OK schema: items: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_model.Task' type: array security: - BearerAuth: [] @@ -4046,8 +6055,7 @@ paths: "201": description: Created schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_model.Task' security: - BearerAuth: [] summary: 创建任务 @@ -4080,8 +6088,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_model.Task' security: - BearerAuth: [] summary: 任务详情 @@ -4104,8 +6111,7 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/oci-portal_internal_model.Task' security: - BearerAuth: [] summary: 更新任务 @@ -4123,8 +6129,9 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + items: + $ref: '#/definitions/oci-portal_internal_model.TaskLog' + type: array security: - BearerAuth: [] summary: 任务执行日志 @@ -4142,13 +6149,11 @@ paths: "202": description: Accepted schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.triggerResponse' "409": description: 任务正在执行中 schema: - additionalProperties: true - type: object + $ref: '#/definitions/internal_api.errorResponse' security: - BearerAuth: [] summary: 立即执行任务(异步触发,结果经任务日志轮询获取) @@ -4174,9 +6179,7 @@ paths: "403": description: 时间戳超窗或证书源非 Oracle 域 schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/internal_api.errorResponse' "404": description: secret 无效(不暴露端点存在性) summary: OCI 日志回传入口(ONS HTTPS 订阅投递) diff --git a/internal/aiwire/anyjson.go b/internal/aiwire/anyjson.go new file mode 100644 index 0000000..f5ae4b6 --- /dev/null +++ b/internal/aiwire/anyjson.go @@ -0,0 +1,5 @@ +package aiwire + +// AnyJSON 仅供 swagger 文档渲染:经 .swaggo 全局替换,代表任意 JSON 值 +// (json.RawMessage 与 string/数组联合类型),运行时代码不使用。 +type AnyJSON struct{} diff --git a/internal/aiwire/moderations.go b/internal/aiwire/moderations.go new file mode 100644 index 0000000..7d35cce --- /dev/null +++ b/internal/aiwire/moderations.go @@ -0,0 +1,45 @@ +package aiwire + +import "encoding/json" + +// ModerationsRequest 是 /ai/v1/moderations 请求体;input 兼容 OpenAI 的 +// string 与 []string 两种形态,model 字段接受但忽略(上游为服务级 API)。 +type ModerationsRequest struct { + Model string `json:"model,omitempty"` + Input json.RawMessage `json:"input"` +} + +// ModerationPii 是一处 PII 命中(OCI 扩展,OpenAI 协议无对应物)。 +type ModerationPii struct { + Text string `json:"text"` + Label string `json:"label"` + Score float64 `json:"score"` + Offset int `json:"offset"` + Length int `json:"length"` +} + +// ModerationResult 是一条输入的审核结果:categories / category_scores 用 +// OCI 原生维度(overall / blocklist / prompt_injection),pii 为扩展字段。 +type ModerationResult struct { + Flagged bool `json:"flagged"` + Categories map[string]bool `json:"categories"` + CategoryScores map[string]float64 `json:"category_scores"` + Pii []ModerationPii `json:"pii,omitempty"` +} + +// ModerationsResponse 是 /ai/v1/moderations 响应体(OpenAI moderations 外壳)。 +type ModerationsResponse struct { + ID string `json:"id"` + Model string `json:"model"` + Results []ModerationResult `json:"results"` +} + +// SpeechRequest 描述 /ai/v1/audio/speech 请求体的已知字段(文档用途)。 +// 直通端点实际按原样透传,未列字段与 xAI 专属参数(如 output_format)同样保留。 +type SpeechRequest struct { + Model string `json:"model"` + Input string `json:"input"` + Voice string `json:"voice,omitempty"` + ResponseFormat string `json:"response_format,omitempty"` + Language string `json:"language,omitempty"` +} diff --git a/internal/aiwire/rerank.go b/internal/aiwire/rerank.go new file mode 100644 index 0000000..c5f87eb --- /dev/null +++ b/internal/aiwire/rerank.go @@ -0,0 +1,28 @@ +package aiwire + +// RerankRequest 是 /ai/v1/rerank 请求体(Jina / Cohere 通行风格)。 +type RerankRequest struct { + Model string `json:"model"` + Query string `json:"query"` + Documents []string `json:"documents"` + TopN *int `json:"top_n,omitempty"` + ReturnDocuments *bool `json:"return_documents,omitempty"` +} + +// RerankDocument 包装原文,仅在 return_documents 时返回。 +type RerankDocument struct { + Text string `json:"text"` +} + +// RerankResult 是一条重排结果:index 指向请求 documents 下标。 +type RerankResult struct { + Index int `json:"index"` + RelevanceScore float64 `json:"relevance_score"` + Document *RerankDocument `json:"document,omitempty"` +} + +// RerankResponse 是 /ai/v1/rerank 响应体。 +type RerankResponse struct { + Model string `json:"model"` + Results []RerankResult `json:"results"` +} diff --git a/internal/aiwire/responses.go b/internal/aiwire/responses.go index f735a24..f4b1e5c 100644 --- a/internal/aiwire/responses.go +++ b/internal/aiwire/responses.go @@ -184,3 +184,16 @@ type RespError struct { type RespIncomplete struct { Reason string `json:"reason"` } + +// RespResponse 描述 /ai/v1/responses 非流式响应的常用顶层字段(文档用途)。 +// 直通端点原样返回上游 JSON,未列字段(reasoning、incomplete_details 等)同样保留。 +type RespResponse struct { + ID string `json:"id"` + Object string `json:"object"` + CreatedAt int64 `json:"created_at"` + Status string `json:"status"` + Model string `json:"model"` + Output json.RawMessage `json:"output"` + Usage *RespUsage `json:"usage,omitempty"` + Error *RespError `json:"error,omitempty"` +} diff --git a/internal/api/about.go b/internal/api/about.go index 4941924..0e6cabe 100644 --- a/internal/api/about.go +++ b/internal/api/about.go @@ -30,7 +30,7 @@ func SetAboutRuntime(dbDriver, dbPath string) { // // @Summary 返回构建、运行时长与资源占用信息,「设置 · 关于」页展示 // @Tags 设置 -// @Success 200 {object} map[string]any +// @Success 200 {object} aboutResponse // @Security BearerAuth // @Router /api/v1/about [get] func about(c *gin.Context) { diff --git a/internal/api/aiadmin.go b/internal/api/aiadmin.go index 19c8e05..0c87489 100644 --- a/internal/api/aiadmin.go +++ b/internal/api/aiadmin.go @@ -6,6 +6,9 @@ import ( "github.com/gin-gonic/gin" + _ "oci-portal/internal/aiwire" // swagger 注解引用 + _ "oci-portal/internal/model" // swagger 注解引用 + "oci-portal/internal/service" ) @@ -18,7 +21,7 @@ type aiAdminHandler struct { // @Summary ---- 密钥 ---- // @Tags AI 管理 -// @Success 200 {object} map[string]any +// @Success 200 {object} itemsResponse[model.AiKey] // @Security BearerAuth // @Router /api/v1/ai-keys [get] func (h *aiAdminHandler) listKeys(c *gin.Context) { @@ -35,7 +38,7 @@ func (h *aiAdminHandler) listKeys(c *gin.Context) { // @Summary 生成密钥 // @Tags AI 管理 // @Param body body object true "请求体(见接口说明)" -// @Success 201 {object} map[string]any +// @Success 201 {object} aiKeyCreateResponse "key 为明文密钥,仅本次返回" // @Security BearerAuth // @Router /api/v1/ai-keys [post] func (h *aiAdminHandler) createKey(c *gin.Context) { @@ -110,7 +113,7 @@ func (h *aiAdminHandler) deleteKey(c *gin.Context) { // @Tags AI 管理 // @Param id path int true "配置 ID" // @Param body body object true "请求体(见接口说明)" -// @Success 200 {object} map[string]any +// @Success 200 {object} model.AiKey // @Security BearerAuth // @Router /api/v1/ai-keys/{id}/content-log [put] func (h *aiAdminHandler) updateKeyContentLog(c *gin.Context) { @@ -137,7 +140,7 @@ func (h *aiAdminHandler) updateKeyContentLog(c *gin.Context) { // // @Summary 分页查询内容日志 // @Tags AI 管理 -// @Success 200 {object} map[string]any +// @Success 200 {object} pagedResponse[model.AiCallLog] // @Security BearerAuth // @Router /api/v1/ai-content-logs [get] func (h *aiAdminHandler) listContentLogs(c *gin.Context) { @@ -157,7 +160,7 @@ func (h *aiAdminHandler) listContentLogs(c *gin.Context) { // @Summary ---- 渠道 ---- // @Tags AI 管理 -// @Success 200 {object} map[string]any +// @Success 200 {object} itemsResponse[model.AiChannel] // @Security BearerAuth // @Router /api/v1/ai-channels [get] func (h *aiAdminHandler) listChannels(c *gin.Context) { @@ -172,7 +175,7 @@ func (h *aiAdminHandler) listChannels(c *gin.Context) { // @Summary 创建 AI 渠道 // @Tags AI 管理 // @Param body body service.ChannelInput true "请求体" -// @Success 201 {object} map[string]any +// @Success 201 {object} model.AiChannel // @Security BearerAuth // @Router /api/v1/ai-channels [post] func (h *aiAdminHandler) createChannel(c *gin.Context) { @@ -236,7 +239,7 @@ func (h *aiAdminHandler) deleteChannel(c *gin.Context) { // @Summary 触发探测:服务可见性 + 模型同步 + 配额试调,返回更新后的渠道 // @Tags AI 管理 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {object} model.AiChannel // @Security BearerAuth // @Router /api/v1/ai-channels/{id}/probe [post] func (h *aiAdminHandler) probeChannel(c *gin.Context) { @@ -255,7 +258,7 @@ func (h *aiAdminHandler) probeChannel(c *gin.Context) { // @Summary 同步渠道模型缓存 // @Tags AI 管理 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {object} itemsResponse[model.AiModelCache] // @Security BearerAuth // @Router /api/v1/ai-channels/{id}/sync-models [post] func (h *aiAdminHandler) syncChannelModels(c *gin.Context) { @@ -275,7 +278,7 @@ func (h *aiAdminHandler) syncChannelModels(c *gin.Context) { // @Summary ---- 聚合模型与调用日志 ---- // @Tags AI 管理 -// @Success 200 {object} map[string]any +// @Success 200 {object} itemsResponse[aiwire.Model] // @Security BearerAuth // @Router /api/v1/ai-models [get] func (h *aiAdminHandler) gatewayModels(c *gin.Context) { @@ -291,7 +294,7 @@ func (h *aiAdminHandler) gatewayModels(c *gin.Context) { // @Summary 模型黑名单列表 // @Tags AI 管理 -// @Success 200 {object} map[string]any +// @Success 200 {object} itemsResponse[model.AiModelBlacklist] // @Security BearerAuth // @Router /api/v1/ai-blacklist [get] func (h *aiAdminHandler) listBlacklist(c *gin.Context) { @@ -308,7 +311,7 @@ func (h *aiAdminHandler) listBlacklist(c *gin.Context) { // @Summary 添加模型黑名单 // @Tags AI 管理 // @Param body body object true "请求体:{name: 模型名}" -// @Success 201 {object} map[string]any +// @Success 201 {object} itemResponse[model.AiModelBlacklist] // @Security BearerAuth // @Router /api/v1/ai-blacklist [post] func (h *aiAdminHandler) addBlacklist(c *gin.Context) { @@ -347,7 +350,7 @@ func (h *aiAdminHandler) removeBlacklist(c *gin.Context) { // @Summary AI 调用日志列表 // @Tags AI 管理 -// @Success 200 {object} map[string]any +// @Success 200 {object} pagedResponse[model.AiContentLog] // @Security BearerAuth // @Router /api/v1/ai-logs [get] func (h *aiAdminHandler) listLogs(c *gin.Context) { diff --git a/internal/api/aigateway.go b/internal/api/aigateway.go index 5859550..ceb385d 100644 --- a/internal/api/aigateway.go +++ b/internal/api/aigateway.go @@ -165,8 +165,8 @@ func fillUsage(entry *model.AiCallLog, u *aiwire.Usage) { // // @Summary OpenAI 兼容向量嵌入 // @Tags AI 网关 -// @Param body body object true "OpenAI embeddings 请求体" -// @Success 200 {object} map[string]any "OpenAI 兼容响应" +// @Param body body aiwire.EmbeddingsRequest true "OpenAI embeddings 请求体" +// @Success 200 {object} aiwire.EmbeddingsResponse "OpenAI 兼容响应" // @Router /ai/v1/embeddings [post] func (h *aiGatewayHandler) embeddings(c *gin.Context) { var req aiwire.EmbeddingsRequest @@ -218,8 +218,8 @@ const anthDefaultMaxTokens = 8192 // // @Summary Anthropic Messages 兼容端点 // @Tags AI 网关 -// @Param body body object true "Anthropic messages 请求体(支持 stream;经 OCI OpenAI 兼容面直通;max_tokens 可缺省,默认 8192)" -// @Success 200 {object} map[string]any "Anthropic 兼容响应(流式为 SSE)" +// @Param body body aiwire.MessagesRequest true "Anthropic messages 请求体(支持 stream;经 OCI OpenAI 兼容面直通;max_tokens 可缺省,默认 8192)" +// @Success 200 {object} aiwire.MessagesResponse "Anthropic 兼容响应(非流式;流式为 SSE 事件序列)" // @Router /ai/v1/messages [post] func (h *aiGatewayHandler) messages(c *gin.Context) { var req aiwire.MessagesRequest @@ -381,8 +381,8 @@ func writeAnthEvents(c *gin.Context, events []service.AnthEvent) { // // @Summary OpenAI Chat Completions 兼容端点 // @Tags AI 网关 -// @Param body body object true "OpenAI chat/completions 请求体(支持 stream;经 Responses 转换直通)" -// @Success 200 {object} map[string]any "OpenAI 兼容响应(流式为 SSE,末尾 data: [DONE])" +// @Param body body aiwire.ChatRequest true "OpenAI chat/completions 请求体(支持 stream;经 Responses 转换直通)" +// @Success 200 {object} aiwire.ChatResponse "OpenAI 兼容响应(非流式;流式为 SSE,末尾 data: [DONE])" // @Router /ai/v1/chat/completions [post] func (h *aiGatewayHandler) chatCompletions(c *gin.Context) { var req aiwire.ChatRequest @@ -528,7 +528,7 @@ func writeChatChunks(c *gin.Context, chunks []aiwire.ChatChunk) { // // @Summary 可用模型列表 // @Tags AI 网关 -// @Success 200 {object} map[string]any "OpenAI 兼容 models 列表" +// @Success 200 {object} aiwire.ModelList "OpenAI 兼容 models 列表" // @Router /ai/v1/models [get] func (h *aiGatewayHandler) listModels(c *gin.Context) { list, err := h.gw.GatewayModels(c.Request.Context(), keyGroup(c)) @@ -552,8 +552,8 @@ func (h *aiGatewayHandler) listModels(c *gin.Context) { // // @Summary OpenAI Responses 兼容端点 // @Tags AI 网关 -// @Param body body object true "OpenAI responses 请求体(支持 stream;web_search/x_search 服务端工具仅非流式)" -// @Success 200 {object} map[string]any "OpenAI 兼容响应(流式为 SSE)" +// @Param body body aiwire.RespRequest true "OpenAI responses 请求体(支持 stream;服务端工具 web_search/x_search/code_interpreter/mcp 含流式;未列字段原样透传上游)" +// @Success 200 {object} aiwire.RespResponse "OpenAI 兼容响应(非流式;流式为 SSE);直通仅建模常用字段,未列字段原样返回" // @Router /ai/v1/responses [post] func (h *aiGatewayHandler) responses(c *gin.Context) { raw, err := c.GetRawData() diff --git a/internal/api/aigateway_extras.go b/internal/api/aigateway_extras.go new file mode 100644 index 0000000..51130ef --- /dev/null +++ b/internal/api/aigateway_extras.go @@ -0,0 +1,119 @@ +package api + +import ( + "net/http" + "strings" + "time" + + "github.com/gin-gonic/gin" + + "oci-portal/internal/aiwire" + "oci-portal/internal/service" +) + +// audioSpeech 是 OpenAI /ai/v1/audio/speech 端点(TTS,直通兼容面)。 +// +// @Summary OpenAI Audio Speech 兼容端点(文本转语音) +// @Tags AI 网关 +// @Param body body aiwire.SpeechRequest true "OpenAI audio speech 请求体(model/input 必填,voice 见 xAI Grok Voice 列表,language 缺省 auto;未列字段原样透传)" +// @Success 200 {file} binary "音频字节(Content-Type 透传上游,默认 audio/mpeg)" +// @Router /ai/v1/audio/speech [post] +func (h *aiGatewayHandler) audioSpeech(c *gin.Context) { + raw, err := c.GetRawData() + if err != nil { + aiError(c, http.StatusBadRequest, "invalid_request_error", err.Error()) + return + } + modelName, body, err := service.SpeechBodyNormalize(raw) + if err != nil { + aiError(c, http.StatusBadRequest, "invalid_request_error", err.Error()) + return + } + if !checkKeyModel(c, modelName) { + return + } + start := time.Now() + audio, contentType, meta, err := h.gw.Speech(c.Request.Context(), modelName, body, keyGroup(c)) + entry := h.logEntry(c, "speech", modelName, false, meta, start) + if err != nil { + upstreamError(c, err) + entry.ErrMsg = err.Error() + h.logFailure(c, entry, string(raw)) + return + } + entry.Status = http.StatusOK + callID := h.gw.LogCall(entry) + h.maybeLogContent(c, callID, "speech", modelName, false, string(raw), nil) + if contentType == "" { + contentType = "audio/mpeg" + } + c.Data(http.StatusOK, contentType, audio) +} + +// rerank 是 /ai/v1/rerank 端点(Jina / Cohere 风格文档重排)。 +// +// @Summary 文档重排端点(Cohere Rerank) +// @Tags AI 网关 +// @Param body body aiwire.RerankRequest true "重排请求体(model/query/documents 必填,可选 top_n/return_documents)" +// @Success 200 {object} aiwire.RerankResponse "重排结果(results[].index 指向入参下标)" +// @Router /ai/v1/rerank [post] +func (h *aiGatewayHandler) rerank(c *gin.Context) { + var req aiwire.RerankRequest + if err := c.ShouldBindJSON(&req); err != nil { + aiError(c, http.StatusBadRequest, "invalid_request_error", err.Error()) + return + } + if strings.TrimSpace(req.Model) == "" || strings.TrimSpace(req.Query) == "" || len(req.Documents) == 0 { + aiError(c, http.StatusBadRequest, "invalid_request_error", "model、query 与 documents 不能为空") + return + } + if !checkKeyModel(c, req.Model) { + return + } + start := time.Now() + resp, meta, err := h.gw.Rerank(c.Request.Context(), req, keyGroup(c)) + entry := h.logEntry(c, "rerank", req.Model, false, meta, start) + if err != nil { + upstreamError(c, err) + entry.ErrMsg = err.Error() + h.logFailure(c, entry, req) + return + } + entry.Status = http.StatusOK + callID := h.gw.LogCall(entry) + h.maybeLogContent(c, callID, "rerank", req.Model, false, req, resp) + c.JSON(http.StatusOK, resp) +} + +// moderations 是 /ai/v1/moderations 端点(OpenAI 外壳映射 OCI Guardrails)。 +// +// @Summary 内容审核端点(OCI Guardrails) +// @Tags AI 网关 +// @Param body body aiwire.ModerationsRequest true "审核请求体(input 为字符串或字符串数组,单次至多 8 条;model 接受但忽略)" +// @Success 200 {object} aiwire.ModerationsResponse "审核结果(categories/category_scores 为 overall/blocklist/prompt_injection,pii 为扩展字段)" +// @Router /ai/v1/moderations [post] +func (h *aiGatewayHandler) moderations(c *gin.Context) { + var req aiwire.ModerationsRequest + if err := c.ShouldBindJSON(&req); err != nil { + aiError(c, http.StatusBadRequest, "invalid_request_error", err.Error()) + return + } + inputs, err := service.ModerationInputs(req.Input) + if err != nil { + aiError(c, http.StatusBadRequest, "invalid_request_error", err.Error()) + return + } + start := time.Now() + resp, meta, err := h.gw.Moderations(c.Request.Context(), aiRandID("modr_"), inputs, keyGroup(c)) + entry := h.logEntry(c, "moderations", "oci-guardrails", false, meta, start) + if err != nil { + upstreamError(c, err) + entry.ErrMsg = err.Error() + h.logFailure(c, entry, req) + return + } + entry.Status = http.StatusOK + callID := h.gw.LogCall(entry) + h.maybeLogContent(c, callID, "moderations", "oci-guardrails", false, req, resp) + c.JSON(http.StatusOK, resp) +} diff --git a/internal/api/aigateway_test.go b/internal/api/aigateway_test.go index 081662c..ff6a8f1 100644 --- a/internal/api/aigateway_test.go +++ b/internal/api/aigateway_test.go @@ -95,6 +95,14 @@ func TestAiGatewayKeyModelRestrict(t *testing.T) { {"chat completions 不支持内容块拒绝", "open-key-12345", "/ai/v1/chat/completions", `{"model":"ghost-model","messages":[{"role":"user","content":[{"type":"input_audio"}]}]}`, 400, []string{"invalid_request_error"}}, + {"audio speech 白名单外拦截", "limited-key-1234", "/ai/v1/audio/speech", + `{"model":"meta.llama-3.3-70b-instruct","input":"你好"}`, 404, deny}, + {"rerank 白名单外拦截", "limited-key-1234", "/ai/v1/rerank", + `{"model":"meta.llama-3.3-70b-instruct","query":"q","documents":["d"]}`, 404, deny}, + {"rerank 缺 documents 拒绝", "open-key-12345", "/ai/v1/rerank", + `{"model":"ghost-model","query":"q"}`, 400, []string{"invalid_request_error"}}, + {"moderations 空 input 拒绝", "open-key-12345", "/ai/v1/moderations", + `{"input":[]}`, 400, []string{"invalid_request_error"}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/api/attachment.go b/internal/api/attachment.go index 150ed94..b59e730 100644 --- a/internal/api/attachment.go +++ b/internal/api/attachment.go @@ -15,7 +15,7 @@ import ( // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body object true "请求体(见接口说明)" -// @Success 200 {object} map[string]any +// @Success 200 {object} publicIpResponse // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/change-public-ip [post] func (h *ociConfigHandler) changePublicIP(c *gin.Context) { @@ -40,7 +40,7 @@ func (h *ociConfigHandler) changePublicIP(c *gin.Context) { // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body object true "请求体(见接口说明)" -// @Success 201 {object} map[string]any +// @Success 201 {object} ipv6AddressResponse // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/ipv6-addresses [post] func (h *ociConfigHandler) addInstanceIpv6(c *gin.Context) { @@ -92,7 +92,7 @@ type attachVnicRequest struct { // @Tags 计算 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.Vnic // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/vnics [get] func (h *ociConfigHandler) listInstanceVnics(c *gin.Context) { @@ -113,7 +113,7 @@ func (h *ociConfigHandler) listInstanceVnics(c *gin.Context) { // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body attachVnicRequest true "请求体" -// @Success 201 {object} map[string]any +// @Success 201 {object} oci.Vnic // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/vnics [post] func (h *ociConfigHandler) attachVnic(c *gin.Context) { @@ -160,7 +160,7 @@ func (h *ociConfigHandler) detachVnic(c *gin.Context) { // @Param id path int true "配置 ID" // @Param vnicId path string true "vnicId" // @Param body body object true "请求体(见接口说明)" -// @Success 201 {object} map[string]any +// @Success 201 {object} addressResponse // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/vnics/{vnicId}/ipv6-addresses [post] func (h *ociConfigHandler) addVnicIpv6(c *gin.Context) { @@ -195,7 +195,7 @@ type attachBootVolumeRequest struct { // @Tags 存储 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.BootVolumeAttachment // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/boot-volume-attachments [get] func (h *ociConfigHandler) listBootVolumeAttachments(c *gin.Context) { @@ -216,7 +216,7 @@ func (h *ociConfigHandler) listBootVolumeAttachments(c *gin.Context) { // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body attachBootVolumeRequest true "请求体" -// @Success 201 {object} map[string]any +// @Success 201 {object} oci.BootVolumeAttachment // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/boot-volume-attachments [post] func (h *ociConfigHandler) attachBootVolume(c *gin.Context) { @@ -242,7 +242,7 @@ func (h *ociConfigHandler) attachBootVolume(c *gin.Context) { // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body attachBootVolumeRequest true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.BootVolumeAttachment // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/replace-boot-volume [post] func (h *ociConfigHandler) replaceBootVolume(c *gin.Context) { @@ -293,7 +293,7 @@ type attachVolumeRequest struct { // @Summary 块存储卷列表 // @Tags 存储 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.BlockVolume // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/volumes [get] func (h *ociConfigHandler) listBlockVolumes(c *gin.Context) { @@ -313,7 +313,7 @@ func (h *ociConfigHandler) listBlockVolumes(c *gin.Context) { // @Tags 存储 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.VolumeAttachment // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/volume-attachments [get] func (h *ociConfigHandler) listVolumeAttachments(c *gin.Context) { @@ -334,7 +334,7 @@ func (h *ociConfigHandler) listVolumeAttachments(c *gin.Context) { // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body attachVolumeRequest true "请求体" -// @Success 201 {object} map[string]any +// @Success 201 {object} oci.VolumeAttachment // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/volume-attachments [post] func (h *ociConfigHandler) attachVolume(c *gin.Context) { diff --git a/internal/api/auth.go b/internal/api/auth.go index 5372215..57ad755 100644 --- a/internal/api/auth.go +++ b/internal/api/auth.go @@ -32,9 +32,9 @@ type loginRequest struct { // @Accept json // @Produce json // @Param body body loginRequest true "登录凭据" -// @Success 200 {object} map[string]any "token 与 expiresAt" -// @Failure 401 {object} map[string]string "凭据错误" -// @Failure 428 {object} map[string]any "需要两步验证码(totpRequired=true)" +// @Success 200 {object} tokenResponse "token 与 expiresAt" +// @Failure 401 {object} errorResponse "凭据错误" +// @Failure 428 {object} totpRequiredResponse "需要两步验证码(totpRequired=true)" // @Router /api/v1/auth/login [post] func (h *authHandler) login(c *gin.Context) { var req loginRequest diff --git a/internal/api/authx.go b/internal/api/authx.go index 4eaba3b..965c7b7 100644 --- a/internal/api/authx.go +++ b/internal/api/authx.go @@ -8,6 +8,8 @@ import ( "github.com/gin-gonic/gin" + _ "oci-portal/internal/model" // swagger 注解引用 + "oci-portal/internal/service" ) @@ -23,7 +25,7 @@ type authxHandler struct { // // @Summary 两步验证状态 // @Tags 认证 -// @Success 200 {object} map[string]bool "enabled" +// @Success 200 {object} enabledResponse "enabled" // @Security BearerAuth // @Router /api/v1/auth/totp [get] func (h *authxHandler) totpStatus(c *gin.Context) { @@ -39,8 +41,8 @@ func (h *authxHandler) totpStatus(c *gin.Context) { // // @Summary 发起两步验证设置 // @Tags 认证 -// @Success 200 {object} map[string]string "secret 与 otpauthUri" -// @Failure 409 {object} map[string]string "已启用" +// @Success 200 {object} totpSetupResponse "secret 与 otpauthUri" +// @Failure 409 {object} errorResponse "已启用" // @Security BearerAuth // @Router /api/v1/auth/totp/setup [post] func (h *authxHandler) totpSetup(c *gin.Context) { @@ -128,7 +130,7 @@ func (h *authxHandler) respondFreshToken(c *gin.Context) { // // @Summary 撤销全部会话 // @Tags 认证 -// @Success 200 {object} map[string]string "新 token 与 expiresAt" +// @Success 200 {object} tokenResponse "新 token 与 expiresAt" // @Security BearerAuth // @Router /api/v1/auth/revoke-sessions [post] func (h *authxHandler) revokeSessions(c *gin.Context) { @@ -146,7 +148,7 @@ func (h *authxHandler) revokeSessions(c *gin.Context) { // // @Summary 登录凭据摘要 // @Tags 认证 -// @Success 200 {object} map[string]any "username 与 passwordLoginDisabled" +// @Success 200 {object} credentialsResponse "username 与 passwordLoginDisabled" // @Security BearerAuth // @Router /api/v1/auth/credentials [get] func (h *authxHandler) getCredentials(c *gin.Context) { @@ -167,7 +169,7 @@ func (h *authxHandler) getCredentials(c *gin.Context) { // @Tags 认证 // @Param body body service.UpdateCredentialsInput true "新凭据(当前密码必验)" // @Success 204 "已更新,请重新登录" -// @Failure 401 {object} map[string]string "当前密码错误" +// @Failure 401 {object} errorResponse "当前密码错误" // @Security BearerAuth // @Router /api/v1/auth/credentials [put] func (h *authxHandler) updateCredentials(c *gin.Context) { @@ -199,7 +201,7 @@ func (h *authxHandler) updateCredentials(c *gin.Context) { // @Tags 认证 // @Param body body object true "{disabled: bool}" // @Success 204 "已保存" -// @Failure 409 {object} map[string]string "未绑定外部身份" +// @Failure 409 {object} errorResponse "未绑定外部身份" // @Security BearerAuth // @Router /api/v1/auth/password-login [put] func (h *authxHandler) updatePasswordLogin(c *gin.Context) { @@ -230,7 +232,7 @@ func (h *authxHandler) updatePasswordLogin(c *gin.Context) { // // @Summary 外部登录 provider 列表 // @Tags 认证 -// @Success 200 {object} map[string]any "providers 与 passwordLoginDisabled" +// @Success 200 {object} oauthProvidersResponse "providers 与 passwordLoginDisabled" // @Router /api/v1/auth/oauth/providers [get] func (h *authxHandler) oauthProviders(c *gin.Context) { providers := h.oauth.Providers(c.Request.Context()) @@ -247,7 +249,7 @@ func (h *authxHandler) oauthProviders(c *gin.Context) { // @Tags 认证 // @Param provider path string true "oidc / github" // @Param mode query string false "bind=绑定当前账号(需 Bearer),缺省登录" -// @Success 200 {object} map[string]string "url" +// @Success 200 {object} urlResponse "url" // @Router /api/v1/auth/oauth/{provider}/authorize [get] func (h *authxHandler) oauthAuthorize(c *gin.Context) { provider := c.Param("provider") @@ -333,7 +335,7 @@ func oauthErrText(err error) string { // // @Summary 已绑定外部身份 // @Tags 认证 -// @Success 200 {object} map[string]any "items" +// @Success 200 {object} itemsResponse[model.UserIdentity] "items" // @Security BearerAuth // @Router /api/v1/auth/identities [get] func (h *authxHandler) identities(c *gin.Context) { @@ -351,7 +353,7 @@ func (h *authxHandler) identities(c *gin.Context) { // @Tags 认证 // @Param id path int true "身份 ID" // @Success 204 "已解绑" -// @Failure 409 {object} map[string]string "最后一个身份不可解绑" +// @Failure 409 {object} errorResponse "最后一个身份不可解绑" // @Security BearerAuth // @Router /api/v1/auth/identities/{id} [delete] func (h *authxHandler) unbindIdentity(c *gin.Context) { diff --git a/internal/api/console.go b/internal/api/console.go index 454ebdd..c93491a 100644 --- a/internal/api/console.go +++ b/internal/api/console.go @@ -4,6 +4,8 @@ import ( "net/http" "github.com/gin-gonic/gin" + + _ "oci-portal/internal/oci" // swagger 注解引用 ) // ---- 控制台连接(VNC / 串口) ---- @@ -18,7 +20,7 @@ type createConsoleConnectionRequest struct { // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body createConsoleConnectionRequest true "请求体" -// @Success 201 {object} map[string]any +// @Success 201 {object} oci.ConsoleConnection // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/console-connections [post] func (h *ociConfigHandler) createConsoleConnection(c *gin.Context) { @@ -43,7 +45,7 @@ func (h *ociConfigHandler) createConsoleConnection(c *gin.Context) { // @Tags 计算 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.ConsoleConnection // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/console-connections [get] func (h *ociConfigHandler) listConsoleConnections(c *gin.Context) { diff --git a/internal/api/federation.go b/internal/api/federation.go index 6871862..99690bc 100644 --- a/internal/api/federation.go +++ b/internal/api/federation.go @@ -41,7 +41,7 @@ func boolOr(v *bool, def bool) bool { // @Tags 租户 IAM // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.IdentityProviderInfo // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/identity-providers [get] func (h *ociConfigHandler) listIdentityProviders(c *gin.Context) { @@ -62,7 +62,7 @@ func (h *ociConfigHandler) listIdentityProviders(c *gin.Context) { // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" // @Param body body createIdpRequest true "请求体" -// @Success 201 {object} map[string]any +// @Success 201 {object} oci.IdentityProviderInfo // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/identity-providers [post] func (h *ociConfigHandler) createIdentityProvider(c *gin.Context) { @@ -102,7 +102,7 @@ func (h *ociConfigHandler) createIdentityProvider(c *gin.Context) { // @Param domainId query string false "身份域 OCID(缺省 Default 域)" // @Param idpId path string true "idpId" // @Param body body object true "请求体(见接口说明)" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.IdentityProviderInfo // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/identity-providers/{idpId}/activate [post] func (h *ociConfigHandler) activateIdentityProvider(c *gin.Context) { @@ -149,7 +149,7 @@ func (h *ociConfigHandler) deleteIdentityProvider(c *gin.Context) { // @Tags 租户 IAM // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" -// @Success 200 {object} map[string]any +// @Success 200 {file} file "SAML 元数据 XML(附件下载)" // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/saml-metadata [get] func (h *ociConfigHandler) downloadSamlMetadata(c *gin.Context) { @@ -170,7 +170,7 @@ func (h *ociConfigHandler) downloadSamlMetadata(c *gin.Context) { // @Tags 租户 IAM // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.SignOnRuleInfo // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/sign-on-rules [get] func (h *ociConfigHandler) listSignOnRules(c *gin.Context) { @@ -191,7 +191,7 @@ func (h *ociConfigHandler) listSignOnRules(c *gin.Context) { // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" // @Param body body object true "请求体(见接口说明)" -// @Success 201 {object} map[string]any +// @Success 201 {object} oci.SignOnRuleInfo // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/sign-on-exemptions [post] func (h *ociConfigHandler) createMfaExemption(c *gin.Context) { diff --git a/internal/api/instance.go b/internal/api/instance.go index e3e8b45..d11334e 100644 --- a/internal/api/instance.go +++ b/internal/api/instance.go @@ -11,7 +11,7 @@ import ( // @Summary 可用域列表 // @Tags 租户配置 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} string // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/availability-domains [get] func (h *ociConfigHandler) availabilityDomains(c *gin.Context) { @@ -67,7 +67,7 @@ type instanceActionRequest struct { // @Summary 实例列表 // @Tags 计算 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.Instance // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances [get] func (h *ociConfigHandler) listInstances(c *gin.Context) { @@ -87,7 +87,7 @@ func (h *ociConfigHandler) listInstances(c *gin.Context) { // @Tags 计算 // @Param id path int true "配置 ID" // @Param body body createInstanceRequest true "请求体" -// @Success 201 {object} map[string]any +// @Success 201 {object} createInstancesResponse "部分成功仍 201,errors 为逐台失败信息" // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances [post] func (h *ociConfigHandler) createInstance(c *gin.Context) { @@ -147,7 +147,7 @@ func (h *ociConfigHandler) createInstance(c *gin.Context) { // @Tags 计算 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.Instance // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId} [get] func (h *ociConfigHandler) getInstance(c *gin.Context) { @@ -168,7 +168,7 @@ func (h *ociConfigHandler) getInstance(c *gin.Context) { // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body updateInstanceRequest true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.Instance // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId} [put] func (h *ociConfigHandler) updateInstance(c *gin.Context) { @@ -220,7 +220,7 @@ func (h *ociConfigHandler) terminateInstance(c *gin.Context) { // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body instanceActionRequest true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.Instance // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/action [post] func (h *ociConfigHandler) instanceAction(c *gin.Context) { @@ -253,7 +253,7 @@ type updateBootVolumeRequest struct { // @Summary 引导卷列表 // @Tags 存储 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.BootVolume // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/boot-volumes [get] func (h *ociConfigHandler) listBootVolumes(c *gin.Context) { @@ -273,7 +273,7 @@ func (h *ociConfigHandler) listBootVolumes(c *gin.Context) { // @Tags 存储 // @Param id path int true "配置 ID" // @Param bootVolumeId path string true "bootVolumeId" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.BootVolume // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/boot-volumes/{bootVolumeId} [get] func (h *ociConfigHandler) getBootVolume(c *gin.Context) { @@ -294,7 +294,7 @@ func (h *ociConfigHandler) getBootVolume(c *gin.Context) { // @Param id path int true "配置 ID" // @Param bootVolumeId path string true "bootVolumeId" // @Param body body updateBootVolumeRequest true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.BootVolume // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/boot-volumes/{bootVolumeId} [put] func (h *ociConfigHandler) updateBootVolume(c *gin.Context) { diff --git a/internal/api/logevent.go b/internal/api/logevent.go index 98ebf8d..0d34a4e 100644 --- a/internal/api/logevent.go +++ b/internal/api/logevent.go @@ -7,6 +7,8 @@ import ( "github.com/gin-gonic/gin" + _ "oci-portal/internal/model" // swagger 注解引用 + "oci-portal/internal/service" ) @@ -20,7 +22,7 @@ type logEventHandler struct { // @Summary 查询配置的回调地址 // @Tags 任务与日志回传 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {object} logWebhookStatusResponse // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/log-webhook [get] func (h *logEventHandler) getWebhook(c *gin.Context) { @@ -45,7 +47,7 @@ func (h *logEventHandler) getWebhook(c *gin.Context) { // @Summary 生成 // @Tags 任务与日志回传 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {object} service.LogWebhookInfo // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/log-webhook [post] func (h *logEventHandler) ensureWebhook(c *gin.Context) { @@ -87,7 +89,7 @@ func (h *logEventHandler) revokeWebhook(c *gin.Context) { // @Tags 任务与日志回传 // @Param configId query int false "按配置过滤" // @Param q query string false "关键字" -// @Success 200 {object} map[string]any "items 与 total" +// @Success 200 {object} pagedResponse[model.LogEvent] "items 与 total" // @Security BearerAuth // @Router /api/v1/log-events [get] func (h *logEventHandler) list(c *gin.Context) { @@ -111,7 +113,7 @@ func (h *logEventHandler) list(c *gin.Context) { // @Summary 查询 OCI 侧链路状态与关键事件清单 // @Tags 任务与日志回传 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {object} service.RelayView // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/log-relay [get] func (h *logEventHandler) getRelay(c *gin.Context) { @@ -132,7 +134,7 @@ func (h *logEventHandler) getRelay(c *gin.Context) { // @Summary 一键建立回传链路 // @Tags 任务与日志回传 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {object} service.RelayView // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/log-relay [post] func (h *logEventHandler) setupRelay(c *gin.Context) { diff --git a/internal/api/network.go b/internal/api/network.go index 5ad3b68..03058d9 100644 --- a/internal/api/network.go +++ b/internal/api/network.go @@ -11,7 +11,7 @@ import ( // @Summary 实例形状列表 // @Tags 租户配置 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.ComputeShape // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/shapes [get] func (h *ociConfigHandler) shapes(c *gin.Context) { @@ -30,7 +30,7 @@ func (h *ociConfigHandler) shapes(c *gin.Context) { // @Summary 镜像列表 // @Tags 租户配置 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.Image // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/images [get] func (h *ociConfigHandler) images(c *gin.Context) { @@ -54,7 +54,7 @@ func (h *ociConfigHandler) images(c *gin.Context) { // @Tags 租户配置 // @Param id path int true "配置 ID" // @Param imageId path string true "imageId" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.Image // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/images/{imageId} [get] func (h *ociConfigHandler) getImage(c *gin.Context) { @@ -89,7 +89,7 @@ type renameRequest struct { // @Summary VCN 列表 // @Tags 网络 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.VCN // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/vcns [get] func (h *ociConfigHandler) listVCNs(c *gin.Context) { @@ -109,7 +109,7 @@ func (h *ociConfigHandler) listVCNs(c *gin.Context) { // @Tags 网络 // @Param id path int true "配置 ID" // @Param body body createVCNRequest true "请求体" -// @Success 201 {object} map[string]any +// @Success 201 {object} oci.VCN // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/vcns [post] func (h *ociConfigHandler) createVCN(c *gin.Context) { @@ -141,7 +141,7 @@ func (h *ociConfigHandler) createVCN(c *gin.Context) { // @Tags 网络 // @Param id path int true "配置 ID" // @Param vcnId path string true "vcnId" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.VCN // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/vcns/{vcnId} [get] func (h *ociConfigHandler) getVCN(c *gin.Context) { @@ -162,7 +162,7 @@ func (h *ociConfigHandler) getVCN(c *gin.Context) { // @Param id path int true "配置 ID" // @Param vcnId path string true "vcnId" // @Param body body renameRequest true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.VCN // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/vcns/{vcnId} [put] func (h *ociConfigHandler) updateVCN(c *gin.Context) { @@ -211,7 +211,7 @@ type enableIPv6Request struct { // @Param id path int true "配置 ID" // @Param vcnId path string true "vcnId" // @Param body body enableIPv6Request true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} ipv6StepsResponse // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/vcns/{vcnId}/enable-ipv6 [post] func (h *ociConfigHandler) enableVCNIPv6(c *gin.Context) { @@ -247,7 +247,7 @@ type createSubnetRequest struct { // @Summary 子网列表 // @Tags 网络 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.Subnet // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/subnets [get] func (h *ociConfigHandler) listSubnets(c *gin.Context) { @@ -267,7 +267,7 @@ func (h *ociConfigHandler) listSubnets(c *gin.Context) { // @Tags 网络 // @Param id path int true "配置 ID" // @Param body body createSubnetRequest true "请求体" -// @Success 201 {object} map[string]any +// @Success 201 {object} oci.Subnet // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/subnets [post] func (h *ociConfigHandler) createSubnet(c *gin.Context) { @@ -300,7 +300,7 @@ func (h *ociConfigHandler) createSubnet(c *gin.Context) { // @Tags 网络 // @Param id path int true "配置 ID" // @Param subnetId path string true "subnetId" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.Subnet // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/subnets/{subnetId} [get] func (h *ociConfigHandler) getSubnet(c *gin.Context) { @@ -321,7 +321,7 @@ func (h *ociConfigHandler) getSubnet(c *gin.Context) { // @Param id path int true "配置 ID" // @Param subnetId path string true "subnetId" // @Param body body renameRequest true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.Subnet // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/subnets/{subnetId} [put] func (h *ociConfigHandler) updateSubnet(c *gin.Context) { @@ -381,7 +381,7 @@ type updateSecurityListRequest struct { // @Summary 安全列表清单 // @Tags 网络 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.SecurityList // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/security-lists [get] func (h *ociConfigHandler) listSecurityLists(c *gin.Context) { @@ -401,7 +401,7 @@ func (h *ociConfigHandler) listSecurityLists(c *gin.Context) { // @Tags 网络 // @Param id path int true "配置 ID" // @Param body body createSecurityListRequest true "请求体" -// @Success 201 {object} map[string]any +// @Success 201 {object} oci.SecurityList // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/security-lists [post] func (h *ociConfigHandler) createSecurityList(c *gin.Context) { @@ -432,7 +432,7 @@ func (h *ociConfigHandler) createSecurityList(c *gin.Context) { // @Tags 网络 // @Param id path int true "配置 ID" // @Param securityListId path string true "securityListId" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.SecurityList // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/security-lists/{securityListId} [get] func (h *ociConfigHandler) getSecurityList(c *gin.Context) { @@ -453,7 +453,7 @@ func (h *ociConfigHandler) getSecurityList(c *gin.Context) { // @Param id path int true "配置 ID" // @Param securityListId path string true "securityListId" // @Param body body updateSecurityListRequest true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.SecurityList // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/security-lists/{securityListId} [put] func (h *ociConfigHandler) updateSecurityList(c *gin.Context) { diff --git a/internal/api/ociconfig.go b/internal/api/ociconfig.go index 2aa38b6..0ad180c 100644 --- a/internal/api/ociconfig.go +++ b/internal/api/ociconfig.go @@ -9,8 +9,10 @@ import ( "strconv" "github.com/gin-gonic/gin" + "github.com/oracle/oci-go-sdk/v65/common" "gorm.io/gorm" + _ "oci-portal/internal/model" // swagger 注解引用 "oci-portal/internal/oci" "oci-portal/internal/service" @@ -39,7 +41,7 @@ type importRequest struct { // @Summary 导入租户配置 // @Tags 租户配置 // @Param body body importRequest true "API Key 配置(私钥密文落库)" -// @Success 201 {object} map[string]any +// @Success 201 {object} model.OciConfig // @Security BearerAuth // @Router /api/v1/oci-configs [post] func (h *ociConfigHandler) create(c *gin.Context) { @@ -71,7 +73,7 @@ func (h *ociConfigHandler) create(c *gin.Context) { // @Summary 租户配置列表 // @Tags 租户配置 -// @Success 200 {object} map[string]any "items" +// @Success 200 {array} service.ConfigSummary // @Security BearerAuth // @Router /api/v1/oci-configs [get] func (h *ociConfigHandler) list(c *gin.Context) { @@ -86,7 +88,7 @@ func (h *ociConfigHandler) list(c *gin.Context) { // @Summary 租户配置详情 // @Tags 租户配置 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {object} model.OciConfig // @Security BearerAuth // @Router /api/v1/oci-configs/{id} [get] func (h *ociConfigHandler) get(c *gin.Context) { @@ -105,7 +107,7 @@ func (h *ociConfigHandler) get(c *gin.Context) { // @Summary 验证配置连通性并刷新画像 // @Tags 租户配置 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {object} configChangesResponse "config 与 changes 字段变更对照" // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/verify [post] func (h *ociConfigHandler) verify(c *gin.Context) { @@ -139,7 +141,7 @@ type updateConfigRequest struct { // @Tags 租户配置 // @Param id path int true "配置 ID" // @Param body body object true "可更新字段(别名/分组/代理/多区域开关等)" -// @Success 200 {object} map[string]any +// @Success 200 {object} configChangesResponse "config 与 changes 字段变更对照" // @Security BearerAuth // @Router /api/v1/oci-configs/{id} [put] func (h *ociConfigHandler) update(c *gin.Context) { @@ -194,7 +196,7 @@ func (h *ociConfigHandler) remove(c *gin.Context) { // @Summary 列出租户下全部 ACTIVE compartment // @Tags 租户配置 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.Compartment // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/compartments [get] func (h *ociConfigHandler) compartments(c *gin.Context) { @@ -216,7 +218,7 @@ func (h *ociConfigHandler) compartments(c *gin.Context) { // @Summary 返回筛选器用区域列表:未开多区域支持只含默认区域 // @Tags 租户配置 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} service.RegionSubscriptionView // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/cached-regions [get] func (h *ociConfigHandler) cachedRegions(c *gin.Context) { @@ -237,7 +239,7 @@ func (h *ociConfigHandler) cachedRegions(c *gin.Context) { // @Summary 返回筛选器用区间列表:未开多区间支持返回空数组 // @Tags 租户配置 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.Compartment // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/cached-compartments [get] func (h *ociConfigHandler) cachedCompartments(c *gin.Context) { diff --git a/internal/api/overview.go b/internal/api/overview.go index e0bf49b..86b3524 100644 --- a/internal/api/overview.go +++ b/internal/api/overview.go @@ -4,13 +4,15 @@ import ( "net/http" "github.com/gin-gonic/gin" + + _ "oci-portal/internal/service" // swagger 注解引用 ) // overview 返回总览页聚合数据(本地快照,不发云端请求)。 // // @Summary 返回总览页聚合数据 // @Tags 租户配置 -// @Success 200 {object} map[string]any +// @Success 200 {object} service.Overview // @Security BearerAuth // @Router /api/v1/overview [get] func (h *ociConfigHandler) overview(c *gin.Context) { diff --git a/internal/api/proxy.go b/internal/api/proxy.go index be8b64b..d59c4f0 100644 --- a/internal/api/proxy.go +++ b/internal/api/proxy.go @@ -18,7 +18,7 @@ type proxyHandler struct { // // @Summary 代理列表 // @Tags 设置 -// @Success 200 {object} map[string]any "items" +// @Success 200 {object} itemsResponse[service.ProxyView] "items" // @Security BearerAuth // @Router /api/v1/proxies [get] func (h *proxyHandler) list(c *gin.Context) { @@ -35,7 +35,7 @@ func (h *proxyHandler) list(c *gin.Context) { // @Summary 创建代理 // @Tags 设置 // @Param body body service.ProxyInput true "代理配置(密码只写不回)" -// @Success 201 {object} map[string]any +// @Success 201 {object} service.ProxyView // @Security BearerAuth // @Router /api/v1/proxies [post] func (h *proxyHandler) create(c *gin.Context) { @@ -58,7 +58,7 @@ func (h *proxyHandler) create(c *gin.Context) { // @Tags 设置 // @Param id path int true "代理 ID" // @Param body body service.ProxyInput true "代理配置(密码缺省沿用)" -// @Success 200 {object} map[string]any +// @Success 200 {object} service.ProxyView // @Security BearerAuth // @Router /api/v1/proxies/{id} [put] func (h *proxyHandler) update(c *gin.Context) { @@ -104,7 +104,7 @@ func (h *proxyHandler) remove(c *gin.Context) { // @Summary 批量导入代理 // @Tags 设置 // @Param body body object true "请求体(见接口说明)" -// @Success 200 {object} map[string]any +// @Success 200 {object} service.ImportResult // @Security BearerAuth // @Router /api/v1/proxies/import [post] func (h *proxyHandler) importBatch(c *gin.Context) { @@ -128,7 +128,7 @@ func (h *proxyHandler) importBatch(c *gin.Context) { // @Summary 手动重测代理出口地区,同步返回最新视图 // @Tags 设置 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {object} service.ProxyView // @Security BearerAuth // @Router /api/v1/proxies/{id}/probe [post] func (h *proxyHandler) probe(c *gin.Context) { @@ -150,7 +150,7 @@ func (h *proxyHandler) probe(c *gin.Context) { // @Tags 设置 // @Param id path int true "代理 ID" // @Param body body object true "请求体 {\"ociConfigIds\": [1,2]}" -// @Success 200 {object} map[string]any "usedBy" +// @Success 200 {object} usedByResponse "usedBy" // @Security BearerAuth // @Router /api/v1/proxies/{id}/tenants [put] func (h *proxyHandler) setTenants(c *gin.Context) { diff --git a/internal/api/region.go b/internal/api/region.go index 5d746ff..09942ec 100644 --- a/internal/api/region.go +++ b/internal/api/region.go @@ -6,6 +6,8 @@ import ( "github.com/gin-gonic/gin" + _ "oci-portal/internal/service" // swagger 注解引用 + "oci-portal/internal/oci" ) @@ -13,7 +15,7 @@ import ( // // @Summary 返回本地维护的完整区域表 // @Tags 租户配置 -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.RegionInfo // @Security BearerAuth // @Router /api/v1/regions [get] func listRegions(c *gin.Context) { @@ -28,7 +30,7 @@ func listRegions(c *gin.Context) { // @Summary 区域订阅列表 // @Tags 租户配置 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} service.RegionSubscriptionView // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/region-subscriptions [get] func (h *ociConfigHandler) regionSubscriptions(c *gin.Context) { @@ -52,7 +54,7 @@ type subscribeRegionRequest struct { // @Tags 租户配置 // @Param id path int true "配置 ID" // @Param body body subscribeRegionRequest true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {array} service.RegionSubscriptionView // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/region-subscriptions [post] func (h *ociConfigHandler) subscribeRegion(c *gin.Context) { @@ -76,7 +78,7 @@ func (h *ociConfigHandler) subscribeRegion(c *gin.Context) { // @Summary 服务限额查询 // @Tags 租户配置 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.LimitValue // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/limits [get] func (h *ociConfigHandler) limits(c *gin.Context) { diff --git a/internal/api/routes_ai.go b/internal/api/routes_ai.go index 9538497..f311d79 100644 --- a/internal/api/routes_ai.go +++ b/internal/api/routes_ai.go @@ -15,6 +15,9 @@ func registerAiGateway(r *gin.Engine, aiGateway *service.AiGatewayService) { ai.POST("/responses", aih.responses) ai.POST("/messages", aih.messages) ai.POST("/embeddings", aih.embeddings) + ai.POST("/audio/speech", aih.audioSpeech) + ai.POST("/rerank", aih.rerank) + ai.POST("/moderations", aih.moderations) ai.GET("/models", aih.listModels) } diff --git a/internal/api/settings.go b/internal/api/settings.go index c3852c9..1452fae 100644 --- a/internal/api/settings.go +++ b/internal/api/settings.go @@ -19,7 +19,7 @@ type settingsHandler struct { // // @Summary 返回脱敏后的 Telegram 配置,绝不回 token 明文 // @Tags 设置 -// @Success 200 {object} map[string]any +// @Success 200 {object} service.TelegramView // @Security BearerAuth // @Router /api/v1/settings/telegram [get] func (h *settingsHandler) getTelegram(c *gin.Context) { @@ -44,7 +44,7 @@ type updateTelegramRequest struct { // @Summary 保存配置并返回最新脱敏视图 // @Tags 设置 // @Param body body updateTelegramRequest true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} service.TelegramView // @Security BearerAuth // @Router /api/v1/settings/telegram [put] func (h *settingsHandler) updateTelegram(c *gin.Context) { @@ -84,7 +84,7 @@ func (h *settingsHandler) testTelegram(c *gin.Context) { // // @Summary 返回全部通知渠道的脱敏视图 // @Tags 设置 -// @Success 200 {object} map[string]any +// @Success 200 {object} itemsResponse[service.NotifyChannelView] // @Security BearerAuth // @Router /api/v1/settings/notify-channels [get] func (h *settingsHandler) listNotifyChannels(c *gin.Context) { @@ -119,7 +119,7 @@ type updateNotifyChannelRequest struct { // @Tags 设置 // @Param type path string true "渠道类型(webhook/ntfy/bark/smtp)" // @Param body body updateNotifyChannelRequest true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} itemsResponse[service.NotifyChannelView] // @Security BearerAuth // @Router /api/v1/settings/notify-channels/{type} [put] func (h *settingsHandler) updateNotifyChannel(c *gin.Context) { @@ -160,7 +160,7 @@ func (h *settingsHandler) testNotifyChannel(c *gin.Context) { // // @Summary 返回全部通知事件开关 // @Tags 设置 -// @Success 200 {object} map[string]any +// @Success 200 {object} service.NotifyEventsView // @Security BearerAuth // @Router /api/v1/settings/notify-events [get] func (h *settingsHandler) getNotifyEvents(c *gin.Context) { @@ -178,7 +178,7 @@ func (h *settingsHandler) getNotifyEvents(c *gin.Context) { // @Summary 全量保存五个事件开关并返回最新值 // @Tags 设置 // @Param body body service.NotifyEventsView true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} service.NotifyEventsView // @Security BearerAuth // @Router /api/v1/settings/notify-events [put] func (h *settingsHandler) updateNotifyEvents(c *gin.Context) { @@ -198,7 +198,7 @@ func (h *settingsHandler) updateNotifyEvents(c *gin.Context) { // // @Summary 返回全部通知模板 // @Tags 设置 -// @Success 200 {object} map[string]any +// @Success 200 {object} itemsResponse[service.NotifyTemplateView] // @Security BearerAuth // @Router /api/v1/settings/notify-templates [get] func (h *settingsHandler) listNotifyTemplates(c *gin.Context) { @@ -263,7 +263,7 @@ func (h *settingsHandler) testNotifyTemplate(c *gin.Context) { // // @Summary 返回任务行为设置 // @Tags 设置 -// @Success 200 {object} map[string]any +// @Success 200 {object} service.TaskSettingsView // @Security BearerAuth // @Router /api/v1/settings/task [get] func (h *settingsHandler) getTaskSettings(c *gin.Context) { @@ -280,7 +280,7 @@ func (h *settingsHandler) getTaskSettings(c *gin.Context) { // @Summary 保存任务行为设置并返回最新值 // @Tags 设置 // @Param body body service.TaskSettingsView true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} service.TaskSettingsView // @Security BearerAuth // @Router /api/v1/settings/task [put] func (h *settingsHandler) updateTaskSettings(c *gin.Context) { @@ -304,7 +304,7 @@ func (h *settingsHandler) updateTaskSettings(c *gin.Context) { // // @Summary 返回安全设置 // @Tags 设置 -// @Success 200 {object} map[string]any +// @Success 200 {object} service.SecuritySettings // @Security BearerAuth // @Router /api/v1/settings/security [get] func (h *settingsHandler) getSecurity(c *gin.Context) { @@ -321,7 +321,7 @@ func (h *settingsHandler) getSecurity(c *gin.Context) { // @Summary 保存安全设置并返回最新值 // @Tags 设置 // @Param body body service.SecuritySettings true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} service.SecuritySettings // @Security BearerAuth // @Router /api/v1/settings/security [put] func (h *settingsHandler) updateSecurity(c *gin.Context) { diff --git a/internal/api/subscription.go b/internal/api/subscription.go index 197f1a3..31b16d2 100644 --- a/internal/api/subscription.go +++ b/internal/api/subscription.go @@ -4,12 +4,14 @@ import ( "net/http" "github.com/gin-gonic/gin" + + _ "oci-portal/internal/oci" // swagger 注解引用 ) // @Summary 订阅列表 // @Tags 租户配置 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.SubscriptionInfo // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/subscriptions [get] func (h *ociConfigHandler) subscriptions(c *gin.Context) { @@ -29,7 +31,7 @@ func (h *ociConfigHandler) subscriptions(c *gin.Context) { // @Tags 租户配置 // @Param id path int true "配置 ID" // @Param subscriptionId path string true "subscriptionId" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.SubscriptionDetail // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/subscriptions/{subscriptionId} [get] func (h *ociConfigHandler) subscriptionDetail(c *gin.Context) { @@ -48,7 +50,7 @@ func (h *ociConfigHandler) subscriptionDetail(c *gin.Context) { // @Summary 限额服务列表 // @Tags 租户配置 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.LimitService // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/limits/services [get] func (h *ociConfigHandler) limitServices(c *gin.Context) { diff --git a/internal/api/swagger_resp.go b/internal/api/swagger_resp.go new file mode 100644 index 0000000..3730161 --- /dev/null +++ b/internal/api/swagger_resp.go @@ -0,0 +1,176 @@ +package api + +import ( + "encoding/json" + "time" + + "oci-portal/internal/model" + "oci-portal/internal/oci" + "oci-portal/internal/service" +) + +// 本文件的类型仅供 swagger 文档渲染(@Success/@Failure 注解引用), +// 运行时代码不使用;字段与各 handler 返回的 gin.H 外壳保持一致。 + +// errorResponse 是统一错误响应外壳。 +type errorResponse struct { + Error string `json:"error"` +} + +// itemsResponse 是 {"items": [...]} 列表外壳。 +type itemsResponse[T any] struct { + Items []T `json:"items"` +} + +// pagedResponse 是 {"items": [...], "total": n} 分页外壳。 +type pagedResponse[T any] struct { + Items []T `json:"items"` + Total int64 `json:"total"` +} + +// itemResponse 是 {"item": {...}} 单项外壳。 +type itemResponse[T any] struct { + Item T `json:"item"` +} + +// triggerResponse 是任务触发受理响应。 +type triggerResponse struct { + Triggered bool `json:"triggered"` +} + +// tokenResponse 是登录 / 换发令牌响应。 +type tokenResponse struct { + Token string `json:"token"` + ExpiresAt time.Time `json:"expiresAt"` +} + +// totpRequiredResponse 是密码通过但需两步验证码的 428 响应。 +type totpRequiredResponse struct { + Error string `json:"error"` + TotpRequired bool `json:"totpRequired"` +} + +// enabledResponse 是布尔开关查询响应。 +type enabledResponse struct { + Enabled bool `json:"enabled"` +} + +// totpSetupResponse 是 TOTP 初始化响应。 +type totpSetupResponse struct { + Secret string `json:"secret"` + OtpauthUri string `json:"otpauthUri"` +} + +// credentialsResponse 是当前登录账号信息。 +type credentialsResponse struct { + Username string `json:"username"` + PasswordLoginDisabled bool `json:"passwordLoginDisabled"` +} + +// oauthProvidersResponse 是外部登录 provider 列表。 +type oauthProvidersResponse struct { + Providers []service.ProviderInfo `json:"providers"` + PasswordLoginDisabled bool `json:"passwordLoginDisabled"` +} + +// urlResponse 是跳转地址响应。 +type urlResponse struct { + URL string `json:"url"` +} + +// aboutResponse 是「设置 · 关于」页构建与运行信息。 +type aboutResponse struct { + Version string `json:"version"` + BuildTime string `json:"buildTime"` + GoVersion string `json:"goVersion"` + Platform string `json:"platform"` + StartedAt string `json:"startedAt"` + UptimeSeconds int64 `json:"uptimeSeconds"` + Resources aboutResources `json:"resources"` +} + +// aboutResources 是进程资源占用快照。 +type aboutResources struct { + CpuAvgPercent float64 `json:"cpuAvgPercent"` + NumCpu int `json:"numCpu"` + Goroutines int `json:"goroutines"` + MemHeapBytes uint64 `json:"memHeapBytes"` + MemSysBytes uint64 `json:"memSysBytes"` + DbEngine string `json:"dbEngine"` + DbBytes int64 `json:"dbBytes"` +} + +// publicIpResponse 是换绑公网 IP 结果。 +type publicIpResponse struct { + PublicIp string `json:"publicIp"` +} + +// ipv6AddressResponse 是实例新增 IPv6 结果。 +type ipv6AddressResponse struct { + Ipv6Address string `json:"ipv6Address"` +} + +// addressResponse 是 VNIC 新增 IPv6 结果。 +type addressResponse struct { + Address string `json:"address"` +} + +// ipv6StepsResponse 是 VCN 开启 IPv6 的分步结果。 +type ipv6StepsResponse struct { + Steps []oci.IPv6Step `json:"steps"` +} + +// configChangesResponse 是租户配置校验 / 更新结果(config 与字段变更对照)。 +type configChangesResponse struct { + Config *model.OciConfig `json:"config"` + Changes service.Changes `json:"changes"` +} + +// aiKeyCreateResponse 是 AI 密钥创建结果;key 为明文,仅本次返回。 +type aiKeyCreateResponse struct { + Key string `json:"key"` + Item model.AiKey `json:"item"` +} + +// usedByResponse 是代理关联租户结果(关联数)。 +type usedByResponse struct { + UsedBy int64 `json:"usedBy"` +} + +// rawDetailResponse 是审计事件原文响应。 +type rawDetailResponse struct { + Raw json.RawMessage `json:"raw"` +} + +// passwordResponse 是租户用户重置密码结果(一次性明文)。 +type passwordResponse struct { + Password string `json:"password"` +} + +// deletedTotpResponse 是清除 MFA 设备结果。 +type deletedTotpResponse struct { + DeletedTotpDevices int `json:"deletedTotpDevices"` +} + +// deletedApiKeysResponse 是清理用户 API Key 结果。 +type deletedApiKeysResponse struct { + DeletedApiKeys int `json:"deletedApiKeys"` +} + +// createInstancesResponse 是批量创建实例结果;部分成功仍 201,errors 为逐台失败信息。 +type createInstancesResponse struct { + Instances []oci.Instance `json:"instances"` + Errors []string `json:"errors"` +} + +// logWebhookStatusResponse 是日志回传 webhook 状态。 +type logWebhookStatusResponse struct { + Exists bool `json:"exists"` + Webhook *service.LogWebhookInfo `json:"webhook,omitempty"` +} + +// webConsoleSessionResponse 是网页控制台会话创建结果。 +type webConsoleSessionResponse struct { + SessionId string `json:"sessionId"` + Type string `json:"type"` +} diff --git a/internal/api/systemlog.go b/internal/api/systemlog.go index 3b804f6..7787f5f 100644 --- a/internal/api/systemlog.go +++ b/internal/api/systemlog.go @@ -6,6 +6,7 @@ import ( "github.com/gin-gonic/gin" + _ "oci-portal/internal/model" // swagger 注解引用 "oci-portal/internal/service" ) @@ -18,7 +19,7 @@ type systemLogHandler struct { // // @Summary 系统操作日志列表 // @Tags 设置 -// @Success 200 {object} map[string]any "items 与 total" +// @Success 200 {object} pagedResponse[model.SystemLog] "items 与 total" // @Security BearerAuth // @Router /api/v1/system-logs [get] func (h *systemLogHandler) list(c *gin.Context) { diff --git a/internal/api/task.go b/internal/api/task.go index 599e265..f74e138 100644 --- a/internal/api/task.go +++ b/internal/api/task.go @@ -8,6 +8,7 @@ import ( "github.com/gin-gonic/gin" + _ "oci-portal/internal/model" // swagger 注解引用 "oci-portal/internal/service" ) @@ -33,7 +34,7 @@ type updateTaskRequest struct { // @Summary 创建任务 // @Tags 任务与日志回传 // @Param body body createTaskRequest true "任务定义(类型/cron/payload)" -// @Success 201 {object} map[string]any +// @Success 201 {object} model.Task // @Security BearerAuth // @Router /api/v1/tasks [post] func (h *taskHandler) create(c *gin.Context) { @@ -57,7 +58,7 @@ func (h *taskHandler) create(c *gin.Context) { // @Summary 任务列表 // @Tags 任务与日志回传 -// @Success 200 {array} map[string]any +// @Success 200 {array} model.Task // @Security BearerAuth // @Router /api/v1/tasks [get] func (h *taskHandler) list(c *gin.Context) { @@ -72,7 +73,7 @@ func (h *taskHandler) list(c *gin.Context) { // @Summary 任务详情 // @Tags 任务与日志回传 // @Param id path int true "任务 ID" -// @Success 200 {object} map[string]any +// @Success 200 {object} model.Task // @Security BearerAuth // @Router /api/v1/tasks/{id} [get] func (h *taskHandler) get(c *gin.Context) { @@ -92,7 +93,7 @@ func (h *taskHandler) get(c *gin.Context) { // @Tags 任务与日志回传 // @Param id path int true "任务 ID" // @Param body body updateTaskRequest true "可更新字段" -// @Success 200 {object} map[string]any +// @Success 200 {object} model.Task // @Security BearerAuth // @Router /api/v1/tasks/{id} [put] func (h *taskHandler) update(c *gin.Context) { @@ -139,7 +140,7 @@ func (h *taskHandler) remove(c *gin.Context) { // @Summary 任务执行日志 // @Tags 任务与日志回传 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} model.TaskLog // @Security BearerAuth // @Router /api/v1/tasks/{id}/logs [get] func (h *taskHandler) logs(c *gin.Context) { @@ -159,8 +160,8 @@ func (h *taskHandler) logs(c *gin.Context) { // @Summary 立即执行任务(异步触发,结果经任务日志轮询获取) // @Tags 任务与日志回传 // @Param id path int true "配置 ID" -// @Success 202 {object} map[string]any -// @Failure 409 {object} map[string]any "任务正在执行中" +// @Success 202 {object} triggerResponse +// @Failure 409 {object} errorResponse "任务正在执行中" // @Security BearerAuth // @Router /api/v1/tasks/{id}/run [post] func (h *taskHandler) run(c *gin.Context) { diff --git a/internal/api/tenant.go b/internal/api/tenant.go index 56fd9e7..9d2c9f7 100644 --- a/internal/api/tenant.go +++ b/internal/api/tenant.go @@ -18,7 +18,7 @@ import ( // @Tags 计算 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.InstanceTraffic // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/traffic [get] func (h *ociConfigHandler) instanceTraffic(c *gin.Context) { @@ -38,7 +38,7 @@ func (h *ociConfigHandler) instanceTraffic(c *gin.Context) { // @Summary 配置成本快照 // @Tags 成本 // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.CostItem // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/costs [get] func (h *ociConfigHandler) costs(c *gin.Context) { @@ -75,7 +75,7 @@ func (h *ociConfigHandler) costs(c *gin.Context) { // @Param id path int true "配置 ID" // @Param cursor query string false "续查游标(上次响应原样带回)" // @Param limit query int false "单批目标条数,缺省 100,上限 200" -// @Success 200 {object} map[string]any +// @Success 200 {object} service.AuditEventsView // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/audit-events [get] func (h *ociConfigHandler) getAuditEvents(c *gin.Context) { @@ -103,7 +103,7 @@ func (h *ociConfigHandler) getAuditEvents(c *gin.Context) { // @Summary 按 eventId 取回原始事件 JSON:缓存命中秒开, // @Tags 租户 IAM // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {object} rawDetailResponse "raw 为事件原文 JSON" // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/audit-events/detail [get] func (h *ociConfigHandler) getAuditEventDetail(c *gin.Context) { @@ -145,7 +145,7 @@ type createTenantUserRequest struct { // @Summary 租户身份域列表 // @Tags 租户 IAM // @Param id path int true "配置 ID" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.IdentityDomain // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/domains [get] func (h *ociConfigHandler) listIdentityDomains(c *gin.Context) { @@ -165,7 +165,7 @@ func (h *ociConfigHandler) listIdentityDomains(c *gin.Context) { // @Tags 租户 IAM // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.TenantUser // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/users [get] func (h *ociConfigHandler) listTenantUsers(c *gin.Context) { @@ -186,7 +186,7 @@ func (h *ociConfigHandler) listTenantUsers(c *gin.Context) { // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" // @Param userId path string true "userId" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.TenantUserDetail // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/users/{userId} [get] func (h *ociConfigHandler) getTenantUserDetail(c *gin.Context) { @@ -207,7 +207,7 @@ func (h *ociConfigHandler) getTenantUserDetail(c *gin.Context) { // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" // @Param body body createTenantUserRequest true "请求体" -// @Success 201 {object} map[string]any +// @Success 201 {object} oci.TenantUser // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/users [post] func (h *ociConfigHandler) createTenantUser(c *gin.Context) { @@ -253,7 +253,7 @@ type updateTenantUserRequest struct { // @Param domainId query string false "身份域 OCID(缺省 Default 域)" // @Param userId path string true "userId" // @Param body body updateTenantUserRequest true "请求体" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.TenantUser // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/users/{userId} [put] func (h *ociConfigHandler) updateTenantUser(c *gin.Context) { @@ -306,7 +306,7 @@ func (h *ociConfigHandler) deleteTenantUser(c *gin.Context) { // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" // @Param userId path string true "userId" -// @Success 200 {object} map[string]any +// @Success 200 {object} passwordResponse "一次性明文密码" // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/users/{userId}/reset-password [post] func (h *ociConfigHandler) resetTenantUserPassword(c *gin.Context) { @@ -327,7 +327,7 @@ func (h *ociConfigHandler) resetTenantUserPassword(c *gin.Context) { // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" // @Param userId path string true "userId" -// @Success 200 {object} map[string]any +// @Success 200 {object} deletedTotpResponse // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/users/{userId}/mfa-devices [delete] func (h *ociConfigHandler) deleteTenantUserMfa(c *gin.Context) { @@ -347,7 +347,7 @@ func (h *ociConfigHandler) deleteTenantUserMfa(c *gin.Context) { // @Tags 租户 IAM // @Param id path int true "配置 ID" // @Param userId path string true "userId" -// @Success 200 {object} map[string]any +// @Success 200 {object} deletedApiKeysResponse // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/users/{userId}/api-keys [delete] func (h *ociConfigHandler) deleteTenantUserApiKeys(c *gin.Context) { @@ -370,7 +370,7 @@ func (h *ociConfigHandler) deleteTenantUserApiKeys(c *gin.Context) { // @Tags 租户 IAM // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.NotificationRecipients // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/notification-recipients [get] func (h *ociConfigHandler) getNotificationRecipients(c *gin.Context) { @@ -391,7 +391,7 @@ func (h *ociConfigHandler) getNotificationRecipients(c *gin.Context) { // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" // @Param body body object true "请求体(见接口说明)" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.NotificationRecipients // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/notification-recipients [put] func (h *ociConfigHandler) updateNotificationRecipients(c *gin.Context) { @@ -418,7 +418,7 @@ func (h *ociConfigHandler) updateNotificationRecipients(c *gin.Context) { // @Tags 租户 IAM // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" -// @Success 200 {object} map[string]any +// @Success 200 {array} oci.PasswordPolicyInfo // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/password-policies [get] func (h *ociConfigHandler) listPasswordPolicies(c *gin.Context) { @@ -440,7 +440,7 @@ func (h *ociConfigHandler) listPasswordPolicies(c *gin.Context) { // @Param domainId query string false "身份域 OCID(缺省 Default 域)" // @Param policyId path string true "policyId" // @Param body body object true "请求体(见接口说明)" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.PasswordPolicyInfo // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/password-policies/{policyId} [put] func (h *ociConfigHandler) updatePasswordPolicy(c *gin.Context) { @@ -473,7 +473,7 @@ func (h *ociConfigHandler) updatePasswordPolicy(c *gin.Context) { // @Tags 租户 IAM // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.IdentitySettingInfo // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/identity-settings [get] func (h *ociConfigHandler) getIdentitySetting(c *gin.Context) { @@ -494,7 +494,7 @@ func (h *ociConfigHandler) getIdentitySetting(c *gin.Context) { // @Param id path int true "配置 ID" // @Param domainId query string false "身份域 OCID(缺省 Default 域)" // @Param body body object true "请求体(见接口说明)" -// @Success 200 {object} map[string]any +// @Success 200 {object} oci.IdentitySettingInfo // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/identity-settings [put] func (h *ociConfigHandler) updateIdentitySetting(c *gin.Context) { diff --git a/internal/api/webconsole.go b/internal/api/webconsole.go index 270d337..9b4fde7 100644 --- a/internal/api/webconsole.go +++ b/internal/api/webconsole.go @@ -29,7 +29,7 @@ type createConsoleSessionRequest struct { // @Param id path int true "配置 ID" // @Param instanceId path string true "实例 OCID" // @Param body body object true "{type: serial|vnc}" -// @Success 200 {object} map[string]any "sessionId 与 wsPath" +// @Success 201 {object} webConsoleSessionResponse "sessionId 与 type" // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/console-sessions [post] func (h *consoleHandler) create(c *gin.Context) { diff --git a/internal/api/webhook.go b/internal/api/webhook.go index 06e2223..f1f0c10 100644 --- a/internal/api/webhook.go +++ b/internal/api/webhook.go @@ -53,7 +53,7 @@ type webhookHandler struct { // @Param secret path string true "面板生成的回传密钥(鉴权凭据)" // @Param body body object true "ONS 消息原文(SubscriptionConfirmation / Notification)" // @Success 200 "已受理" -// @Failure 403 {object} map[string]string "时间戳超窗或证书源非 Oracle 域" +// @Failure 403 {object} errorResponse "时间戳超窗或证书源非 Oracle 域" // @Failure 404 "secret 无效(不暴露端点存在性)" // @Router /api/v1/webhooks/oci-logs/{secret} [post] func (h *webhookHandler) handle(c *gin.Context) { diff --git a/internal/model/models.go b/internal/model/models.go index e7cd491..ad3c6f5 100644 --- a/internal/model/models.go +++ b/internal/model/models.go @@ -273,7 +273,7 @@ type AiChannel struct { } // AiModelCache 是渠道区域的可用模型缓存(整渠道覆盖式同步)。 -// Capability 为 CHAT / EMBEDDING;存量空串视为 CHAT(加列前只同步对话模型)。 +// Capability 为 CHAT / EMBEDDING / RERANK / TTS;存量空串视为 CHAT(加列前只同步对话模型)。 type AiModelCache struct { ID uint `gorm:"primaryKey" json:"-"` ChannelID uint `gorm:"index" json:"channelId"` diff --git a/internal/oci/client.go b/internal/oci/client.go index f559b58..7be374a 100644 --- a/internal/oci/client.go +++ b/internal/oci/client.go @@ -106,6 +106,12 @@ type Client interface { GenAiCompatResponses(ctx context.Context, cred Credentials, region string, body []byte) ([]byte, error) // GenAiCompatResponsesStream 流式直通 /actions/v1/responses,建立成功返回 SSE body。 GenAiCompatResponsesStream(ctx context.Context, cred Credentials, region string, body []byte) (io.ReadCloser, error) + // GenAiCompatSpeech 直通 OpenAI Audio Speech 请求体到 /openai/v1/audio/speech,返回音频与 Content-Type。 + GenAiCompatSpeech(ctx context.Context, cred Credentials, region string, body []byte) ([]byte, string, error) + // GenAiRerank 文档重排,返回按相关度排序的下标与得分。 + GenAiRerank(ctx context.Context, cred Credentials, region, modelOcid, query string, documents []string, topN *int) ([]RerankRank, error) + // GenAiApplyGuardrails 对单条文本执行内容审核 / PII / 提示注入检测。 + GenAiApplyGuardrails(ctx context.Context, cred Credentials, region, text string) (*GuardrailsOutcome, error) // 控制台连接:创建(VNC/串口连接串)、列出、删除。 CreateConsoleConnection(ctx context.Context, cred Credentials, region, instanceID, sshPublicKey string) (ConsoleConnection, error) ListConsoleConnections(ctx context.Context, cred Credentials, region, instanceID string) ([]ConsoleConnection, error) diff --git a/internal/oci/genai.go b/internal/oci/genai.go index 7bab6a2..d79bf60 100644 --- a/internal/oci/genai.go +++ b/internal/oci/genai.go @@ -131,6 +131,11 @@ func modelCapability(m generativeai.ModelSummary) string { return "CHAT" case generativeai.ModelCapabilityTextEmbeddings: capability = "EMBEDDING" + case generativeai.ModelCapabilityTextRerank: + capability = "RERANK" + case generativeai.ModelCapabilityEnum("TEXT_TO_AUDIO"): + // SDK v65.120 尚无该枚举常量,按原始字符串匹配(xai.grok-tts) + capability = "TTS" } } return capability diff --git a/internal/oci/genai_guard.go b/internal/oci/genai_guard.go new file mode 100644 index 0000000..53a2550 --- /dev/null +++ b/internal/oci/genai_guard.go @@ -0,0 +1,127 @@ +package oci + +import ( + "context" + "fmt" + + "github.com/oracle/oci-go-sdk/v65/common" + "github.com/oracle/oci-go-sdk/v65/generativeaiinference" +) + +// RerankRank 是重排结果的一项:index 指向入参 documents 下标。 +type RerankRank struct { + Index int + Score float64 +} + +// GuardrailCategory 是内容审核分类得分(OVERALL / BLOCKLIST)。 +type GuardrailCategory struct { + Name string + Score float64 +} + +// GuardrailPiiHit 是一处 PII 命中(片段原文与位置)。 +type GuardrailPiiHit struct { + Text string + Label string + Score float64 + Offset int + Length int +} + +// GuardrailsOutcome 汇总 ApplyGuardrails 三能力结果。 +type GuardrailsOutcome struct { + Categories []GuardrailCategory + Pii []GuardrailPiiHit + PromptInjectionScore *float64 +} + +// GenAiRerank 实现 Client:文档重排(on-demand serving),返回按相关度排序的下标与得分。 +func (c *RealClient) GenAiRerank(ctx context.Context, cred Credentials, region, modelOcid, query string, documents []string, topN *int) ([]RerankRank, error) { + ic, err := c.genAiInferenceClient(cred, region) + if err != nil { + return nil, err + } + resp, err := ic.RerankText(ctx, generativeaiinference.RerankTextRequest{ + RerankTextDetails: generativeaiinference.RerankTextDetails{ + CompartmentId: &cred.TenancyOCID, + ServingMode: generativeaiinference.OnDemandServingMode{ModelId: &modelOcid}, + Input: &query, + Documents: documents, + TopN: topN, + }, + }) + if err != nil { + return nil, fmt.Errorf("genai rerank: %w", err) + } + ranks := make([]RerankRank, 0, len(resp.DocumentRanks)) + for _, r := range resp.DocumentRanks { + if r.Index == nil || r.RelevanceScore == nil { + continue + } + ranks = append(ranks, RerankRank{Index: *r.Index, Score: *r.RelevanceScore}) + } + return ranks, nil +} + +// GenAiApplyGuardrails 实现 Client:对单条文本执行内容审核 / PII / 提示注入三检测。 +func (c *RealClient) GenAiApplyGuardrails(ctx context.Context, cred Credentials, region, text string) (*GuardrailsOutcome, error) { + ic, err := c.genAiInferenceClient(cred, region) + if err != nil { + return nil, err + } + resp, err := ic.ApplyGuardrails(ctx, generativeaiinference.ApplyGuardrailsRequest{ + ApplyGuardrailsDetails: generativeaiinference.ApplyGuardrailsDetails{ + CompartmentId: &cred.TenancyOCID, + Input: generativeaiinference.GuardrailsTextInput{Content: common.String(text)}, + GuardrailConfigs: &generativeaiinference.GuardrailConfigs{ + ContentModerationConfig: &generativeaiinference.ContentModerationConfiguration{Categories: []string{"OVERALL"}}, + PersonallyIdentifiableInformationConfig: &generativeaiinference.PersonallyIdentifiableInformationConfiguration{Types: []string{}}, + PromptInjectionConfig: &generativeaiinference.PromptInjectionConfiguration{}, + }, + }, + }) + if err != nil { + return nil, fmt.Errorf("genai guardrails: %w", err) + } + return guardrailsOutcome(resp.Results), nil +} + +// guardrailsOutcome 把 SDK 结果换算为 IR;空段置空切片,得分缺失跳过。 +func guardrailsOutcome(r *generativeaiinference.GuardrailsResults) *GuardrailsOutcome { + out := &GuardrailsOutcome{} + if r == nil { + return out + } + if r.ContentModeration != nil { + for _, cat := range r.ContentModeration.Categories { + if cat.Name == nil || cat.Score == nil { + continue + } + out.Categories = append(out.Categories, GuardrailCategory{Name: *cat.Name, Score: *cat.Score}) + } + } + for _, hit := range r.PersonallyIdentifiableInformation { + h := GuardrailPiiHit{} + if hit.Text != nil { + h.Text = *hit.Text + } + if hit.Label != nil { + h.Label = *hit.Label + } + if hit.Score != nil { + h.Score = *hit.Score + } + if hit.Offset != nil { + h.Offset = *hit.Offset + } + if hit.Length != nil { + h.Length = *hit.Length + } + out.Pii = append(out.Pii, h) + } + if r.PromptInjection != nil && r.PromptInjection.Score != nil { + out.PromptInjectionScore = r.PromptInjection.Score + } + return out +} diff --git a/internal/oci/genai_responses.go b/internal/oci/genai_responses.go index a1e9516..36eecb1 100644 --- a/internal/oci/genai_responses.go +++ b/internal/oci/genai_responses.go @@ -14,9 +14,9 @@ import ( const compatResponsesLimit = int64(8 << 20) // GenAiCompatResponses 实现 Client:把 OpenAI Responses 请求体直通到 OCI -// `/20231130/actions/v1/responses`(IAM 签名)。该端点实测可执行 xAI 服务端工具 -// (web_search / x_search),但不在 Oracle 文档化工具白名单内,行为可能随服务 -// 版本、模型或区域变化;调用方须自行校验并改写请求体(store/stream)。 +// `/20231130/actions/v1/responses`(IAM 签名)。xAI 服务端工具(web_search / +// x_search / code_interpreter)与 mcp 已被 Oracle 文档正式支持,工具参数与限制 +// 遵循 xAI 规格;调用方须自行校验并改写请求体(store/stream)。 func (c *RealClient) GenAiCompatResponses(ctx context.Context, cred Credentials, region string, body []byte) ([]byte, error) { ic, err := c.genAiInferenceClient(cred, region) if err != nil { diff --git a/internal/oci/genai_speech.go b/internal/oci/genai_speech.go new file mode 100644 index 0000000..8d258d7 --- /dev/null +++ b/internal/oci/genai_speech.go @@ -0,0 +1,44 @@ +package oci + +import ( + "bytes" + "context" + "fmt" + "io" + "net/http" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +// compatSpeechLimit 限制 TTS 音频响应体大小(长文本 mp3 给足余量)。 +const compatSpeechLimit = int64(64 << 20) + +// GenAiCompatSpeech 实现 Client:把 OpenAI Audio Speech 请求体直通到 OCI +// 兼容面 `/openai/v1/audio/speech`(IAM 签名,BasePath 置空——该面与 +// /20231130/actions 面并存,实测仅前者承载 TTS)。返回音频字节与 Content-Type。 +func (c *RealClient) GenAiCompatSpeech(ctx context.Context, cred Credentials, region string, body []byte) ([]byte, string, error) { + ic, err := c.genAiInferenceClient(cred, region) + if err != nil { + return nil, "", err + } + client := ic.BaseClient + common.UpdateEndpointTemplateForOptions(&client) + common.SetMissingTemplateParams(&client) + client.BasePath = "" + request, err := http.NewRequestWithContext(ctx, http.MethodPost, "/openai/v1/audio/speech", bytes.NewReader(body)) + if err != nil { + return nil, "", fmt.Errorf("build compat speech request: %w", err) + } + request.Header.Set("Content-Type", "application/json") + request.Header.Set("opc-compartment-id", cred.TenancyOCID) + response, err := client.Call(ctx, request) + if err != nil { + return nil, "", err + } + defer response.Body.Close() + payload, err := io.ReadAll(io.LimitReader(response.Body, compatSpeechLimit)) + if err != nil { + return nil, "", fmt.Errorf("read compat speech body: %w", err) + } + return payload, response.Header.Get("Content-Type"), nil +} diff --git a/internal/service/aigateway_extras.go b/internal/service/aigateway_extras.go new file mode 100644 index 0000000..6f6efa8 --- /dev/null +++ b/internal/service/aigateway_extras.go @@ -0,0 +1,248 @@ +package service + +import ( + "context" + "encoding/json" + "fmt" + "strings" + "time" + + "oci-portal/internal/aiwire" + "oci-portal/internal/model" + "oci-portal/internal/oci" +) + +// moderationsMaxInputs 限制单次审核条数,防止批量滥用拖垮渠道配额。 +const moderationsMaxInputs = 8 + +// SpeechBodyNormalize 校验并规范化 TTS 请求体:model / input 必填; +// xAI 上游把 language 当必填(实测缺失返回 422),缺省注入 "auto"。 +// 其余字段(voice / response_format / extra_body 平铺项)原样保留。 +func SpeechBodyNormalize(raw []byte) (string, []byte, error) { + dec := json.NewDecoder(strings.NewReader(string(raw))) + dec.UseNumber() + var body map[string]any + if err := dec.Decode(&body); err != nil { + return "", nil, fmt.Errorf("解析请求体: %w", err) + } + modelName, _ := body["model"].(string) + input, _ := body["input"].(string) + if strings.TrimSpace(modelName) == "" || strings.TrimSpace(input) == "" { + return "", nil, fmt.Errorf("model 与 input 不能为空") + } + if lang, ok := body["language"].(string); !ok || strings.TrimSpace(lang) == "" { + body["language"] = "auto" + } + out, err := json.Marshal(body) + if err != nil { + return "", nil, fmt.Errorf("重组请求体: %w", err) + } + return modelName, out, nil +} + +// Speech 编排 TTS 调用:按 TTS 能力选渠道,可重试错误换渠道(上限 3 次)。 +func (s *AiGatewayService) Speech(ctx context.Context, modelName string, body []byte, group string) ([]byte, string, ChatMeta, error) { + meta := ChatMeta{} + excluded := map[uint]bool{} + var lastErr error + for attempt := 0; attempt < 3; attempt++ { + cand, err := s.pick(ctx, modelName, group, "TTS", excluded) + if err != nil { + return nil, "", meta, firstErr(lastErr, err) + } + meta.ChannelID, meta.ChannelName = cand.ch.ID, cand.ch.Name + cred, err := s.configs.credentialsByID(ctx, cand.ch.OciConfigID) + if err != nil { + return nil, "", meta, err + } + audio, contentType, err := s.client.GenAiCompatSpeech(ctx, cred, cand.ch.Region, body) + if err == nil { + s.markSuccess(ctx, cand.ch.ID) + return audio, contentType, meta, nil + } + if done := s.retryStep(ctx, cand.ch.ID, err, excluded, &meta, &lastErr); done { + return nil, "", meta, err + } + } + return nil, "", meta, lastErr +} + +// Rerank 编排文档重排:按 RERANK 能力选渠道,装配 Jina 风格响应。 +func (s *AiGatewayService) Rerank(ctx context.Context, req aiwire.RerankRequest, group string) (*aiwire.RerankResponse, ChatMeta, error) { + meta := ChatMeta{} + excluded := map[uint]bool{} + var lastErr error + for attempt := 0; attempt < 3; attempt++ { + cand, err := s.pick(ctx, req.Model, group, "RERANK", excluded) + if err != nil { + return nil, meta, firstErr(lastErr, err) + } + meta.ChannelID, meta.ChannelName = cand.ch.ID, cand.ch.Name + cred, err := s.configs.credentialsByID(ctx, cand.ch.OciConfigID) + if err != nil { + return nil, meta, err + } + ranks, err := s.client.GenAiRerank(ctx, cred, cand.ch.Region, cand.modelOcid, req.Query, req.Documents, req.TopN) + if err == nil { + s.markSuccess(ctx, cand.ch.ID) + return rerankResponse(req, ranks), meta, nil + } + if done := s.retryStep(ctx, cand.ch.ID, err, excluded, &meta, &lastErr); done { + return nil, meta, err + } + } + return nil, meta, lastErr +} + +// retryStep 统一处理换渠道重试:不可重试返回 true 终止,可重试记罚并排除渠道。 +func (s *AiGatewayService) retryStep(ctx context.Context, chID uint, err error, excluded map[uint]bool, meta *ChatMeta, lastErr *error) bool { + retry, penalize := switchable(err) + if !retry { + return true + } + if penalize { + s.markFailure(ctx, chID) + } + excluded[chID] = true + meta.Retries++ + *lastErr = err + return false +} + +// rerankResponse 把上游排序结果装配为对外响应;return_documents 时回填原文。 +func rerankResponse(req aiwire.RerankRequest, ranks []oci.RerankRank) *aiwire.RerankResponse { + out := &aiwire.RerankResponse{Model: req.Model, Results: make([]aiwire.RerankResult, 0, len(ranks))} + withDoc := req.ReturnDocuments != nil && *req.ReturnDocuments + for _, r := range ranks { + if r.Index < 0 || r.Index >= len(req.Documents) { + continue + } + item := aiwire.RerankResult{Index: r.Index, RelevanceScore: r.Score} + if withDoc { + item.Document = &aiwire.RerankDocument{Text: req.Documents[r.Index]} + } + out.Results = append(out.Results, item) + } + return out +} + +// ModerationInputs 解析 moderations 的 input 字段:string 或 []string, +// 条数与空值校验(上限 moderationsMaxInputs)。 +func ModerationInputs(raw json.RawMessage) ([]string, error) { + var single string + if err := json.Unmarshal(raw, &single); err == nil { + if strings.TrimSpace(single) == "" { + return nil, fmt.Errorf("input 不能为空") + } + return []string{single}, nil + } + var many []string + if err := json.Unmarshal(raw, &many); err != nil { + return nil, fmt.Errorf("input 需为字符串或字符串数组") + } + if len(many) == 0 || len(many) > moderationsMaxInputs { + return nil, fmt.Errorf("input 条数需在 1~%d 之间", moderationsMaxInputs) + } + for _, item := range many { + if strings.TrimSpace(item) == "" { + return nil, fmt.Errorf("input 含空条目") + } + } + return many, nil +} + +// Moderations 编排内容审核:guardrails 为服务级 API 无模型维度, +// 按分组选启用渠道(整批同渠道),可重试错误换渠道(上限 3 次)。 +func (s *AiGatewayService) Moderations(ctx context.Context, id string, inputs []string, group string) (*aiwire.ModerationsResponse, ChatMeta, error) { + meta := ChatMeta{} + excluded := map[uint]bool{} + var lastErr error + for attempt := 0; attempt < 3; attempt++ { + ch, err := s.pickGuardChannel(ctx, group, excluded) + if err != nil { + return nil, meta, firstErr(lastErr, err) + } + meta.ChannelID, meta.ChannelName = ch.ID, ch.Name + resp, err := s.moderateOnce(ctx, ch, id, inputs) + if err == nil { + s.markSuccess(ctx, ch.ID) + return resp, meta, nil + } + if done := s.retryStep(ctx, ch.ID, err, excluded, &meta, &lastErr); done { + return nil, meta, err + } + } + return nil, meta, lastErr +} + +// pickGuardChannel 按分组挑一个启用且未熔断的渠道(权重加成,不查模型缓存)。 +func (s *AiGatewayService) pickGuardChannel(ctx context.Context, group string, excluded map[uint]bool) (model.AiChannel, error) { + q := s.db.WithContext(ctx).Where("enabled = ?", true) + if group != "" { + q = q.Where("channel_group = ?", group) + } + var channels []model.AiChannel + if err := q.Find(&channels).Error; err != nil { + return model.AiChannel{}, err + } + now := time.Now() + avail := channels[:0] + for _, ch := range channels { + if excluded[ch.ID] || (ch.DisabledUntil != nil && ch.DisabledUntil.After(now)) { + continue + } + avail = append(avail, ch) + } + if len(avail) == 0 { + return model.AiChannel{}, ErrAiNoChannel + } + return weightedPick(topPriority(avail)), nil +} + +// moderateOnce 在单渠道上逐条审核并装配 OpenAI moderations 外壳。 +func (s *AiGatewayService) moderateOnce(ctx context.Context, ch model.AiChannel, id string, inputs []string) (*aiwire.ModerationsResponse, error) { + cred, err := s.configs.credentialsByID(ctx, ch.OciConfigID) + if err != nil { + return nil, err + } + out := &aiwire.ModerationsResponse{ID: id, Model: "oci-guardrails", + Results: make([]aiwire.ModerationResult, 0, len(inputs))} + for _, text := range inputs { + outcome, err := s.client.GenAiApplyGuardrails(ctx, cred, ch.Region, text) + if err != nil { + return nil, err + } + out.Results = append(out.Results, moderationResult(outcome)) + } + return out, nil +} + +// moderationFlagThreshold 是判定违规的得分阈值(上游 CM / PI 为二值得分)。 +const moderationFlagThreshold = 0.5 + +// moderationResult 把 guardrails 结果映射为 OpenAI moderations 条目: +// flagged 由内容审核与提示注入判定,PII 命中只作扩展信息不参与 flagged。 +func moderationResult(outcome *oci.GuardrailsOutcome) aiwire.ModerationResult { + res := aiwire.ModerationResult{Categories: map[string]bool{}, CategoryScores: map[string]float64{}} + for _, cat := range outcome.Categories { + key := strings.ToLower(cat.Name) + res.Categories[key] = cat.Score >= moderationFlagThreshold + res.CategoryScores[key] = cat.Score + if res.Categories[key] { + res.Flagged = true + } + } + if outcome.PromptInjectionScore != nil { + hit := *outcome.PromptInjectionScore >= moderationFlagThreshold + res.Categories["prompt_injection"] = hit + res.CategoryScores["prompt_injection"] = *outcome.PromptInjectionScore + if hit { + res.Flagged = true + } + } + for _, p := range outcome.Pii { + res.Pii = append(res.Pii, aiwire.ModerationPii{Text: p.Text, Label: p.Label, + Score: p.Score, Offset: p.Offset, Length: p.Length}) + } + return res +} diff --git a/internal/service/aigateway_extras_test.go b/internal/service/aigateway_extras_test.go new file mode 100644 index 0000000..5818956 --- /dev/null +++ b/internal/service/aigateway_extras_test.go @@ -0,0 +1,164 @@ +package service + +import ( + "context" + "encoding/json" + "errors" + "strings" + "testing" + "time" + + "oci-portal/internal/aiwire" + "oci-portal/internal/model" + "oci-portal/internal/oci" +) + +// TestSpeechBodyNormalize 断言 TTS 请求体校验与 language 缺省注入。 +func TestSpeechBodyNormalize(t *testing.T) { + tests := []struct { + name string + raw string + wantErr bool + wantLang string + }{ + {"缺 model 拒绝", `{"input":"你好"}`, true, ""}, + {"缺 input 拒绝", `{"model":"xai.grok-tts"}`, true, ""}, + {"language 缺省注入 auto", `{"model":"xai.grok-tts","input":"你好","voice":"ara"}`, false, "auto"}, + {"language 已有保留", `{"model":"xai.grok-tts","input":"你好","language":"zh"}`, false, "zh"}, + {"非 JSON 拒绝", ``, true, ""}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + modelName, body, err := SpeechBodyNormalize([]byte(tt.raw)) + if (err != nil) != tt.wantErr { + t.Fatalf("err = %v, wantErr %v", err, tt.wantErr) + } + if err != nil { + return + } + var out map[string]any + _ = json.Unmarshal(body, &out) + if modelName != "xai.grok-tts" || out["language"] != tt.wantLang { + t.Fatalf("model=%s language=%v, want %s", modelName, out["language"], tt.wantLang) + } + }) + } +} + +// TestModerationInputs 断言 input 的 string / []string 解析与边界校验。 +func TestModerationInputs(t *testing.T) { + tests := []struct { + name string + raw string + wantN int + wantErr bool + }{ + {"单字符串", `"hello"`, 1, false}, + {"数组", `["a","b"]`, 2, false}, + {"空字符串拒绝", `""`, 0, true}, + {"空数组拒绝", `[]`, 0, true}, + {"含空条目拒绝", `["a",""]`, 0, true}, + {"超上限拒绝", `["1","2","3","4","5","6","7","8","9"]`, 0, true}, + {"非法类型拒绝", `{"x":1}`, 0, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ModerationInputs(json.RawMessage(tt.raw)) + if (err != nil) != tt.wantErr || len(got) != tt.wantN { + t.Fatalf("got %v (err=%v), want n=%d wantErr=%v", got, err, tt.wantN, tt.wantErr) + } + }) + } +} + +// TestModerationResultMapping 断言 guardrails 结果到 OpenAI 外壳的映射与 flagged 判定。 +func TestModerationResultMapping(t *testing.T) { + one := 1.0 + zero := 0.0 + tests := []struct { + name string + outcome oci.GuardrailsOutcome + wantFlagged bool + wantPii int + }{ + {"内容审核命中", oci.GuardrailsOutcome{Categories: []oci.GuardrailCategory{{Name: "OVERALL", Score: 1}}}, true, 0}, + {"提示注入命中", oci.GuardrailsOutcome{PromptInjectionScore: &one}, true, 0}, + {"仅 PII 不 flag", oci.GuardrailsOutcome{Categories: []oci.GuardrailCategory{{Name: "OVERALL", Score: 0}}, + PromptInjectionScore: &zero, Pii: []oci.GuardrailPiiHit{{Text: "Jane", Label: "PERSON", Score: 0.99}}}, false, 1}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := moderationResult(&tt.outcome) + if res.Flagged != tt.wantFlagged || len(res.Pii) != tt.wantPii { + t.Fatalf("res = %+v, want flagged=%v pii=%d", res, tt.wantFlagged, tt.wantPii) + } + }) + } +} + +// TestAiRerank 断言重排编排:能力路由、top_n 透传、return_documents 回填与越界防御。 +func TestAiRerank(t *testing.T) { + client := &gatewayStubClient{ + fakeClient: &fakeClient{tenancy: oci.TenancyInfo{Name: "t"}}, + rerankRanks: []oci.RerankRank{{Index: 1, Score: 0.9}, {Index: 0, Score: 0.4}, {Index: 9, Score: 0.1}}, + } + gw, svc := newTestGateway(t, client) + cfg := importAliveConfig(t, svc) + ch := seedChannel(t, gw, cfg.ID, "us-chicago-1", 1, 1) + gw.db.Create(&model.AiModelCache{ChannelID: ch.ID, ModelOcid: "ocid1..rr", Name: "cohere.rerank-v4.0-fast", + Vendor: "cohere", Capability: "RERANK", SyncedAt: time.Now()}) + ctx := context.Background() + yes := true + req := aiwire.RerankRequest{Model: "cohere.rerank-v4.0-fast", Query: "q", Documents: []string{"d0", "d1"}, ReturnDocuments: &yes} + resp, _, err := gw.Rerank(ctx, req, "") + if err != nil || len(resp.Results) != 2 { + t.Fatalf("Rerank = %+v, %v(越界 index 应被丢弃)", resp, err) + } + if resp.Results[0].Index != 1 || resp.Results[0].Document == nil || resp.Results[0].Document.Text != "d1" { + t.Fatalf("results[0] = %+v", resp.Results[0]) + } + // 对话模型名打 rerank:能力不匹配 → 未知模型 + if _, _, err := gw.Rerank(ctx, aiwire.RerankRequest{Model: "meta.llama-3.3-70b-instruct", Query: "q", Documents: []string{"d"}}, ""); !errors.Is(err, ErrAiUnknownModel) { + t.Errorf("chat 模型走 rerank err = %v, want ErrAiUnknownModel", err) + } +} + +// TestAiSpeech 断言 TTS 编排走 TTS 能力路由并透传音频与 Content-Type。 +func TestAiSpeech(t *testing.T) { + client := &gatewayStubClient{ + fakeClient: &fakeClient{tenancy: oci.TenancyInfo{Name: "t"}}, + speechAudio: []byte{0xFF, 0xF3}, speechCT: "audio/mpeg", + } + gw, svc := newTestGateway(t, client) + cfg := importAliveConfig(t, svc) + ch := seedChannel(t, gw, cfg.ID, "us-chicago-1", 1, 1) + gw.db.Create(&model.AiModelCache{ChannelID: ch.ID, ModelOcid: "ocid1..tts", Name: "xai.grok-tts", + Vendor: "xai", Capability: "TTS", SyncedAt: time.Now()}) + audio, ct, _, err := gw.Speech(context.Background(), "xai.grok-tts", []byte(`{"model":"xai.grok-tts","input":"你好","language":"auto"}`), "") + if err != nil || ct != "audio/mpeg" || len(audio) != 2 { + t.Fatalf("Speech = %d bytes, ct=%s, %v", len(audio), ct, err) + } +} + +// TestAiModerations 断言审核编排:无模型维度按分组选渠道,多条输入逐条聚合。 +func TestAiModerations(t *testing.T) { + one := 1.0 + client := &gatewayStubClient{ + fakeClient: &fakeClient{tenancy: oci.TenancyInfo{Name: "t"}}, + guardOutcome: &oci.GuardrailsOutcome{Categories: []oci.GuardrailCategory{{Name: "OVERALL", Score: 1}}, PromptInjectionScore: &one}, + } + gw, svc := newTestGateway(t, client) + cfg := importAliveConfig(t, svc) + seedChannel(t, gw, cfg.ID, "us-chicago-1", 1, 1) + resp, meta, err := gw.Moderations(context.Background(), "modr_test", []string{"a", "b"}, "") + if err != nil || len(resp.Results) != 2 || !resp.Results[0].Flagged || resp.ID != "modr_test" { + t.Fatalf("Moderations = %+v, meta=%+v, %v", resp, meta, err) + } + if !strings.Contains(resp.Model, "guardrails") { + t.Errorf("model = %s", resp.Model) + } + // 分组不匹配 → 无可用渠道 + if _, _, err := gw.Moderations(context.Background(), "modr_x", []string{"a"}, "ghost-group"); !errors.Is(err, ErrAiNoChannel) { + t.Errorf("ghost 分组 err = %v, want ErrAiNoChannel", err) + } +} diff --git a/internal/service/aigateway_test.go b/internal/service/aigateway_test.go index 8e90d4d..5b48f39 100644 --- a/internal/service/aigateway_test.go +++ b/internal/service/aigateway_test.go @@ -61,6 +61,26 @@ type gatewayStubClient struct { passErrs []error passCalls int passRegions []string + + speechAudio []byte + speechCT string + speechErr error + rerankRanks []oci.RerankRank + rerankErr error + guardOutcome *oci.GuardrailsOutcome + guardErr error +} + +func (f *gatewayStubClient) GenAiCompatSpeech(ctx context.Context, cred oci.Credentials, region string, body []byte) ([]byte, string, error) { + return f.speechAudio, f.speechCT, f.speechErr +} + +func (f *gatewayStubClient) GenAiRerank(ctx context.Context, cred oci.Credentials, region, modelOcid, query string, documents []string, topN *int) ([]oci.RerankRank, error) { + return f.rerankRanks, f.rerankErr +} + +func (f *gatewayStubClient) GenAiApplyGuardrails(ctx context.Context, cred oci.Credentials, region, text string) (*oci.GuardrailsOutcome, error) { + return f.guardOutcome, f.guardErr } func (f *gatewayStubClient) GenAiCompatResponses(ctx context.Context, cred oci.Credentials, region string, body []byte) ([]byte, error) { diff --git a/internal/service/airesponses.go b/internal/service/airesponses.go index d4ed5ea..d4825bc 100644 --- a/internal/service/airesponses.go +++ b/internal/service/airesponses.go @@ -22,34 +22,21 @@ func respRejectStateful(req aiwire.RespRequest) error { return nil } -// RespServerTools 报告工具列表是否含 xAI 服务端工具(web_search / x_search)。 -func RespServerTools(tools []aiwire.RespTool) bool { - for _, t := range tools { - if t.Type == "web_search" || t.Type == "x_search" { - return true - } - } - return false -} - // RespPassthroughValidate 校验直通请求:模型必填,有状态特性不支持,工具类型 -// 只放行 function 与已实测的 web_search / x_search;流式仅在含服务端工具时拒绝 -// (工具流式事件形态未实测,不放开)。 +// 只放行 function 与 Oracle 文档化的服务端工具(web_search / x_search / +// code_interpreter / mcp)。 func RespPassthroughValidate(req aiwire.RespRequest) error { if strings.TrimSpace(req.Model) == "" { return fmt.Errorf("model 不能为空") } - if req.Stream && RespServerTools(req.Tools) { - return fmt.Errorf("服务端工具暂不支持流式:请去掉 stream 或改用 function 工具") - } if err := respRejectStateful(req); err != nil { return err } for _, t := range req.Tools { switch t.Type { - case "function", "web_search", "x_search": + case "function", "web_search", "x_search", "code_interpreter", "mcp": default: - return fmt.Errorf("不支持的工具类型 %q:服务端工具仅支持 web_search / x_search", t.Type) + return fmt.Errorf("不支持的工具类型 %q:服务端工具仅支持 web_search / x_search / code_interpreter / mcp", t.Type) } } return nil diff --git a/internal/service/airesponses_test.go b/internal/service/airesponses_test.go index 33acfc2..6553f26 100644 --- a/internal/service/airesponses_test.go +++ b/internal/service/airesponses_test.go @@ -24,27 +24,6 @@ func deref(p *int) int { return *p } -func TestRespServerTools(t *testing.T) { - tests := []struct { - name string - tools []aiwire.RespTool - want bool - }{ - {"web_search", []aiwire.RespTool{{Type: "web_search"}}, true}, - {"x_search混用", []aiwire.RespTool{{Type: "function", Name: "f"}, {Type: "x_search"}}, true}, - {"仅function", []aiwire.RespTool{{Type: "function", Name: "f"}}, false}, - {"空", nil, false}, - {"其他类型", []aiwire.RespTool{{Type: "code_interpreter"}}, false}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if got := RespServerTools(test.tools); got != test.want { - t.Fatalf("got %v, want %v", got, test.want) - } - }) - } -} - func TestRespPassthroughValidate(t *testing.T) { prev := "resp_1" bg := true @@ -56,12 +35,14 @@ func TestRespPassthroughValidate(t *testing.T) { {"合法", aiwire.RespRequest{Model: "m", Tools: []aiwire.RespTool{{Type: "web_search"}}}, false}, {"混用function", aiwire.RespRequest{Model: "m", Tools: []aiwire.RespTool{{Type: "web_search"}, {Type: "function", Name: "f"}}}, false}, {"缺model", aiwire.RespRequest{Tools: []aiwire.RespTool{{Type: "web_search"}}}, true}, - {"工具加流式拒绝", aiwire.RespRequest{Model: "m", Stream: true, Tools: []aiwire.RespTool{{Type: "web_search"}}}, true}, + {"服务端工具流式放行", aiwire.RespRequest{Model: "m", Stream: true, Tools: []aiwire.RespTool{{Type: "web_search"}}}, false}, {"无工具流式放行", aiwire.RespRequest{Model: "m", Stream: true}, false}, {"function工具流式放行", aiwire.RespRequest{Model: "m", Stream: true, Tools: []aiwire.RespTool{{Type: "function", Name: "f"}}}, false}, + {"code_interpreter放行", aiwire.RespRequest{Model: "m", Tools: []aiwire.RespTool{{Type: "code_interpreter"}}}, false}, + {"mcp流式放行", aiwire.RespRequest{Model: "m", Stream: true, Tools: []aiwire.RespTool{{Type: "mcp"}}}, false}, {"有状态拒绝", aiwire.RespRequest{Model: "m", PreviousResponseID: prev}, true}, {"background拒绝", aiwire.RespRequest{Model: "m", Background: &bg}, true}, - {"未知工具拒绝", aiwire.RespRequest{Model: "m", Tools: []aiwire.RespTool{{Type: "web_search"}, {Type: "mcp"}}}, true}, + {"未知工具拒绝", aiwire.RespRequest{Model: "m", Tools: []aiwire.RespTool{{Type: "web_search"}, {Type: "file_search"}}}, true}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) {