/
Alex_Ural
/
opencode
Обзор
Документация
Войти
/
Alex_Ural
/
opencode
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
packages/codemode/src/openapi/index.ts
130 строк
4 KB
Aiden Cline
feat(codemode): sync v2 implementation (#35574)
06 июл 2026, 21:19
Не верифицирован
06 июл 2026, 21:19
d5aa79c
Код
Авторство
О чём код?
import { HttpClient } from "effect/unstable/http" import { make, type Definition } from "../tool.js" import { invoke } from "./runtime.js" import { componentDefinitions, inputSchema, isRecord, methods, nonEmptyString, operationInput, operationOutput, operationPath, operationSecurityRequirements, securityRequirements, securitySchemes, specServerUrl, validateBaseUrl, } from "./spec.js" import type { Operation, Options, Result, Skipped, Tools } from "./types.js" export type { AuthResolver, Credential, Document, Operation, Options, Result, SecurityScheme, Skipped, Tools, } from "./types.js" /** * Builds a CodeMode tool subtree from an OpenAPI 3.x document, one tool per * operation. Auth is resolved host-side via `auth.resolve` and never * model-visible. Tools require `HttpClient.HttpClient`; unrepresentable * operations land in `skipped`. */ export const fromSpec = (options: Options): Result => { const document = options.spec const schemes = securitySchemes(document) const defaultSecurity = securityRequirements(document.security) const definitions = componentDefinitions(document) const paths = isRecord(document.paths) ? document.paths : {} const used = new Set<string>() const namespaces = new Set<string>() const skipped: Array<Skipped> = [] const tools = Object.create(null) as Tools for (const [path, pathValue] of Object.entries(paths)) { if (!isRecord(pathValue)) continue for (const [method, operationValue] of Object.entries(pathValue)) { if (!methods.has(method) || !isRecord(operationValue)) continue const segments = operationPath(method, path, operationValue, used, namespaces) const operation: Operation = { operationId: nonEmptyString(operationValue.operationId), method: method.toUpperCase(), path, summary: nonEmptyString(operationValue.summary), description: nonEmptyString(operationValue.description), } const output = operationOutput(document, operationValue, definitions) if (!output.ok) { skipped.push({ method: operation.method, path, reason: output.reason }) continue } const resolvedBaseUrl = (() => { if (options.baseUrl !== undefined) return validateBaseUrl(options.baseUrl) if (operationValue.servers !== undefined) return specServerUrl(operationValue) if (pathValue.servers !== undefined) return specServerUrl(pathValue) return specServerUrl(document) })() if (!resolvedBaseUrl.ok) { skipped.push({ method: operation.method, path, reason: resolvedBaseUrl.reason }) continue } const parsedInput = operationInput(document, pathValue, operationValue) if (!parsedInput.ok) { skipped.push({ method: operation.method, path, reason: parsedInput.reason }) continue } const input = parsedInput.value const security = operationSecurityRequirements(operationValue.security, defaultSecurity, schemes) if (!security.ok) { skipped.push({ method: operation.method, path, reason: security.reason }) continue } const plan = { operation, url: `${resolvedBaseUrl.value.replace(/\/+$/, "")}${path}`, fields: input.fields, body: input.body, security: security.value, schemes, auth: options.auth, headers: options.headers ?? {}, } used.add(segments.join(".")) for (const index of segments.slice(0, -1).keys()) namespaces.add(segments.slice(0, index + 1).join(".")) setTool( tools, segments, make({ description: operation.description ?? operation.summary ?? `${operation.method} ${path}`, input: inputSchema(input.fields, definitions), output: output.value, run: (input) => invoke(plan, input), }), ) } } return { tools, skipped } } const setTool = (tools: Tools, path: ReadonlyArray<string>, definition: Definition<HttpClient.HttpClient>): void => { const [head, ...rest] = path if (head === undefined) return if (rest.length === 0) { tools[head] = definition return } const child = tools[head] if (child === undefined || !isRecord(child) || child._tag === "CodeModeTool") { tools[head] = Object.create(null) as Tools } setTool(tools[head] as Tools, rest, definition) }