Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@copilot-extensions/preview-sdk

Package Overview
Dependencies
Maintainers
0
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@copilot-extensions/preview-sdk - npm Package Compare versions

Comparing version 2.6.1 to 3.0.0

78

dreamcode.md

@@ -23,33 +23,27 @@ # Copilot Extension Dreamcode

import {
CopilotExtension,
createNodeMiddleware,
} from "@octokit/copilot-extension";
import { CopilotAgent, createNodeMiddleware } from "@octokit/copilot-extension";
const copilotExtension = new CopilotExtension({
const agent = new CopilotAgent({
userAgent: "my-app-name",
});
copilotExtension.on(
"message",
async ({ message, octokit, prompt, respond, log }) => {
log.info("Received a message:", message.content);
agent.on("message", async ({ message, octokit, prompt, respond, log }) => {
log.info("Received a message:", message.content);
const { data: user } = await octokit.request("GET /user");
await respond.text(`Hello, ${user.login}!`);
const { data: user } = await octokit.request("GET /user");
await respond.text(`Hello, ${user.login}!`);
await respond.confirmation({
title: "Would you like to hear a joke?",
message: "I have a joke about construction, but I'm still working on it.",
id: "joke",
// optional
meta: {
other: "data",
},
});
}
);
await respond.confirmation({
title: "Would you like to hear a joke?",
message: "I have a joke about construction, but I'm still working on it.",
id: "joke",
// optional
meta: {
other: "data",
},
});
});
// https://github.com/github/copilot-partners/blob/6d1cde3a1abb147da53f1a39864661dc824d40b5/docs/confirmations.md
copilotExtension.on(
agent.on(
"confirmation",

@@ -64,3 +58,5 @@ async ({ confirmation, octokit, prompt, respond, log }) => {

await respond.text(
prompt.stream("Please tell me a joke about Mona Lisa, Github's mascot.")
prompt.stream(
"Please tell me a joke about Mona Lisa, Github's mascot.",
),
);

@@ -72,4 +68,7 @@ return;

await respond.text("Hmm, something went wrong. Please try again later.");
}
},
);
createServer(createNodeMiddleware(agent)).listen(3000);
agent.log.info("Listening on http://localhost:3000");
```

@@ -84,8 +83,5 @@

import {
CopilotExtension,
createNodeMiddleware,
} from "@octokit/copilot-extension";
import { CopilotAgent, createNodeMiddleware } from "@octokit/copilot-extension";
const copilotExtension = new CopilotExtension({
const copilotAgent = new CopilotAgent({
userAgent: "book-a-flight",

@@ -95,5 +91,5 @@

model: {
// either "gpt-3.5-turbo" or "gpt-4". Maybe "default" if we support that server-side or want to support that in the SDK?
// Defaults to "gpt-4". Get available models from https://api.githubcopilot.com/models
name: "gpt-4",
// optional, setting to default for demo purposes
// Defaults to "https://api.githubcopilot.com/chat/completions"
endpoint: "https://api.githubcopilot.com/chat/completions",

@@ -177,3 +173,3 @@ // when enabled, messages are passed through to Copilot's chat completions API

// to the chat completions API.
copilotExtension.on("message", async ({ log }) => {
copilotAgent.on("message", async ({ log }) => {
log.info("Received a message:", message.content);

@@ -183,12 +179,12 @@

});
copilotExtension.on("function_call", async ({ log, name, parameters }) => {
copilotAgent.on("function_call", async ({ log, name, parameters }) => {
log.info(
"Received a function call for %s with parameters %o",
name,
parameters
parameters,
);
});
createServer(createNodeMiddleware(copilotExtension)).listen(3000);
copilotExtension.log.info("Listening on http://localhost:3000");
createServer(createNodeMiddleware(copilotAgent)).listen(3000);
copilotAgent.log.info("Listening on http://localhost:3000");
```

@@ -200,11 +196,11 @@

// verify the payload and call handlers
await copilotExtension.verifyAndReceive({ payload, signature, keyId });
await copilotAgent.verifyAndReceive({ payload, signature, keyId });
// same, but skip verification
await copilotExtension.receive({ payload });
await copilotAgent.receive({ payload });
// and if you don't want to use the event-based API
const { isValidRequest, payload } = await copilotExtension.verifyAndParse(
const { isValidRequest, payload } = await copilotAgent.verifyAndParse(
payload,
signature,
keyId
keyId,
);

@@ -211,0 +207,0 @@ ```

@@ -17,13 +17,7 @@ import { request } from "@octokit/request";

interface VerifyRequestInterface {
(
rawBody: string,
signature: string,
key: string
): Promise<boolean>;
(rawBody: string, signature: string, key: string): Promise<boolean>;
}
interface FetchVerificationKeysInterface {
(
requestOptions?: RequestOptions,
): Promise<VerificationPublicKey[]>;
(requestOptions?: RequestOptions): Promise<VerificationPublicKey[]>;
}

@@ -43,58 +37,91 @@

export interface CreateAckEventInterface {
(): ResponseEvent<"ack">
(): ResponseEvent<"ack">;
}
export interface CreateTextEventInterface {
(message: string): ResponseEvent<"text">
(message: string): ResponseEvent<"text">;
}
export type CreateConfirmationEventOptions = { id: string, title: string, message: string, metadata?: Record<string, unknown> }
export type CreateConfirmationEventOptions = {
id: string;
title: string;
message: string;
metadata?: Record<string, unknown>;
};
export interface CreateConfirmationEventInterface {
(options: CreateConfirmationEventOptions): ResponseEvent<"copilot_confirmation">
(
options: CreateConfirmationEventOptions,
): ResponseEvent<"copilot_confirmation">;
}
export interface CreateReferencesEventInterface {
(references: CopilotReference[]): ResponseEvent<"copilot_references">
(references: CopilotReference[]): ResponseEvent<"copilot_references">;
}
export interface CreateErrorsEventInterface {
(errors: CopilotError[]): ResponseEvent<"copilot_errors">
(errors: CopilotError[]): ResponseEvent<"copilot_errors">;
}
export interface CreateDoneEventInterface {
(): ResponseEvent<"done">
(): ResponseEvent<"done">;
}
type ResponseEventType = "ack" | "done" | "text" | "copilot_references" | "copilot_confirmation" | "copilot_errors"
type EventsWithoutEventKey = "ack" | "done" | "text"
type ResponseEventType =
| "ack"
| "done"
| "text"
| "copilot_references"
| "copilot_confirmation"
| "copilot_errors";
type EventsWithoutEventKey = "ack" | "done" | "text";
type ResponseEvent<T extends ResponseEventType = "text"> =
T extends EventsWithoutEventKey ? {
data: T extends "ack" ? CopilotAckResponseEventData : T extends "done" ? CopilotDoneResponseEventData : T extends "text" ? CopilotTextResponseEventData : never
toString: () => string
} : {
event: T
data: T extends "copilot_references" ? CopilotReferenceResponseEventData : T extends "copilot_confirmation" ? CopilotConfirmationResponseEventData : T extends "copilot_errors" ? CopilotErrorsResponseEventData : never
toString: () => string
}
T extends EventsWithoutEventKey
? {
data: T extends "ack"
? CopilotAckResponseEventData
: T extends "done"
? CopilotDoneResponseEventData
: T extends "text"
? CopilotTextResponseEventData
: never;
toString: () => string;
}
: {
event: T;
data: T extends "copilot_references"
? CopilotReferenceResponseEventData
: T extends "copilot_confirmation"
? CopilotConfirmationResponseEventData
: T extends "copilot_errors"
? CopilotErrorsResponseEventData
: never;
toString: () => string;
};
type CopilotAckResponseEventData = {
choices: [{
delta: InteropMessage<"assistant">
}]
}
choices: [
{
delta: InteropMessage<"assistant">;
},
];
};
type CopilotDoneResponseEventData = {
choices: [{
finish_reason: "stop"
delta: {
content: null
}
}]
}
choices: [
{
finish_reason: "stop";
delta: {
content: null;
};
},
];
};
type CopilotTextResponseEventData = {
choices: [{
delta: InteropMessage<"assistant">
}]
}
choices: [
{
delta: InteropMessage<"assistant">;
},
];
};
type CopilotConfirmationResponseEventData = {
type: 'action';
type: "action";
title: string;

@@ -106,5 +133,5 @@ message: string;

};
}
type CopilotErrorsResponseEventData = CopilotError[]
type CopilotReferenceResponseEventData = CopilotReference[]
};
type CopilotErrorsResponseEventData = CopilotError[];
type CopilotReferenceResponseEventData = CopilotReference[];

@@ -116,3 +143,3 @@ type CopilotError = {

identifier: string;
}
};

@@ -136,101 +163,100 @@ interface CopilotReference {

export interface CopilotRequestPayload {
copilot_thread_id: string
messages: CopilotMessage[]
stop: any
top_p: number
temperature: number
max_tokens: number
presence_penalty: number
frequency_penalty: number
copilot_skills: any[]
agent: string
copilot_thread_id: string;
messages: CopilotMessage[];
stop: any;
top_p: number;
temperature: number;
max_tokens: number;
presence_penalty: number;
frequency_penalty: number;
copilot_skills: any[];
agent: string;
}
export interface OpenAICompatibilityPayload {
messages: InteropMessage[]
messages: InteropMessage[];
}
export interface CopilotMessage {
role: string
content: string
copilot_references: MessageCopilotReference[]
copilot_confirmations?: MessageCopilotConfirmation[]
role: string;
content: string;
copilot_references?: MessageCopilotReference[];
copilot_confirmations?: MessageCopilotConfirmation[];
tool_calls?: {
"function": {
"arguments": string,
"name": string
},
"id": string,
"type": "function"
}[]
name?: string
[key: string]: unknown
function: {
arguments: string;
name: string;
};
id: string;
type: "function";
}[];
name?: string;
[key: string]: unknown;
}
export interface InteropMessage<TRole extends string = string> {
role: TRole
content: string
name?: string
[key: string]: unknown
role: TRole;
content: string;
name?: string;
[key: string]: unknown;
}
export interface MessageCopilotReference {
type: string
data: CopilotReferenceData
id: string
is_implicit: boolean
metadata: CopilotReferenceMetadata
type: string;
data: CopilotReferenceData;
id: string;
is_implicit: boolean;
metadata: CopilotReferenceMetadata;
}
export interface CopilotReferenceData {
type: string
id: number
name?: string
ownerLogin?: string
ownerType?: string
readmePath?: string
description?: string
commitOID?: string
ref?: string
refInfo?: CopilotReferenceDataRefInfo
visibility?: string
languages?: CopilotReferenceDataLanguage[]
login?: string
avatarURL?: string
url?: string
type: string;
id: number;
name?: string;
ownerLogin?: string;
ownerType?: string;
readmePath?: string;
description?: string;
commitOID?: string;
ref?: string;
refInfo?: CopilotReferenceDataRefInfo;
visibility?: string;
languages?: CopilotReferenceDataLanguage[];
login?: string;
avatarURL?: string;
url?: string;
}
export interface CopilotReferenceDataRefInfo {
name: string
type: string
name: string;
type: string;
}
export interface CopilotReferenceDataLanguage {
name: string
percent: number
name: string;
percent: number;
}
export interface CopilotReferenceMetadata {
display_name: string
display_icon: string
display_url: string
display_name: string;
display_icon: string;
display_url: string;
}
export interface MessageCopilotConfirmation {
state: "dismissed" | "accepted"
state: "dismissed" | "accepted";
confirmation: {
id: string
[key: string]: unknown
}
id: string;
[key: string]: unknown;
};
}
export interface ParseRequestBodyInterface {
(body: string): CopilotRequestPayload
(body: string): CopilotRequestPayload;
}
export interface TransformPayloadForOpenAICompatibilityInterface {
(payload: CopilotRequestPayload): OpenAICompatibilityPayload
(payload: CopilotRequestPayload): OpenAICompatibilityPayload;
}
export interface VerifyAndParseRequestInterface {

@@ -245,3 +271,2 @@ (

export interface GetUserMessageInterface {

@@ -255,3 +280,3 @@ (payload: CopilotRequestPayload): string;

metadata: Record<string, unknown>;
}
};

@@ -264,13 +289,13 @@ export interface GetUserConfirmationInterface {

/**
/**
* model names supported by Copilot API
* A list of currently supported models can be retrieved at
* https://api.githubcopilot.com/models. We set `ModelName` to `string`
* https://api.githubcopilot.com/models. We set `ModelName` to `string`
* instead of a union of the supported models as we cannot give
* guarantees about the supported models in the future.
*/
export type ModelName = string
export type ModelName = string;
export interface PromptFunction {
type: "function"
type: "function";
function: {

@@ -282,22 +307,28 @@ name: string;

strict?: boolean | null;
}
};
}
export type PromptOptions = {
model?: ModelName
token: string
tools?: PromptFunction[]
messages?: InteropMessage[]
token: string;
endpoint?: string;
model?: ModelName;
tools?: PromptFunction[];
messages?: InteropMessage[];
request?: {
fetch?: Function
}
}
fetch?: Function;
};
};
export type PromptResult = {
requestId: string
message: CopilotMessage
}
requestId: string;
message: CopilotMessage;
};
export type PromptStreamResult = {
requestId: string;
stream: ReadableStream<Uint8Array>;
};
// https://stackoverflow.com/a/69328045
type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] }
type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };

@@ -307,4 +338,12 @@ interface PromptInterface {

(options: WithRequired<PromptOptions, "messages">): Promise<PromptResult>;
stream: PromptStreamInterface;
}
interface PromptStreamInterface {
(userPrompt: string, options: PromptOptions): Promise<PromptStreamResult>;
(
options: WithRequired<PromptOptions, "messages">,
): Promise<PromptStreamResult>;
}
interface GetFunctionCallsInterface {

@@ -314,6 +353,6 @@ (payload: PromptResult): {

function: {
name: string,
arguments: string,
}
}[]
name: string;
arguments: string;
};
}[];
}

@@ -341,2 +380,2 @@

export declare const prompt: PromptInterface;
export declare const getFunctionCalls: GetFunctionCallsInterface;
export declare const getFunctionCalls: GetFunctionCallsInterface;

@@ -29,3 +29,7 @@ import { expectType } from "tsd";

export async function verifyRequestByKeyIdTest(rawBody: string, signature: string, keyId: string) {
export async function verifyRequestByKeyIdTest(
rawBody: string,
signature: string,
keyId: string,
) {
const result = await verifyRequestByKeyId(rawBody, signature, keyId);

@@ -53,3 +57,7 @@ expectType<boolean>(result);

export async function verifyRequestTest(rawBody: string, signature: string, key: string) {
export async function verifyRequestTest(
rawBody: string,
signature: string,
key: string,
) {
const result = await verifyRequest(rawBody, signature, key);

@@ -87,11 +95,12 @@ expectType<boolean>(result);

expectType<{
choices: [{
delta: InteropMessage<"assistant">
}]
choices: [
{
delta: InteropMessage<"assistant">;
},
];
}>(event.data);
// @ts-expect-error - .event is required
event.event
event.event;
}

@@ -105,9 +114,11 @@

expectType<{
choices: [{
delta: InteropMessage<"assistant">
}]
choices: [
{
delta: InteropMessage<"assistant">;
},
];
}>(event.data);
// @ts-expect-error - .event is required
event.event
event.event;
}

@@ -119,3 +130,3 @@

title: "test",
message: "test"
message: "test",
});

@@ -130,4 +141,4 @@

someOtherId: "test",
}
})
},
});

@@ -138,3 +149,3 @@ expectType<() => string>(event.toString);

expectType<{
type: 'action';
type: "action";
title: string;

@@ -174,15 +185,17 @@ message: string;

expectType<{
type: string;
id: string;
data?: {
[key: string]: unknown;
};
is_implicit?: boolean;
metadata?: {
display_name: string;
display_icon?: string;
display_url?: string;
};
}[]>(event.data);
expectType<
{
type: string;
id: string;
data?: {
[key: string]: unknown;
};
is_implicit?: boolean;
metadata?: {
display_name: string;
display_icon?: string;
display_url?: string;
};
}[]
>(event.data);

@@ -193,27 +206,33 @@ expectType<"copilot_references">(event.event);

export function createErrorsEventTest() {
const event = createErrorsEvent([{
type: "reference",
code: "1",
message: "test reference error",
identifier: "reference-identifier",
}, {
type: "function",
code: "1",
message: "test function error",
identifier: "function-identifier",
}, {
type: "agent",
code: "1",
message: "test agent error",
identifier: "agent-identifier",
}]);
const event = createErrorsEvent([
{
type: "reference",
code: "1",
message: "test reference error",
identifier: "reference-identifier",
},
{
type: "function",
code: "1",
message: "test function error",
identifier: "function-identifier",
},
{
type: "agent",
code: "1",
message: "test agent error",
identifier: "agent-identifier",
},
]);
expectType<() => string>(event.toString);
expectType<string>(event.toString());
expectType<{
type: "reference" | "function" | "agent";
code: string;
message: string;
identifier: string;
}[]>(event.data);
expectType<
{
type: "reference" | "function" | "agent";
code: string;
message: string;
identifier: string;
}[]
>(event.data);

@@ -229,23 +248,25 @@ expectType<"copilot_errors">(event.event);

expectType<{
"choices": [
choices: [
{
"finish_reason": "stop",
"delta": {
"content": null
}
}
]
finish_reason: "stop";
delta: {
content: null;
};
},
];
}>(event.data);
// @ts-expect-error - .event is required
event.event
event.event;
}
export function parseRequestBodyTest(body: string) {
const result = parseRequestBody(body)
const result = parseRequestBody(body);
expectType<CopilotRequestPayload>(result);
}
export function transformPayloadForOpenAICompatibilityTest(payload: CopilotRequestPayload) {
const result = transformPayloadForOpenAICompatibility(payload)
export function transformPayloadForOpenAICompatibilityTest(
payload: CopilotRequestPayload,
) {
const result = transformPayloadForOpenAICompatibility(payload);
expectType<{

@@ -255,28 +276,37 @@ messages: {

role: string;
name?: string
[key: string]: unknown
}[]
}
>(result);
name?: string;
[key: string]: unknown;
}[];
}>(result);
}
export async function verifyAndParseRequestTest(rawBody: string, signature: string, keyId: string) {
const result = await verifyAndParseRequest(rawBody, signature, keyId)
expectType<{ isValidRequest: boolean, payload: CopilotRequestPayload }>(result);
export async function verifyAndParseRequestTest(
rawBody: string,
signature: string,
keyId: string,
) {
const result = await verifyAndParseRequest(rawBody, signature, keyId);
expectType<{ isValidRequest: boolean; payload: CopilotRequestPayload }>(
result,
);
}
export function getUserMessageTest(payload: CopilotRequestPayload) {
const result = getUserMessage(payload)
expectType<string>(result)
const result = getUserMessage(payload);
expectType<string>(result);
}
export function getUserConfirmationTest(payload: CopilotRequestPayload) {
const result = getUserConfirmation(payload)
const result = getUserConfirmation(payload);
if (result === undefined) {
expectType<undefined>(result)
return
expectType<undefined>(result);
return;
}
expectType<{ accepted: boolean; id?: string; metadata: Record<string, unknown> }>(result)
expectType<{
accepted: boolean;
id?: string;
metadata: Record<string, unknown>;
}>(result);
}

@@ -286,23 +316,21 @@

const result = await prompt("What is the capital of France?", {
model: "gpt-4",
token: "secret",
})
});
expectType<string>(result.requestId)
expectType<string>(result.message.content)
expectType<string>(result.requestId);
expectType<string>(result.message.content);
// with custom fetch
await prompt("What is the capital of France?", {
model: "gpt-4",
token: "secret",
request: {
fetch: () => { }
}
})
fetch: () => {},
},
});
// @ts-expect-error - 2nd argument is required
prompt("What is the capital of France?")
prompt("What is the capital of France?");
// @ts-expect-error - token argument is required
prompt("What is the capital of France?", { model: "" })
prompt("What is the capital of France?", { model: "" });
}

@@ -312,3 +340,2 @@

await prompt("What is the capital of France?", {
model: "gpt-4",
token: "secret",

@@ -323,6 +350,6 @@ tools: [

strict: true,
}
}
]
})
},
},
],
});
}

@@ -333,3 +360,3 @@

model: "gpt-4",
token: 'secret',
token: "secret",
messages: [

@@ -345,3 +372,3 @@ { role: "user", content: "What is the capital of France?" },

model: "gpt-4",
token: 'secret',
token: "secret",
messages: [

@@ -355,11 +382,34 @@ { role: "user", content: "What is the capital of France?" },

export async function getFunctionCallsTest(promptResponsePayload: PromptResult) {
const result = getFunctionCalls(promptResponsePayload)
export async function otherPromptOptionsTest() {
const result = await prompt("What is the capital of France?", {
token: "secret",
model: "gpt-4",
endpoint: "https://api.githubcopilot.com",
});
}
expectType<{
id: string, function: {
name: string,
arguments: string,
}
}[]>(result)
}
export async function promptStreamTest() {
const result = await prompt.stream("What is the capital of France?", {
model: "gpt-4",
token: "secret",
});
expectType<string>(result.requestId);
expectType<ReadableStream<Uint8Array>>(result.stream);
}
export async function getFunctionCallsTest(
promptResponsePayload: PromptResult,
) {
const result = getFunctionCalls(promptResponsePayload);
expectType<
{
id: string;
function: {
name: string;
arguments: string;
};
}[]
>(result);
}
// @ts-check
/** @type {import('..').PromptInterface} */
export async function prompt(userPrompt, promptOptions) {
const options = typeof userPrompt === "string" ? promptOptions : userPrompt;
const promptFetch = options.request?.fetch || fetch;
const modelName = options.model || "gpt-4";
function parsePromptArguments(userPrompt, promptOptions) {
const { request: requestOptions, ...options } =
typeof userPrompt === "string" ? promptOptions : userPrompt;
const promptFetch = requestOptions?.fetch || fetch;
const model = options.model || "gpt-4";
const endpoint =
options.endpoint || "https://api.githubcopilot.com/chat/completions";
const systemMessage = options.tools
? "You are a helpful assistant. Use the supplied tools to assist the user."
: "You are a helpful assistant.";
const toolsChoice = options.tools ? "auto" : undefined;

@@ -32,40 +37,83 @@ const messages = [

const response = await promptFetch(
"https://api.githubcopilot.com/chat/completions",
return [promptFetch, { ...options, messages, model, endpoint, toolsChoice }];
}
async function sendPromptRequest(promptFetch, options) {
const { endpoint, token, ...payload } = options;
const method = "POST";
const headers = {
accept: "application/json",
"content-type": "application/json; charset=UTF-8",
"user-agent": "copilot-extensions/preview-sdk.js",
authorization: `Bearer ${token}`,
};
const response = await promptFetch(endpoint, {
method,
headers,
body: JSON.stringify(payload),
});
if (response.ok) {
return response;
}
const body = await response.text();
console.log({ body });
throw Object.assign(
new Error(
`[@copilot-extensions/preview-sdk] An error occured with the chat completions API`,
),
{
method: "POST",
headers: {
accept: "application/json",
"content-type": "application/json; charset=UTF-8",
"user-agent": "copilot-extensions/preview-sdk.js",
authorization: `Bearer ${options.token}`,
name: "PromptError",
request: {
method: "POST",
url: endpoint,
headers: {
...headers,
authorization: `Bearer [REDACTED]`,
},
body: payload,
},
body: JSON.stringify({
messages: messages,
model: modelName,
toolChoice: options.tools ? "auto" : undefined,
tools: options.tools,
}),
}
response: {
status: response.status,
headers: [...response.headers],
body: body,
},
},
);
}
export async function prompt(userPrompt, promptOptions) {
const [promptFetch, options] = parsePromptArguments(
userPrompt,
promptOptions,
);
const response = await sendPromptRequest(promptFetch, options);
const requestId = response.headers.get("x-request-id");
if (response.ok) {
const data = await response.json();
const data = await response.json();
return {
requestId: response.headers.get("x-request-id"),
message: data.choices[0].message,
};
}
const requestId = response.headers.get("x-request-id");
return {
requestId: requestId,
message: {
role: "Sssistant",
content: `Sorry, an error occured with the chat completions API. (Status: ${response.status}, request ID: ${requestId})`,
},
requestId,
message: data.choices[0].message,
};
}
prompt.stream = async function promptStream(userPrompt, promptOptions) {
const [promptFetch, options] = parsePromptArguments(
userPrompt,
promptOptions,
);
const response = await sendPromptRequest(promptFetch, {
...options,
stream: true,
});
return {
requestId: response.headers.get("x-request-id"),
stream: response.body,
};
};
/** @type {import('..').GetFunctionCallsInterface} */

@@ -72,0 +120,0 @@ export function getFunctionCalls(payload) {

@@ -8,3 +8,3 @@ {

"type": "module",
"version": "2.6.1",
"version": "3.0.0",
"keywords": [

@@ -11,0 +11,0 @@ "ai",

@@ -5,4 +5,18 @@ # `@copilot-extensions/preview-sdk`

⚠️ **This SDK is a preview and subject to change**. We will however adhere to [semantic versioning](https://semver.org/), so it's save to use for early experimentation. Just beware there will be breaking changes. Best to watch this repository's releases for updates.
This SDK simplifies the process of building GitHub Copilot Extensions. Building Copilot Extensions previously required manual handling of request verification, response formatting, and API interactions. This SDK simplifies these tasks, allowing you to focus on your extension's core functionality rather than building boilerplate code. Use it to integrate your tools, APIs, or data sources directly into Copilot Chat.
We consider this SDK alpha software in terms of API stability, but we adhere to semantic-versioning, so it's safe to use today.
## Key features
- Request payload verification
- Payload parsing
- Response building
## Benefits
- Handles security and response formatting requirements
- Provides utilities for common extension tasks
- Streamlines the development process
## Usage

@@ -21,3 +35,3 @@

token: process.env.GITHUB_TOKEN,
}
},
);

@@ -77,3 +91,3 @@ // true or false

signature,
key
key,
);

@@ -116,3 +130,3 @@

signature,
key
key,
);

@@ -164,3 +178,3 @@ // true or false

message: "This will do something.",
}).toString()
}).toString(),
);

@@ -273,3 +287,3 @@ ```

signature,
key
key,
);

@@ -417,2 +431,18 @@

#### `prompt.stream(message, options)`
Works the same way as `prompt()`, but resolves with a `stream` key instead of a `message` key.
```js
import { prompt } from "@copilot-extensions/preview-sdk";
const { requestId, stream } = prompt.stream("What is the capital of France?", {
token: process.env.TOKEN,
});
for await (const chunk of stream) {
console.log(new TextDecoder().decode(chunk));
}
```
### `getFunctionCalls()`

@@ -419,0 +449,0 @@

@@ -81,3 +81,3 @@ import { test, suite } from "node:test";

},
}
},
);

@@ -94,3 +94,3 @@ const testRequest = defaultRequest.defaults({

{ isValidRequest: true, payload: JSON.parse(RAW_BODY) },
result
result,
);

@@ -141,5 +141,5 @@ });

},
result
result,
);
});
});
import { test, suite } from "node:test";
import assert from "node:assert";

@@ -56,3 +57,3 @@ import { MockAgent } from "undici";

},
}
},
);

@@ -88,2 +89,3 @@

body: JSON.stringify({
model: "<custom-model>",
messages: [

@@ -95,3 +97,2 @@ { role: "system", content: "You are a helpful assistant." },

],
model: "<custom-model>",
}),

@@ -115,3 +116,3 @@ })

},
}
},
);

@@ -177,3 +178,3 @@

},
}
},
);

@@ -198,2 +199,63 @@

test("options.endpoint", async (t) => {
const mockAgent = new MockAgent();
function fetchMock(url, opts) {
opts ||= {};
opts.dispatcher = mockAgent;
return fetch(url, opts);
}
mockAgent.disableNetConnect();
const mockPool = mockAgent.get("https://my-copilot-endpoint.test");
mockPool
.intercept({
method: "post",
path: `/chat/completions`,
body: JSON.stringify({
messages: [
{
role: "system",
content: "You are a helpful assistant.",
},
{
role: "user",
content: "What is the capital of France?",
},
],
model: "gpt-4",
}),
})
.reply(
200,
{
choices: [
{
message: {
content: "<response text>",
},
},
],
},
{
headers: {
"content-type": "application/json",
"x-request-id": "<request-id>",
},
},
);
const result = await prompt("What is the capital of France?", {
token: "secret",
endpoint: "https://my-copilot-endpoint.test/chat/completions",
request: { fetch: fetchMock },
});
t.assert.deepEqual(result, {
requestId: "<request-id>",
message: {
content: "<response text>",
},
});
});
test("single options argument", async (t) => {

@@ -239,3 +301,3 @@ const mockAgent = new MockAgent();

},
}
},
);

@@ -276,2 +338,8 @@

body: JSON.stringify({
tools: [
{
type: "function",
function: { name: "the_function", description: "The function" },
},
],
messages: [

@@ -286,9 +354,3 @@ {

model: "gpt-4",
toolChoice: "auto",
tools: [
{
type: "function",
function: { name: "the_function", description: "The function" },
},
],
toolsChoice: "auto",
}),

@@ -312,3 +374,3 @@ })

},
}
},
);

@@ -373,15 +435,47 @@

const result = await prompt("What is the capital of France?", {
token: "secret",
request: { fetch: fetchMock },
});
t.assert.deepEqual(result, {
message: {
content:
"Sorry, an error occured with the chat completions API. (Status: 400, request ID: <request-id>)",
role: "Sssistant",
await assert.rejects(
async () => {
await prompt("What is the capital of France?", {
token: "secret",
request: { fetch: fetchMock },
});
},
requestId: "<request-id>",
});
{
name: "PromptError",
message:
"[@copilot-extensions/preview-sdk] An error occured with the chat completions API",
request: {
method: "POST",
url: "https://api.githubcopilot.com/chat/completions",
headers: {
"content-type": "application/json; charset=UTF-8",
"user-agent": "copilot-extensions/preview-sdk.js",
accept: "application/json",
authorization: "Bearer [REDACTED]",
},
body: {
messages: [
{
content: "You are a helpful assistant.",
role: "system",
},
{
content: "What is the capital of France?",
role: "user",
},
],
model: "gpt-4",
toolsChoice: undefined,
},
},
response: {
status: 400,
headers: [
["content-type", "text/plain"],
["x-request-id", "<request-id>"],
],
body: "Bad Request",
},
},
);
});

@@ -419,3 +513,3 @@

};
})
}),
);

@@ -422,0 +516,0 @@ });

@@ -61,3 +61,3 @@ import { test } from "node:test";

},
}
},
);

@@ -175,3 +175,3 @@ const testRequest = defaultRequest.defaults({

},
}
},
);

@@ -178,0 +178,0 @@ const testRequest = defaultRequest.defaults({

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc