@link-assistant/agent 0.26.14 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/package.json +43 -33
- package/src/agent/agent.ts +12 -7
- package/src/auth/azure-login.ts +241 -0
- package/src/auth/plugins.ts +9 -0
- package/src/auth/provider-logins.ts +804 -0
- package/src/cli/cmd/auth.ts +4 -0
- package/src/cli/cmd/models.ts +68 -13
- package/src/cli/model-config.js +7 -4
- package/src/index.js +3 -0
- package/src/provider/env-template.ts +115 -0
- package/src/provider/extra-providers.ts +347 -0
- package/src/provider/kilo.ts +19 -0
- package/src/provider/model-discovery.ts +690 -0
- package/src/provider/models.ts +11 -1
- package/src/provider/parity-loaders.ts +595 -0
- package/src/provider/provider.ts +257 -182
- package/src/provider/transform.ts +29 -0
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ This is an MVP implementation of an OpenCode-compatible CLI agent, focused on ma
|
|
|
24
24
|
|
|
25
25
|
- ✅ **JSON Input/Output**: Compatible with `opencode run --format json`
|
|
26
26
|
- ✅ **Plain Text Input**: Also accepts plain text messages (auto-converted to JSON format)
|
|
27
|
-
- ✅ **Flexible Model Selection**: Defaults to free Kilo Nemotron 3 Super (Kilo authentication recommended), supports [
|
|
27
|
+
- ✅ **Flexible Model Selection**: Defaults to free Kilo Nemotron 3 Super (Kilo authentication recommended), supports every [models.dev](https://models.dev) provider OpenCode supports ([full list](../docs/providers.md)), OpenCode's subscription logins, [gpt4free](../docs/gpt4free.md), Pollinations, local servers, [Formal AI](../docs/formal-ai.md) and [Claude OAuth](../docs/claude-oauth.md), with [live model discovery](../docs/model-discovery.md)
|
|
28
28
|
- ✅ **No Restrictions**: Fully unrestricted file system and command execution access (no sandbox)
|
|
29
29
|
- ✅ **Minimal Footprint**: Built with Bun.sh for maximum efficiency
|
|
30
30
|
- ✅ **Full Tool Support**: 13 tools including websearch, codesearch, batch - all enabled by default
|
|
@@ -735,7 +735,7 @@ This agent is **exclusively built for Bun** for the following reasons:
|
|
|
735
735
|
4. **Minimalism**: Single runtime target keeps the codebase simple
|
|
736
736
|
5. **Bun Ecosystem**: Leverages Bun-specific features and optimizations
|
|
737
737
|
|
|
738
|
-
**Not supporting Node.js or Deno is intentional** to keep the project focused and minimal. If you need Node.js/Deno compatibility, consider using [OpenCode](https://github.com/
|
|
738
|
+
**Not supporting Node.js or Deno is intentional** to keep the project focused and minimal. If you need Node.js/Deno compatibility, consider using [OpenCode](https://github.com/anomalyco/opencode) instead.
|
|
739
739
|
|
|
740
740
|
## Project Structure
|
|
741
741
|
|
|
@@ -753,7 +753,7 @@ js/
|
|
|
753
753
|
|
|
754
754
|
## Architecture
|
|
755
755
|
|
|
756
|
-
This agent-cli reproduces the core architecture of [OpenCode](https://github.com/
|
|
756
|
+
This agent-cli reproduces the core architecture of [OpenCode](https://github.com/anomalyco/opencode)'s `run --format json` command:
|
|
757
757
|
|
|
758
758
|
- **Streaming JSON Events**: Instead of single responses, outputs real-time event stream
|
|
759
759
|
- **Event Types**: `tool_use`, `text`, `step_start`, `step_finish`, `error`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@link-assistant/agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "A minimal, public domain AI CLI agent compatible with OpenCode's JSON interface. Bun-only runtime.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -51,19 +51,28 @@
|
|
|
51
51
|
"LICENSE"
|
|
52
52
|
],
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@agentclientprotocol/sdk": "^
|
|
55
|
-
"@ai-sdk/
|
|
56
|
-
"@ai-sdk/
|
|
57
|
-
"@ai-sdk/
|
|
58
|
-
"@ai-sdk/
|
|
59
|
-
"@ai-sdk/
|
|
60
|
-
"@ai-sdk/
|
|
61
|
-
"@ai-sdk/
|
|
62
|
-
"@ai-sdk/
|
|
63
|
-
"@ai-sdk/
|
|
64
|
-
"@ai-sdk/
|
|
65
|
-
"@ai-sdk/
|
|
66
|
-
"@ai-sdk/
|
|
54
|
+
"@agentclientprotocol/sdk": "^2.0.1",
|
|
55
|
+
"@ai-sdk/alibaba": "^2.0.74",
|
|
56
|
+
"@ai-sdk/amazon-bedrock": "^5.0.122",
|
|
57
|
+
"@ai-sdk/anthropic": "^4.0.86",
|
|
58
|
+
"@ai-sdk/azure": "^4.0.108",
|
|
59
|
+
"@ai-sdk/cerebras": "^3.0.76",
|
|
60
|
+
"@ai-sdk/cohere": "^4.0.67",
|
|
61
|
+
"@ai-sdk/deepinfra": "^3.0.76",
|
|
62
|
+
"@ai-sdk/deepseek": "^3.0.71",
|
|
63
|
+
"@ai-sdk/fireworks": "^3.0.79",
|
|
64
|
+
"@ai-sdk/gateway": "^4.0.122",
|
|
65
|
+
"@ai-sdk/google": "^4.0.103",
|
|
66
|
+
"@ai-sdk/google-vertex": "^5.0.120",
|
|
67
|
+
"@ai-sdk/groq": "^4.0.68",
|
|
68
|
+
"@ai-sdk/mcp": "^2.0.82",
|
|
69
|
+
"@ai-sdk/mistral": "^4.0.70",
|
|
70
|
+
"@ai-sdk/openai": "^4.0.100",
|
|
71
|
+
"@ai-sdk/openai-compatible": "^3.0.76",
|
|
72
|
+
"@ai-sdk/perplexity": "^5.0.18",
|
|
73
|
+
"@ai-sdk/provider": "^4.0.32",
|
|
74
|
+
"@ai-sdk/togetherai": "^3.0.77",
|
|
75
|
+
"@ai-sdk/xai": "^5.0.28",
|
|
67
76
|
"@clack/prompts": "^1.8.1",
|
|
68
77
|
"@hono/standard-validator": "^0.4.0",
|
|
69
78
|
"@hono/zod-validator": "^0.9.1",
|
|
@@ -71,53 +80,54 @@
|
|
|
71
80
|
"@octokit/graphql": "^9.0.5",
|
|
72
81
|
"@octokit/rest": "^22.0.1",
|
|
73
82
|
"@openauthjs/openauth": "^0.4.3",
|
|
74
|
-
"@opencode-ai/sdk": "^1.19.
|
|
83
|
+
"@opencode-ai/sdk": "^1.19.4",
|
|
75
84
|
"@openrouter/ai-sdk-provider": "^3.1.0",
|
|
76
|
-
"@opentui/core": "0.6.
|
|
77
|
-
"@opentui/solid": "0.6.
|
|
85
|
+
"@opentui/core": "^0.6.6",
|
|
86
|
+
"@opentui/solid": "^0.6.6",
|
|
78
87
|
"@parcel/watcher": "^2.6.0",
|
|
79
88
|
"@solid-primitives/event-bus": "^1.1.4",
|
|
80
|
-
"@standard-community/standard-json": "^0.3.
|
|
81
|
-
"@standard-community/standard-openapi": "^0.2.
|
|
82
|
-
"@zip.js/zip.js": "^2.
|
|
83
|
-
"ai": "^7.0.
|
|
84
|
-
"chokidar": "^
|
|
89
|
+
"@standard-community/standard-json": "^0.3.7",
|
|
90
|
+
"@standard-community/standard-openapi": "^0.2.11",
|
|
91
|
+
"@zip.js/zip.js": "^2.24.0",
|
|
92
|
+
"ai": "^7.0.149",
|
|
93
|
+
"chokidar": "^6.0.0",
|
|
85
94
|
"clipboardy": "^5.3.2",
|
|
86
|
-
"command-stream": "^2.
|
|
95
|
+
"command-stream": "^2.4.0",
|
|
87
96
|
"decimal.js": "^10.6.0",
|
|
88
97
|
"diff": "^9.0.0",
|
|
89
98
|
"fuzzysort": "^4.0.2",
|
|
90
99
|
"glob": "^13.0.6",
|
|
91
|
-
"
|
|
100
|
+
"google-auth-library": "^11.3.1",
|
|
101
|
+
"gpt-tokenizer": "^4.1.0",
|
|
92
102
|
"gray-matter": "^4.0.3",
|
|
93
103
|
"hono": "^4.13.13",
|
|
94
|
-
"hono-openapi": "^1.
|
|
95
|
-
"ignore": "^7.0.
|
|
104
|
+
"hono-openapi": "^1.5.0",
|
|
105
|
+
"ignore": "^7.0.13",
|
|
96
106
|
"jsonc-parser": "^3.3.1",
|
|
97
107
|
"lino-arguments": "^0.3.0",
|
|
98
108
|
"lino-objects-codec": "^0.9.2",
|
|
99
109
|
"log-lazy": "^1.0.4",
|
|
100
110
|
"minimatch": "^10.2.6",
|
|
101
|
-
"remeda": "^2.
|
|
111
|
+
"remeda": "^2.53.0",
|
|
102
112
|
"solid-js": "1.9.12",
|
|
103
113
|
"strip-ansi": "^7.2.0",
|
|
104
114
|
"test-anywhere": "^0.9.1",
|
|
105
115
|
"tree-sitter-bash": "^0.25.1",
|
|
106
116
|
"turndown": "^7.2.4",
|
|
107
117
|
"ulid": "^3.0.2",
|
|
108
|
-
"vscode-jsonrpc": "^
|
|
109
|
-
"vscode-languageserver-types": "^3.18.
|
|
118
|
+
"vscode-jsonrpc": "^10.0.0",
|
|
119
|
+
"vscode-languageserver-types": "^3.18.5",
|
|
110
120
|
"web-tree-sitter": "0.25.10",
|
|
111
121
|
"xdg-basedir": "^5.1.0",
|
|
112
122
|
"yargs": "^18.2.0",
|
|
113
|
-
"zod": "^4.6.
|
|
123
|
+
"zod": "^4.6.7"
|
|
114
124
|
},
|
|
115
125
|
"devDependencies": {
|
|
116
126
|
"@changesets/cli": "^3.0.3",
|
|
117
127
|
"@eslint/js": "^10.0.1",
|
|
118
|
-
"eslint": "^10.
|
|
128
|
+
"eslint": "^10.13.0",
|
|
119
129
|
"eslint-config-prettier": "^10.1.8",
|
|
120
|
-
"eslint-plugin-prettier": "^5.5.
|
|
130
|
+
"eslint-plugin-prettier": "^5.5.7",
|
|
121
131
|
"eslint-plugin-promise": "^7.3.0",
|
|
122
132
|
"husky": "^9.1.7",
|
|
123
133
|
"lint-staged": "^17.6.0",
|
|
@@ -138,7 +148,7 @@
|
|
|
138
148
|
"allowScripts": {
|
|
139
149
|
"@parcel/watcher@2.6.0": true,
|
|
140
150
|
"tree-sitter-bash@0.25.1": true,
|
|
141
|
-
"node-pty@1.
|
|
151
|
+
"node-pty@1.1.0": true
|
|
142
152
|
},
|
|
143
153
|
"overrides": {
|
|
144
154
|
"seroval": "^1.6.9",
|
package/src/agent/agent.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Config } from '../config/file-config';
|
|
2
2
|
import z from 'zod';
|
|
3
3
|
import { Provider } from '../provider/provider';
|
|
4
|
-
import {
|
|
4
|
+
import { generateText, Output } from 'ai';
|
|
5
5
|
import PROMPT_GENERATE from './generate.txt';
|
|
6
6
|
import { SystemPrompt } from '../session/system';
|
|
7
7
|
import { Instance } from '../project/instance';
|
|
@@ -136,7 +136,10 @@ export namespace Agent {
|
|
|
136
136
|
const system = SystemPrompt.header(defaultModel.providerID);
|
|
137
137
|
system.push(PROMPT_GENERATE);
|
|
138
138
|
const existing = await list();
|
|
139
|
-
|
|
139
|
+
// generateObject is deprecated in AI SDK 7 and printed a
|
|
140
|
+
// DeprecationWarning on every call (#337); structured output now goes
|
|
141
|
+
// through generateText's `output` setting.
|
|
142
|
+
const result = await generateText({
|
|
140
143
|
temperature: 0.3,
|
|
141
144
|
// The system prompt belongs in `instructions`, not in `prompt`: the AI SDK
|
|
142
145
|
// warns that a system message inside the prompt enables prompt
|
|
@@ -152,13 +155,15 @@ export namespace Agent {
|
|
|
152
155
|
},
|
|
153
156
|
],
|
|
154
157
|
model: model.language,
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
output: Output.object({
|
|
159
|
+
schema: z.object({
|
|
160
|
+
identifier: z.string(),
|
|
161
|
+
whenToUse: z.string(),
|
|
162
|
+
systemPrompt: z.string(),
|
|
163
|
+
}),
|
|
159
164
|
}),
|
|
160
165
|
});
|
|
161
|
-
return result.
|
|
166
|
+
return result.output;
|
|
162
167
|
}
|
|
163
168
|
}
|
|
164
169
|
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { Auth } from './index';
|
|
2
|
+
import type { AuthPlugin } from './plugins';
|
|
3
|
+
import { Log } from '../util/log';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Microsoft Entra ID login for Azure OpenAI / AI Services through the Azure
|
|
7
|
+
* CLI session, ported from OpenCode's Azure plugin
|
|
8
|
+
* (https://github.com/anomalyco/opencode,
|
|
9
|
+
* packages/core/src/plugin/provider/azure.ts) (#334).
|
|
10
|
+
*
|
|
11
|
+
* Like OpenCode, no token is stored: `agent auth login` remembers the
|
|
12
|
+
* resource name, and every request mints (and caches) a bearer token with
|
|
13
|
+
* `az account get-access-token` for the scope of the target URL.
|
|
14
|
+
*/
|
|
15
|
+
export namespace AzureLogin {
|
|
16
|
+
const log = Log.create({ service: 'azure-login' });
|
|
17
|
+
|
|
18
|
+
export const COGNITIVE_SCOPE = 'https://cognitiveservices.azure.com/.default';
|
|
19
|
+
export const FOUNDRY_SCOPE = 'https://ai.azure.com/.default';
|
|
20
|
+
/** Stored in `refresh` to mark an Azure CLI login. */
|
|
21
|
+
export const CLI_MARKER = 'azure-cli';
|
|
22
|
+
/**
|
|
23
|
+
* `@ai-sdk/azure` insists on an API key; requests replace the resulting
|
|
24
|
+
* `api-key` header with the Entra bearer token.
|
|
25
|
+
*/
|
|
26
|
+
export const PLACEHOLDER_KEY = 'azure-entra-id';
|
|
27
|
+
// A resource name becomes a hostname label, so nothing else is accepted.
|
|
28
|
+
export const RESOURCE_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9-]*$/;
|
|
29
|
+
const REFRESH_MARGIN_MS = 5 * 60_000;
|
|
30
|
+
const TIMEOUT_MS = 10_000;
|
|
31
|
+
|
|
32
|
+
export type Run = (args: string[]) => Promise<string>;
|
|
33
|
+
|
|
34
|
+
/** Run the Azure CLI and return stdout; fails with its stderr. */
|
|
35
|
+
export const runAz: Run = async (args) => {
|
|
36
|
+
const proc = Bun.spawn(['az', ...args], {
|
|
37
|
+
stdin: 'ignore',
|
|
38
|
+
stdout: 'pipe',
|
|
39
|
+
stderr: 'pipe',
|
|
40
|
+
env: process.env,
|
|
41
|
+
});
|
|
42
|
+
const timer = setTimeout(() => proc.kill(), TIMEOUT_MS);
|
|
43
|
+
try {
|
|
44
|
+
const [stdout, stderr, code] = await Promise.all([
|
|
45
|
+
new Response(proc.stdout).text(),
|
|
46
|
+
new Response(proc.stderr).text(),
|
|
47
|
+
proc.exited,
|
|
48
|
+
]);
|
|
49
|
+
if (code !== 0) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`az ${args.slice(0, 2).join(' ')} failed: ${stderr.trim() || `exit ${code}`}`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
return stdout;
|
|
55
|
+
} finally {
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export function parseToken(stdout: string): {
|
|
61
|
+
access: string;
|
|
62
|
+
expires: number;
|
|
63
|
+
} {
|
|
64
|
+
const data = JSON.parse(stdout);
|
|
65
|
+
if (typeof data?.accessToken !== 'string' || !data.accessToken) {
|
|
66
|
+
throw new Error('Azure CLI returned no access token');
|
|
67
|
+
}
|
|
68
|
+
const expires =
|
|
69
|
+
typeof data.expires_on === 'number'
|
|
70
|
+
? data.expires_on * 1000
|
|
71
|
+
: Date.parse(data.expiresOn ?? '');
|
|
72
|
+
if (!Number.isFinite(expires)) {
|
|
73
|
+
throw new Error('Azure CLI returned an invalid token expiration');
|
|
74
|
+
}
|
|
75
|
+
return { access: data.accessToken, expires };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Token getter with a per-scope cache refreshed 5 minutes early. */
|
|
79
|
+
export function tokenSource(
|
|
80
|
+
run: Run = runAz,
|
|
81
|
+
now: () => number = Date.now
|
|
82
|
+
): (scope: string) => Promise<string> {
|
|
83
|
+
const cache = new Map<string, { access: string; expires: number }>();
|
|
84
|
+
const pending = new Map<string, Promise<string>>();
|
|
85
|
+
return (scope) => {
|
|
86
|
+
const cached = cache.get(scope);
|
|
87
|
+
if (cached && cached.expires - now() > REFRESH_MARGIN_MS) {
|
|
88
|
+
return Promise.resolve(cached.access);
|
|
89
|
+
}
|
|
90
|
+
const inflight = pending.get(scope);
|
|
91
|
+
if (inflight) return inflight;
|
|
92
|
+
const request = run([
|
|
93
|
+
'account',
|
|
94
|
+
'get-access-token',
|
|
95
|
+
'--scope',
|
|
96
|
+
scope,
|
|
97
|
+
'--output',
|
|
98
|
+
'json',
|
|
99
|
+
])
|
|
100
|
+
.then((stdout) => {
|
|
101
|
+
const token = parseToken(stdout);
|
|
102
|
+
cache.set(scope, token);
|
|
103
|
+
return token.access;
|
|
104
|
+
})
|
|
105
|
+
.finally(() => pending.delete(scope));
|
|
106
|
+
pending.set(scope, request);
|
|
107
|
+
return request;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Foundry project endpoints use their own audience, like OpenCode. */
|
|
112
|
+
export function scopeFor(url: string): string {
|
|
113
|
+
const target = new URL(url);
|
|
114
|
+
return target.hostname.endsWith('.services.ai.azure.com') &&
|
|
115
|
+
!target.pathname.startsWith('/models')
|
|
116
|
+
? FOUNDRY_SCOPE
|
|
117
|
+
: COGNITIVE_SCOPE;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Swap the `api-key` header for an Entra bearer token. */
|
|
121
|
+
export function entraFetch(
|
|
122
|
+
token: (scope: string) => Promise<string>,
|
|
123
|
+
base: typeof fetch = fetch
|
|
124
|
+
): typeof fetch {
|
|
125
|
+
return (async (input: any, init?: RequestInit) => {
|
|
126
|
+
const url =
|
|
127
|
+
typeof input === 'string'
|
|
128
|
+
? input
|
|
129
|
+
: input instanceof URL
|
|
130
|
+
? input.href
|
|
131
|
+
: input.url;
|
|
132
|
+
const headers = new Headers(
|
|
133
|
+
init?.headers ?? (input instanceof Request ? input.headers : undefined)
|
|
134
|
+
);
|
|
135
|
+
headers.delete('api-key');
|
|
136
|
+
headers.delete('x-api-key');
|
|
137
|
+
headers.set('authorization', `Bearer ${await token(scopeFor(url))}`);
|
|
138
|
+
return base(input, { ...init, headers });
|
|
139
|
+
}) as typeof fetch;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function isCliLogin(info: Auth.Info | undefined): boolean {
|
|
143
|
+
return info?.type === 'oauth' && info.refresh === CLI_MARKER;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* SDK options for a stored Azure CLI login, or undefined if there is none.
|
|
148
|
+
* Used by the `azure` custom loader in provider.ts.
|
|
149
|
+
*/
|
|
150
|
+
export async function options(
|
|
151
|
+
info?: Auth.Info,
|
|
152
|
+
token: (scope: string) => Promise<string> = defaultToken()
|
|
153
|
+
): Promise<Record<string, any> | undefined> {
|
|
154
|
+
if (!isCliLogin(info) || info?.type !== 'oauth') return undefined;
|
|
155
|
+
const resourceName =
|
|
156
|
+
info.enterpriseUrl || process.env['AZURE_RESOURCE_NAME'];
|
|
157
|
+
if (!resourceName || !RESOURCE_PATTERN.test(resourceName)) {
|
|
158
|
+
log.warn(() => ({
|
|
159
|
+
message: 'Azure CLI login has no valid resource name, ignoring it',
|
|
160
|
+
}));
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
resourceName,
|
|
165
|
+
apiKey: PLACEHOLDER_KEY,
|
|
166
|
+
fetch: entraFetch(token),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
let shared: ((scope: string) => Promise<string>) | undefined;
|
|
171
|
+
function defaultToken() {
|
|
172
|
+
return (shared ??= tokenSource());
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function makePlugin(run: Run = runAz): AuthPlugin {
|
|
176
|
+
return {
|
|
177
|
+
provider: 'azure',
|
|
178
|
+
methods: [
|
|
179
|
+
{
|
|
180
|
+
label: 'Microsoft Entra ID (Azure CLI)',
|
|
181
|
+
type: 'oauth',
|
|
182
|
+
prompts: [
|
|
183
|
+
{
|
|
184
|
+
type: 'text',
|
|
185
|
+
key: 'resourceName',
|
|
186
|
+
message: 'Azure OpenAI or AI Services resource name',
|
|
187
|
+
placeholder: process.env['AZURE_RESOURCE_NAME'] || 'my-models',
|
|
188
|
+
validate: (value) =>
|
|
189
|
+
!value && process.env['AZURE_RESOURCE_NAME']
|
|
190
|
+
? undefined
|
|
191
|
+
: RESOURCE_PATTERN.test(value)
|
|
192
|
+
? undefined
|
|
193
|
+
: 'Use letters, digits and hyphens only',
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
async authorize(inputs = {}) {
|
|
197
|
+
const resourceName =
|
|
198
|
+
inputs['resourceName']?.trim() ||
|
|
199
|
+
process.env['AZURE_RESOURCE_NAME']?.trim() ||
|
|
200
|
+
'';
|
|
201
|
+
if (!RESOURCE_PATTERN.test(resourceName)) {
|
|
202
|
+
log.error(() => ({ message: 'invalid Azure resource name' }));
|
|
203
|
+
return { type: 'failed' as const };
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
url: '',
|
|
207
|
+
instructions:
|
|
208
|
+
'Using your Azure CLI session (`az login`) for Microsoft Entra ID.',
|
|
209
|
+
method: 'auto' as const,
|
|
210
|
+
async callback() {
|
|
211
|
+
try {
|
|
212
|
+
// Prove the CLI session works before saving the login.
|
|
213
|
+
await tokenSource(run)(COGNITIVE_SCOPE);
|
|
214
|
+
} catch (error) {
|
|
215
|
+
log.error(() => ({
|
|
216
|
+
message:
|
|
217
|
+
'Azure CLI token request failed; install the Azure CLI and run `az login`',
|
|
218
|
+
error:
|
|
219
|
+
error instanceof Error ? error.message : String(error),
|
|
220
|
+
}));
|
|
221
|
+
return { type: 'failed' as const };
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
type: 'success' as const,
|
|
225
|
+
provider: 'azure',
|
|
226
|
+
refresh: CLI_MARKER,
|
|
227
|
+
access: '',
|
|
228
|
+
expires: 0,
|
|
229
|
+
enterpriseUrl: resourceName,
|
|
230
|
+
};
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
{ label: 'Manually enter API Key', type: 'api' },
|
|
236
|
+
],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export const Plugin = makePlugin();
|
|
241
|
+
}
|
package/src/auth/plugins.ts
CHANGED
|
@@ -4,6 +4,8 @@ import * as net from 'node:net';
|
|
|
4
4
|
import { Auth } from './index';
|
|
5
5
|
import { Log } from '../util/log';
|
|
6
6
|
import { createVerboseFetch } from '../util/verbose-fetch';
|
|
7
|
+
import { ProviderLogins } from './provider-logins';
|
|
8
|
+
import { AzureLogin } from './azure-login';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Auth Plugins Module
|
|
@@ -78,6 +80,8 @@ export interface AuthPlugin {
|
|
|
78
80
|
apiKey?: string;
|
|
79
81
|
baseURL?: string;
|
|
80
82
|
fetch?: typeof fetch;
|
|
83
|
+
/** Extra SDK options, e.g. GitLab's `instanceUrl`. */
|
|
84
|
+
options?: Record<string, any>;
|
|
81
85
|
}>;
|
|
82
86
|
}
|
|
83
87
|
|
|
@@ -2819,6 +2823,11 @@ const plugins: Record<string, AuthPlugin> = {
|
|
|
2819
2823
|
'qwen-coder': QwenPlugin,
|
|
2820
2824
|
alibaba: AlibabaPlugin,
|
|
2821
2825
|
kilo: KiloPlugin,
|
|
2826
|
+
xai: ProviderLogins.XAIPlugin,
|
|
2827
|
+
poe: ProviderLogins.PoePlugin,
|
|
2828
|
+
digitalocean: ProviderLogins.DigitalOceanPlugin,
|
|
2829
|
+
gitlab: ProviderLogins.GitLabPlugin,
|
|
2830
|
+
azure: AzureLogin.Plugin,
|
|
2822
2831
|
};
|
|
2823
2832
|
|
|
2824
2833
|
/**
|