-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs(examples): hello world, prompt #84
Changes from 15 commits
fc01ac5
01315e3
97db5cc
54c7182
b3cec6a
6b0300c
0d5663a
fbb3721
514fa22
5d36cb4
76493da
82fef70
e5f95f3
a91d03b
67160bc
7799456
a86354c
373f42a
7e058b9
01f1a0e
037f7ab
a577333
6bc910d
0fcccbf
d10e4ed
45ead22
7057fd2
cc0ad34
55a290b
7aba451
f46d975
1db7290
4f59a32
dd6093a
5c4aadf
6a0551d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { createServer } from "node:http"; | ||
|
||
import { | ||
createTextEvent, | ||
createDoneEvent, | ||
} from "@copilot-extensions/preview-sdk"; | ||
|
||
const server = createServer((request, ressponse) => { | ||
console.log(`Received [${request.method}]`); | ||
if (request.method === "GET") { | ||
return ressponse.end("ok"); | ||
} | ||
|
||
ressponse.write(createTextEvent("Hello, world!")); | ||
ressponse.end(createDoneEvent()); | ||
}); | ||
|
||
const PORT = process.env.PORT || 3000; | ||
server.listen(PORT, () => { | ||
console.log(`Server is running on port ${PORT}`); | ||
}); |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure if we should commit lock files for the examples, they might just create a lot of noise There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair point, I'll remove them There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"private": true, | ||
"scripts": { | ||
"start": "node index.js", | ||
"watch": "node --watch index.js" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does node support a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. woah today I learned, thanks! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Copilot told me it was available! |
||
}, | ||
"dependencies": { | ||
"@copilot-extensions/preview-sdk": "latest" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,99 @@ | ||||||
import http from 'http'; | ||||||
rajbos marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
import { | ||||||
createAckEvent, | ||||||
createDoneEvent, | ||||||
createTextEvent, | ||||||
parseRequestBody, | ||||||
prompt, | ||||||
createConfirmationEvent | ||||||
} from "@copilot-extensions/preview-sdk"; | ||||||
|
||||||
|
||||||
// Define the handler function | ||||||
const handler = async (request, response) => { | ||||||
if (request.method === 'POST') { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would reverse condition and do an early return to avoid indentation
Suggested change
|
||||||
console.log('Received POST request'); | ||||||
|
||||||
// get a token to use | ||||||
const tokenForUser = request.headers['x-github-token']; | ||||||
if (tokenForUser) { | ||||||
console.log('Token length:', tokenForUser.length); | ||||||
} else { | ||||||
console.log('X-GitHub-Token header not found'); | ||||||
} | ||||||
|
||||||
// Collect incoming data chunks to use in the `on("end")` event | ||||||
let body = ''; | ||||||
request.on('data', chunk => { | ||||||
body += chunk.toString(); | ||||||
}); | ||||||
|
||||||
// Parse the collected data once the request ends | ||||||
request.on('end', async () => { | ||||||
try { | ||||||
// start sending the response back to Copilot | ||||||
console.log('Handling response'); | ||||||
// header to indicate the state | ||||||
response.writeHead(200, { 'Content-Type': 'application/json' }); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this is needed. The content is not valid JSON code anyway |
||||||
// write the acknowledge event to let Copilot know we are handling the request | ||||||
// this will also show the message "" in the chat | ||||||
response.write(createAckEvent()); | ||||||
|
||||||
// parse the incoming body as that has the information we need to handle the request / user prompt | ||||||
const payload = parseRequestBody(body); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I would create a separate method to read the body text instead of moving all the core logic into the |
||||||
|
||||||
// start writing text in the response | ||||||
const textEvent = createTextEvent(`Hello GitHubber, \n\n`); | ||||||
// add new lines to mark the difference between the fixed text and the dynamic text | ||||||
response.write("\n\n"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the new lines are included in
Suggested change
|
||||||
|
||||||
// add a first system prompt for the payload.messages to add instructions | ||||||
payload.messages.unshift({ role: "system", content: "You are a helpful assistant that talks like a pirate." }); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WE are doing this system message unshifting inside
Suggested change
|
||||||
|
||||||
// get an authentication token to use | ||||||
const tokenForUser = request.headers['x-github-token']; | ||||||
|
||||||
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 result = await prompt(payload_message.content, { | ||||||
messages: payload.messages, // we are giving the prompt the existing messages in this chat conversation | ||||||
model: "gpt-4", | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. setting Line 4 in b7063d6
|
||||||
token: tokenForUser | ||||||
}); | ||||||
|
||||||
// write the prompt response back to Copilot | ||||||
// note that this is only send when the entire response from the Copilot API is ready | ||||||
response.write(createTextEvent(result.message.content)); | ||||||
|
||||||
// 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'); | ||||||
} | ||||||
}); | ||||||
} else { | ||||||
// 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'); | ||||||
} | ||||||
gr2m marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
}; | ||||||
|
||||||
// Create an HTTP server | ||||||
const server = http.createServer((req, res) => { | ||||||
handler(req, res); | ||||||
}); | ||||||
rajbos marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
// Define the port to listen on | ||||||
const PORT = 3000; | ||||||
|
||||||
// Start the server | ||||||
server.listen(PORT, () => { | ||||||
console.log(`Server is listening on port ${PORT}`); | ||||||
}); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"private": true, | ||
"scripts": { | ||
"start": "node index.js", | ||
"watch": "node --watch index.js" | ||
}, | ||
"dependencies": { | ||
"@copilot-extensions/preview-sdk": "latest" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
This folder contains examples to show how you can use the Copilot Agent SDK in your own projects. | ||
Keep in mind that the SDK is in preview, so things might be changed already! | ||
|
||
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). | ||
|
||
# Examples | ||
Here's an overview of the examples in this folder: | ||
- 1-hello-world: A simple example that responds to all prompts with a message: "Hello, world!" | ||
- 2-handle-prompt: An example that responds to prompts with a message: "Hello, world!" and then forwards the prompt to the Copilot API. The response from the Copilot API is then sent back to the user. | ||
|
||
## 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. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,7 @@ | |
"license": "MIT", | ||
"description": "JavaScript SDK for Copilot Extensions", | ||
"dependencies": { | ||
"@copilot-extensions/preview-sdk": "^4.0.3", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. did you add this dependency on itself intentionally? If yes, why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, probably ran an npm install command at the wrong folder. Removed it! |
||
"@octokit/request": "^9.1.3", | ||
"@octokit/request-error": "^6.1.4" | ||
}, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should log out both the method and the URL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see you removed the brackets as well. It's a preference of mine to be able to differentiate between fixed text and variable text, and makes it really easy to see when a value is empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can leave in the brackets if you prefer. But values cannot be empty in this context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added