diff --git a/action.yml b/action.yml index 83cf3d3..0973463 100644 --- a/action.yml +++ b/action.yml @@ -1,23 +1,23 @@ -name: The name of your action here -description: Provide a description here -author: Your name or organization here +name: 'AI Inference' +description: Generate an AI response based on a provided prompt +author: 'GitHub' # Add your action's branding here. This will appear on the GitHub Marketplace. branding: - icon: heart + icon: 'play-circle' color: red # Define your inputs here. inputs: - milliseconds: + prompt: description: Your input description here required: true - default: '1000' + default: '' # Define your outputs here. outputs: - time: - description: Your output description here + response: + description: The response from the model runs: using: node20 diff --git a/package-lock.json b/package-lock.json index 37b52bd..1b8eedb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,9 @@ "@actions/core": "^1.11.1" }, "devDependencies": { + "@azure-rest/ai-inference": "latest", + "@azure/core-auth": "latest", + "@azure/core-sse": "latest", "@eslint/compat": "^1.2.7", "@github/local-action": "^3.1.3", "@jest/globals": "^29.7.0", @@ -420,6 +423,44 @@ "node": ">=6.0.0" } }, + "node_modules/@azure-rest/ai-inference": { + "version": "1.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@azure-rest/ai-inference/-/ai-inference-1.0.0-beta.6.tgz", + "integrity": "sha512-j5FrJDTHu2P2+zwFVe5j2edasOIhqkFj+VkDjbhGkQuOoIAByF0egRkgs0G1k03HyJ7bOOT9BkRF7MIgr/afhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure-rest/core-client": "^2.1.0", + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.9.0", + "@azure/core-lro": "^2.7.2", + "@azure/core-rest-pipeline": "^1.18.2", + "@azure/core-tracing": "^1.2.0", + "@azure/logger": "^1.1.4", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure-rest/core-client": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@azure-rest/core-client/-/core-client-2.3.4.tgz", + "integrity": "sha512-AQXtD5VqsoOswDmxQR0YyVkYa1tZ0HyfC/fsqfntYZ7EEgaimfCGN2nAfiN3KXy1F4TfcoByhmtX2bVOO2vAEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-rest-pipeline": "^1.5.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@azure/abort-controller": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", @@ -524,6 +565,19 @@ "node": ">=18.0.0" } }, + "node_modules/@azure/core-sse": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@azure/core-sse/-/core-sse-2.1.3.tgz", + "integrity": "sha512-KSSdIKy8kvWCpYr8Hzpu22j3wcXsVTYE0IlgmI1T/aHvBDsLgV91y90UTfVWnuiuApRLCCVC4gS09ApBGOmYQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@azure/core-tracing": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.2.0.tgz", diff --git a/package.json b/package.json index 303fe4b..03687d9 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,9 @@ "@actions/core": "^1.11.1" }, "devDependencies": { + "@azure-rest/ai-inference": "latest", + "@azure/core-auth": "latest", + "@azure/core-sse": "latest", "@eslint/compat": "^1.2.7", "@github/local-action": "^3.1.3", "@jest/globals": "^29.7.0", diff --git a/src/main.ts b/src/main.ts index d0ee6d3..430d40e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,6 @@ import * as core from '@actions/core' -import { wait } from './wait.js' +import ModelClient, { isUnexpected } from '@azure-rest/ai-inference' +import { AzureKeyCredential } from '@azure/core-auth' /** * The main function for the action. @@ -8,18 +9,43 @@ import { wait } from './wait.js' */ export async function run(): Promise { try { - const ms: string = core.getInput('milliseconds') + const prompt: string = core.getInput('prompt') + const systemPrompt: string = core.getInput('system_prompt') + const modelName = core.getInput('model_name') || 'gpt-4o' - // Debug logs are only output if the `ACTIONS_STEP_DEBUG` secret is true - core.debug(`Waiting ${ms} milliseconds ...`) + const token = process.env['GITHUB_TOKEN'] + if (token === undefined) { + throw new Error('GITHUB_TOKEN is not set') + } + const endpoint = 'https://models.inference.ai.azure.com' - // Log the current timestamp, wait, then log the new timestamp - core.debug(new Date().toTimeString()) - await wait(parseInt(ms, 10)) - core.debug(new Date().toTimeString()) + const client = ModelClient(endpoint, new AzureKeyCredential(token)) + + const response = await client.path('/chat/completions').post({ + body: { + messages: [ + { + role: 'system', + content: systemPrompt || 'You are a helpful assistant.' + }, + { role: 'user', content: prompt } + ], + temperature: 1.0, + top_p: 1.0, + max_tokens: 1000, + model: modelName + } + }) + + if (isUnexpected(response)) { + throw response.body.error + } + + const modelResponse: string | null = + response.body.choices[0].message.content // Set outputs for other workflow steps to use - core.setOutput('time', new Date().toTimeString()) + core.setOutput('response', modelResponse || '') } catch (error) { // Fail the workflow run if an error occurs if (error instanceof Error) core.setFailed(error.message) diff --git a/src/wait.ts b/src/wait.ts deleted file mode 100644 index c79f721..0000000 --- a/src/wait.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Waits for a number of milliseconds. - * - * @param milliseconds The number of milliseconds to wait. - * @returns Resolves with 'done!' after the wait is over. - */ -export async function wait(milliseconds: number): Promise { - return new Promise((resolve) => { - if (isNaN(milliseconds)) throw new Error('milliseconds is not a number') - - setTimeout(() => resolve('done!'), milliseconds) - }) -}