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
16 changes: 14 additions & 2 deletions lib/prompt-templates/create-local-circuit-prompt.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import {
fp,
getFootprintNamesByType,
getFootprintSizes,
fp,
} from "@tscircuit/footprinter"

async function fetchFileContent(url: string): Promise<string> {
async function fetchFileContent(
url: string,
{ optional = false }: { optional?: boolean } = {},
): Promise<string> {
try {
const response = await fetch(url)
if (!response.ok) {
Expand All @@ -14,6 +17,7 @@ async function fetchFileContent(url: string): Promise<string> {
}
return await response.text()
} catch (error) {
if (optional) return ""
console.error("Error fetching file content:", error)
throw error
}
Expand Down Expand Up @@ -44,13 +48,21 @@ export const createLocalCircuitPrompt = async () => {
.join("\n")
.replace(/\n\n+/g, "\n\n")

const generatedDocs = (
await fetchFileContent("https://docs.tscircuit.com/ai.txt", {
optional: true,
})
).trim()

return `
You are an expert in electronic circuit design and tscircuit, and your job is to create a circuit board in tscircuit with the user-provided description.

YOU MUST ABIDE BY THE RULES IN THE RULES SECTION

## tscircuit API overview

${generatedDocs ? `### Generated tscircuit docs\n\n${generatedDocs}\n\n` : ""}

Here's an overview of the tscircuit API:

<board width="10mm" height="10mm" /> // usually the root component
Expand Down
64 changes: 64 additions & 0 deletions tests/prompt-templates/create-local-circuit-prompt.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { afterEach, expect, test } from "bun:test"
import { createLocalCircuitPrompt } from "../../lib/prompt-templates/create-local-circuit-prompt"

const originalFetch = globalThis.fetch

afterEach(() => {
globalThis.fetch = originalFetch
})

test("includes generated tscircuit docs in the local circuit prompt", async () => {
const fetchedUrls: string[] = []

globalThis.fetch = (async (url: string | URL | Request) => {
const urlString = String(url)
fetchedUrls.push(urlString)

if (urlString === "https://docs.tscircuit.com/ai.txt") {
return new Response("Generated docs: use schematic-only examples")
}

if (
urlString ===
"https://raw.githubusercontent.com/tscircuit/props/main/generated/COMPONENT_TYPES.md"
) {
return new Response('# Component Types\n<resistor resistance="1k" />')
}

return new Response("Not found", { status: 404, statusText: "Not Found" })
}) as typeof fetch

const prompt = await createLocalCircuitPrompt()

expect(fetchedUrls).toContain("https://docs.tscircuit.com/ai.txt")
expect(prompt).toContain("### Generated tscircuit docs")
expect(prompt).toContain("Generated docs: use schematic-only examples")
})

test("still creates the local circuit prompt when generated docs are unavailable", async () => {
globalThis.fetch = (async (url: string | URL | Request) => {
const urlString = String(url)

if (urlString === "https://docs.tscircuit.com/ai.txt") {
return new Response("Temporarily unavailable", {
status: 503,
statusText: "Service Unavailable",
})
}

if (
urlString ===
"https://raw.githubusercontent.com/tscircuit/props/main/generated/COMPONENT_TYPES.md"
) {
return new Response('# Component Types\n<capacitor capacitance="1uF" />')
}

return new Response("Not found", { status: 404, statusText: "Not Found" })
}) as typeof fetch

const prompt = await createLocalCircuitPrompt()

expect(prompt).toContain("You are an expert in electronic circuit design")
expect(prompt).toContain('<capacitor capacitance="1uF" />')
expect(prompt).not.toContain("Temporarily unavailable")
})
77 changes: 41 additions & 36 deletions tests/tscircuitCoder.test.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,44 @@
import { createTscircuitCoder } from "lib/tscircuit-coder/tscircuitCoder"
import { expect, test } from "bun:test"
import { createTscircuitCoder } from "lib/tscircuit-coder/tscircuitCoder"
import { getPrimarySourceCodeFromVfs } from "lib/utils/get-primary-source-code-from-vfs"

test("TscircuitCoder submitPrompt streams and updates vfs", async () => {
const streamedChunks: string[] = []
let vfsUpdated = false
const tscircuitCoder = createTscircuitCoder()
tscircuitCoder.on("streamedChunk", (chunk: string) => {
streamedChunks.push(chunk)
})
tscircuitCoder.on("vfsChanged", () => {
vfsUpdated = true
})

await tscircuitCoder.submitPrompt({
prompt: "create bridge rectifier circuit",
})

await tscircuitCoder.submitPrompt({
prompt: "add a transistor component",
})

let codeWithTransistor = getPrimarySourceCodeFromVfs(tscircuitCoder.vfs)
expect(codeWithTransistor).toInclude("transistor")

await tscircuitCoder.submitPrompt({
prompt: "add a tssop20 chip",
})

let codeWithChip = getPrimarySourceCodeFromVfs(tscircuitCoder.vfs)
expect(codeWithChip).toInclude("tssop20")
expect(codeWithChip).toInclude("transistor")

expect(streamedChunks.length).toBeGreaterThan(0)
const vfsKeys = Object.keys(tscircuitCoder.vfs)
expect(vfsKeys.length).toBeGreaterThan(0)
expect(vfsUpdated).toBe(true)
})
const testWithOpenAiKey = process.env.OPENAI_API_KEY ? test : test.skip

testWithOpenAiKey(
"TscircuitCoder submitPrompt streams and updates vfs",
async () => {
const streamedChunks: string[] = []
let vfsUpdated = false
const tscircuitCoder = createTscircuitCoder()
tscircuitCoder.on("streamedChunk", (chunk: string) => {
streamedChunks.push(chunk)
})
tscircuitCoder.on("vfsChanged", () => {
vfsUpdated = true
})

await tscircuitCoder.submitPrompt({
prompt: "create bridge rectifier circuit",
})

await tscircuitCoder.submitPrompt({
prompt: "add a transistor component",
})

const codeWithTransistor = getPrimarySourceCodeFromVfs(tscircuitCoder.vfs)
expect(codeWithTransistor).toInclude("transistor")

await tscircuitCoder.submitPrompt({
prompt: "add a tssop20 chip",
})

const codeWithChip = getPrimarySourceCodeFromVfs(tscircuitCoder.vfs)
expect(codeWithChip).toInclude("tssop20")
expect(codeWithChip).toInclude("transistor")

expect(streamedChunks.length).toBeGreaterThan(0)
const vfsKeys = Object.keys(tscircuitCoder.vfs)
expect(vfsKeys.length).toBeGreaterThan(0)
expect(vfsUpdated).toBe(true)
},
)
6 changes: 4 additions & 2 deletions tests/utils/generate-random-prompts.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { describe, it, expect } from "bun:test"
import { describe, expect, it } from "bun:test"
import { generateRandomPrompts } from "../../lib/utils/generate-random-prompts"

const itWithOpenAiKey = process.env.OPENAI_API_KEY ? it : it.skip

describe("generateRandomPrompts", () => {
it("should return an array of prompts", async () => {
itWithOpenAiKey("should return an array of prompts", async () => {
const prompts = await generateRandomPrompts(3)

expect(Array.isArray(prompts)).toBe(true)
Expand Down
Loading