diff --git a/docs/src/content/docs/getting-started/configuration.mdx b/docs/src/content/docs/getting-started/configuration.mdx index d3d5ab90d1..e8aa0c3744 100644 --- a/docs/src/content/docs/getting-started/configuration.mdx +++ b/docs/src/content/docs/getting-started/configuration.mdx @@ -214,7 +214,7 @@ for GitHub Models, you can use the `GITHUB_MODELS_TOKEN` variable instead. ## Azure OpenAI The [Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#chat-completions) provider, `azure` uses the `AZURE_OPENAI_...` environment variables. -You can use a managed identity (recommended) or a API key to authenticate with the Azure OpenAI service. +You can use a managed identity (recommended) or a API key to authenticate with the Azure OpenAI service. You can also use a service principal as documented in [automation](/genaiscript/getting-started/automating-scripts). ### Managed Identity (Entra ID) @@ -262,6 +262,16 @@ Navigate to **deployments** and make sure that you have your LLM deployed and co
  • +Open a terminal and **login** with [Azure CLI](https://learn.microsoft.com/en-us/javascript/api/overview/azure/identity-readme?view=azure-node-latest#authenticate-via-the-azure-cli). + +```sh +az login +``` + +
  • + +
  • + Update the `model` field in the `script` function to match the model deployment name in your Azure resource. ```js 'model: "azure:deployment-id"' @@ -273,30 +283,10 @@ script({
  • -
  • - -Open a terminal and login to Azure. See Visual Studio or CLI instructions below. - -
  • - -#### Visual Studio Code - -Visual Studio Code will ask you to allow using the **Microsoft** account -and then will open a browser where you can choose the user or service principal. - -#### CLI - -Login with [Azure CLI](https://learn.microsoft.com/en-us/javascript/api/overview/azure/identity-readme?view=azure-node-latest#authenticate-via-the-azure-cli) -then use the [cli](/genaiscript/reference/cli) as usual. - -```sh -az login -``` - ### API Key diff --git a/packages/cli/src/nodehost.ts b/packages/cli/src/nodehost.ts index 15899a1095..ff9acb3f22 100644 --- a/packages/cli/src/nodehost.ts +++ b/packages/cli/src/nodehost.ts @@ -175,6 +175,11 @@ export class NodeHost implements RuntimeHost { if (!this._azureToken) throw new Error("Azure token not available") tok.token = "Bearer " + this._azureToken.token } + if (!tok) { + const { provider } = parseModelIdentifier(modelId) + if (provider === MODEL_PROVIDER_AZURE) + throw new Error("Azure end point not configured") + } if (!tok && this.clientLanguageModel) { return { model: modelId, diff --git a/packages/core/src/connection.ts b/packages/core/src/connection.ts index ad59bb6884..82878493b0 100644 --- a/packages/core/src/connection.ts +++ b/packages/core/src/connection.ts @@ -361,22 +361,4 @@ export async function updateConnectionConfiguration( if (!content.includes(DOT_ENV_FILENAME)) await writeText(".gitignore", content + `\n${DOT_ENV_FILENAME}\n`) } - - // update .env - const { config, model } = dotEnvTemplate(provider, apiType) - let src = config - const current = await tryReadText(DOT_ENV_FILENAME) - if (current) { - if (!current.includes("GENAISCRIPT_DEFAULT_MODEL")) - src = - dedent` - - ## GenAIScript defaults - GENAISCRIPT_DEFAULT_MODEL="${model}" - # GENAISCRIPT_DEFAULT_TEMPERATURE=${DEFAULT_TEMPERATURE} - - ` + src - src = current + "\n" + src - } - await writeText(DOT_ENV_FILENAME, src) } diff --git a/packages/vscode/src/azuremanager.ts b/packages/vscode/src/azuremanager.ts deleted file mode 100644 index 693dccb104..0000000000 --- a/packages/vscode/src/azuremanager.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { AZURE_OPENAI_TOKEN_SCOPES } from "../../core/src/constants" -import { errorMessage } from "../../core/src/error" -import { ExtensionState } from "./state" -import * as vscode from "vscode" - -export class AzureManager { - private _session: vscode.AuthenticationSession - - constructor(readonly state: ExtensionState) { - const { context } = state - const { subscriptions } = context - subscriptions.push( - vscode.authentication.onDidChangeSessions((e) => { - if (e.provider.id === "microsoft") this._session = undefined - }) - ) - } - - async getOpenAIToken() { - if (this._session) return this._session.accessToken - - try { - const session = await vscode.authentication.getSession( - "microsoft", - AZURE_OPENAI_TOKEN_SCOPES, - { - createIfNone: false, - silent: true, - } - ) - this._session = session - return this._session.accessToken - } catch {} - - try { - // get new session - const session = await vscode.authentication.getSession( - "microsoft", - AZURE_OPENAI_TOKEN_SCOPES, - { - forceNewSession: true, - clearSessionPreference: true, - } - ) - this._session = session - return this._session.accessToken - } catch (e) { - const msg = errorMessage(e) - vscode.window.showErrorMessage(msg) - throw e - } - } -} diff --git a/packages/vscode/src/extension.ts b/packages/vscode/src/extension.ts index 861e07356d..d6714a6533 100644 --- a/packages/vscode/src/extension.ts +++ b/packages/vscode/src/extension.ts @@ -12,12 +12,17 @@ import { activateTestController } from "./testcontroller" import { activateDocsNotebook } from "./docsnotebook" import { activateTraceTreeDataProvider } from "./tracetree" import { registerCommand } from "./commands" -import { EXTENSION_ID, TOOL_NAME } from "../../core/src/constants" +import { + DOCS_CONFIGURATION_URL, + EXTENSION_ID, + TOOL_NAME, +} from "../../core/src/constants" import type MarkdownIt from "markdown-it" import MarkdownItGitHubAlerts from "markdown-it-github-alerts" import { activateConnectionInfoTree } from "./connectioninfotree" import { updateConnectionConfiguration } from "../../core/src/connection" import { APIType } from "../../core/src/host" +import { openUrlInTab } from "./browser" export async function activate(context: ExtensionContext) { const state = new ExtensionState(context) @@ -37,10 +42,9 @@ export async function activate(context: ExtensionContext) { "genaiscript.connection.configure", async (provider?: string, apiType?: APIType) => { await updateConnectionConfiguration(provider, apiType) - const doc = await vscode.workspace.openTextDocument( - state.host.toUri("./.env") + await vscode.env.openExternal( + vscode.Uri.parse(DOCS_CONFIGURATION_URL) ) - await vscode.window.showTextDocument(doc) } ), registerCommand("genaiscript.request.abort", async () => { diff --git a/packages/vscode/src/lmaccess.ts b/packages/vscode/src/lmaccess.ts index 8b2a0abef9..464189eba6 100644 --- a/packages/vscode/src/lmaccess.ts +++ b/packages/vscode/src/lmaccess.ts @@ -10,6 +10,7 @@ import { MODEL_PROVIDER_OPENAI, MODEL_PROVIDER_CLIENT, MODEL_PROVIDER_GITHUB, + TOOL_NAME, } from "../../core/src/constants" import { APIType } from "../../core/src/host" import { parseModelIdentifier } from "../../core/src/models" @@ -143,11 +144,18 @@ export async function pickLanguageModel( if (res.model) return res.model else { - await vscode.commands.executeCommand( - "genaiscript.connection.configure", - res.provider, - res.apiType - ) + const configure = "Configure..." + vscode.window + .showWarningMessage( + `${TOOL_NAME} - model connection not configured.`, + configure + ) + .then((res) => { + if (res === configure) + vscode.commands.executeCommand( + "genaiscript.connection.configure" + ) + }) return undefined } } diff --git a/packages/vscode/src/vshost.ts b/packages/vscode/src/vshost.ts index ff7fa3ddd1..4bb5510f52 100644 --- a/packages/vscode/src/vshost.ts +++ b/packages/vscode/src/vshost.ts @@ -1,22 +1,17 @@ import * as vscode from "vscode" import { createVSPath } from "./vspath" import { TerminalServerManager } from "./servermanager" -import { AzureManager } from "./azuremanager" import { Uri } from "vscode" import { ExtensionState } from "./state" import { Utils } from "vscode-uri" import { checkFileExists, readFileText } from "./fs" import { filterGitIgnore } from "../../core/src/gitignore" -import { - parseDefaultsFromEnv, - parseTokenFromEnv, -} from "../../core/src/connection" +import { parseDefaultsFromEnv } from "../../core/src/connection" import { DEFAULT_EMBEDDINGS_MODEL, DEFAULT_MODEL, DEFAULT_TEMPERATURE, DOT_ENV_FILENAME, - MODEL_PROVIDER_AZURE, } from "../../core/src/constants" import { dotEnvTryParse } from "../../core/src/dotenv" import { @@ -26,7 +21,7 @@ import { Host, } from "../../core/src/host" import { TraceOptions, AbortSignalOptions } from "../../core/src/trace" -import { arrayify, logVerbose, unique } from "../../core/src/util" +import { arrayify, unique } from "../../core/src/util" import { LanguageModel } from "../../core/src/chat" export class VSCodeHost extends EventTarget implements Host { @@ -34,7 +29,6 @@ export class VSCodeHost extends EventTarget implements Host { userState: any = {} readonly path = createVSPath() readonly server: TerminalServerManager - private _azure: AzureManager readonly defaultModelOptions = { model: DEFAULT_MODEL, temperature: DEFAULT_TEMPERATURE, @@ -56,11 +50,6 @@ export class VSCodeHost extends EventTarget implements Host { await parseDefaultsFromEnv(env) } - get azure() { - if (!this._azure) this._azure = new AzureManager(this.state) - return this._azure - } - get context() { return this.state.context } @@ -198,20 +187,6 @@ export class VSCodeHost extends EventTarget implements Host { modelId, options ) - const { token: askToken } = options || {} - if ( - askToken && - tok && - !tok.token && - tok.provider === MODEL_PROVIDER_AZURE - ) { - const azureToken = await this.azure.getOpenAIToken() - if (!azureToken) throw new Error("Azure token not available") - tok.token = "Bearer " + azureToken - tok.curlHeaders = { - Authorization: "Bearer ***", - } - } return tok }