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

async function fetchFileContent(url: string): Promise<string> {
Expand All @@ -19,6 +19,25 @@ async function fetchFileContent(url: string): Promise<string> {
}
}

const GENERATED_DOCS_URL = "https://docs.tscircuit.com/ai.txt"

let generatedDocsPromise: Promise<string> | null = null

const fetchGeneratedDocs = async () => {
generatedDocsPromise ??= fetchFileContent(GENERATED_DOCS_URL).catch(
(error) => {
console.error("Error fetching generated tscircuit docs:", error)
return ""
},
)

return generatedDocsPromise
}

export const clearGeneratedDocsCacheForTests = () => {
generatedDocsPromise = null
}

export const createLocalCircuitPrompt = async () => {
const footprintNamesByType = getFootprintNamesByType()
const footprintSizes = getFootprintSizes()
Expand All @@ -33,22 +52,33 @@ export const createLocalCircuitPrompt = async () => {
"",
)

const propsDoc =
(await fetchFileContent(
const [propsDoc, generatedDocs] = await Promise.all([
fetchFileContent(
"https://raw.githubusercontent.com/tscircuit/props/main/generated/COMPONENT_TYPES.md",
)) || ""
),
fetchGeneratedDocs(),
])

const cleanedPropsDoc = propsDoc
.split("\n")
.filter((line) => !line.startsWith("#"))
.join("\n")
.replace(/\n\n+/g, "\n\n")

const generatedDocsSection = generatedDocs.trim()
? `
## Generated tscircuit docs

${generatedDocs.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

${generatedDocsSection}
## tscircuit API overview

Here's an overview of the tscircuit API:
Expand Down
59 changes: 59 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,59 @@
import { afterEach, beforeEach, expect, it } from "bun:test"
import {
clearGeneratedDocsCacheForTests,
createLocalCircuitPrompt,
} from "lib/prompt-templates/create-local-circuit-prompt"

const originalFetch = globalThis.fetch
const originalConsoleError = console.error

beforeEach(() => {
clearGeneratedDocsCacheForTests()
console.error = () => {}
})

afterEach(() => {
globalThis.fetch = originalFetch
console.error = originalConsoleError
clearGeneratedDocsCacheForTests()
})

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

globalThis.fetch = (async (input: RequestInfo | URL) => {
const url = input.toString()
requestedUrls.push(url)

if (url === "https://docs.tscircuit.com/ai.txt") {
return new Response("GENERATED_AI_DOCS_SENTINEL", { status: 200 })
}

return new Response("# Components\nmock component props", { status: 200 })
}) as typeof fetch

const prompt = await createLocalCircuitPrompt()

expect(prompt).toContain("## Generated tscircuit docs")
expect(prompt).toContain("GENERATED_AI_DOCS_SENTINEL")
expect(prompt).toContain("mock component props")
expect(requestedUrls).toContain("https://docs.tscircuit.com/ai.txt")
})

it("still creates a local circuit prompt when generated docs fetch fails", async () => {
globalThis.fetch = (async (input: RequestInfo | URL) => {
const url = input.toString()

if (url === "https://docs.tscircuit.com/ai.txt") {
return new Response("not found", { status: 404, statusText: "Not Found" })
}

return new Response("# Components\nmock component props", { status: 200 })
}) as typeof fetch

const prompt = await createLocalCircuitPrompt()

expect(prompt).toContain("## tscircuit API overview")
expect(prompt).toContain("mock component props")
expect(prompt).not.toContain("## Generated tscircuit docs")
})
10 changes: 6 additions & 4 deletions tests/tscircuitCoder.test.ts → tests/tscircuit-coder.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
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 openAiTest = process.env.OPENAI_API_KEY ? test : test.skip

openAiTest("TscircuitCoder submitPrompt streams and updates vfs", async () => {
const streamedChunks: string[] = []
let vfsUpdated = false
const tscircuitCoder = createTscircuitCoder()
Expand All @@ -21,14 +23,14 @@ test("TscircuitCoder submitPrompt streams and updates vfs", async () => {
prompt: "add a transistor component",
})

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

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

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

Expand Down
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"

describe("generateRandomPrompts", () => {
it("should return an array of prompts", async () => {
const openAiIt = process.env.OPENAI_API_KEY ? it : it.skip

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

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