From 05d3e65f767360a38a508ad198df15ca3f8c2bbe Mon Sep 17 00:00:00 2001 From: Vladimir Glafirov Date: Fri, 20 Mar 2026 18:55:22 +0100 Subject: [PATCH] feat: enable GitLab Agent Platform with workflow model discovery (#18014) --- bun.lock | 26 ++-- packages/opencode/package.json | 4 +- packages/opencode/src/plugin/index.ts | 2 +- packages/opencode/src/provider/provider.ts | 128 ++++++++++++++++-- .../opencode/src/server/routes/provider.ts | 3 + packages/opencode/src/session/llm.ts | 29 ++++ .../opencode/test/provider/gitlab-duo.test.ts | 123 ++++++++++++++++- .../test/tool/fixtures/models-api.json | 2 +- .../web/src/content/docs/ar/providers.mdx | 12 +- .../web/src/content/docs/bs/providers.mdx | 12 +- .../web/src/content/docs/da/providers.mdx | 12 +- .../web/src/content/docs/de/providers.mdx | 12 +- .../web/src/content/docs/es/providers.mdx | 12 +- .../web/src/content/docs/fr/providers.mdx | 12 +- .../web/src/content/docs/it/providers.mdx | 12 +- .../web/src/content/docs/ja/providers.mdx | 12 +- .../web/src/content/docs/ko/providers.mdx | 12 +- .../web/src/content/docs/nb/providers.mdx | 12 +- .../web/src/content/docs/pl/providers.mdx | 12 +- packages/web/src/content/docs/providers.mdx | 53 ++++++-- .../web/src/content/docs/pt-br/providers.mdx | 12 +- .../web/src/content/docs/ru/providers.mdx | 12 +- .../web/src/content/docs/th/providers.mdx | 12 +- .../web/src/content/docs/tr/providers.mdx | 12 +- .../web/src/content/docs/zh-cn/providers.mdx | 12 +- .../web/src/content/docs/zh-tw/providers.mdx | 12 +- 26 files changed, 393 insertions(+), 181 deletions(-) diff --git a/bun.lock b/bun.lock index ee8746c42..58cfe892f 100644 --- a/bun.lock +++ b/bun.lock @@ -325,8 +325,6 @@ "@aws-sdk/credential-providers": "3.993.0", "@clack/prompts": "1.0.0-alpha.1", "@effect/platform-node": "catalog:", - "@gitlab/gitlab-ai-provider": "3.6.0", - "@gitlab/opencode-gitlab-auth": "1.3.3", "@hono/standard-validator": "0.1.5", "@hono/zod-validator": "catalog:", "@modelcontextprotocol/sdk": "1.25.2", @@ -358,6 +356,7 @@ "drizzle-orm": "catalog:", "effect": "catalog:", "fuzzysort": "3.1.0", + "gitlab-ai-provider": "5.2.2", "glob": "13.0.5", "google-auth-library": "10.5.0", "gray-matter": "4.0.3", @@ -368,6 +367,7 @@ "mime-types": "3.0.2", "minimatch": "10.0.3", "open": "10.1.2", + "opencode-gitlab-auth": "2.0.0", "opentui-spinner": "0.0.6", "partial-json": "0.1.7", "remeda": "catalog:", @@ -1110,10 +1110,6 @@ "@fontsource/inter": ["@fontsource/inter@5.2.8", "", {}, "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg=="], - "@gitlab/gitlab-ai-provider": ["@gitlab/gitlab-ai-provider@3.6.0", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=2.0.0", "@ai-sdk/provider-utils": ">=3.0.0" } }, "sha512-8LmcIQ86xkMtC7L4P1/QYVEC+yKMTRerfPeniaaQGalnzXKtX6iMHLjLPOL9Rxp55lOXi6ed0WrFuJzZx+fNRg=="], - - "@gitlab/opencode-gitlab-auth": ["@gitlab/opencode-gitlab-auth@1.3.3", "", { "dependencies": { "@fastify/rate-limit": "^10.2.0", "@opencode-ai/plugin": "*", "fastify": "^5.2.0", "open": "^10.0.0" } }, "sha512-FT+KsCmAJjtqWr1YAq0MywGgL9kaLQ4apmsoowAXrPqHtoYf2i/nY10/A+L06kNj22EATeEDRpbB1NWXMto/SA=="], - "@graphql-typed-document-node/core": ["@graphql-typed-document-node/core@3.2.0", "", { "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ=="], "@happy-dom/global-registrator": ["@happy-dom/global-registrator@20.0.11", "", { "dependencies": { "@types/node": "^20.0.0", "happy-dom": "^20.0.11" } }, "sha512-GqNqiShBT/lzkHTMC/slKBrvN0DsD4Di8ssBk4aDaVgEn+2WMzE6DXxq701ndSXj7/0cJ8mNT71pM7Bnrr6JRw=="], @@ -3032,6 +3028,8 @@ "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], + "gitlab-ai-provider": ["gitlab-ai-provider@5.2.2", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=2.0.0", "@ai-sdk/provider-utils": ">=3.0.0" } }, "sha512-ejwnie62rimfVHbjYZ2tsnqwLjF9YLgXD3OQA458gHz8hUvw7vEnhuyuMv5PmWQtyS3ISAghiX7r5SBhUWeCTA=="], + "glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="], "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], @@ -3784,6 +3782,8 @@ "opencode": ["opencode@workspace:packages/opencode"], + "opencode-gitlab-auth": ["opencode-gitlab-auth@2.0.0", "", { "dependencies": { "@fastify/rate-limit": "^10.2.0", "@opencode-ai/plugin": "*", "fastify": "^5.2.0", "open": "^10.0.0" } }, "sha512-jmZOOvYIurRScQCtdBqIW5HbP1JbmIiq7UtI7NGgn2vjke46g9d4NVPBg5/ZmFFVIBwZcgyFgJ7b8kGEOR9ujA=="], + "opencontrol": ["opencontrol@0.0.6", "", { "dependencies": { "@modelcontextprotocol/sdk": "1.6.1", "@tsconfig/bun": "1.0.7", "hono": "4.7.4", "zod": "3.24.2", "zod-to-json-schema": "3.24.3" }, "bin": { "opencontrol": "bin/index.mjs" } }, "sha512-QeCrpOK5D15QV8kjnGVeD/BHFLwcVr+sn4T6KKmP0WAMs2pww56e4h+eOGHb5iPOufUQXbdbBKi6WV2kk7tefQ=="], "openid-client": ["openid-client@5.6.4", "", { "dependencies": { "jose": "^4.15.4", "lru-cache": "^6.0.0", "object-hash": "^2.2.0", "oidc-token-hash": "^5.0.3" } }, "sha512-T1h3B10BRPKfcObdBklX639tVz+xh34O7GjofqrqiAQdm7eHsQ00ih18x6wuJ/E6FxdtS2u3FmUGPDeEcMwzNA=="], @@ -4246,7 +4246,7 @@ "socket.io-client": ["socket.io-client@4.8.3", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-client": "~6.6.1", "socket.io-parser": "~4.2.4" } }, "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g=="], - "socket.io-parser": ["socket.io-parser@4.2.5", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1" } }, "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ=="], + "socket.io-parser": ["socket.io-parser@4.2.6", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1" } }, "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg=="], "socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="], @@ -5060,10 +5060,6 @@ "@fastify/proxy-addr/ipaddr.js": ["ipaddr.js@2.3.0", "", {}, "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg=="], - "@gitlab/gitlab-ai-provider/openai": ["openai@6.27.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-osTKySlrdYrLYTt0zjhY8yp0JUBmWDCN+Q+QxsV4xMQnnoVFpylgKGgxwN8sSdTNw0G4y+WUXs4eCMWpyDNWZQ=="], - - "@gitlab/gitlab-ai-provider/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@hey-api/openapi-ts/open": ["open@11.0.0", "", { "dependencies": { "default-browser": "^5.4.0", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.1.0", "wsl-utils": "^0.3.0" } }, "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw=="], "@hey-api/openapi-ts/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], @@ -5460,6 +5456,10 @@ "gaxios/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], + "gitlab-ai-provider/openai": ["openai@6.32.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-j3k+BjydAf8yQlcOI7WUQMQTbbF5GEIMAE2iZYCOzwwB3S2pCheaWYp+XZRNAch4jWVc52PMDGRRjutao3lLCg=="], + + "gitlab-ai-provider/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], "globby/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], @@ -5536,6 +5536,8 @@ "opencode/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.32", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-YspqqyJPzHjqWrjt4y/Wgc2aJgCcQj5uIJgZpq2Ar/lH30cEVhgE+keePDbjKpetD9UwNggCj7u6kO3unS23OQ=="], + "opencode-gitlab-auth/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], + "opencontrol/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.6.1", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^4.1.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA=="], "opencontrol/@tsconfig/bun": ["@tsconfig/bun@1.0.7", "", {}, "sha512-udGrGJBNQdXGVulehc1aWT73wkR9wdaGBtB6yL70RJsqwW/yJhIg6ZbRlPOfIUiFNrnBuYLBi9CSmMKfDC7dvA=="], @@ -6286,6 +6288,8 @@ "node-gyp/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], + "opencode-gitlab-auth/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], + "opencode/@ai-sdk/openai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.20", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ=="], "opencode/@ai-sdk/openai-compatible/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.20", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ=="], diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 3e73a7021..f888cc829 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -89,9 +89,9 @@ "@ai-sdk/xai": "2.0.51", "@aws-sdk/credential-providers": "3.993.0", "@clack/prompts": "1.0.0-alpha.1", + "gitlab-ai-provider": "5.2.2", + "opencode-gitlab-auth": "2.0.0", "@effect/platform-node": "catalog:", - "@gitlab/gitlab-ai-provider": "3.6.0", - "@gitlab/opencode-gitlab-auth": "1.3.3", "@hono/standard-validator": "0.1.5", "@hono/zod-validator": "catalog:", "@modelcontextprotocol/sdk": "1.25.2", diff --git a/packages/opencode/src/plugin/index.ts b/packages/opencode/src/plugin/index.ts index 755ce2c21..9e294f4f5 100644 --- a/packages/opencode/src/plugin/index.ts +++ b/packages/opencode/src/plugin/index.ts @@ -11,7 +11,7 @@ import { CodexAuthPlugin } from "./codex" import { Session } from "../session" import { NamedError } from "@opencode-ai/util/error" import { CopilotAuthPlugin } from "./copilot" -import { gitlabAuthPlugin as GitlabAuthPlugin } from "@gitlab/opencode-gitlab-auth" +import { gitlabAuthPlugin as GitlabAuthPlugin } from "opencode-gitlab-auth" export namespace Plugin { const log = Log.create({ service: "plugin" }) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 9c9c8e834..6ab45d028 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -40,7 +40,12 @@ import { createGateway } from "@ai-sdk/gateway" import { createTogetherAI } from "@ai-sdk/togetherai" import { createPerplexity } from "@ai-sdk/perplexity" import { createVercel } from "@ai-sdk/vercel" -import { createGitLab, VERSION as GITLAB_PROVIDER_VERSION } from "@gitlab/gitlab-ai-provider" +import { + createGitLab, + VERSION as GITLAB_PROVIDER_VERSION, + isWorkflowModel, + discoverWorkflowModels, +} from "gitlab-ai-provider" import { fromNodeProviderChain } from "@aws-sdk/credential-providers" import { GoogleAuth } from "google-auth-library" import { ProviderTransform } from "./transform" @@ -124,18 +129,20 @@ export namespace Provider { "@ai-sdk/togetherai": createTogetherAI, "@ai-sdk/perplexity": createPerplexity, "@ai-sdk/vercel": createVercel, - "@gitlab/gitlab-ai-provider": createGitLab, + "gitlab-ai-provider": createGitLab, // @ts-ignore (TODO: kill this code so we dont have to maintain it) "@ai-sdk/github-copilot": createGitHubCopilotOpenAICompatible, } type CustomModelLoader = (sdk: any, modelID: string, options?: Record) => Promise type CustomVarsLoader = (options: Record) => Record + type CustomDiscoverModels = () => Promise> type CustomLoader = (provider: Info) => Promise<{ autoload: boolean getModel?: CustomModelLoader vars?: CustomVarsLoader options?: Record + discoverModels?: CustomDiscoverModels }> function useLanguageModel(sdk: any) { @@ -533,28 +540,105 @@ export namespace Provider { ...(providerConfig?.options?.aiGatewayHeaders || {}), } + const featureFlags = { + duo_agent_platform_agentic_chat: true, + duo_agent_platform: true, + ...(providerConfig?.options?.featureFlags || {}), + } + return { autoload: !!apiKey, options: { instanceUrl, apiKey, aiGatewayHeaders, - featureFlags: { - duo_agent_platform_agentic_chat: true, - duo_agent_platform: true, - ...(providerConfig?.options?.featureFlags || {}), - }, + featureFlags, }, - async getModel(sdk: ReturnType, modelID: string) { + async getModel(sdk: ReturnType, modelID: string, options?: Record) { + if (modelID.startsWith("duo-workflow-")) { + const workflowRef = options?.workflowRef as string | undefined + // Use the static mapping if it exists, otherwise use duo-workflow with selectedModelRef + const sdkModelID = isWorkflowModel(modelID) ? modelID : "duo-workflow" + const model = sdk.workflowChat(sdkModelID, { + featureFlags, + }) + if (workflowRef) { + model.selectedModelRef = workflowRef + } + return model + } return sdk.agenticChat(modelID, { aiGatewayHeaders, - featureFlags: { - duo_agent_platform_agentic_chat: true, - duo_agent_platform: true, - ...(providerConfig?.options?.featureFlags || {}), - }, + featureFlags, }) }, + async discoverModels(): Promise> { + if (!apiKey) { + log.info("gitlab model discovery skipped: no apiKey") + return {} + } + + try { + const token = apiKey + const getHeaders = (): Record => + auth?.type === "api" ? { "PRIVATE-TOKEN": token } : { Authorization: `Bearer ${token}` } + + log.info("gitlab model discovery starting", { instanceUrl }) + const result = await discoverWorkflowModels( + { instanceUrl, getHeaders }, + { workingDirectory: Instance.directory }, + ) + + if (!result.models.length) { + log.info("gitlab model discovery skipped: no models found", { + project: result.project ? { id: result.project.id, path: result.project.pathWithNamespace } : null, + }) + return {} + } + + const models: Record = {} + for (const m of result.models) { + if (!input.models[m.id]) { + models[m.id] = { + id: ModelID.make(m.id), + providerID: ProviderID.make("gitlab"), + name: `Agent Platform (${m.name})`, + family: "", + api: { + id: m.id, + url: instanceUrl, + npm: "gitlab-ai-provider", + }, + status: "active", + headers: {}, + options: { workflowRef: m.ref }, + cost: { input: 0, output: 0, cache: { read: 0, write: 0 } }, + limit: { context: m.context, output: m.output }, + capabilities: { + temperature: false, + reasoning: true, + attachment: true, + toolcall: true, + input: { text: true, audio: false, image: true, video: false, pdf: true }, + output: { text: true, audio: false, image: false, video: false, pdf: false }, + interleaved: false, + }, + release_date: "", + variants: {}, + } + } + } + + log.info("gitlab model discovery complete", { + count: Object.keys(models).length, + models: Object.keys(models), + }) + return models + } catch (e) { + log.warn("gitlab model discovery failed", { error: e }) + return {} + } + }, } }, "cloudflare-workers-ai": async (input) => { @@ -853,6 +937,9 @@ export namespace Provider { const varsLoaders: { [providerID: string]: CustomVarsLoader } = {} + const discoveryLoaders: { + [providerID: string]: CustomDiscoverModels + } = {} const sdk = new Map() log.info("init") @@ -1009,6 +1096,7 @@ export namespace Provider { if (result && (result.autoload || providers[providerID])) { if (result.getModel) modelLoaders[providerID] = result.getModel if (result.vars) varsLoaders[providerID] = result.vars + if (result.discoverModels) discoveryLoaders[providerID] = result.discoverModels const opts = result.options ?? {} const patch: Partial = providers[providerID] ? { options: opts } : { source: "custom", options: opts } mergeProvider(providerID, patch) @@ -1070,6 +1158,18 @@ export namespace Provider { log.info("found", { providerID }) } + const gitlab = ProviderID.make("gitlab") + if (discoveryLoaders[gitlab] && providers[gitlab]) { + await (async () => { + const discovered = await discoveryLoaders[gitlab]() + for (const [modelID, model] of Object.entries(discovered)) { + if (!providers[gitlab].models[modelID]) { + providers[gitlab].models[modelID] = model + } + } + })().catch((e) => log.warn("state discovery error", { id: "gitlab", error: e })) + } + return { models: languages, providers, @@ -1250,7 +1350,7 @@ export namespace Provider { try { const language = s.modelLoaders[model.providerID] - ? await s.modelLoaders[model.providerID](sdk, model.api.id, provider.options) + ? await s.modelLoaders[model.providerID](sdk, model.api.id, { ...provider.options, ...model.options }) : sdk.languageModel(model.api.id) s.models.set(key, language) return language diff --git a/packages/opencode/src/server/routes/provider.ts b/packages/opencode/src/server/routes/provider.ts index 3ac3e7c64..64fe34f45 100644 --- a/packages/opencode/src/server/routes/provider.ts +++ b/packages/opencode/src/server/routes/provider.ts @@ -9,6 +9,9 @@ import { ProviderID } from "../../provider/schema" import { mapValues } from "remeda" import { errors } from "../error" import { lazy } from "../../util/lazy" +import { Log } from "../../util/log" + +const log = Log.create({ service: "server" }) export const ProviderRoutes = lazy(() => new Hono() diff --git a/packages/opencode/src/session/llm.ts b/packages/opencode/src/session/llm.ts index 48a36741c..748fd3eb2 100644 --- a/packages/opencode/src/session/llm.ts +++ b/packages/opencode/src/session/llm.ts @@ -12,6 +12,7 @@ import { jsonSchema, } from "ai" import { mergeDeep, pipe } from "remeda" +import { GitLabWorkflowLanguageModel } from "gitlab-ai-provider" import { ProviderTransform } from "@/provider/transform" import { Config } from "@/config/config" import { Instance } from "@/project/instance" @@ -184,6 +185,34 @@ export namespace LLM { }) } + // Wire up toolExecutor for DWS workflow models so that tool calls + // from the workflow service are executed via opencode's tool system + // and results sent back over the WebSocket. + if (language instanceof GitLabWorkflowLanguageModel) { + const workflowModel = language + workflowModel.toolExecutor = async (toolName, argsJson, _requestID) => { + const t = tools[toolName] + if (!t || !t.execute) { + return { result: "", error: `Unknown tool: ${toolName}` } + } + try { + const result = await t.execute!(JSON.parse(argsJson), { + toolCallId: _requestID, + messages: input.messages, + abortSignal: input.abort, + }) + const output = typeof result === "string" ? result : (result?.output ?? JSON.stringify(result)) + return { + result: output, + metadata: typeof result === "object" ? result?.metadata : undefined, + title: typeof result === "object" ? result?.title : undefined, + } + } catch (e: any) { + return { result: "", error: e.message ?? String(e) } + } + } + } + return streamText({ onError(error) { l.error("stream error", { diff --git a/packages/opencode/test/provider/gitlab-duo.test.ts b/packages/opencode/test/provider/gitlab-duo.test.ts index f30e3297d..15c797022 100644 --- a/packages/opencode/test/provider/gitlab-duo.test.ts +++ b/packages/opencode/test/provider/gitlab-duo.test.ts @@ -1,12 +1,13 @@ -import { test, expect } from "bun:test" +import { test, expect, describe } from "bun:test" import path from "path" -import { ProviderID } from "../../src/provider/schema" +import { ProviderID, ModelID } from "../../src/provider/schema" import { tmpdir } from "../fixture/fixture" import { Instance } from "../../src/project/instance" import { Provider } from "../../src/provider/provider" import { Env } from "../../src/env" import { Global } from "../../src/global" +import { GitLabWorkflowLanguageModel } from "gitlab-ai-provider" test("GitLab Duo: loads provider with API key from environment", async () => { await using tmp = await tmpdir({ @@ -287,3 +288,121 @@ test("GitLab Duo: has multiple agentic chat models available", async () => { }, }) }) + +describe("GitLab Duo: workflow model routing", () => { + test("duo-workflow-* model routes through workflowChat", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json" })) + }, + }) + await Instance.provide({ + directory: tmp.path, + init: async () => { + Env.set("GITLAB_TOKEN", "test-token") + }, + fn: async () => { + const providers = await Provider.list() + const gitlab = providers[ProviderID.gitlab] + expect(gitlab).toBeDefined() + gitlab.models["duo-workflow-sonnet-4-6"] = { + id: ModelID.make("duo-workflow-sonnet-4-6"), + providerID: ProviderID.make("gitlab"), + name: "Agent Platform (Claude Sonnet 4.6)", + family: "", + api: { id: "duo-workflow-sonnet-4-6", url: "https://gitlab.com", npm: "gitlab-ai-provider" }, + status: "active", + headers: {}, + options: { workflowRef: "claude_sonnet_4_6" }, + cost: { input: 0, output: 0, cache: { read: 0, write: 0 } }, + limit: { context: 200000, output: 64000 }, + capabilities: { + temperature: false, + reasoning: true, + attachment: true, + toolcall: true, + input: { text: true, audio: false, image: true, video: false, pdf: true }, + output: { text: true, audio: false, image: false, video: false, pdf: false }, + interleaved: false, + }, + release_date: "", + variants: {}, + } + const model = await Provider.getModel(ProviderID.gitlab, ModelID.make("duo-workflow-sonnet-4-6")) + expect(model).toBeDefined() + expect(model.options?.workflowRef).toBe("claude_sonnet_4_6") + const language = await Provider.getLanguage(model) + expect(language).toBeDefined() + expect(language).toBeInstanceOf(GitLabWorkflowLanguageModel) + }, + }) + }) + + test("duo-chat-* model routes through agenticChat (not workflow)", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json" })) + }, + }) + await Instance.provide({ + directory: tmp.path, + init: async () => { + Env.set("GITLAB_TOKEN", "test-token") + }, + fn: async () => { + const providers = await Provider.list() + expect(providers[ProviderID.gitlab]).toBeDefined() + const model = await Provider.getModel(ProviderID.gitlab, ModelID.make("duo-chat-sonnet-4-5")) + expect(model).toBeDefined() + const language = await Provider.getLanguage(model) + expect(language).toBeDefined() + expect(language).not.toBeInstanceOf(GitLabWorkflowLanguageModel) + }, + }) + }) + + test("model.options merged with provider.options in getLanguage", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json" })) + }, + }) + await Instance.provide({ + directory: tmp.path, + init: async () => { + Env.set("GITLAB_TOKEN", "test-token") + }, + fn: async () => { + const providers = await Provider.list() + const gitlab = providers[ProviderID.gitlab] + expect(gitlab.options?.featureFlags).toBeDefined() + const model = await Provider.getModel(ProviderID.gitlab, ModelID.make("duo-chat-sonnet-4-5")) + expect(model).toBeDefined() + expect(model.options).toBeDefined() + }, + }) + }) +}) + +describe("GitLab Duo: static models", () => { + test("static duo-chat models always present regardless of discovery", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json" })) + }, + }) + await Instance.provide({ + directory: tmp.path, + init: async () => { + Env.set("GITLAB_TOKEN", "test-token") + }, + fn: async () => { + const providers = await Provider.list() + const models = Object.keys(providers[ProviderID.gitlab].models) + expect(models).toContain("duo-chat-haiku-4-5") + expect(models).toContain("duo-chat-sonnet-4-5") + expect(models).toContain("duo-chat-opus-4-5") + }, + }) + }) +}) diff --git a/packages/opencode/test/tool/fixtures/models-api.json b/packages/opencode/test/tool/fixtures/models-api.json index 391e78369..715224cd3 100644 --- a/packages/opencode/test/tool/fixtures/models-api.json +++ b/packages/opencode/test/tool/fixtures/models-api.json @@ -32933,7 +32933,7 @@ "gitlab": { "id": "gitlab", "env": ["GITLAB_TOKEN"], - "npm": "@gitlab/gitlab-ai-provider", + "npm": "gitlab-ai-provider", "name": "GitLab Duo", "doc": "https://docs.gitlab.com/user/duo_agent_platform/", "models": { diff --git a/packages/web/src/content/docs/ar/providers.mdx b/packages/web/src/content/docs/ar/providers.mdx index f5dd70125..951d6701c 100644 --- a/packages/web/src/content/docs/ar/providers.mdx +++ b/packages/web/src/content/docs/ar/providers.mdx @@ -752,7 +752,7 @@ export GITLAB_TOKEN=glpat-... :::note يجب على مدير GitLab لديك تفعيل ما يلي: -1. [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) للمستخدم أو المجموعة أو المثيل +1. [Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) للمستخدم أو المجموعة أو المثيل 2. Feature flags (عبر Rails console): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -774,7 +774,7 @@ callback URL ‏`http://127.0.0.1:8080/callback` ونطاقات الصلاحيا export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -مزيد من التوثيق على صفحة [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth). +مزيد من التوثيق على صفحة [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth). ##### التهيئة @@ -786,11 +786,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -804,7 +800,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/bs/providers.mdx b/packages/web/src/content/docs/bs/providers.mdx index 6bdcf4577..1aae0a93a 100644 --- a/packages/web/src/content/docs/bs/providers.mdx +++ b/packages/web/src/content/docs/bs/providers.mdx @@ -760,7 +760,7 @@ export GITLAB_TOKEN=glpat-... :::note Vaš GitLab administrator mora omogućiti sljedeće: -1. [Duo Agent Platforma](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) za korisnika, grupu ili instancu +1. [Duo Agent Platforma](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) za korisnika, grupu ili instancu 2. Zastavice funkcija (preko Rails konzole): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -782,7 +782,7 @@ Zatim izložite ID aplikacije kao varijablu okruženja: export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -Više dokumentacije na početnoj stranici [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth). +Više dokumentacije na početnoj stranici [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth). ##### Konfiguracija @@ -794,11 +794,7 @@ Prilagodite putem `opencode.json`: "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -812,7 +808,7 @@ Za pristup GitLab alatima (zahtjevi za spajanje, problemi, cjevovodi, CI/CD, itd ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/da/providers.mdx b/packages/web/src/content/docs/da/providers.mdx index c5cfe23fa..bcd82c845 100644 --- a/packages/web/src/content/docs/da/providers.mdx +++ b/packages/web/src/content/docs/da/providers.mdx @@ -749,7 +749,7 @@ export GITLAB_TOKEN=glpat-... :::note Din GitLab-administrator skal aktivere følgende: -1. [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) for brugeren, gruppen eller instansen +1. [Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) for brugeren, gruppen eller instansen 2. Funktionsflag (via Rails-konsollen): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -771,7 +771,7 @@ Udsæt derefter applikations-ID som miljøvariabel: export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -Mere dokumentation på [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth) hjemmesiden. +Mere dokumentation på [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth) hjemmesiden. ##### Konfiguration @@ -783,11 +783,7 @@ Tilpas gennem `opencode.json`: "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -801,7 +797,7 @@ For at få adgang til GitLab-værktøjer (merge requests, problemer, pipelines, ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/de/providers.mdx b/packages/web/src/content/docs/de/providers.mdx index fa447594d..c012a78fc 100644 --- a/packages/web/src/content/docs/de/providers.mdx +++ b/packages/web/src/content/docs/de/providers.mdx @@ -755,7 +755,7 @@ export GITLAB_TOKEN=glpat-... :::note Ihr GitLab-Administrator muss Folgendes aktivieren: -1. [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) für den Benutzer, die Gruppe oder die Instanz +1. [Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) für den Benutzer, die Gruppe oder die Instanz 2. Feature-Flags (über die Rails-Konsole): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -777,7 +777,7 @@ Stellen Sie dann die Anwendung ID als Umgebungsvariable bereit: export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -Weitere Dokumentation auf der [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth)-Homepage. +Weitere Dokumentation auf der [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth)-Homepage. ##### Konfiguration @@ -789,11 +789,7 @@ Anpassen über `opencode.json`: "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -807,7 +803,7 @@ So greifen Sie auf GitLab-Tools zu (Zusammenführungsanfragen, Probleme, Pipelin ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/es/providers.mdx b/packages/web/src/content/docs/es/providers.mdx index 2ee033f00..b81297140 100644 --- a/packages/web/src/content/docs/es/providers.mdx +++ b/packages/web/src/content/docs/es/providers.mdx @@ -757,7 +757,7 @@ export GITLAB_TOKEN=glpat-... :::note Su administrador GitLab debe habilitar lo siguiente: -1. [Plataforma de agente Duo](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) para el usuario, grupo o instancia +1. [Plataforma de agente Duo](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) para el usuario, grupo o instancia 2. Indicadores de funciones (a través de la consola Rails): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -779,7 +779,7 @@ Luego exponga el ID de la aplicación como variable de entorno: export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -Más documentación en la página de inicio de [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth). +Más documentación en la página de inicio de [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth). ##### Configuración @@ -791,11 +791,7 @@ Personalizar a través de `opencode.json`: "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -809,7 +805,7 @@ Para acceder a herramientas GitLab (solicitudes de fusión, problemas, canalizac ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/fr/providers.mdx b/packages/web/src/content/docs/fr/providers.mdx index 36e1ed2d2..d7b065797 100644 --- a/packages/web/src/content/docs/fr/providers.mdx +++ b/packages/web/src/content/docs/fr/providers.mdx @@ -763,7 +763,7 @@ export GITLAB_TOKEN=glpat-... :::note Votre administrateur GitLab doit activer les éléments suivants : -1. [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) pour l'utilisateur, le groupe ou l'instance +1. [Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) pour l'utilisateur, le groupe ou l'instance 2. Indicateurs de fonctionnalités (via la console Rails) : - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -785,7 +785,7 @@ Exposez ensuite l'ID de l'application en tant que variable d'environnement : export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -Plus de documentation sur la page d'accueil [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth). +Plus de documentation sur la page d'accueil [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth). ##### Configuration @@ -797,11 +797,7 @@ Personnalisez via `opencode.json` : "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -815,7 +811,7 @@ Pour accéder aux outils GitLab (demandes de fusion, tickets, pipelines, CI/CD, ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/it/providers.mdx b/packages/web/src/content/docs/it/providers.mdx index c0c5489d0..58bb28407 100644 --- a/packages/web/src/content/docs/it/providers.mdx +++ b/packages/web/src/content/docs/it/providers.mdx @@ -733,7 +733,7 @@ export GITLAB_TOKEN=glpat-... :::note Il tuo amministratore GitLab deve abilitare quanto segue: -1. [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) per l'utente, gruppo o istanza +1. [Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) per l'utente, gruppo o istanza 2. Feature flags (via Rails console): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -755,7 +755,7 @@ Poi esponi l'ID applicazione come variabile d'ambiente: export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -Maggior documentazione sulla homepage di [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth). +Maggior documentazione sulla homepage di [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth). ##### Configurazione @@ -767,11 +767,7 @@ Personalizza tramite `opencode.json`: "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -785,7 +781,7 @@ Per accedere agli strumenti GitLab (merge requests, issues, pipelines, CI/CD, ec ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/ja/providers.mdx b/packages/web/src/content/docs/ja/providers.mdx index 388dc8e41..f7e88d8c5 100644 --- a/packages/web/src/content/docs/ja/providers.mdx +++ b/packages/web/src/content/docs/ja/providers.mdx @@ -797,7 +797,7 @@ export GITLAB_TOKEN=glpat-... :::note GitLab 管理者は以下を有効にする必要があります。 -1. [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) (ユーザー、グループ、またはインスタンス用) +1. [Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) (ユーザー、グループ、またはインスタンス用) 2. 機能フラグ (Rails コンソール経由): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -819,7 +819,7 @@ GitLab 管理者は以下を有効にする必要があります。 export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -詳細については、[opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth) ホームページ。 +詳細については、[opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth) ホームページ。 ##### 設定 @@ -831,11 +831,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -849,7 +845,7 @@ GitLab ツール (マージリクエスト、問題、パイプライン、CI/CD ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/ko/providers.mdx b/packages/web/src/content/docs/ko/providers.mdx index c543c719d..ccbbc4838 100644 --- a/packages/web/src/content/docs/ko/providers.mdx +++ b/packages/web/src/content/docs/ko/providers.mdx @@ -758,7 +758,7 @@ export GITLAB_TOKEN=glpat-... :::note GitLab 관리자는 다음을 활성화해야 합니다: -1. [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) (사용자, 그룹 또는 인스턴스) +1. [Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) (사용자, 그룹 또는 인스턴스) 2. 기능 플래그 (Rails 콘솔을 통해): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -779,7 +779,7 @@ GitLab 관리자는 다음을 활성화해야 합니다: export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -[opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth) 홈페이지에 추가 문서가 있습니다. +[opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth) 홈페이지에 추가 문서가 있습니다. #### 구성 @@ -791,11 +791,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -809,7 +805,7 @@ GitLab 도구(병합 요청, 이슈, 파이프라인, CI/CD 등)에 액세스하 ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/nb/providers.mdx b/packages/web/src/content/docs/nb/providers.mdx index 682f923f8..9e025a96f 100644 --- a/packages/web/src/content/docs/nb/providers.mdx +++ b/packages/web/src/content/docs/nb/providers.mdx @@ -757,7 +757,7 @@ export GITLAB_TOKEN=glpat-... :::note GitLab-administratoren din må aktivere følgende: -1. [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) for brukeren, gruppen eller forekomsten +1. [Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) for brukeren, gruppen eller forekomsten 2. Funksjonsflagg (via Rails-konsollen): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -779,7 +779,7 @@ Utsett deretter applikasjonen ID som miljøvariabel: export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -Mer dokumentasjon på [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth) hjemmeside. +Mer dokumentasjon på [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth) hjemmeside. ##### Konfigurasjon @@ -791,11 +791,7 @@ Tilpass gjennom `opencode.json`: "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -809,7 +805,7 @@ For å få tilgang til GitLab-verktøy (sammenslåingsforespørsler, problemer, ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/pl/providers.mdx b/packages/web/src/content/docs/pl/providers.mdx index fa5090110..aeb627233 100644 --- a/packages/web/src/content/docs/pl/providers.mdx +++ b/packages/web/src/content/docs/pl/providers.mdx @@ -755,7 +755,7 @@ export GITLAB_TOKEN=glpat-... :::note Twój administrator GitLab musi włączyć następujące opcje: -1. [Platforma Duo Agent](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) dla użytkownika, grupy lub instancji +1. [Platforma Duo Agent](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) dla użytkownika, grupy lub instancji 2. Feature flags (via Rails console): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -777,7 +777,7 @@ Następnie ustaw ID aplikacji jako zmienną środowiskową: export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -Więcej informacji znajdziesz na stronie [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth). +Więcej informacji znajdziesz na stronie [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth). ##### Konfiguracja @@ -789,11 +789,7 @@ Customize through `opencode.json`: "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -807,7 +803,7 @@ To access GitLab tools (merge requests, issues, pipelines, CI/CD, etc.): ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/providers.mdx b/packages/web/src/content/docs/providers.mdx index da55875f8..b14c8ab10 100644 --- a/packages/web/src/content/docs/providers.mdx +++ b/packages/web/src/content/docs/providers.mdx @@ -722,7 +722,20 @@ Cloudflare Workers AI lets you run AI models on Cloudflare's global network dire ### GitLab Duo -GitLab Duo provides AI-powered agentic chat with native tool calling capabilities through GitLab's Anthropic proxy. +:::caution[Experimental] +GitLab Duo support in OpenCode is experimental. Features, configuration, and +behavior may change in future releases. +::: + +OpenCode integrates with the [GitLab Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/), +providing AI-powered agentic chat with native tool calling capabilities. + +:::note[License requirements] +GitLab Duo Agent Platform requires a **Premium** or **Ultimate** GitLab +subscription. It is available on GitLab.com and GitLab Self-Managed. +See [GitLab Duo Agent Platform prerequisites](https://docs.gitlab.com/user/duo_agent_platform/#prerequisites) +for full requirements. +::: 1. Run the `/connect` command and select GitLab. @@ -807,13 +820,15 @@ export GITLAB_TOKEN=glpat-... ``` :::note -Your GitLab administrator must enable the following: +Your GitLab administrator must: -1. [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) for the user, group, or instance -2. Feature flags (via Rails console): - - `agent_platform_claude_code` - - `third_party_agents_enabled` - ::: +1. [Turn on GitLab Duo](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/#turn-gitlab-duo-on-or-off) + for the user, group, or instance +2. [Turn on the Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/#turn-gitlab-duo-agent-platform-on-or-off) + (GitLab 18.8+) or [enable beta and experimental features](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/#turn-on-beta-and-experimental-features) + (GitLab 18.7 and earlier) +3. For Self-Managed, [configure your instance](https://docs.gitlab.com/administration/gitlab_duo/configure/gitlab_self_managed/) + ::: ##### OAuth for Self-Hosted instances @@ -831,7 +846,7 @@ Then expose application ID as environment variable: export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -More documentation on [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth) homepage. +More documentation on [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth) homepage. ##### Configuration @@ -843,17 +858,27 @@ Customize through `opencode.json`: "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } } ``` +##### GitLab Duo Agent Platform (DAP) Workflow Models + +DAP workflow models provide an alternative execution path that routes tool calls +through GitLab's Duo Workflow Service (DWS) instead of the standard agentic chat. +When a `duo-workflow-*` model is selected, OpenCode will: + +1. Discover available models from your GitLab namespace +2. Present a selection picker if multiple models are available +3. Cache the selected model to disk for fast subsequent startups +4. Route tool execution requests through OpenCode's permission-gated tool system + +Available DAP workflow models follow the `duo-workflow-*` naming convention and +are dynamically discovered from your GitLab instance. + ##### GitLab API Tools (Optional, but highly recommended) To access GitLab tools (merge requests, issues, pipelines, CI/CD, etc.): @@ -861,7 +886,7 @@ To access GitLab tools (merge requests, issues, pipelines, CI/CD, etc.): ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/pt-br/providers.mdx b/packages/web/src/content/docs/pt-br/providers.mdx index 2ef2ebdc0..4424a55fc 100644 --- a/packages/web/src/content/docs/pt-br/providers.mdx +++ b/packages/web/src/content/docs/pt-br/providers.mdx @@ -759,7 +759,7 @@ export GITLAB_TOKEN=glpat-... :::note Seu administrador do GitLab deve habilitar o seguinte: -1. [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) para o usuário, grupo ou instância +1. [Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) para o usuário, grupo ou instância 2. Flags de recurso (via console Rails): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -781,7 +781,7 @@ Em seguida, exponha o ID do aplicativo como variável de ambiente: export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -Mais documentação na página [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth). +Mais documentação na página [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth). ##### Configuração @@ -793,11 +793,7 @@ Personalize através do `opencode.json`: "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -811,7 +807,7 @@ Para acessar ferramentas do GitLab (merge requests, issues, pipelines, CI/CD, et ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/ru/providers.mdx b/packages/web/src/content/docs/ru/providers.mdx index c36dfd9f7..1cb3873c3 100644 --- a/packages/web/src/content/docs/ru/providers.mdx +++ b/packages/web/src/content/docs/ru/providers.mdx @@ -755,7 +755,7 @@ export GITLAB_TOKEN=glpat-... :::note Ваш администратор GitLab должен включить следующее: -1. [Платформа Duo Agent](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) для пользователя, группы или экземпляра +1. [Платформа Duo Agent](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) для пользователя, группы или экземпляра 2. Флаги функций (через консоль Rails): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -777,7 +777,7 @@ URL обратного вызова `http://127.0.0.1:8080/callback` и след export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -Дополнительная документация на домашней странице [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth). +Дополнительная документация на домашней странице [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth). ##### Конфигурация @@ -789,11 +789,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -807,7 +803,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/th/providers.mdx b/packages/web/src/content/docs/th/providers.mdx index 122ade427..73489b96a 100644 --- a/packages/web/src/content/docs/th/providers.mdx +++ b/packages/web/src/content/docs/th/providers.mdx @@ -756,7 +756,7 @@ export GITLAB_TOKEN=glpat-... :::note ผู้ดูแลระบบ GitLab ของคุณต้องเปิดใช้งานสิ่งต่อไปนี้: -1. [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) สำหรับผู้ใช้ กลุ่ม หรืออินสแตนซ์ +1. [Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) สำหรับผู้ใช้ กลุ่ม หรืออินสแตนซ์ 2. แฟล็กคุณลักษณะ (ผ่านคอนโซล Rails): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -778,7 +778,7 @@ export GITLAB_TOKEN=glpat-... export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -เอกสารประกอบเพิ่มเติมเกี่ยวกับหน้าแรกของ [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth) +เอกสารประกอบเพิ่มเติมเกี่ยวกับหน้าแรกของ [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth) ##### การกำหนดค่า @@ -790,11 +790,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -808,7 +804,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/tr/providers.mdx b/packages/web/src/content/docs/tr/providers.mdx index 1ddc65131..871f9e128 100644 --- a/packages/web/src/content/docs/tr/providers.mdx +++ b/packages/web/src/content/docs/tr/providers.mdx @@ -757,7 +757,7 @@ export GITLAB_TOKEN=glpat-... :::note GitLab yöneticiniz aşağıdakileri etkinleştirmelidir: -1. Kullanıcı, grup veya örnek için [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) +1. Kullanıcı, grup veya örnek için [Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) 2. Feature flags (via Rails console): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -779,7 +779,7 @@ Then expose application ID as environment variable: export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -Daha fazla belge [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth) ana sayfasında. +Daha fazla belge [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth) ana sayfasında. ##### Yapılandırma @@ -791,11 +791,7 @@ Daha fazla belge [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/op "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -809,7 +805,7 @@ GitLab araçlarına (birleştirme istekleri, sorunlar, işlem hatları, CI/CD vb ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/zh-cn/providers.mdx b/packages/web/src/content/docs/zh-cn/providers.mdx index 571b73024..25b7d03a4 100644 --- a/packages/web/src/content/docs/zh-cn/providers.mdx +++ b/packages/web/src/content/docs/zh-cn/providers.mdx @@ -725,7 +725,7 @@ export GITLAB_TOKEN=glpat-... :::note 你的 GitLab 管理员必须启用以下功能: -1. 为用户、群组或实例启用 [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) +1. 为用户、群组或实例启用 [Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) 2. 功能标志(通过 Rails 控制台): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -745,7 +745,7 @@ export GITLAB_TOKEN=glpat-... export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -更多文档请参阅 [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth) 主页。 +更多文档请参阅 [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth) 主页。 ##### 配置 @@ -757,11 +757,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -775,7 +771,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ``` diff --git a/packages/web/src/content/docs/zh-tw/providers.mdx b/packages/web/src/content/docs/zh-tw/providers.mdx index b673b1ade..1024444d1 100644 --- a/packages/web/src/content/docs/zh-tw/providers.mdx +++ b/packages/web/src/content/docs/zh-tw/providers.mdx @@ -746,7 +746,7 @@ export GITLAB_TOKEN=glpat-... :::note 您的 GitLab 管理員必須啟用以下功能: -1. 為使用者、群組或實例啟用 [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) +1. 為使用者、群組或實例啟用 [Duo Agent Platform](https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/) 2. 功能旗標(透過 Rails 控制台): - `agent_platform_claude_code` - `third_party_agents_enabled` @@ -766,7 +766,7 @@ export GITLAB_TOKEN=glpat-... export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ``` -更多文件請參閱 [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth) 首頁。 +更多文件請參閱 [opencode-gitlab-auth](https://www.npmjs.com/package/opencode-gitlab-auth) 首頁。 ##### 設定 @@ -778,11 +778,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here "provider": { "gitlab": { "options": { - "instanceUrl": "https://gitlab.com", - "featureFlags": { - "duo_agent_platform_agentic_chat": true, - "duo_agent_platform": true - } + "instanceUrl": "https://gitlab.com" } } } @@ -796,7 +792,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here ```json title="opencode.json" { "$schema": "https://opencode.ai/config.json", - "plugin": ["@gitlab/opencode-gitlab-plugin"] + "plugin": ["opencode-gitlab-plugin"] } ```