mirror of
https://github.com/anomalyco/opencode.git
synced 2026-02-22 08:44:32 +00:00
Compare commits
4 Commits
composer
...
add-api-sh
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6a49ed85c | ||
|
|
77cdfcdb64 | ||
|
|
950df3de19 | ||
|
|
1d9f05e4f5 |
@@ -5,8 +5,16 @@ import DESCRIPTION from "./github-triage.txt"
|
||||
const TEAM = {
|
||||
desktop: ["adamdotdevin", "iamdavidhill", "Brendonovich", "nexxeln"],
|
||||
zen: ["fwang", "MrMushrooooom"],
|
||||
tui: ["thdxr", "kommander", "rekram1-node"],
|
||||
core: ["thdxr", "rekram1-node", "jlongster"],
|
||||
tui: [
|
||||
"thdxr",
|
||||
"kommander",
|
||||
// "rekram1-node" (on vacation)
|
||||
],
|
||||
core: [
|
||||
"thdxr",
|
||||
// "rekram1-node", (on vacation)
|
||||
"jlongster",
|
||||
],
|
||||
docs: ["R44VC0RP"],
|
||||
windows: ["Hona"],
|
||||
} as const
|
||||
@@ -42,10 +50,7 @@ async function githubFetch(endpoint: string, options: RequestInit = {}) {
|
||||
export default tool({
|
||||
description: DESCRIPTION,
|
||||
args: {
|
||||
assignee: tool.schema
|
||||
.enum(ASSIGNEES as [string, ...string[]])
|
||||
.describe("The username of the assignee")
|
||||
.default("rekram1-node"),
|
||||
assignee: tool.schema.enum(ASSIGNEES as [string, ...string[]]).describe("The username of the assignee"),
|
||||
labels: tool.schema
|
||||
.array(tool.schema.enum(["nix", "opentui", "perf", "web", "desktop", "zen", "docs", "windows", "core"]))
|
||||
.describe("The labels(s) to add to the issue")
|
||||
@@ -68,7 +73,8 @@ export default tool({
|
||||
results.push("Dropped label: nix (issue does not mention nix)")
|
||||
}
|
||||
|
||||
const assignee = nix ? "rekram1-node" : web ? pick(TEAM.desktop) : args.assignee
|
||||
// const assignee = nix ? "rekram1-node" : web ? pick(TEAM.desktop) : args.assignee
|
||||
const assignee = web ? pick(TEAM.desktop) : args.assignee
|
||||
|
||||
if (labels.includes("zen") && !zen) {
|
||||
throw new Error("Only add the zen label when issue title/body contains 'zen'")
|
||||
|
||||
@@ -4,3 +4,5 @@ Choose labels and assignee using the current triage policy and ownership rules.
|
||||
Pick the most fitting labels for the issue and assign one owner.
|
||||
|
||||
If unsure, choose the team/section with the most overlap with the issue and assign a member from that team at random.
|
||||
|
||||
(Note: rekram1-node is on vacation, do not assign issues to him.)
|
||||
|
||||
@@ -25,6 +25,12 @@ if (envPath) {
|
||||
const scriptPath = fs.realpathSync(__filename)
|
||||
const scriptDir = path.dirname(scriptPath)
|
||||
|
||||
//
|
||||
const cached = path.join(scriptDir, ".opencode")
|
||||
if (fs.existsSync(cached)) {
|
||||
run(cached)
|
||||
}
|
||||
|
||||
const platformMap = {
|
||||
darwin: "darwin",
|
||||
linux: "linux",
|
||||
|
||||
@@ -109,8 +109,14 @@ async function main() {
|
||||
// On non-Windows platforms, just verify the binary package exists
|
||||
// Don't replace the wrapper script - it handles binary execution
|
||||
const { binaryPath } = findBinary()
|
||||
console.log(`Platform binary verified at: ${binaryPath}`)
|
||||
console.log("Wrapper script will handle binary execution")
|
||||
const target = path.join(__dirname, "bin", ".opencode")
|
||||
if (fs.existsSync(target)) fs.unlinkSync(target)
|
||||
try {
|
||||
fs.linkSync(binaryPath, target)
|
||||
} catch {
|
||||
fs.copyFileSync(binaryPath, target)
|
||||
}
|
||||
fs.chmodSync(target, 0o755)
|
||||
} catch (error) {
|
||||
console.error("Failed to setup opencode binary:", error.message)
|
||||
process.exit(1)
|
||||
|
||||
@@ -65,7 +65,13 @@ export namespace ModelsDev {
|
||||
status: z.enum(["alpha", "beta", "deprecated"]).optional(),
|
||||
options: z.record(z.string(), z.any()),
|
||||
headers: z.record(z.string(), z.string()).optional(),
|
||||
provider: z.object({ npm: z.string().optional(), api: z.string().optional() }).optional(),
|
||||
provider: z
|
||||
.object({
|
||||
npm: z.string().optional(),
|
||||
api: z.string().optional(),
|
||||
shape: z.enum(["responses", "completions"]).optional(),
|
||||
})
|
||||
.optional(),
|
||||
variants: z.record(z.string(), z.record(z.string(), z.any())).optional(),
|
||||
})
|
||||
export type Model = z.infer<typeof Model>
|
||||
|
||||
@@ -109,7 +109,7 @@ export namespace Provider {
|
||||
"@ai-sdk/github-copilot": createGitHubCopilotOpenAICompatible,
|
||||
}
|
||||
|
||||
type CustomModelLoader = (sdk: any, modelID: string, options?: Record<string, any>) => Promise<any>
|
||||
type CustomModelLoader = (sdk: any, model: Model, options?: Record<string, any>) => Promise<any>
|
||||
type CustomLoader = (provider: Info) => Promise<{
|
||||
autoload: boolean
|
||||
getModel?: CustomModelLoader
|
||||
@@ -153,8 +153,9 @@ export namespace Provider {
|
||||
openai: async () => {
|
||||
return {
|
||||
autoload: false,
|
||||
async getModel(sdk: any, modelID: string, _options?: Record<string, any>) {
|
||||
return sdk.responses(modelID)
|
||||
async getModel(sdk: any, model: Model, _options?: Record<string, any>) {
|
||||
if (model.api.shape === "completions") return sdk.chat(model.api.id)
|
||||
return sdk.responses(model.api.id)
|
||||
},
|
||||
options: {},
|
||||
}
|
||||
@@ -162,9 +163,12 @@ export namespace Provider {
|
||||
"github-copilot": async () => {
|
||||
return {
|
||||
autoload: false,
|
||||
async getModel(sdk: any, modelID: string, _options?: Record<string, any>) {
|
||||
if (sdk.responses === undefined && sdk.chat === undefined) return sdk.languageModel(modelID)
|
||||
return shouldUseCopilotResponsesApi(modelID) ? sdk.responses(modelID) : sdk.chat(modelID)
|
||||
async getModel(sdk: any, model: Model, _options?: Record<string, any>) {
|
||||
const shape = model.api.shape
|
||||
if (sdk.responses === undefined && sdk.chat === undefined) return sdk.languageModel(model.api.id)
|
||||
if (shape === "responses") return sdk.responses(model.api.id)
|
||||
if (shape === "completions") return sdk.chat(model.api.id)
|
||||
return shouldUseCopilotResponsesApi(model.api.id) ? sdk.responses(model.api.id) : sdk.chat(model.api.id)
|
||||
},
|
||||
options: {},
|
||||
}
|
||||
@@ -172,9 +176,12 @@ export namespace Provider {
|
||||
"github-copilot-enterprise": async () => {
|
||||
return {
|
||||
autoload: false,
|
||||
async getModel(sdk: any, modelID: string, _options?: Record<string, any>) {
|
||||
if (sdk.responses === undefined && sdk.chat === undefined) return sdk.languageModel(modelID)
|
||||
return shouldUseCopilotResponsesApi(modelID) ? sdk.responses(modelID) : sdk.chat(modelID)
|
||||
async getModel(sdk: any, model: Model, _options?: Record<string, any>) {
|
||||
const shape = model.api.shape
|
||||
if (sdk.responses === undefined && sdk.chat === undefined) return sdk.languageModel(model.api.id)
|
||||
if (shape === "responses") return sdk.responses(model.api.id)
|
||||
if (shape === "completions") return sdk.chat(model.api.id)
|
||||
return shouldUseCopilotResponsesApi(model.api.id) ? sdk.responses(model.api.id) : sdk.chat(model.api.id)
|
||||
},
|
||||
options: {},
|
||||
}
|
||||
@@ -182,12 +189,12 @@ export namespace Provider {
|
||||
azure: async () => {
|
||||
return {
|
||||
autoload: false,
|
||||
async getModel(sdk: any, modelID: string, options?: Record<string, any>) {
|
||||
if (options?.["useCompletionUrls"]) {
|
||||
return sdk.chat(modelID)
|
||||
} else {
|
||||
return sdk.responses(modelID)
|
||||
}
|
||||
async getModel(sdk: any, model: Model, options?: Record<string, any>) {
|
||||
if (sdk.responses === undefined || sdk.chat === undefined) return sdk.languageModel(model.api.id)
|
||||
if (model.api.shape === "completions") return sdk.chat(model.api.id)
|
||||
if (model.api.shape === "responses") return sdk.responses(model.api.id)
|
||||
if (options?.["useCompletionUrls"]) return sdk.chat(model.api.id)
|
||||
return sdk.responses(model.api.id)
|
||||
},
|
||||
options: {},
|
||||
}
|
||||
@@ -196,12 +203,12 @@ export namespace Provider {
|
||||
const resourceName = Env.get("AZURE_COGNITIVE_SERVICES_RESOURCE_NAME")
|
||||
return {
|
||||
autoload: false,
|
||||
async getModel(sdk: any, modelID: string, options?: Record<string, any>) {
|
||||
if (options?.["useCompletionUrls"]) {
|
||||
return sdk.chat(modelID)
|
||||
} else {
|
||||
return sdk.responses(modelID)
|
||||
}
|
||||
async getModel(sdk: any, model: Model, options?: Record<string, any>) {
|
||||
if (sdk.responses === undefined || sdk.chat === undefined) return sdk.languageModel(model.api.id)
|
||||
if (model.api.shape === "completions") return sdk.chat(model.api.id)
|
||||
if (model.api.shape === "responses") return sdk.responses(model.api.id)
|
||||
if (options?.["useCompletionUrls"]) return sdk.chat(model.api.id)
|
||||
return sdk.responses(model.api.id)
|
||||
},
|
||||
options: {
|
||||
baseURL: resourceName ? `https://${resourceName}.cognitiveservices.azure.com/openai` : undefined,
|
||||
@@ -269,7 +276,8 @@ export namespace Provider {
|
||||
return {
|
||||
autoload: true,
|
||||
options: providerOptions,
|
||||
async getModel(sdk: any, modelID: string, options?: Record<string, any>) {
|
||||
async getModel(sdk: any, model: Model, options?: Record<string, any>) {
|
||||
let modelID = model.api.id
|
||||
// Skip region prefixing if model already has a cross-region inference profile prefix
|
||||
// Models from models.dev may already include prefixes like us., eu., global., etc.
|
||||
const crossRegionPrefixes = ["global.", "us.", "eu.", "jp.", "apac.", "au."]
|
||||
@@ -406,8 +414,8 @@ export namespace Provider {
|
||||
return fetch(input, { ...init, headers })
|
||||
},
|
||||
},
|
||||
async getModel(sdk: any, modelID: string) {
|
||||
const id = String(modelID).trim()
|
||||
async getModel(sdk: any, model: Model) {
|
||||
const id = String(model.api.id).trim()
|
||||
return sdk.languageModel(id)
|
||||
},
|
||||
}
|
||||
@@ -423,8 +431,8 @@ export namespace Provider {
|
||||
project,
|
||||
location,
|
||||
},
|
||||
async getModel(sdk: any, modelID) {
|
||||
const id = String(modelID).trim()
|
||||
async getModel(sdk: any, model: Model) {
|
||||
const id = String(model.api.id).trim()
|
||||
return sdk.languageModel(id)
|
||||
},
|
||||
}
|
||||
@@ -448,8 +456,8 @@ export namespace Provider {
|
||||
return {
|
||||
autoload: !!envServiceKey,
|
||||
options: envServiceKey ? { deploymentId, resourceGroup } : {},
|
||||
async getModel(sdk: any, modelID: string) {
|
||||
return sdk(modelID)
|
||||
async getModel(sdk: any, model: Model) {
|
||||
return sdk(model.api.id)
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -494,8 +502,8 @@ export namespace Provider {
|
||||
...(providerConfig?.options?.featureFlags || {}),
|
||||
},
|
||||
},
|
||||
async getModel(sdk: ReturnType<typeof createGitLab>, modelID: string) {
|
||||
return sdk.agenticChat(modelID, {
|
||||
async getModel(sdk: ReturnType<typeof createGitLab>, model: Model) {
|
||||
return sdk.agenticChat(model.api.id, {
|
||||
aiGatewayHeaders,
|
||||
featureFlags: {
|
||||
duo_agent_platform_agentic_chat: true,
|
||||
@@ -524,8 +532,8 @@ export namespace Provider {
|
||||
apiKey,
|
||||
baseURL: `https://api.cloudflare.com/client/v4/accounts/${accountId}/ai/v1`,
|
||||
},
|
||||
async getModel(sdk: any, modelID: string) {
|
||||
return sdk.languageModel(modelID)
|
||||
async getModel(sdk: any, model: Model) {
|
||||
return sdk.languageModel(model.api.id)
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -560,9 +568,9 @@ export namespace Provider {
|
||||
|
||||
return {
|
||||
autoload: true,
|
||||
async getModel(_sdk: any, modelID: string, _options?: Record<string, any>) {
|
||||
async getModel(_sdk: any, model: Model, _options?: Record<string, any>) {
|
||||
// Model IDs use Unified API format: provider/model (e.g., "anthropic/claude-sonnet-4-5")
|
||||
return aigateway(unified(modelID))
|
||||
return aigateway(unified(model.api.id))
|
||||
},
|
||||
options: {},
|
||||
}
|
||||
@@ -598,6 +606,7 @@ export namespace Provider {
|
||||
id: z.string(),
|
||||
url: z.string(),
|
||||
npm: z.string(),
|
||||
shape: z.enum(["responses", "completions"]).optional(),
|
||||
}),
|
||||
name: z.string(),
|
||||
family: z.string().optional(),
|
||||
@@ -686,6 +695,7 @@ export namespace Provider {
|
||||
id: model.id,
|
||||
url: model.provider?.api ?? provider.api!,
|
||||
npm: model.provider?.npm ?? provider.npm ?? "@ai-sdk/openai-compatible",
|
||||
shape: model.provider?.shape,
|
||||
},
|
||||
status: model.status ?? "active",
|
||||
headers: model.headers ?? {},
|
||||
@@ -836,6 +846,7 @@ export namespace Provider {
|
||||
existingModel?.api.npm ??
|
||||
modelsDev[providerID]?.npm ??
|
||||
"@ai-sdk/openai-compatible",
|
||||
shape: model.provider?.shape ?? existingModel?.api.shape,
|
||||
url: model.provider?.api ?? provider?.api ?? existingModel?.api.url ?? modelsDev[providerID]?.api,
|
||||
},
|
||||
status: model.status ?? existingModel?.status ?? "active",
|
||||
@@ -1177,7 +1188,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, provider.options)
|
||||
: sdk.languageModel(model.api.id)
|
||||
s.models.set(key, language)
|
||||
return language
|
||||
|
||||
Reference in New Issue
Block a user