Skip to content

Commit 825d4d5

Browse files
committed
Include generated docs in local circuit prompt
1 parent 0fd302e commit 825d4d5

4 files changed

Lines changed: 121 additions & 42 deletions

File tree

lib/prompt-templates/create-local-circuit-prompt.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
2+
fp,
23
getFootprintNamesByType,
34
getFootprintSizes,
4-
fp,
55
} from "@tscircuit/footprinter"
66

77
async function fetchFileContent(url: string): Promise<string> {
@@ -19,6 +19,18 @@ async function fetchFileContent(url: string): Promise<string> {
1919
}
2020
}
2121

22+
async function fetchOptionalFileContent(url: string): Promise<string> {
23+
try {
24+
const response = await fetch(url)
25+
if (!response.ok) {
26+
return ""
27+
}
28+
return await response.text()
29+
} catch {
30+
return ""
31+
}
32+
}
33+
2234
export const createLocalCircuitPrompt = async () => {
2335
const footprintNamesByType = getFootprintNamesByType()
2436
const footprintSizes = getFootprintSizes()
@@ -33,22 +45,33 @@ export const createLocalCircuitPrompt = async () => {
3345
"",
3446
)
3547

36-
const propsDoc =
37-
(await fetchFileContent(
48+
const [propsDoc, generatedDocs] = await Promise.all([
49+
fetchFileContent(
3850
"https://raw.githubusercontent.com/tscircuit/props/main/generated/COMPONENT_TYPES.md",
39-
)) || ""
51+
),
52+
fetchOptionalFileContent("https://docs.tscircuit.com/ai.txt"),
53+
])
4054

4155
const cleanedPropsDoc = propsDoc
4256
.split("\n")
4357
.filter((line) => !line.startsWith("#"))
4458
.join("\n")
4559
.replace(/\n\n+/g, "\n\n")
4660

61+
const generatedDocsSection = generatedDocs.trim()
62+
? `
63+
## Auto-generated tscircuit docs
64+
65+
${generatedDocs.trim()}
66+
`
67+
: ""
68+
4769
return `
4870
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.
4971
5072
YOU MUST ABIDE BY THE RULES IN THE RULES SECTION
5173
74+
${generatedDocsSection}
5275
## tscircuit API overview
5376
5477
Here's an overview of the tscircuit API:
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { afterEach, describe, expect, it } from "bun:test"
2+
import { createLocalCircuitPrompt } from "../../lib/prompt-templates/create-local-circuit-prompt"
3+
4+
const originalFetch = globalThis.fetch
5+
6+
afterEach(() => {
7+
globalThis.fetch = originalFetch
8+
})
9+
10+
describe("createLocalCircuitPrompt", () => {
11+
it("includes generated ai docs when available", async () => {
12+
globalThis.fetch = (async (url) => {
13+
const href = url.toString()
14+
if (href.includes("COMPONENT_TYPES.md")) {
15+
return new Response("# Components\n\n<resistor />", { status: 200 })
16+
}
17+
if (href === "https://docs.tscircuit.com/ai.txt") {
18+
return new Response("Generated docs: use <smtpad /> carefully.", {
19+
status: 200,
20+
})
21+
}
22+
throw new Error(`Unexpected fetch URL: ${href}`)
23+
}) as typeof fetch
24+
25+
const prompt = await createLocalCircuitPrompt()
26+
27+
expect(prompt).toContain("## Auto-generated tscircuit docs")
28+
expect(prompt).toContain("Generated docs: use <smtpad /> carefully.")
29+
})
30+
31+
it("still creates a prompt when generated ai docs are unavailable", async () => {
32+
globalThis.fetch = (async (url) => {
33+
const href = url.toString()
34+
if (href.includes("COMPONENT_TYPES.md")) {
35+
return new Response("# Components\n\n<capacitor />", { status: 200 })
36+
}
37+
if (href === "https://docs.tscircuit.com/ai.txt") {
38+
return new Response("missing", { status: 503, statusText: "Down" })
39+
}
40+
throw new Error(`Unexpected fetch URL: ${href}`)
41+
}) as typeof fetch
42+
43+
const prompt = await createLocalCircuitPrompt()
44+
45+
expect(prompt).toContain("## tscircuit API overview")
46+
expect(prompt).toContain("<capacitor />")
47+
expect(prompt).not.toContain("## Auto-generated tscircuit docs")
48+
})
49+
})

tests/tscircuitCoder.test.ts

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,44 @@
1-
import { createTscircuitCoder } from "lib/tscircuit-coder/tscircuitCoder"
21
import { expect, test } from "bun:test"
2+
import { createTscircuitCoder } from "lib/tscircuit-coder/tscircuitCoder"
33
import { getPrimarySourceCodeFromVfs } from "lib/utils/get-primary-source-code-from-vfs"
44

5-
test("TscircuitCoder submitPrompt streams and updates vfs", async () => {
6-
const streamedChunks: string[] = []
7-
let vfsUpdated = false
8-
const tscircuitCoder = createTscircuitCoder()
9-
tscircuitCoder.on("streamedChunk", (chunk: string) => {
10-
streamedChunks.push(chunk)
11-
})
12-
tscircuitCoder.on("vfsChanged", () => {
13-
vfsUpdated = true
14-
})
15-
16-
await tscircuitCoder.submitPrompt({
17-
prompt: "create bridge rectifier circuit",
18-
})
19-
20-
await tscircuitCoder.submitPrompt({
21-
prompt: "add a transistor component",
22-
})
23-
24-
let codeWithTransistor = getPrimarySourceCodeFromVfs(tscircuitCoder.vfs)
25-
expect(codeWithTransistor).toInclude("transistor")
26-
27-
await tscircuitCoder.submitPrompt({
28-
prompt: "add a tssop20 chip",
29-
})
30-
31-
let codeWithChip = getPrimarySourceCodeFromVfs(tscircuitCoder.vfs)
32-
expect(codeWithChip).toInclude("tssop20")
33-
expect(codeWithChip).toInclude("transistor")
34-
35-
expect(streamedChunks.length).toBeGreaterThan(0)
36-
const vfsKeys = Object.keys(tscircuitCoder.vfs)
37-
expect(vfsKeys.length).toBeGreaterThan(0)
38-
expect(vfsUpdated).toBe(true)
39-
})
5+
const testWithOpenAi = process.env.OPENAI_API_KEY ? test : test.skip
6+
7+
testWithOpenAi(
8+
"TscircuitCoder submitPrompt streams and updates vfs",
9+
async () => {
10+
const streamedChunks: string[] = []
11+
let vfsUpdated = false
12+
const tscircuitCoder = createTscircuitCoder()
13+
tscircuitCoder.on("streamedChunk", (chunk: string) => {
14+
streamedChunks.push(chunk)
15+
})
16+
tscircuitCoder.on("vfsChanged", () => {
17+
vfsUpdated = true
18+
})
19+
20+
await tscircuitCoder.submitPrompt({
21+
prompt: "create bridge rectifier circuit",
22+
})
23+
24+
await tscircuitCoder.submitPrompt({
25+
prompt: "add a transistor component",
26+
})
27+
28+
const codeWithTransistor = getPrimarySourceCodeFromVfs(tscircuitCoder.vfs)
29+
expect(codeWithTransistor).toInclude("transistor")
30+
31+
await tscircuitCoder.submitPrompt({
32+
prompt: "add a tssop20 chip",
33+
})
34+
35+
const codeWithChip = getPrimarySourceCodeFromVfs(tscircuitCoder.vfs)
36+
expect(codeWithChip).toInclude("tssop20")
37+
expect(codeWithChip).toInclude("transistor")
38+
39+
expect(streamedChunks.length).toBeGreaterThan(0)
40+
const vfsKeys = Object.keys(tscircuitCoder.vfs)
41+
expect(vfsKeys.length).toBeGreaterThan(0)
42+
expect(vfsUpdated).toBe(true)
43+
},
44+
)

tests/utils/generate-random-prompts.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { describe, it, expect } from "bun:test"
1+
import { describe, expect, it } from "bun:test"
22
import { generateRandomPrompts } from "../../lib/utils/generate-random-prompts"
33

4+
const itWithOpenAi = process.env.OPENAI_API_KEY ? it : it.skip
5+
46
describe("generateRandomPrompts", () => {
5-
it("should return an array of prompts", async () => {
7+
itWithOpenAi("should return an array of prompts", async () => {
68
const prompts = await generateRandomPrompts(3)
79

810
expect(Array.isArray(prompts)).toBe(true)

0 commit comments

Comments
 (0)