Skip to content

Commit

Permalink
Merge branch 'main' into 9-cache
Browse files Browse the repository at this point in the history
  • Loading branch information
gr2m authored Sep 18, 2024
2 parents 861f2e3 + 38e210f commit 2cca2a9
Show file tree
Hide file tree
Showing 14 changed files with 439 additions and 57 deletions.
10 changes: 10 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!--
This pull request template provides suggested sections for framing your work.
You're welcome to change or remove headers if it doesn't fit your use case. :)
-->

### What are you trying to accomplish?

### What approach did you choose and why?

### What should reviewers focus on?
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
coverage
examples/**/package-lock.json
node_modules
11 changes: 11 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Security Policy

## Supported Versions

Important security fixes will be back-ported to at least the two most recent versions.

## Reporting a Vulnerability

This repository uses GitHub's [private vulnerability reporting](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability) feature.

You can submit a vulnerability report at https://github.com/copilot-extensions/preview-sdk.js/security/advisories/new.
27 changes: 27 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Examples

This folder contains examples to show how you can use the Copilot Agent SDK in your own projects.

If you find any issues or have any questions, please let us know by opening an issue, pull requests welcome (please read the [contribution guidelines](../CONTRIBUTING.md) first).

## Running the examples

These examples are setup so that you can run them inside a GitHub Codespace. To do so, follow these steps:

1. Open the GitHub Codespace by clicking the "Code" button in the top right of the repository and selecting "Open with Codespaces".
2. Once the Codespace is open, you can run the examples by running the following command in the terminal:

```sh
# go to the correct folder
cd examples/<example-name>
# install dependencies
npm install
# run the example
npm run start
```

> [!IMPORTANT]
> By default, the examples will run on port 3000 and ports in Codespaces are private by default. If you want to access the examples from your browser, you'll need to make the port public. To do so, click on the "Ports" tab in the Codespace and right click, Go to "Port Visibility" next to port 3000 and set it to `public`. Do be aware that this will make the port accessible to anyone with the link to your Codespace. The port visibility setting is not saved when the Codespace is stopped, so you'll need to set it again if you restart the Codespace or node. The url does stay the same as long as the Codespace is not deleted.
> [!TIP]
> Don't forget to set the Codespace url (with the port) in your GitHub App that you are using. The Copilot backend needs to be able to reach your Codespace to send messages to your extension. If your app is not running, the port is not public, or the codespace is stopped, the extension will not work.
26 changes: 26 additions & 0 deletions examples/hello-world-without-sdk/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { createServer } from "node:http";

const server = createServer((request, response) => {
if (request.method === "GET") {
return response.end("ok");
}

const textObject = {
choices: [
{ index: 0, delta: { content: "Hello, world!", role: "assistant" } },
],
};

const endObject = {
choices: [{ index: 0, finish_reason: "stop", delta: { content: null } }],
};

// note the "\n\n"s, they are significant.
response.write(`data: ${JSON.stringify(textObject)}\n\n`);
response.end(`data: ${JSON.stringify(endObject)}\n\ndata: [DONE]\n\n`);
});

const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
11 changes: 11 additions & 0 deletions examples/hello-world-without-sdk/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"private": true,
"type": "module",
"scripts": {
"start": "node index.js",
"watch": "node --watch index.js"
},
"dependencies": {
"@copilot-extensions/preview-sdk": "../../"
}
}
22 changes: 22 additions & 0 deletions examples/hello-world/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { createServer } from "node:http";

import {
createTextEvent,
createDoneEvent,
} from "@copilot-extensions/preview-sdk";

const server = createServer((request, response) => {
console.log(`Received [${request.method}] to [${request.url}]`);

if (request.method === "GET") {
return response.end("ok");
}

response.write(createTextEvent("Hello, world!"));
response.end(createDoneEvent());
});

const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
11 changes: 11 additions & 0 deletions examples/hello-world/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"private": true,
"type": "module",
"scripts": {
"start": "node index.js",
"watch": "node --watch index.js"
},
"dependencies": {
"@copilot-extensions/preview-sdk": "../../"
}
}
108 changes: 108 additions & 0 deletions examples/prompt/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { createServer } from "node:http";
import { Octokit } from "octokit";
import {
createAckEvent,
createDoneEvent,
prompt,
verifyAndParseRequest,
} from "@copilot-extensions/preview-sdk";

// Define the port to listen on
const PORT = 3000;

// Define the handler function
async function handler(request, response) {
console.log(`Received [${request.method}] to [${request.url}]`);

if (request.method !== "POST") {
// Handle other request methods if necessary
response.writeHead(405, { "Content-Type": "text/plain" });
console.log(`Method ${request.method} not allowed`);

response.end("Method Not Allowed");
return;
}

// get a token to use
const tokenForUser = request.headers["x-github-token"];

// get the user information with the token
const octokit = new Octokit({ auth: tokenForUser });
const user = await octokit.request("GET /user");

// Collect incoming data chunks to use in the `on("end")` event
const body = await getBody(request);
const signature = String(request.headers["github-public-key-signature"]);
const keyID = String(request.headers["github-public-key-identifier"]);

try {
const { isValidRequest, payload } = await verifyAndParseRequest(
body,
signature,
keyID,
{
token: tokenForUser,
},
);

if (!isValidRequest) {
console.error("Request verification failed");
response.writeHead(401, { "Content-Type": "text/plain" });
response.end("Request could not be verified");
return;
}

// write the acknowledge event to let Copilot know we are handling the request
// this will also show the message "Copilot is responding" in the chat
response.write(createAckEvent());

console.log("Calling the GitHub Copilot API with the user prompt");
// the prompt to forward to the Copilot API is the last message in the payload
const payload_message = payload.messages[payload.messages.length - 1];
const { stream } = await prompt.stream(payload_message.content, {
system: `You are a helpful assistant that replies to user messages as if you were the Blackbeard Pirate. Start every response with the user's name, which is @${user.data.login}`, // extra instructions for the prompt
messages: payload.messages, // we are giving the prompt the existing messages in this chat conversation for context
token: tokenForUser,
});

// stream the prompt response back to Copilot
for await (const chunk of stream) {
response.write(new TextDecoder().decode(chunk));
}

// write the done event to let Copilot know we are done handling the request
response.end(createDoneEvent());
console.log("Response sent");
} catch (error) {
console.error("Error:", error);
response.writeHead(500, { "Content-Type": "text/plain" });
response.end("Internal Server Error");
}
}

// Create an HTTP server
const server = createServer(handler);

// Start the server
server.listen(PORT);
console.log(`Server started at http://localhost:${PORT}`);

/**
*
* @param {import("node:http").IncomingMessage} request
* @returns
*/
function getBody(request) {
return new Promise((resolve) => {
const bodyParts = [];
let body;
request
.on("data", (chunk) => {
bodyParts.push(chunk);
})
.on("end", () => {
body = Buffer.concat(bodyParts).toString();
resolve(body);
});
});
}
12 changes: 12 additions & 0 deletions examples/prompt/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"private": true,
"type": "module",
"scripts": {
"start": "node index.js",
"watch": "node --watch index.js"
},
"dependencies": {
"@copilot-extensions/preview-sdk": "../../",
"octokit": "^4.0.2"
}
}
Loading

0 comments on commit 2cca2a9

Please sign in to comment.