@soederpop/luca 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +71 -0
- package/README.md +78 -0
- package/bun.lock +2928 -0
- package/bunfig.toml +3 -0
- package/commands/audit-docs.ts +740 -0
- package/commands/build-scaffolds.ts +154 -0
- package/commands/generate-api-docs.ts +114 -0
- package/commands/update-introspection.ts +67 -0
- package/docs/CLI.md +335 -0
- package/docs/README.md +88 -0
- package/docs/TABLE-OF-CONTENTS.md +157 -0
- package/docs/apis/clients/elevenlabs.md +84 -0
- package/docs/apis/clients/graph.md +56 -0
- package/docs/apis/clients/openai.md +69 -0
- package/docs/apis/clients/rest.md +41 -0
- package/docs/apis/clients/websocket.md +107 -0
- package/docs/apis/features/agi/assistant.md +471 -0
- package/docs/apis/features/agi/assistants-manager.md +154 -0
- package/docs/apis/features/agi/claude-code.md +602 -0
- package/docs/apis/features/agi/conversation-history.md +352 -0
- package/docs/apis/features/agi/conversation.md +333 -0
- package/docs/apis/features/agi/docs-reader.md +121 -0
- package/docs/apis/features/agi/openai-codex.md +318 -0
- package/docs/apis/features/agi/openapi.md +138 -0
- package/docs/apis/features/agi/semantic-search.md +387 -0
- package/docs/apis/features/agi/skills-library.md +216 -0
- package/docs/apis/features/node/container-link.md +133 -0
- package/docs/apis/features/node/content-db.md +313 -0
- package/docs/apis/features/node/disk-cache.md +379 -0
- package/docs/apis/features/node/dns.md +651 -0
- package/docs/apis/features/node/docker.md +705 -0
- package/docs/apis/features/node/downloader.md +81 -0
- package/docs/apis/features/node/esbuild.md +59 -0
- package/docs/apis/features/node/file-manager.md +182 -0
- package/docs/apis/features/node/fs.md +581 -0
- package/docs/apis/features/node/git.md +330 -0
- package/docs/apis/features/node/google-auth.md +174 -0
- package/docs/apis/features/node/google-calendar.md +187 -0
- package/docs/apis/features/node/google-docs.md +151 -0
- package/docs/apis/features/node/google-drive.md +225 -0
- package/docs/apis/features/node/google-sheets.md +179 -0
- package/docs/apis/features/node/grep.md +290 -0
- package/docs/apis/features/node/helpers.md +135 -0
- package/docs/apis/features/node/ink.md +334 -0
- package/docs/apis/features/node/ipc-socket.md +260 -0
- package/docs/apis/features/node/json-tree.md +86 -0
- package/docs/apis/features/node/launcher-app-command-listener.md +145 -0
- package/docs/apis/features/node/networking.md +281 -0
- package/docs/apis/features/node/nlp.md +133 -0
- package/docs/apis/features/node/opener.md +97 -0
- package/docs/apis/features/node/os.md +118 -0
- package/docs/apis/features/node/package-finder.md +402 -0
- package/docs/apis/features/node/postgres.md +212 -0
- package/docs/apis/features/node/proc.md +430 -0
- package/docs/apis/features/node/process-manager.md +210 -0
- package/docs/apis/features/node/python.md +278 -0
- package/docs/apis/features/node/repl.md +88 -0
- package/docs/apis/features/node/runpod.md +673 -0
- package/docs/apis/features/node/secure-shell.md +169 -0
- package/docs/apis/features/node/semantic-search.md +401 -0
- package/docs/apis/features/node/sqlite.md +211 -0
- package/docs/apis/features/node/telegram.md +254 -0
- package/docs/apis/features/node/tts.md +118 -0
- package/docs/apis/features/node/ui.md +703 -0
- package/docs/apis/features/node/vault.md +64 -0
- package/docs/apis/features/node/vm.md +84 -0
- package/docs/apis/features/node/window-manager.md +337 -0
- package/docs/apis/features/node/yaml-tree.md +85 -0
- package/docs/apis/features/node/yaml.md +176 -0
- package/docs/apis/features/web/asset-loader.md +47 -0
- package/docs/apis/features/web/container-link.md +133 -0
- package/docs/apis/features/web/esbuild.md +59 -0
- package/docs/apis/features/web/helpers.md +135 -0
- package/docs/apis/features/web/network.md +30 -0
- package/docs/apis/features/web/speech.md +55 -0
- package/docs/apis/features/web/vault.md +64 -0
- package/docs/apis/features/web/vm.md +84 -0
- package/docs/apis/features/web/voice.md +67 -0
- package/docs/apis/servers/express.md +127 -0
- package/docs/apis/servers/mcp.md +213 -0
- package/docs/apis/servers/websocket.md +99 -0
- package/docs/documentation-audit.md +134 -0
- package/docs/examples/content-db.md +77 -0
- package/docs/examples/disk-cache.md +83 -0
- package/docs/examples/docker.md +101 -0
- package/docs/examples/downloader.md +70 -0
- package/docs/examples/esbuild.md +80 -0
- package/docs/examples/file-manager.md +82 -0
- package/docs/examples/fs.md +83 -0
- package/docs/examples/git.md +85 -0
- package/docs/examples/google-auth.md +88 -0
- package/docs/examples/google-calendar.md +94 -0
- package/docs/examples/google-docs.md +82 -0
- package/docs/examples/google-drive.md +96 -0
- package/docs/examples/google-sheets.md +95 -0
- package/docs/examples/grep.md +85 -0
- package/docs/examples/ink-blocks.md +75 -0
- package/docs/examples/ink-renderer.md +41 -0
- package/docs/examples/ink.md +103 -0
- package/docs/examples/ipc-socket.md +103 -0
- package/docs/examples/json-tree.md +91 -0
- package/docs/examples/launcher-app-command-listener.md +120 -0
- package/docs/examples/networking.md +58 -0
- package/docs/examples/nlp.md +91 -0
- package/docs/examples/opener.md +78 -0
- package/docs/examples/os.md +72 -0
- package/docs/examples/package-finder.md +89 -0
- package/docs/examples/port-exposer.md +89 -0
- package/docs/examples/postgres.md +91 -0
- package/docs/examples/proc.md +81 -0
- package/docs/examples/process-manager.md +79 -0
- package/docs/examples/python.md +91 -0
- package/docs/examples/repl.md +93 -0
- package/docs/examples/runpod.md +119 -0
- package/docs/examples/secure-shell.md +92 -0
- package/docs/examples/sqlite.md +86 -0
- package/docs/examples/telegram.md +77 -0
- package/docs/examples/tts.md +86 -0
- package/docs/examples/ui.md +80 -0
- package/docs/examples/vault.md +70 -0
- package/docs/examples/vm.md +86 -0
- package/docs/examples/window-manager.md +125 -0
- package/docs/examples/yaml-tree.md +93 -0
- package/docs/examples/yaml.md +104 -0
- package/docs/ideas/class-registration-refactor-possibilities.md +197 -0
- package/docs/ideas/container-use-api.md +9 -0
- package/docs/ideas/easy-auth-for-express-servers-and-luca-serve.md +0 -0
- package/docs/ideas/feature-stacks.md +22 -0
- package/docs/ideas/luca-cli-self-sufficiency-demo.md +23 -0
- package/docs/ideas/mcp-design.md +9 -0
- package/docs/ideas/web-container-debugging-feature.md +13 -0
- package/docs/introspection-audit.md +49 -0
- package/docs/introspection.md +154 -0
- package/docs/mcp/readme.md +162 -0
- package/docs/models.ts +38 -0
- package/docs/philosophy.md +85 -0
- package/docs/principles.md +7 -0
- package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +34 -0
- package/docs/prompts/mcp-test-easy-command.md +27 -0
- package/docs/reports/assistant-bugs.md +38 -0
- package/docs/reports/attach-pattern-usage.md +18 -0
- package/docs/reports/code-audit-results.md +391 -0
- package/docs/reports/introspection-audit-tasks.md +378 -0
- package/docs/reports/luca-mcp-improvements.md +128 -0
- package/docs/scaffolds/client.md +140 -0
- package/docs/scaffolds/command.md +106 -0
- package/docs/scaffolds/endpoint.md +176 -0
- package/docs/scaffolds/feature.md +148 -0
- package/docs/scaffolds/server.md +187 -0
- package/docs/tasks/web-container-helper-discovery.md +71 -0
- package/docs/todos.md +1 -0
- package/docs/tutorials/01-getting-started.md +106 -0
- package/docs/tutorials/02-container.md +210 -0
- package/docs/tutorials/03-scripts.md +194 -0
- package/docs/tutorials/04-features-overview.md +196 -0
- package/docs/tutorials/05-state-and-events.md +171 -0
- package/docs/tutorials/06-servers.md +157 -0
- package/docs/tutorials/07-endpoints.md +198 -0
- package/docs/tutorials/08-commands.md +171 -0
- package/docs/tutorials/09-clients.md +162 -0
- package/docs/tutorials/10-creating-features.md +198 -0
- package/docs/tutorials/11-contentbase.md +191 -0
- package/docs/tutorials/12-assistants.md +215 -0
- package/docs/tutorials/13-introspection.md +147 -0
- package/docs/tutorials/14-type-system.md +174 -0
- package/docs/tutorials/15-project-patterns.md +222 -0
- package/docs/tutorials/16-google-features.md +534 -0
- package/docs/tutorials/17-tui-blocks.md +530 -0
- package/docs/tutorials/18-semantic-search.md +334 -0
- package/index.ts +1 -0
- package/luca.console.ts +9 -0
- package/main.py +6 -0
- package/package.json +154 -0
- package/pyproject.toml +7 -0
- package/scripts/animations/chrome-glitch.ts +55 -0
- package/scripts/animations/index.ts +16 -0
- package/scripts/animations/neon-pulse.ts +64 -0
- package/scripts/animations/types.ts +6 -0
- package/scripts/build-web.ts +28 -0
- package/scripts/examples/ask-luca-expert.ts +42 -0
- package/scripts/examples/assistant-questions.ts +12 -0
- package/scripts/examples/excalidraw-expert.ts +75 -0
- package/scripts/examples/expert-chat.ts +0 -0
- package/scripts/examples/file-manager.ts +14 -0
- package/scripts/examples/ideas.ts +12 -0
- package/scripts/examples/interactive-chat.ts +20 -0
- package/scripts/examples/openai-tool-calls.ts +113 -0
- package/scripts/examples/opening-a-web-browser.ts +5 -0
- package/scripts/examples/telegram-bot.ts +79 -0
- package/scripts/examples/telegram-ink-ui.ts +302 -0
- package/scripts/examples/using-assistant-with-mcp.ts +560 -0
- package/scripts/examples/using-claude-code.ts +10 -0
- package/scripts/examples/using-contentdb.ts +35 -0
- package/scripts/examples/using-conversations.ts +35 -0
- package/scripts/examples/using-disk-cache.ts +10 -0
- package/scripts/examples/using-docker-shell.ts +75 -0
- package/scripts/examples/using-elevenlabs.ts +25 -0
- package/scripts/examples/using-google-calendar.ts +57 -0
- package/scripts/examples/using-google-docs.ts +74 -0
- package/scripts/examples/using-google-drive.ts +74 -0
- package/scripts/examples/using-google-sheets.ts +89 -0
- package/scripts/examples/using-nlp.ts +55 -0
- package/scripts/examples/using-ollama.ts +10 -0
- package/scripts/examples/using-openai-codex.ts +23 -0
- package/scripts/examples/using-postgres.ts +55 -0
- package/scripts/examples/using-runpod.ts +32 -0
- package/scripts/examples/using-tts.ts +40 -0
- package/scripts/examples/vm-loading-esm-modules.ts +16 -0
- package/scripts/scaffold.ts +391 -0
- package/scripts/scratch.ts +15 -0
- package/scripts/test-command-listener.ts +123 -0
- package/scripts/test-window-manager-lifecycle.ts +86 -0
- package/scripts/test-window-manager.ts +43 -0
- package/scripts/update-introspection-data.ts +58 -0
- package/src/agi/README.md +14 -0
- package/src/agi/container.server.ts +114 -0
- package/src/agi/endpoints/ask.ts +60 -0
- package/src/agi/endpoints/conversations/[id].ts +45 -0
- package/src/agi/endpoints/conversations.ts +31 -0
- package/src/agi/endpoints/experts.ts +37 -0
- package/src/agi/features/assistant.ts +767 -0
- package/src/agi/features/assistants-manager.ts +260 -0
- package/src/agi/features/claude-code.ts +1111 -0
- package/src/agi/features/conversation-history.ts +497 -0
- package/src/agi/features/conversation.ts +799 -0
- package/src/agi/features/openai-codex.ts +631 -0
- package/src/agi/features/openapi.ts +438 -0
- package/src/agi/features/skills-library.ts +425 -0
- package/src/agi/index.ts +6 -0
- package/src/agi/lib/token-counter.ts +122 -0
- package/src/browser.ts +25 -0
- package/src/bus.ts +100 -0
- package/src/cli/cli.ts +70 -0
- package/src/client.ts +461 -0
- package/src/clients/civitai/index.ts +541 -0
- package/src/clients/client-template.ts +41 -0
- package/src/clients/comfyui/index.ts +597 -0
- package/src/clients/elevenlabs/index.ts +291 -0
- package/src/clients/openai/index.ts +451 -0
- package/src/clients/supabase/index.ts +366 -0
- package/src/command.ts +164 -0
- package/src/commands/chat.ts +182 -0
- package/src/commands/console.ts +192 -0
- package/src/commands/describe.ts +433 -0
- package/src/commands/eval.ts +116 -0
- package/src/commands/help.ts +214 -0
- package/src/commands/index.ts +14 -0
- package/src/commands/mcp.ts +64 -0
- package/src/commands/prompt.ts +807 -0
- package/src/commands/run.ts +257 -0
- package/src/commands/sandbox-mcp.ts +439 -0
- package/src/commands/scaffold.ts +79 -0
- package/src/commands/serve.ts +172 -0
- package/src/container.ts +781 -0
- package/src/endpoint.ts +340 -0
- package/src/feature.ts +75 -0
- package/src/hash-object.ts +97 -0
- package/src/helper.ts +543 -0
- package/src/introspection/generated.agi.ts +23388 -0
- package/src/introspection/generated.node.ts +18899 -0
- package/src/introspection/generated.web.ts +2021 -0
- package/src/introspection/index.ts +256 -0
- package/src/introspection/scan.ts +912 -0
- package/src/node/container.ts +354 -0
- package/src/node/feature.ts +13 -0
- package/src/node/features/container-link.ts +558 -0
- package/src/node/features/content-db.ts +475 -0
- package/src/node/features/disk-cache.ts +382 -0
- package/src/node/features/dns.ts +655 -0
- package/src/node/features/docker.ts +912 -0
- package/src/node/features/downloader.ts +92 -0
- package/src/node/features/esbuild.ts +68 -0
- package/src/node/features/file-manager.ts +357 -0
- package/src/node/features/fs.ts +534 -0
- package/src/node/features/git.ts +492 -0
- package/src/node/features/google-auth.ts +502 -0
- package/src/node/features/google-calendar.ts +300 -0
- package/src/node/features/google-docs.ts +404 -0
- package/src/node/features/google-drive.ts +339 -0
- package/src/node/features/google-sheets.ts +279 -0
- package/src/node/features/grep.ts +406 -0
- package/src/node/features/helpers.ts +374 -0
- package/src/node/features/ink.ts +490 -0
- package/src/node/features/ipc-socket.ts +459 -0
- package/src/node/features/json-tree.ts +188 -0
- package/src/node/features/launcher-app-command-listener.ts +388 -0
- package/src/node/features/networking.ts +925 -0
- package/src/node/features/nlp.ts +211 -0
- package/src/node/features/opener.ts +166 -0
- package/src/node/features/os.ts +157 -0
- package/src/node/features/package-finder.ts +539 -0
- package/src/node/features/port-exposer.ts +342 -0
- package/src/node/features/postgres.ts +273 -0
- package/src/node/features/proc.ts +502 -0
- package/src/node/features/process-manager.ts +542 -0
- package/src/node/features/python.ts +444 -0
- package/src/node/features/repl.ts +194 -0
- package/src/node/features/runpod.ts +802 -0
- package/src/node/features/secure-shell.ts +248 -0
- package/src/node/features/semantic-search.ts +924 -0
- package/src/node/features/sqlite.ts +289 -0
- package/src/node/features/telegram.ts +342 -0
- package/src/node/features/tts.ts +184 -0
- package/src/node/features/ui.ts +857 -0
- package/src/node/features/vault.ts +164 -0
- package/src/node/features/vm.ts +312 -0
- package/src/node/features/window-manager.ts +804 -0
- package/src/node/features/yaml-tree.ts +149 -0
- package/src/node/features/yaml.ts +132 -0
- package/src/node.ts +70 -0
- package/src/react/index.ts +175 -0
- package/src/registry.ts +199 -0
- package/src/scaffolds/generated.ts +1613 -0
- package/src/scaffolds/template.ts +37 -0
- package/src/schemas/base.ts +255 -0
- package/src/server.ts +135 -0
- package/src/servers/express.ts +209 -0
- package/src/servers/mcp.ts +805 -0
- package/src/servers/socket.ts +120 -0
- package/src/state.ts +101 -0
- package/src/web/clients/socket.ts +82 -0
- package/src/web/container.ts +74 -0
- package/src/web/extension.ts +30 -0
- package/src/web/feature.ts +12 -0
- package/src/web/features/asset-loader.ts +64 -0
- package/src/web/features/container-link.ts +385 -0
- package/src/web/features/esbuild.ts +79 -0
- package/src/web/features/helpers.ts +267 -0
- package/src/web/features/network.ts +61 -0
- package/src/web/features/speech.ts +87 -0
- package/src/web/features/vault.ts +189 -0
- package/src/web/features/vm.ts +78 -0
- package/src/web/features/voice-recognition.ts +129 -0
- package/src/web/shims/isomorphic-vm.ts +149 -0
- package/test/bus.test.ts +134 -0
- package/test/clients-servers.test.ts +216 -0
- package/test/container-link.test.ts +274 -0
- package/test/features.test.ts +160 -0
- package/test/integration.test.ts +787 -0
- package/test/node-container.test.ts +121 -0
- package/test/rate-limit.test.ts +272 -0
- package/test/semantic-search.test.ts +550 -0
- package/test/state.test.ts +121 -0
- package/test-integration/assistant.test.ts +138 -0
- package/test-integration/assistants-manager.test.ts +123 -0
- package/test-integration/claude-code.test.ts +98 -0
- package/test-integration/conversation-history.test.ts +205 -0
- package/test-integration/conversation.test.ts +137 -0
- package/test-integration/elevenlabs.test.ts +55 -0
- package/test-integration/google-services.test.ts +80 -0
- package/test-integration/helpers.ts +89 -0
- package/test-integration/openai-codex.test.ts +93 -0
- package/test-integration/runpod.test.ts +58 -0
- package/test-integration/server-endpoints.test.ts +97 -0
- package/test-integration/skills-library.test.ts +157 -0
- package/test-integration/telegram.test.ts +46 -0
- package/tsconfig.json +58 -0
- package/uv.lock +8 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Building Assistants
|
|
3
|
+
tags: [assistants, ai, openai, tools, hooks, conversation, CORE.md]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Building Assistants
|
|
7
|
+
|
|
8
|
+
Assistants are AI-powered conversational agents defined by a file-based convention. Each assistant lives in its own folder with a system prompt, tools, hooks, and documentation.
|
|
9
|
+
|
|
10
|
+
## Directory Structure
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
assistants/my-assistant/
|
|
14
|
+
├── CORE.md # System prompt (required)
|
|
15
|
+
├── tools.ts # Tool definitions with Zod schemas
|
|
16
|
+
├── hooks.ts # Lifecycle event handlers
|
|
17
|
+
└── docs/ # Internal documentation the assistant can search
|
|
18
|
+
├── guide.md
|
|
19
|
+
└── faq.md
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## CORE.md -- The System Prompt
|
|
23
|
+
|
|
24
|
+
This is the assistant's personality and instructions. It's a markdown file that becomes the system message:
|
|
25
|
+
|
|
26
|
+
```markdown
|
|
27
|
+
# Customer Support Assistant
|
|
28
|
+
|
|
29
|
+
You are a helpful customer support agent for Acme Corp. You help users with
|
|
30
|
+
billing questions, account issues, and product information.
|
|
31
|
+
|
|
32
|
+
Always research internal docs before answering product questions.
|
|
33
|
+
Be polite and concise.
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## tools.ts -- Tool Definitions
|
|
37
|
+
|
|
38
|
+
Define functions that the assistant can call. Each tool has a Zod schema describing its parameters:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
const { z } = require('zod')
|
|
42
|
+
|
|
43
|
+
async function lookupOrder({ orderId }) {
|
|
44
|
+
// In a real app, query your database
|
|
45
|
+
return {
|
|
46
|
+
orderId,
|
|
47
|
+
status: 'shipped',
|
|
48
|
+
trackingNumber: 'ABC123',
|
|
49
|
+
estimatedDelivery: '2024-01-20',
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function createTicket({ subject, priority, description }) {
|
|
54
|
+
// Create a support ticket
|
|
55
|
+
const ticketId = `TICKET-${Date.now()}`
|
|
56
|
+
return {
|
|
57
|
+
ticketId,
|
|
58
|
+
subject,
|
|
59
|
+
priority,
|
|
60
|
+
message: `Ticket ${ticketId} created successfully`,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function searchProducts({ query, category }) {
|
|
65
|
+
// Search product catalog
|
|
66
|
+
return {
|
|
67
|
+
results: [
|
|
68
|
+
{ name: 'Widget Pro', price: 29.99, inStock: true },
|
|
69
|
+
{ name: 'Widget Lite', price: 19.99, inStock: false },
|
|
70
|
+
],
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const schemas = {
|
|
75
|
+
lookupOrder: z.object({
|
|
76
|
+
orderId: z.string().describe('The order ID to look up'),
|
|
77
|
+
}).describe('Look up an order by its ID to get status and tracking info'),
|
|
78
|
+
|
|
79
|
+
createTicket: z.object({
|
|
80
|
+
subject: z.string().describe('Brief ticket subject line'),
|
|
81
|
+
priority: z.enum(['low', 'medium', 'high']).describe('Ticket priority'),
|
|
82
|
+
description: z.string().describe('Detailed description of the issue'),
|
|
83
|
+
}).describe('Create a new support ticket'),
|
|
84
|
+
|
|
85
|
+
searchProducts: z.object({
|
|
86
|
+
query: z.string().describe('Search terms'),
|
|
87
|
+
category: z.string().optional().describe('Product category filter'),
|
|
88
|
+
}).describe('Search the product catalog'),
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = { lookupOrder, createTicket, searchProducts, schemas }
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Important:** The function name must match the key in the `schemas` object. The `.describe()` on the schema object itself becomes the tool description that the AI model sees.
|
|
95
|
+
|
|
96
|
+
## hooks.ts -- Lifecycle Hooks
|
|
97
|
+
|
|
98
|
+
React to assistant events:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
function started() {
|
|
102
|
+
console.log('[assistant] Session started')
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function response(text) {
|
|
106
|
+
// Called when the assistant produces a text response
|
|
107
|
+
console.log(`[assistant] ${text.slice(0, 100)}...`)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function toolCall(name, args) {
|
|
111
|
+
// Called before a tool is executed
|
|
112
|
+
console.log(`[assistant] Calling tool: ${name}`, args)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function error(err) {
|
|
116
|
+
console.error('[assistant] Error:', err.message)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = { started, response, toolCall, error }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## docs/ -- Internal Documentation
|
|
123
|
+
|
|
124
|
+
The `docs/` folder contains markdown files that the assistant can search using the built-in `researchInternalDocs` tool. This is automatically injected -- you don't need to define it in tools.ts.
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
docs/
|
|
128
|
+
├── billing-faq.md
|
|
129
|
+
├── product-catalog.md
|
|
130
|
+
├── return-policy.md
|
|
131
|
+
└── troubleshooting.md
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
In CORE.md, instruct the assistant to use it:
|
|
135
|
+
|
|
136
|
+
```markdown
|
|
137
|
+
When asked about products, billing, or policies, always use the
|
|
138
|
+
researchInternalDocs tool first to find accurate information before answering.
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Using the Assistant
|
|
142
|
+
|
|
143
|
+
### In a Script
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import container from '@soederpop/luca'
|
|
147
|
+
|
|
148
|
+
const assistant = container.feature('assistant', {
|
|
149
|
+
folder: 'assistants/my-assistant',
|
|
150
|
+
model: 'gpt-4o',
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
// Ask a question
|
|
154
|
+
const answer = await assistant.ask('What is the return policy?')
|
|
155
|
+
console.log(answer)
|
|
156
|
+
|
|
157
|
+
// Multi-turn conversation
|
|
158
|
+
const follow = await assistant.ask('And how long does the refund take?')
|
|
159
|
+
console.log(follow)
|
|
160
|
+
|
|
161
|
+
// Save the conversation
|
|
162
|
+
await assistant.save({ title: 'Return policy inquiry' })
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### In an Endpoint
|
|
166
|
+
|
|
167
|
+
Expose the assistant as an API:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
// endpoints/ask.ts
|
|
171
|
+
import { z } from 'zod'
|
|
172
|
+
import type { EndpointContext } from '@soederpop/luca'
|
|
173
|
+
|
|
174
|
+
export const path = '/api/ask'
|
|
175
|
+
export const description = 'Ask the support assistant a question'
|
|
176
|
+
export const tags = ['assistant']
|
|
177
|
+
|
|
178
|
+
export const postSchema = z.object({
|
|
179
|
+
question: z.string().describe('Your question'),
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
export async function post(params: z.infer<typeof postSchema>, ctx: EndpointContext) {
|
|
183
|
+
const assistant = ctx.container.feature('assistant', {
|
|
184
|
+
folder: 'assistants/my-assistant',
|
|
185
|
+
model: 'gpt-4o',
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
const answer = await assistant.ask(params.question)
|
|
189
|
+
return { answer }
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Streaming Responses
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
const assistant = container.feature('assistant', {
|
|
197
|
+
folder: 'assistants/my-assistant',
|
|
198
|
+
model: 'gpt-4o',
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
// Listen for chunks as they arrive
|
|
202
|
+
assistant.on('chunk', (text) => {
|
|
203
|
+
process.stdout.write(text)
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
await assistant.ask('Explain quantum computing')
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Best Practices
|
|
210
|
+
|
|
211
|
+
1. **Write focused CORE.md prompts** -- tell the assistant exactly what it is and what it should/shouldn't do
|
|
212
|
+
2. **Keep tools simple** -- each tool should do one thing. The AI model is better at composing simple tools than using complex ones
|
|
213
|
+
3. **Use docs/ liberally** -- put all reference material in docs/ so the assistant can look things up rather than relying on the model's training data
|
|
214
|
+
4. **Use Zod `.describe()`** -- the descriptions on schemas and fields are what the model sees to decide when and how to call tools
|
|
215
|
+
5. **Test with real questions** -- ask the assistant the kinds of things real users will ask
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Introspection and Discovery
|
|
3
|
+
tags: [introspection, runtime, discovery, documentation, describe, inspect]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Introspection and Discovery
|
|
7
|
+
|
|
8
|
+
One of Luca's defining features is that everything is discoverable at runtime. You don't need to read documentation to learn what's available -- you can ask the system itself.
|
|
9
|
+
|
|
10
|
+
## Why Introspection Matters
|
|
11
|
+
|
|
12
|
+
Introspection serves two audiences:
|
|
13
|
+
|
|
14
|
+
1. **Developers** -- discover APIs while coding, without leaving the REPL or editor
|
|
15
|
+
2. **AI Agents** -- learn the full API surface dynamically, enabling them to use features they weren't explicitly trained on
|
|
16
|
+
|
|
17
|
+
## Container-Level Introspection
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// Structured data about the entire container
|
|
21
|
+
const info = container.inspect()
|
|
22
|
+
// Returns: registries, enabled features, state schema, available helpers
|
|
23
|
+
|
|
24
|
+
// Human-readable markdown
|
|
25
|
+
const docs = container.inspectAsText()
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Registry-Level Discovery
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// What's available?
|
|
32
|
+
container.features.available
|
|
33
|
+
// => ['fs', 'git', 'proc', 'vm', 'ui', 'diskCache', 'contentDb', ...]
|
|
34
|
+
|
|
35
|
+
// Describe one
|
|
36
|
+
container.features.describe('diskCache')
|
|
37
|
+
// => Markdown documentation for diskCache feature
|
|
38
|
+
|
|
39
|
+
// Describe everything
|
|
40
|
+
container.features.describeAll()
|
|
41
|
+
// => Full documentation for all registered features
|
|
42
|
+
|
|
43
|
+
// Structured introspection data
|
|
44
|
+
container.features.introspect('fs')
|
|
45
|
+
// => { methods, getters, state, options, events, ... }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Same API for all registries:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
container.servers.available
|
|
52
|
+
container.servers.describe('express')
|
|
53
|
+
|
|
54
|
+
container.clients.available
|
|
55
|
+
container.clients.describe('rest')
|
|
56
|
+
|
|
57
|
+
container.commands.available
|
|
58
|
+
container.commands.describe('serve')
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Helper-Level Introspection
|
|
62
|
+
|
|
63
|
+
Every helper instance can describe itself:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
const fs = container.feature('fs')
|
|
67
|
+
|
|
68
|
+
// Structured data
|
|
69
|
+
const info = fs.introspect()
|
|
70
|
+
// => { className, methods: [...], getters: [...], state: {...}, events: [...] }
|
|
71
|
+
|
|
72
|
+
// Human-readable markdown
|
|
73
|
+
const docs = fs.introspectAsText()
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### What's in the Introspection Data?
|
|
77
|
+
|
|
78
|
+
- **Class name** and description (from JSDoc)
|
|
79
|
+
- **Methods** -- name, description, parameters, return type
|
|
80
|
+
- **Getters** -- name, description, type
|
|
81
|
+
- **State schema** -- all observable state fields with descriptions
|
|
82
|
+
- **Options schema** -- all configuration options with descriptions and defaults
|
|
83
|
+
- **Events** -- known event names with descriptions
|
|
84
|
+
|
|
85
|
+
## How It Works
|
|
86
|
+
|
|
87
|
+
Introspection comes from two sources:
|
|
88
|
+
|
|
89
|
+
1. **Build-time extraction** -- Luca's build step parses JSDoc comments, method signatures, and getter types from source code using AST analysis. Run `bun run build:introspection` to update this.
|
|
90
|
+
|
|
91
|
+
2. **Runtime Zod schemas** -- State, options, and events schemas provide descriptions, types, and defaults at runtime via Zod's `.describe()` method.
|
|
92
|
+
|
|
93
|
+
## Practical Example: Dynamic Tool Generation
|
|
94
|
+
|
|
95
|
+
An AI agent can use introspection to generate tool definitions for any feature:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// Agent discovers available features
|
|
99
|
+
const available = container.features.available
|
|
100
|
+
|
|
101
|
+
// Agent learns about a specific feature
|
|
102
|
+
const fsInfo = container.features.introspect('fs')
|
|
103
|
+
|
|
104
|
+
// fsInfo.methods tells the agent:
|
|
105
|
+
// - readFile(path: string): string
|
|
106
|
+
// - writeFile(path: string, content: string): Promise<string>
|
|
107
|
+
// - walk(basePath: string, options?: WalkOptions): { files: string[], directories: string[] }
|
|
108
|
+
// etc.
|
|
109
|
+
|
|
110
|
+
// The agent can now use these methods without prior training on the fs feature
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Using Introspection in Your Features
|
|
114
|
+
|
|
115
|
+
Make your custom features introspectable by:
|
|
116
|
+
|
|
117
|
+
1. Writing JSDoc on the class, methods, and getters
|
|
118
|
+
2. Using Zod `.describe()` on schema fields
|
|
119
|
+
3. Running `bun run build:introspection` after changes
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
/**
|
|
123
|
+
* Manages a pool of database connections with automatic health checking.
|
|
124
|
+
* Connections are recycled when they become stale or unhealthy.
|
|
125
|
+
*/
|
|
126
|
+
export class ConnectionPool extends Feature<PoolState, PoolOptions> {
|
|
127
|
+
/**
|
|
128
|
+
* Acquire a connection from the pool.
|
|
129
|
+
* Blocks until a connection is available or the timeout is reached.
|
|
130
|
+
*/
|
|
131
|
+
async acquire(timeout?: number): Promise<Connection> {
|
|
132
|
+
// ...
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** The number of idle connections currently in the pool */
|
|
136
|
+
get idleCount(): number {
|
|
137
|
+
// ...
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** The number of active connections currently checked out */
|
|
141
|
+
get activeCount(): number {
|
|
142
|
+
// ...
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Now `container.features.describe('connectionPool')` returns rich documentation, and `container.features.introspect('connectionPool')` returns structured data -- all extracted from what you already wrote.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Type System and Module Augmentation
|
|
3
|
+
tags: [types, typescript, zod, module-augmentation, schemas, type-safety]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Type System and Module Augmentation
|
|
7
|
+
|
|
8
|
+
Luca's type system ensures that as you add features, clients, servers, and commands, the container's factory methods stay fully typed. This is powered by Zod schemas and TypeScript module augmentation.
|
|
9
|
+
|
|
10
|
+
## The Pattern
|
|
11
|
+
|
|
12
|
+
When you register a new helper, you augment the corresponding interface so TypeScript knows about it:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { Feature, features, FeatureStateSchema, FeatureOptionsSchema } from '@soederpop/luca'
|
|
16
|
+
import { z } from 'zod'
|
|
17
|
+
|
|
18
|
+
// 1. Define your feature
|
|
19
|
+
export class MyCache extends Feature<MyCacheState, MyCacheOptions> {
|
|
20
|
+
// ...
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 2. Register it
|
|
24
|
+
features.register('myCache', MyCache)
|
|
25
|
+
|
|
26
|
+
// 3. Augment the interface
|
|
27
|
+
declare module '@soederpop/luca' {
|
|
28
|
+
interface AvailableFeatures {
|
|
29
|
+
myCache: typeof MyCache
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 4. Now fully typed everywhere:
|
|
34
|
+
const cache = container.feature('myCache', { ttl: 3600 })
|
|
35
|
+
// ^-- TypeScript knows this is MyCache
|
|
36
|
+
// ^-- autocomplete for MyCache options
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Zod Schemas = Types + Runtime Validation
|
|
40
|
+
|
|
41
|
+
Every schema you define gives you both compile-time types and runtime validation:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// Define once with Zod
|
|
45
|
+
export const UserOptionsSchema = FeatureOptionsSchema.extend({
|
|
46
|
+
apiKey: z.string().describe('API key for authentication'),
|
|
47
|
+
timeout: z.number().default(5000).describe('Request timeout in ms'),
|
|
48
|
+
retries: z.number().default(3).describe('Max retry attempts'),
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
// Extract the type
|
|
52
|
+
export type UserOptions = z.infer<typeof UserOptionsSchema>
|
|
53
|
+
|
|
54
|
+
// Use for static typing
|
|
55
|
+
export class UserService extends Feature<UserState, UserOptions> {
|
|
56
|
+
static override optionsSchema = UserOptionsSchema
|
|
57
|
+
|
|
58
|
+
connect() {
|
|
59
|
+
// this.options is typed: { apiKey: string, timeout: number, retries: number }
|
|
60
|
+
const { apiKey, timeout } = this.options
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The schema also powers:
|
|
66
|
+
- **Runtime validation** when options are passed to the factory
|
|
67
|
+
- **Introspection** -- `.describe()` text appears in `helper.introspect()`
|
|
68
|
+
- **Documentation** -- field descriptions appear in `container.features.describe('userService')`
|
|
69
|
+
|
|
70
|
+
## State Typing
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
const TaskStateSchema = FeatureStateSchema.extend({
|
|
74
|
+
tasks: z.array(z.object({
|
|
75
|
+
id: z.string(),
|
|
76
|
+
title: z.string(),
|
|
77
|
+
done: z.boolean(),
|
|
78
|
+
})).default([]),
|
|
79
|
+
filter: z.enum(['all', 'active', 'done']).default('all'),
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
type TaskState = z.infer<typeof TaskStateSchema>
|
|
83
|
+
|
|
84
|
+
class TaskManager extends Feature<TaskState> {
|
|
85
|
+
static override stateSchema = TaskStateSchema
|
|
86
|
+
|
|
87
|
+
addTask(title: string) {
|
|
88
|
+
const tasks = this.state.get('tasks')
|
|
89
|
+
// ^-- typed as Array<{ id: string, title: string, done: boolean }>
|
|
90
|
+
|
|
91
|
+
this.state.set('tasks', [...(tasks || []), { id: '1', title, done: false }])
|
|
92
|
+
// ^-- TypeScript validates the shape
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Module Augmentation for All Helper Types
|
|
98
|
+
|
|
99
|
+
The pattern is the same for features, clients, servers, and commands:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// Features
|
|
103
|
+
declare module '@soederpop/luca' {
|
|
104
|
+
interface AvailableFeatures {
|
|
105
|
+
myFeature: typeof MyFeature
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Clients
|
|
110
|
+
declare module '@soederpop/luca' {
|
|
111
|
+
interface AvailableClients {
|
|
112
|
+
myClient: typeof MyClient
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Servers
|
|
117
|
+
declare module '@soederpop/luca' {
|
|
118
|
+
interface AvailableServers {
|
|
119
|
+
myServer: typeof MyServer
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Commands
|
|
124
|
+
declare module '@soederpop/luca' {
|
|
125
|
+
interface AvailableCommands {
|
|
126
|
+
myCommand: typeof MyCommand
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Using .describe() Effectively
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const ConfigSchema = z.object({
|
|
135
|
+
host: z.string().describe('Database hostname or IP address'),
|
|
136
|
+
port: z.number().default(5432).describe('Database port'),
|
|
137
|
+
database: z.string().describe('Database name to connect to'),
|
|
138
|
+
ssl: z.boolean().default(false).describe('Whether to use SSL/TLS for the connection'),
|
|
139
|
+
pool: z.object({
|
|
140
|
+
min: z.number().default(2).describe('Minimum connections to keep open'),
|
|
141
|
+
max: z.number().default(10).describe('Maximum connections allowed'),
|
|
142
|
+
}).describe('Connection pool configuration'),
|
|
143
|
+
})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
These descriptions are not just for humans reading the code -- they show up in:
|
|
147
|
+
- `container.features.describe('db')` output
|
|
148
|
+
- `container.features.introspect('db')` data
|
|
149
|
+
- OpenAPI specs when used in endpoint schemas
|
|
150
|
+
- AI agent tool descriptions
|
|
151
|
+
|
|
152
|
+
## The Full Typed Flow
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// 1. You define a feature with schemas
|
|
156
|
+
export class Analytics extends Feature<AnalyticsState, AnalyticsOptions> { ... }
|
|
157
|
+
|
|
158
|
+
// 2. You register + augment
|
|
159
|
+
features.register('analytics', Analytics)
|
|
160
|
+
declare module '@soederpop/luca' {
|
|
161
|
+
interface AvailableFeatures { analytics: typeof Analytics }
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// 3. Now every interaction is typed:
|
|
165
|
+
const a = container.feature('analytics', { trackingId: 'UA-123' })
|
|
166
|
+
// ^-- Analytics instance ^-- autocomplete: 'analytics'
|
|
167
|
+
// ^-- type error if wrong options
|
|
168
|
+
|
|
169
|
+
a.state.get('pageViews') // typed by AnalyticsState
|
|
170
|
+
a.on('pageView', ...) // typed by event definitions
|
|
171
|
+
a.track('click', { ... }) // typed by Analytics methods
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
This is the core principle: **never break the type system.** Every step of `container.feature('name', options)` should give you autocomplete, type checking, and documentation.
|