Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion platform/wab/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,8 @@
"validator": "^13.1.1",
"workerpool": "^6.1.4",
"yargs": "^16.2.0",
"zod": "3.25.28"
"zod": "3.25.28",
"zod-to-json-schema": "^3.24.6"
},
"resolutionsComments": {
"ini": "CVE-2020-7788 for 1.3.5"
Expand Down
22 changes: 22 additions & 0 deletions platform/wab/src/wab/server/AppServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ import {
updateTable,
} from "@/wab/server/routes/cmse";
import { addCommentsRoutes } from "@/wab/server/routes/comments";
import {
queryCopilot,
queryCopilotFeedback,
queryPublicUiCopilot,
queryUiCopilot,
sendCopilotFeedback,
} from "@/wab/server/routes/copilot";
import {
ROUTES_WITH_TIMING,
addInternalRoutes,
Expand Down Expand Up @@ -1241,6 +1248,21 @@ export function addCodegenRoutes(app: express.Application) {
);
}

export function addCopilotRoutes(app: express.Application) {
// Main copilot endpoint for code/chat/sql/debug
app.post("/api/v1/copilot", apiAuth, withNext(queryCopilot));

// UI copilot endpoint for HTML/token generation
app.post("/api/v1/copilot/ui", apiAuth, withNext(queryUiCopilot));

// Public UI copilot endpoint (no auth required)
app.post("/api/v1/copilot/ui/public", withNext(queryPublicUiCopilot));

// Copilot feedback endpoints
app.post("/api/v1/copilot-feedback", apiAuth, withNext(sendCopilotFeedback));
app.get("/api/v1/copilot-feedback", apiAuth, withNext(queryCopilotFeedback));
}

export function addMainAppServerRoutes(
app: express.Application,
config: Config
Expand Down
2 changes: 2 additions & 0 deletions platform/wab/src/wab/server/app-backend-real.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// the top so that we know if we are running production and want newrelic.
import {
addCodegenRoutes,
addCopilotRoutes,
addMainAppServerRoutes,
createApp,
} from "@/wab/server/AppServer";
Expand Down Expand Up @@ -58,6 +59,7 @@ export async function runAppServer(config: Config) {
// protected against.
logger().info("Adding codegen routes");
addCodegenRoutes(application);
addCopilotRoutes(application);
}
},
(application) => {
Expand Down
17 changes: 17 additions & 0 deletions platform/wab/src/wab/server/copilot-backend-real.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { addCopilotRoutes, createApp } from "@/wab/server/AppServer";
import { Config } from "@/wab/server/config";
import { ensureDbConnections } from "@/wab/server/db/DbCon";
import { runExpressApp, setupServerCli } from "@/wab/server/server-common";
import "core-js";

async function runAppServer(config: Config) {
await ensureDbConnections(config.databaseUri);

const { app } = await createApp("copilot", config, addCopilotRoutes);
return runExpressApp(app);
}

export async function copilotBackendMain() {
const { opts, config } = setupServerCli();
await runAppServer(config);
}
7 changes: 7 additions & 0 deletions platform/wab/src/wab/server/copilot-backend.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// tslint:disable:ordered-imports
import { spawn } from "@/wab/shared/common";
import { copilotBackendMain } from "@/wab/server/copilot-backend-real";

if (require.main === module) {
spawn(copilotBackendMain());
}
66 changes: 33 additions & 33 deletions platform/wab/src/wab/server/copilot/llms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import {
getDynamoDbSecrets,
getOpenaiApiKey,
} from "@/wab/server/secrets";
import { DynamoDbCache, SimpleCache } from "@/wab/server/simple-cache";
import {
DynamoDbCache,
InMemoryCache,
SimpleCache,
} from "@/wab/server/simple-cache";
import { last, mkShortId } from "@/wab/shared/common";
import {
ChatCompletionRequestMessageRoleEnum,
Expand Down Expand Up @@ -42,9 +46,6 @@ export class OpenAIWrapper {
createChatCompletionRequest: CreateChatCompletionRequest,
options?: CreateChatCompletionRequestOptions
) => {
if (verbose) {
logger().debug(showCompletionRequest(createChatCompletionRequest));
}
const key = hash(
JSON.stringify([
"OpenAI.createChatCompletion",
Expand Down Expand Up @@ -178,35 +179,34 @@ export function getOpenAI() {
return new OpenAI({ apiKey: openaiApiKey });
}

function createCache(): SimpleCache {
// Only use DynamoDB if we have valid credentials
if (
dynamoDbCredentials?.accessKeyId &&
dynamoDbCredentials?.secretAccessKey
) {
try {
return new DynamoDbCache(
new DynamoDBClient({
credentials: {
...dynamoDbCredentials,
},
region: "us-west-2",
})
);
} catch (error) {
console.warn(
"Failed to create DynamoDB cache, falling back to in-memory cache:",
error
);
}
}
// Use in-memory cache as fallback
return new InMemoryCache();
}

export const createOpenAIClient = (_?: DbMgr) =>
new OpenAIWrapper(
getOpenAI(),
new DynamoDbCache(
new DynamoDBClient({
...(dynamoDbCredentials
? {
credentials: {
...dynamoDbCredentials,
},
}
: {}),
region: "us-west-2",
})
)
);
new OpenAIWrapper(getOpenAI(), createCache());

export const createAnthropicClient = (_?: DbMgr) =>
new AnthropicWrapper(
new DynamoDbCache(
new DynamoDBClient({
...(dynamoDbCredentials
? {
credentials: {
...dynamoDbCredentials,
},
}
: {}),
region: "us-west-2",
})
)
);
new AnthropicWrapper(createCache());
Loading