Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
782e715
feat: add get-system-prompt utility that incorporates auto-generated …
SyedHannanMehdi Mar 29, 2026
dec6b9d
feat: add script to fetch and cache auto-generated tscircuit docs
SyedHannanMehdi Mar 29, 2026
0176828
feat: add getSystemPromptWithDocs that merges base prompt with auto-g…
SyedHannanMehdi Mar 29, 2026
2e1adde
feat: expose systemPrompt with docs for use in eval files
SyedHannanMehdi Mar 29, 2026
2bf336d
feat: update system-prompt to include auto-generated tscircuit docs
SyedHannanMehdi Mar 29, 2026
f8b3dc1
chore: ensure assets directory is tracked by git
SyedHannanMehdi Mar 29, 2026
e063baf
refactor: extract shared BASE_SYSTEM_PROMPT to eliminate duplication …
SyedHannanMehdi Mar 29, 2026
66678c2
fix: use node: specifier for built-in imports; clarify docstring; use…
SyedHannanMehdi Mar 29, 2026
88aaca7
fix: use node: specifier, shared BASE_SYSTEM_PROMPT, consistent <tsci…
SyedHannanMehdi Mar 29, 2026
bf7bd8f
fix: use node: specifier, shared BASE_SYSTEM_PROMPT, consistent <tsci…
SyedHannanMehdi Mar 29, 2026
85c9baa
fix: use node: specifier with default imports for fs and path (align …
SyedHannanMehdi Mar 29, 2026
6f6aa54
fix: use getSystemPromptWithDocs() so eval output is wrapped in <tsci…
SyedHannanMehdi Mar 29, 2026
bb6210a
feat: add getSystemPrompt with auto-generated docs integration
SyedHannanMehdi Mar 29, 2026
7896fea
feat: use @tscircuit/snippets-ai-docs in system prompt
SyedHannanMehdi Mar 29, 2026
142d525
feat: integrate auto-generated docs from @tscircuit/snippets-ai-docs …
SyedHannanMehdi Mar 29, 2026
b9c83ff
fix(scripts): use node: specifier with default imports for fs and path
SyedHannanMehdi Mar 29, 2026
28d961c
feat(lib): extract shared base system prompt builder to eliminate dup…
SyedHannanMehdi Mar 29, 2026
2d695ce
fix(lib): use node: imports, fix misleading docstring, use shared bas…
SyedHannanMehdi Mar 29, 2026
6a6e1a8
fix(lib): use shared base prompt and wrap docs in <tscircuit_docs> block
SyedHannanMehdi Mar 29, 2026
957f1ac
fix(lib): consolidate base prompt, use <tscircuit_docs> wrapper, remo…
SyedHannanMehdi Mar 29, 2026
8c628f6
fix(evals): use getSystemPromptWithDocs which wraps docs in <tscircui…
SyedHannanMehdi Mar 29, 2026
8aca7e8
Add auto-generated docs integration for system prompt
SyedHannanMehdi Mar 30, 2026
bd915ac
Add getSystemPrompt with auto-generated docs fetching
SyedHannanMehdi Mar 30, 2026
4c24823
Add placeholder for generated system prompt asset
SyedHannanMehdi Mar 30, 2026
f466f97
feat: use auto-generated docs in system prompt (fixes #45)
SyedHannanMehdi Mar 30, 2026
cedd104
feat: add script to update local docs cache
SyedHannanMehdi Mar 30, 2026
fb07165
feat: load auto-generated docs from local cache with remote fallback
SyedHannanMehdi Mar 30, 2026
0720729
fix: use node: specifier for fs/path imports in update-docs.ts
SyedHannanMehdi Mar 30, 2026
74204b9
feat: extract shared getBaseSystemPrompt() to eliminate prompt duplic…
SyedHannanMehdi Mar 30, 2026
65f9010
fix: use node: specifier imports, fix misleading docstring, use share…
SyedHannanMehdi Mar 30, 2026
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
Empty file added assets/.gitkeep
Empty file.
4 changes: 4 additions & 0 deletions assets/system-prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# tscircuit AI System Prompt

This file is auto-generated. Do not edit manually.
See scripts/generate-system-prompt.ts to regenerate.
13 changes: 13 additions & 0 deletions evals/eval-with-docs.eval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Eval entry-point that uses a docs-augmented system prompt.
*
* The prompt is built synchronously from the cached docs file
* (`assets/tscircuit-docs.md`). Run `bun scripts/update-docs.ts` first to
* populate the cache.
*
* Docs are wrapped in a `<tscircuit_docs>` XML block so the model can clearly
* identify the reference material.
*/
import { getSystemPromptWithDocs } from "../lib/get-system-prompt-with-docs"

export const systemPrompt = getSystemPromptWithDocs()
31 changes: 31 additions & 0 deletions lib/base-system-prompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Shared base system prompt builder used by all tscircuit prompt benchmark
* variants. Each variant (with docs, without docs, async fetch, etc.) should
* call `getBaseSystemPrompt()` and only customise the docs-loading/wrapping
* strategy on top of it.
*/
export function getBaseSystemPrompt(): string {
return `You are an expert tscircuit developer. tscircuit is a TypeScript library for
creating electronic circuit schematics and PCB layouts using a React-like syntax.

Rules:
- Only output a single tscircuit snippet
- Use only tscircuit components (resistor, capacitor, chip, etc.)
- Do NOT import anything — tscircuit components are available globally in snippets
- Do NOT use \`ReactDOM.render\` or \`import React\`
- The root component export must be named \`MyCircuit\` and use \`export default\`
- Only output the code block, no explanation

Example snippet:

\`\`\`tsx
export default function MyCircuit() {
return (
<board width="10mm" height="10mm">
<resistor resistance="10kohm" footprint="0402" name="R1" schX={3} schY={0} />
</board>
)
}
\`\`\`
`
}
37 changes: 37 additions & 0 deletions lib/get-system-prompt-with-docs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import fs from "node:fs"
import path from "node:path"
import { getBaseSystemPromptText } from "./base-system-prompt"

const CACHED_DOCS_PATH = path.join(
path.dirname(new URL(import.meta.url).pathname),
"../assets/tscircuit-docs.md",
)

/**
* Returns the base system prompt without any docs appended.
* Useful when you want to measure model performance without extra context.
*/
export function getBaseSystemPrompt(): string {
return getBaseSystemPromptText()
}

/**
* Returns the base system prompt with cached component docs appended inside
* a `<tscircuit_docs>` XML block. Falls back to the base prompt if the cache
* file does not exist (run `bun scripts/update-docs.ts` to populate it).
*/
export function getSystemPromptWithDocs(): string {
const base = getBaseSystemPromptText()

if (!fs.existsSync(CACHED_DOCS_PATH)) {
return base
}

const docs = fs.readFileSync(CACHED_DOCS_PATH, "utf-8")

return `${base}
<tscircuit_docs>
${docs.trim()}
</tscircuit_docs>
`
}
109 changes: 109 additions & 0 deletions lib/get-system-prompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* lib/get-system-prompt.ts
*
* Builds the system prompt for tscircuit AI evaluations, incorporating the
* auto-generated component documentation so it stays up-to-date automatically.
*
* Doc source priority:
* 1. assets/tscircuit-docs.md — local cache (committed or generated via
* `bun run update-docs` / `npx tsx scripts/update-docs-cache.ts`)
* 2. Live fetch from GitHub raw URL at runtime
* 3. Empty string (graceful degradation — base prompt still works)
*
* See: https://github.com/tscircuit/prompt-benchmarks/issues/45
*/

import fs from "node:fs/promises"
import path from "node:path"

const DOCS_REMOTE_URL =
"https://raw.githubusercontent.com/tscircuit/docs/main/ai-docs/FULL_DOCS.md"

const DOCS_LOCAL_PATH = path.resolve(
// Works whether this file is in lib/ or dist/lib/
path.dirname(new URL(import.meta.url).pathname),
"..",
"assets",
"tscircuit-docs.md",
)

let _cachedDocs: string | null = null

/**
* Loads the auto-generated tscircuit component docs.
* Tries the local asset first, then falls back to a live network fetch.
* Results are memoised in-process.
*/
export async function fetchAutoGeneratedDocs(): Promise<string> {
if (_cachedDocs !== null) return _cachedDocs

// 1. Try local cache
try {
const local = await fs.readFile(DOCS_LOCAL_PATH, "utf-8")
if (local.trim()) {
_cachedDocs = local
return _cachedDocs
}
} catch {
// File doesn't exist — fall through to network fetch
}

// 2. Try remote fetch
try {
const res = await fetch(DOCS_REMOTE_URL)
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`)
_cachedDocs = await res.text()
} catch (err) {
console.warn(
`[get-system-prompt] Warning: could not load auto-generated docs.\n` +
` Local path: ${DOCS_LOCAL_PATH}\n` +
` Remote URL: ${DOCS_REMOTE_URL}\n`,
err,
)
_cachedDocs = ""
}

return _cachedDocs
}

/** Clear the in-process docs cache (useful in tests). */
export function clearDocsCache() {
_cachedDocs = null
}

/**
* Returns the full system prompt string with auto-generated docs embedded.
*/
export async function getSystemPrompt(): Promise<string> {
const docs = await fetchAutoGeneratedDocs()

const docsSection = docs.trim()
? `\n# tscircuit Component Reference (Auto-Generated)\n\n${docs.trim()}\n`
: ""

return `You are an expert electronics engineer using tscircuit — a TypeScript/React library that lets you design circuits with JSX syntax. Circuits you write are compiled to schematics, PCB layouts, and netlists.
${docsSection}
# Rules

1. Always output a **single TSX code block** — no prose before or after.
2. Wrap everything in a \`<board />\` with realistic dimensions in millimetres, e.g. \`<board width={20} height={20}>\`.
3. Use standard reference designators: R1, C1, L1, U1, D1, LED1, Q1, SW1, J1 …
4. Connect pins with \`<trace from=".R1 > .pin1" to=".C1 > .plus" />\`.
Selector format: \`".<refdes> > .<pinLabel>"\`
5. Use metric SMD footprints for passives: 0402, 0603, 0805, 1206.
6. Export the circuit as the **default export**.
7. Do not add explanatory comments unless essential.

# Minimal example

\`\`\`tsx
export default () => (
<board width={20} height={20}>
<resistor name="R1" resistance="10kohm" footprint="0402" schX={0} schY={0} />
<led name="LED1" color="red" footprint="0402" schX={3} schY={0} />
<trace from=".R1 > .pin2" to=".LED1 > .anode" />
</board>
)
\`\`\`
`
}
48 changes: 48 additions & 0 deletions lib/getSystemPrompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const TSCIRCUIT_DOCS_URL =
"https://raw.githubusercontent.com/tscircuit/docs/main/ai-docs/FULL_DOCS.md"

let cachedDocs: string | null = null

/**
* Fetches the auto-generated tscircuit documentation from the docs repo.
* Falls back to a minimal inline doc string if the fetch fails.
*/
export async function getAutoGeneratedDocs(): Promise<string> {
if (cachedDocs !== null) return cachedDocs

try {
const response = await fetch(TSCIRCUIT_DOCS_URL)
if (!response.ok) {
throw new Error(`Failed to fetch docs: ${response.status} ${response.statusText}`)
}
cachedDocs = await response.text()
return cachedDocs
} catch (e) {
console.warn("[getSystemPrompt] Could not fetch auto-generated docs:", e)
cachedDocs = ""
return cachedDocs
}
}

/**
* Returns the full system prompt for the tscircuit AI benchmark,
* incorporating the latest auto-generated component documentation.
*/
export async function getSystemPrompt(): Promise<string> {
const autoGeneratedDocs = await getAutoGeneratedDocs()

return `You are an expert tscircuit developer. tscircuit lets you design electronics using React/TypeScript (TSX). Circuits are expressed as JSX trees and can be converted to schematics, PCB layouts, and netlists.

${autoGeneratedDocs}

# Instructions

- Output valid TSX that can be run directly with tscircuit
- Always wrap your circuit in a \`<board />\` element with appropriate width/height (in mm)
- Use descriptive reference designators (R1, C1, U1, LED1, etc.)
- Connect component pins using \`<trace from="..." to="..." />\`
- The \`from\` / \`to\` selector format is \`".<refdes> > .<pinLabel>"\` e.g. \`".R1 > .pin1"\`
- Export your circuit as the default export
- Do not add unnecessary comments or explanation — just output the TSX code block
`
}
43 changes: 43 additions & 0 deletions lib/system-prompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import fs from "node:fs"
import path from "node:path"
import { getBaseSystemPrompt } from "./base-system-prompt"

const DOCS_PATH = path.join(
import.meta.dirname ?? __dirname,
"../assets/tscircuit-docs.md",
)

/**
* Returns the base system prompt without docs appended.
*
* If you need the prompt with auto-generated component docs included, use
* `getSystemPromptWithCachedDocs()` (which wraps docs in a `<tscircuit_docs>`
* block) or the async `getSystemPrompt()` from `lib/get-system-prompt.ts`.
*/
export function getSystemPromptBase(): string {
return getBaseSystemPrompt()
}

/**
* Returns the base system prompt with auto-generated tscircuit component docs
* appended (read from the local `assets/tscircuit-docs.md` cache).
*
* The docs are wrapped in a `<tscircuit_docs>` XML block so that models can
* clearly distinguish the reference material from the instructions.
*
* Run `npx tsx scripts/update-docs.ts` to refresh the cached docs file.
*/
export function getSystemPromptWithCachedDocs(): string {
const base = getBaseSystemPrompt()

if (!fs.existsSync(DOCS_PATH)) {
console.warn(
"[system-prompt] assets/tscircuit-docs.md not found — returning base prompt without docs. " +
"Run `npx tsx scripts/update-docs.ts` to generate it.",
)
return base
}

const docs = fs.readFileSync(DOCS_PATH, "utf-8")
return `${base}\n<tscircuit_docs>\n${docs}\n</tscircuit_docs>\n`
}
49 changes: 49 additions & 0 deletions scripts/update-docs-cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* scripts/update-docs-cache.ts
*
* Downloads the latest auto-generated tscircuit docs and writes them to
* assets/tscircuit-docs.md so the system prompt can reference them without a
* network call at evaluation time.
*
* Usage:
* npx tsx scripts/update-docs-cache.ts
* # or via package.json:
* bun run update-docs
*/

import fs from "node:fs/promises"
import path from "node:path"

const DOCS_URL =
"https://raw.githubusercontent.com/tscircuit/docs/main/ai-docs/FULL_DOCS.md"

const OUTPUT_PATH = path.resolve(
path.dirname(new URL(import.meta.url).pathname),
"..",
"assets",
"tscircuit-docs.md",
)

async function main() {
console.log(`Fetching docs from:\n ${DOCS_URL}\n`)

const res = await fetch(DOCS_URL)
if (!res.ok) {
throw new Error(`Failed to fetch docs: ${res.status} ${res.statusText}`)
}

const content = await res.text()

await fs.mkdir(path.dirname(OUTPUT_PATH), { recursive: true })
await fs.writeFile(OUTPUT_PATH, content, "utf-8")

const lines = content.split("\n").length
console.log(
`✓ Wrote ${lines} lines (${content.length} bytes) to:\n ${OUTPUT_PATH}`,
)
}

main().catch((err) => {
console.error("Error updating docs cache:", err)
process.exit(1)
})
35 changes: 35 additions & 0 deletions scripts/update-docs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import fs from "node:fs"
import path from "node:path"

const DOCS_URL =
"https://raw.githubusercontent.com/tscircuit/tscircuit/main/docs/COMPONENTS.md"

const ASSETS_DIR = path.join(import.meta.dirname ?? __dirname, "../assets")
const OUTPUT_PATH = path.join(ASSETS_DIR, "tscircuit-docs.md")

async function fetchDocs(): Promise<string> {
const response = await fetch(DOCS_URL)
if (!response.ok) {
throw new Error(
`Failed to fetch docs: ${response.status} ${response.statusText}`,
)
}
return response.text()
}

async function main() {
console.log("Fetching tscircuit auto-generated docs...")
const docs = await fetchDocs()

if (!fs.existsSync(ASSETS_DIR)) {
fs.mkdirSync(ASSETS_DIR, { recursive: true })
}

fs.writeFileSync(OUTPUT_PATH, docs, "utf-8")
console.log(`Docs written to ${OUTPUT_PATH} (${docs.length} bytes)`)
}

main().catch((err) => {
console.error(err)
process.exit(1)
})
Loading