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
15 changes: 15 additions & 0 deletions design/src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import fs from "fs";
import path from "path";

const CONFIG_PATH = path.join(process.env.HOME || "~", ".gstack", "openai.json");
const DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";

export function resolveApiKey(): string | null {
// 1. Check ~/.gstack/openai.json
Expand Down Expand Up @@ -61,3 +62,17 @@ export function requireApiKey(): string {
}
return key;
}

export function resolveOpenAIBaseUrl(): string {
const baseUrl = process.env.OPENAI_BASE_URL?.trim();
if (!baseUrl) {
return DEFAULT_OPENAI_BASE_URL;
}

return baseUrl.replace(/\/+$/, "");
}

export function openaiUrl(endpoint: string): string {
const normalized = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
return `${resolveOpenAIBaseUrl()}${normalized}`;
}
4 changes: 2 additions & 2 deletions design/src/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import fs from "fs";
import { requireApiKey } from "./auth";
import { openaiUrl, requireApiKey } from "./auth";

export interface CheckResult {
pass: boolean;
Expand All @@ -22,7 +22,7 @@ export async function checkMockup(imagePath: string, brief: string): Promise<Che
const timeout = setTimeout(() => controller.abort(), 60_000);

try {
const response = await fetch("https://api.openai.com/v1/chat/completions", {
const response = await fetch(openaiUrl("/chat/completions"), {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
Expand Down
4 changes: 2 additions & 2 deletions design/src/design-to-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import fs from "fs";
import { requireApiKey } from "./auth";
import { openaiUrl, requireApiKey } from "./auth";
import { readDesignConstraints } from "./memory";

export interface DesignToCodeResult {
Expand Down Expand Up @@ -37,7 +37,7 @@ export async function generateDesignToCodePrompt(
? `\n\nExisting DESIGN.md (use these as constraints):\n${designConstraints}`
: "";

const response = await fetch("https://api.openai.com/v1/chat/completions", {
const response = await fetch(openaiUrl("/chat/completions"), {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
Expand Down
4 changes: 2 additions & 2 deletions design/src/diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import fs from "fs";
import { requireApiKey } from "./auth";
import { openaiUrl, requireApiKey } from "./auth";

export interface DiffResult {
differences: { area: string; description: string; severity: string }[];
Expand All @@ -28,7 +28,7 @@ export async function diffMockups(
const timeout = setTimeout(() => controller.abort(), 60_000);

try {
const response = await fetch("https://api.openai.com/v1/chat/completions", {
const response = await fetch(openaiUrl("/chat/completions"), {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
Expand Down
6 changes: 3 additions & 3 deletions design/src/evolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import fs from "fs";
import path from "path";
import { requireApiKey } from "./auth";
import { openaiUrl, requireApiKey } from "./auth";

export interface EvolveOptions {
screenshot: string; // Path to current site screenshot
Expand Down Expand Up @@ -55,7 +55,7 @@ export async function evolve(options: EvolveOptions): Promise<void> {
const timeout = setTimeout(() => controller.abort(), 120_000);

try {
const response = await fetch("https://api.openai.com/v1/responses", {
const response = await fetch(openaiUrl("/responses"), {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
Expand Down Expand Up @@ -113,7 +113,7 @@ async function analyzeScreenshot(apiKey: string, imageBase64: string): Promise<s
const timeout = setTimeout(() => controller.abort(), 30_000);

try {
const response = await fetch("https://api.openai.com/v1/chat/completions", {
const response = await fetch(openaiUrl("/chat/completions"), {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
Expand Down
4 changes: 2 additions & 2 deletions design/src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import fs from "fs";
import path from "path";
import { requireApiKey } from "./auth";
import { openaiUrl, requireApiKey } from "./auth";
import { parseBrief } from "./brief";
import { createSession, sessionPath } from "./session";
import { checkMockup } from "./check";
Expand Down Expand Up @@ -40,7 +40,7 @@ async function callImageGeneration(
const timeout = setTimeout(() => controller.abort(), 120_000);

try {
const response = await fetch("https://api.openai.com/v1/responses", {
const response = await fetch(openaiUrl("/responses"), {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
Expand Down
6 changes: 3 additions & 3 deletions design/src/iterate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import fs from "fs";
import path from "path";
import { requireApiKey } from "./auth";
import { openaiUrl, requireApiKey } from "./auth";
import { readSession, updateSession } from "./session";

export interface IterateOptions {
Expand Down Expand Up @@ -85,7 +85,7 @@ async function callWithThreading(
const timeout = setTimeout(() => controller.abort(), 120_000);

try {
const response = await fetch("https://api.openai.com/v1/responses", {
const response = await fetch(openaiUrl("/responses"), {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
Expand Down Expand Up @@ -133,7 +133,7 @@ async function callFresh(
const timeout = setTimeout(() => controller.abort(), 120_000);

try {
const response = await fetch("https://api.openai.com/v1/responses", {
const response = await fetch(openaiUrl("/responses"), {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
Expand Down
4 changes: 2 additions & 2 deletions design/src/memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import fs from "fs";
import path from "path";
import { requireApiKey } from "./auth";
import { openaiUrl, requireApiKey } from "./auth";

export interface ExtractedDesign {
colors: { name: string; hex: string; usage: string }[];
Expand All @@ -34,7 +34,7 @@ export async function extractDesignLanguage(imagePath: string): Promise<Extracte
const timeout = setTimeout(() => controller.abort(), 60_000);

try {
const response = await fetch("https://api.openai.com/v1/chat/completions", {
const response = await fetch(openaiUrl("/chat/completions"), {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
Expand Down
4 changes: 2 additions & 2 deletions design/src/variants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import fs from "fs";
import path from "path";
import { requireApiKey } from "./auth";
import { openaiUrl, requireApiKey } from "./auth";
import { parseBrief } from "./brief";

export interface VariantsOptions {
Expand Down Expand Up @@ -54,7 +54,7 @@ async function generateVariant(
const timeout = setTimeout(() => controller.abort(), 120_000);

try {
const response = await fetch("https://api.openai.com/v1/responses", {
const response = await fetch(openaiUrl("/responses"), {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
Expand Down