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
33 changes: 29 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,18 @@ async function fetchFileContent(url: string): Promise<string> {
}
}

async function fetchOptionalFileContent(url: string): Promise<string> {
try {
const response = await fetch(url)
if (!response.ok) {
return ""
}
return await response.text()
} catch {
return ""
}
}

export const createLocalCircuitPrompt = async () => {
const footprintNamesByType = getFootprintNamesByType()
const footprintSizes = getFootprintSizes()
Expand All @@ -33,22 +45,35 @@ 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",
)) || ""
),
fetchOptionalFileContent("https://docs.tscircuit.com/ai.txt"),
])

const cleanedPropsDoc = propsDoc
.split("\n")
.filter((line) => !line.startsWith("#"))
.join("\n")
.replace(/\n\n+/g, "\n\n")
const cleanedGeneratedDocs = generatedDocs.trim().replace(/\n\n+/g, "\n\n")
const generatedDocsSection = cleanedGeneratedDocs
? `## tscircuit Generated Documentation

The following documentation is generated from the current tscircuit docs:

${cleanedGeneratedDocs}

`
: ""

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
62 changes: 62 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,62 @@
import { afterEach, describe, expect, it } from "bun:test"
import { createLocalCircuitPrompt } from "../../lib/prompt-templates/create-local-circuit-prompt"

const originalFetch = globalThis.fetch

const createTextResponse = (
body: string,
options: { ok?: boolean; status?: number; statusText?: string } = {},
) =>
({
ok: options.ok ?? true,
status: options.status ?? 200,
statusText: options.statusText ?? "OK",
text: async () => body,
}) as Response

describe("createLocalCircuitPrompt", () => {
afterEach(() => {
globalThis.fetch = originalFetch
})

it("includes generated docs from the ai.txt feed", async () => {
const fetchedUrls: string[] = []
globalThis.fetch = (async (url: RequestInfo | URL) => {
const urlString = url.toString()
fetchedUrls.push(urlString)

if (urlString === "https://docs.tscircuit.com/ai.txt") {
return createTextResponse("Generated docs content for <board />")
}

return createTextResponse("# Component Types\n\n<board /> props doc")
}) as typeof fetch

const prompt = await createLocalCircuitPrompt()

expect(fetchedUrls).toContain("https://docs.tscircuit.com/ai.txt")
expect(prompt).toContain("## tscircuit Generated Documentation")
expect(prompt).toContain("Generated docs content for <board />")
})

it("keeps creating prompts when the generated docs feed is unavailable", async () => {
globalThis.fetch = (async (url: RequestInfo | URL) => {
const urlString = url.toString()

if (urlString === "https://docs.tscircuit.com/ai.txt") {
return createTextResponse("Not found", {
ok: false,
status: 404,
statusText: "Not Found",
})
}

return createTextResponse("# Component Types\n\n<resistor /> props doc")
}) as typeof fetch

const prompt = await createLocalCircuitPrompt()

expect(prompt).not.toContain("## tscircuit Generated Documentation")
expect(prompt).toContain("<resistor /> props doc")
})
})
44 changes: 44 additions & 0 deletions tests/tscircuit-coder.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { expect, test } from "bun:test"
import { createTscircuitCoder } from "lib/tscircuit-coder/tscircuitCoder"
import { getPrimarySourceCodeFromVfs } from "lib/utils/get-primary-source-code-from-vfs"

const testWithOpenAI = process.env.OPENAI_API_KEY ? test : test.skip

testWithOpenAI(
"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)
},
)
39 changes: 0 additions & 39 deletions tests/tscircuitCoder.test.ts

This file was deleted.

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, test } from "bun:test"
import { generateRandomPrompts } from "../../lib/utils/generate-random-prompts"

const testWithOpenAI = process.env.OPENAI_API_KEY ? test : test.skip

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

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