Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/7flash_jsx-ai.json
T
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
10 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "7flash/jsx-ai", "files": {"README.md": {"eca6e7ab1568f07695dd31dc37b8c9cbe0047a11": {"t": 1786068586.1974843, "n": 9535, "h": "7fb3e4ca66bd0fd8", "c": "# jsx-ai\n\n[![npm](https://img.shields.io/npm/v/jsx-ai.svg?style=flat-square)](https://www.npmjs.com/package/jsx-ai)\n[![bundle](https://img.shields.io/bundlephobia/minzip/jsx-ai?style=flat-square&label=size)](https://bundlephobia.com/package/jsx-ai)\n\nJSX interface for structured LLM calls. Tools, messages, and prompts become composable components.\n\n```tsx\nimport { callLLM } from \"jsx-ai\"\n\nconst result = await callLLM(\n <>\n <system>You are a coding agent</system>\n <tool name=\"exec\" description=\"Run a shell command\">\n <param name=\"command\" type=\"string\" required>The command to run</param>\n </tool>\n <message role=\"user\">List all TypeScript files</message>\n </>,\n { model: \"gemini-2.5-flash\" }\n)\n\nresult.toolCalls // [{ name: \"exec\", args: { command: \"find . -name '*.ts'\" } }]\nresult.text // \"\"\nresult.usage // { inputTokens: 42, outputTokens: 15 }\n```\n\n## Why JSX?\n\n**Before** — tools as JSON schemas, stringly-typed, not reusable:\n\n```ts\nconst response = await fetch(url, {\n body: JSON.stringify({\n model: \"gemini-2.5-flash\",\n systemInstruction: { parts: [{ text: \"You are a coding agent\" }] },\n tools: [{ functionDeclarations: [{\n name: \"exec\",\n description: \"Run a shell command\",\n parameters: { type: \"object\", properties: {\n command: { type: \"string\", description: \"The command to run\" }\n }, required: [\"command\"] }\n }] }],\n contents: [{ role: \"user\", parts: [{ text: \"List all TypeScript files\" }] }],\n })\n})\nconst data = await response.json()\nconst toolCall = data.candidates[0].content.parts[0].functionCall\n```\n\n**After** — same call, composable and provider-agnostic:\n\n```tsx\nconst ExecTool = () => (\n <tool name=\"exec\" description=\"Run a shell command\">\n <param name=\"command\" type=\"string\" required>The command to run</param>\n </tool>\n)\n\nconst result = await callLLM(\n <>\n <system>You are a coding agent</system>\n <ExecTool />\n <message role=\"user\">List all TypeScript files</message>\n </>,\n { model: \"gemini-2.5-flash\" } // or \"gpt-4o\" or \"claude-3-sonnet-20240229\"\n)\n\nresult.toolCalls // [{ name: \"exec\", args: { command: \"find . -name '*.ts'\" } }]\n```\n\n## Installation\n\n```sh\nbun add jsx-ai\n# or: npm install jsx-ai\n```\n\nAdd to `tsconfig.json`:\n```json\n{\n \"compilerOptions\": {\n \"jsx\": \"react-jsx\",\n \"jsxImportSource\": \"jsx-ai\"\n }\n}\n```\n\n## ✨ What You Get\n\n- **Multi-provider** → Gemini, OpenAI, Anthropic, DeepSeek — auto-detected from model name\n- **5 strategies** → native FC, NLT, XML, natural, hybrid — same prompt, different encodings\n- **Composable** → tools and prompts are reusable JSX components\n- **Skills** → two-phase skill loading from `.md` files (discovery → resolution)\n- **Type-safe** → full TypeScript types, custom JSX runtime (not React)\n- **Benchmarked** → multi-turn agentic scenarios scored per strategy\n\n## 🔌 Providers\n\nAuto-detected from model name. Override with `{ provider: \"openai\" }`.\n\n| Model | Provider | Auth | Env var |\n|-------|----------|------|---------|\n| `gemini-*` | Gemini | x-goog-api-key | `GEMINI_API_KEY` |\n| `gpt-*`, `o4-*` | OpenAI | Bearer | `OPENAI_API_KEY` |\n| `claude-*` | Anthropic | x-api-key + version | `ANTHROPIC_API_KEY` |\n| `deepseek-*` | OpenAI (compat) | Bearer | `DEEPSEEK_API_KEY` |\n\n```tsx\n// Gemini (default)\nawait callLLM(<>...</>, { model: \"gemini-2.5-flash\" })\n\n// OpenAI\nawait callLLM(<>...</>, { model: \"gpt-4o\" })\n\n// Anthropic\nawait callLLM(<>...</>, { model: \"claude-3-sonnet-20240229\" })\n```\n\nProvider nuances handled automatically:\n- Gemini: merges consecutive same-role messages (API rejects them otherwise)\n- OpenAI `o4-*`: uses `max_completion_tokens` + forced `temperature=1.0`\n- Anthropic: system prompt as top-level field, `tool_use` blocks, `input_schema`\n- DeepSeek: routes to `api.deepseek.com` with OpenAI-compatible format\n\n### Custom providers\n\n```tsx\nimport { registerProvider } from \"jsx-ai\"\nimport type { Provider } from \"jsx-ai\"\n\nclass MyProvider implements Provider {\n name = \"custom\"\n buildRequest(prepared, model, apiKey) { /* ... */ }\n parseResponse(data) { /* ... */ }\n}\n\nregisterProvider(\"custom\", new MyProvider())\nawait callLLM(<>...</>, { provider: \"custom\", model: \"my-model\" })\n```\n\n## 🎯 Strategies\n\nSame JSX prompt, different tool encodings. Each strategy controls how tools appear to the model and how responses are parsed.\n\n| Strategy | Tools sent as | Response parsed from | Best for |\n|----------|---------------|---------------------|----------|\n| `native` | API `tools` field | Structured FC | Single tool calls, lowest tokens |\n| `nlt` | Text descriptions + native FC | Structured FC | Multi-turn agentic loops |\n| `xml` | Text with XML schema | XML in text | Multi-tool batching |\n| `natural` | Text descriptions | Action blocks in text | Complex reasoning + tools |\n| `hybrid` | API `tools` + text schema | Either | Balanced |\n\n```tsx\n// Strategy via options\nawait callLLM(<>...</>, { strategy: \"nlt\" })\n\n// Or register a custom one\nimport { registerStrategy } from \"jsx-ai\"\nregisterStrategy(\"my-strategy\", { prepare, parseResponse })\n```\n\n### Benchmark results (gemini-2.5-flash, kv-store scenario)\n\n3-turn agentic loop: Plan → Execute → Adapt\n\n| Strategy | Turn 1 (Plan) | Turn 2 (Execute) | Turn 3 (Adapt) | Total |\n|----------|:---:|:---:|:---:|:---:|\n| **nlt** | 100% | 73% | 84% | **86%** |\n| **natural** | 100% | 67% | 69% | **79%** |\n| **native** | 46% | 5% | 33% | **28%** |\n\n> Native FC underperforms in agentic loops because it batches homogeneous tool calls — calling 5× `use_skill` but skipping `set_objectives` in the same turn.\n\n## 📦 JSX Elements\n\n| Element | Props | Description |\n|---------|-------|-------------|\n| `<system>` | — | System instruction (text children) |\n| `<tool>` | `name`, `description` | Tool/function declaration |\n| `<param>` | `name`, `type`, `required`, `enum` | Tool parameter (children = description) |\n| `<message>` | `role` (`user` \\| `assistant`) | Conversation message |\n| `<prompt>` | `model`, `temperature`, `maxTokens`, `strategy` | Optional config wrapper |\n\n## 🧠 Skills\n\nTwo-phase skill loading from `.md` files with YAML frontmatter:\n\n```md\n---\nname: bun-expert\ndescription: Bun runtime expertise — Bun.serve(), bun:sqlite, bun:test\n---\n## Bun Runtime\n- HTTP: Bun.serve() with export default { port, fetch } pattern\n- Database: import { Database } from \"bun:sqlite\"\n- Testing: import { describe, it, expect } from \"bun:test\"\n```\n\n**Phase 1 — Discovery:** skills appear as a lightweight catalog\n\n```tsx\nimport { Skill, UseSkillTool } from \"jsx-ai\"\n\nawait callLLM(\n <>\n <Skill path=\"skills/bun-expert.md\" />\n <Skill path=\"skills/security.md\" />\n <UseSkillTool />\n <message role=\"user\">Build a KV store API</message>\n </>\n)\n// Model sees: \"Available skill: bun-expert — Bun runtime expertise\"\n// Model calls: use_skill({ skill_name: \"bun-expert\" })\n```\n\n**Phase 2 — Resolution:** requested skills expand to full content\n\n```tsx\nimport { Skill, resolveSkills } from \"jsx-ai\"\n\nconst resolved = resolveSkills(skillPaths, [\"bun-expert\"])\n\nawait callLLM(\n <>\n <Skill path=\"skills/bun-expert.md\" resolve />\n <Skill path=\"skills/security.md\" />\n <message role=\"user\">Now implement it</message>\n </>\n)\n// Model sees full bun-expert methodology + just the catalog entry for security\n```\n\n## 🔍 `render(tree)`\n\nInspect the extracted prompt without calling the LLM:\n\n```tsx\nimport { render } from \"jsx-ai\"\n\nconst extracted = render(\n <>\n <system>You are helpful</system>\n <tool name=\"exec\" description=\"Run command\">\n <param name=\"command\" type=\"string\" required>Command</param>\n </tool>\n <message role=\"user\">List files</message>\n </>\n)\n\nextracted.tools // [{ name: \"exec\", parameters: { ... } }]\nextracted.messages // [{ role: \"user\", content: \"List files\" }]\nextracted.system // \"You are helpful\"\n```\n\n## ⚙️ CallOptions\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `model` | `string` | `\"gemini-2.5-flash\"` | Model name (also determines provider) |\n| `provider` | `\"gemini\" \\| \"openai\" \\| \"anthropic\"` | auto-detected | Force a specific provider |\n| `strategy` | `\"native\" \\| \"nlt\" \\| \"xml\" \\| \"natural\" \\| \"hybrid\"` | `\"auto\"` | Tool encoding strategy |\n| `apiKey` | `string` | from env | Override API key |\n| `temperature` | `number` | `0.1` | Sampling temperature |\n| `maxTokens` | `number` | `4000` | Max output tokens |\n\n## 💬 `callText(model, messages, options?)`\n\nSimple text-in/text-out LLM call — no JSX needed. Uses the same provider routing and auth:\n\n```ts\nimport { callText } from \"jsx-ai\"\n\nconst text = await callText(\"gemini-2.5-flash\", [\n { role: \"system\", content: \"You are a planner. Break tasks into steps.\" },\n { role: \"user\", content: \"Build a REST API with authentication\" },\n])\n\nconsole.log(text) // \"1. Set up project with Bun.serve()...\"\n```\n\n## 🔄 `streamLLM(model, messages, options?)`\n\nStream LLM responses token-by-token via SSE. Same provider routing as `callText`:\n\n```ts\nimport { streamLLM } from \"jsx-ai\"\n\nfor await (const chunk of streamLLM(\"gemini-2.5-flash\", [\n { role: \"system\", content: \"You are a storyteller\" },\n { role: \"user\", content: \"Tell me a short story\" },\n])) {\n process.stdout.write(chunk)\n}\n```\n\nOptions for both `callText` and `streamLLM`:\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `temperature` | `number` | `0.3` | Sampling temperature |\n| `maxTokens` | `number` | `8000` | Max output tokens |\n| `apiKey` | `string` | from env | Override API key |\n\n## License\n\nMIT\n"}}}}