@soederpop/luca 0.1.1 → 0.1.3
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 +2 -0
- package/assistants/codingAssistant/hooks.ts +3 -0
- package/assistants/inkbot/CORE.md +69 -0
- package/assistants/inkbot/hooks.ts +14 -0
- package/assistants/inkbot/tools.ts +47 -0
- package/commands/inkbot.ts +353 -0
- package/dist/agi/container.server.d.ts +63 -0
- package/dist/agi/container.server.d.ts.map +1 -0
- package/dist/agi/endpoints/ask.d.ts +20 -0
- package/dist/agi/endpoints/ask.d.ts.map +1 -0
- package/dist/agi/endpoints/conversations/[id].d.ts +27 -0
- package/dist/agi/endpoints/conversations/[id].d.ts.map +1 -0
- package/dist/agi/endpoints/conversations.d.ts +18 -0
- package/dist/agi/endpoints/conversations.d.ts.map +1 -0
- package/dist/agi/endpoints/experts.d.ts +8 -0
- package/dist/agi/endpoints/experts.d.ts.map +1 -0
- package/dist/agi/feature.d.ts +9 -0
- package/dist/agi/feature.d.ts.map +1 -0
- package/dist/agi/features/assistant.d.ts +509 -0
- package/dist/agi/features/assistant.d.ts.map +1 -0
- package/dist/agi/features/assistants-manager.d.ts +236 -0
- package/dist/agi/features/assistants-manager.d.ts.map +1 -0
- package/dist/agi/features/autonomous-assistant.d.ts +281 -0
- package/dist/agi/features/autonomous-assistant.d.ts.map +1 -0
- package/dist/agi/features/browser-use.d.ts +479 -0
- package/dist/agi/features/browser-use.d.ts.map +1 -0
- package/dist/agi/features/claude-code.d.ts +824 -0
- package/dist/agi/features/claude-code.d.ts.map +1 -0
- package/dist/agi/features/conversation-history.d.ts +245 -0
- package/dist/agi/features/conversation-history.d.ts.map +1 -0
- package/dist/agi/features/conversation.d.ts +464 -0
- package/dist/agi/features/conversation.d.ts.map +1 -0
- package/dist/agi/features/docs-reader.d.ts +72 -0
- package/dist/agi/features/docs-reader.d.ts.map +1 -0
- package/dist/agi/features/file-tools.d.ts +110 -0
- package/dist/agi/features/file-tools.d.ts.map +1 -0
- package/dist/agi/features/luca-coder.d.ts +323 -0
- package/dist/agi/features/luca-coder.d.ts.map +1 -0
- package/dist/agi/features/openai-codex.d.ts +381 -0
- package/dist/agi/features/openai-codex.d.ts.map +1 -0
- package/dist/agi/features/openapi.d.ts +200 -0
- package/dist/agi/features/openapi.d.ts.map +1 -0
- package/dist/agi/features/skills-library.d.ts +167 -0
- package/dist/agi/features/skills-library.d.ts.map +1 -0
- package/dist/agi/index.d.ts +5 -0
- package/dist/agi/index.d.ts.map +1 -0
- package/dist/agi/lib/interceptor-chain.d.ts +44 -0
- package/dist/agi/lib/interceptor-chain.d.ts.map +1 -0
- package/dist/agi/lib/token-counter.d.ts +13 -0
- package/dist/agi/lib/token-counter.d.ts.map +1 -0
- package/dist/bootstrap/generated.d.ts +5 -0
- package/dist/bootstrap/generated.d.ts.map +1 -0
- package/dist/browser.d.ts +12 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/bus.d.ts +29 -0
- package/dist/bus.d.ts.map +1 -0
- package/dist/cli/build-info.d.ts +4 -0
- package/dist/cli/build-info.d.ts.map +1 -0
- package/dist/cli/cli.d.ts +3 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/client.d.ts +60 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/clients/civitai/index.d.ts +472 -0
- package/dist/clients/civitai/index.d.ts.map +1 -0
- package/dist/clients/client-template.d.ts +30 -0
- package/dist/clients/client-template.d.ts.map +1 -0
- package/dist/clients/comfyui/index.d.ts +281 -0
- package/dist/clients/comfyui/index.d.ts.map +1 -0
- package/dist/clients/elevenlabs/index.d.ts +197 -0
- package/dist/clients/elevenlabs/index.d.ts.map +1 -0
- package/dist/clients/graph.d.ts +64 -0
- package/dist/clients/graph.d.ts.map +1 -0
- package/dist/clients/openai/index.d.ts +247 -0
- package/dist/clients/openai/index.d.ts.map +1 -0
- package/dist/clients/rest.d.ts +92 -0
- package/dist/clients/rest.d.ts.map +1 -0
- package/dist/clients/supabase/index.d.ts +176 -0
- package/dist/clients/supabase/index.d.ts.map +1 -0
- package/dist/clients/websocket.d.ts +127 -0
- package/dist/clients/websocket.d.ts.map +1 -0
- package/dist/command.d.ts +163 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/commands/bootstrap.d.ts +20 -0
- package/dist/commands/bootstrap.d.ts.map +1 -0
- package/dist/commands/chat.d.ts +37 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/code.d.ts +28 -0
- package/dist/commands/code.d.ts.map +1 -0
- package/dist/commands/console.d.ts +22 -0
- package/dist/commands/console.d.ts.map +1 -0
- package/dist/commands/describe.d.ts +50 -0
- package/dist/commands/describe.d.ts.map +1 -0
- package/dist/commands/eval.d.ts +23 -0
- package/dist/commands/eval.d.ts.map +1 -0
- package/dist/commands/help.d.ts +25 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/index.d.ts +18 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/introspect.d.ts +24 -0
- package/dist/commands/introspect.d.ts.map +1 -0
- package/dist/commands/mcp.d.ts +35 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/prompt.d.ts +38 -0
- package/dist/commands/prompt.d.ts.map +1 -0
- package/dist/commands/run.d.ts +24 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/sandbox-mcp.d.ts +34 -0
- package/dist/commands/sandbox-mcp.d.ts.map +1 -0
- package/dist/commands/save-api-docs.d.ts +21 -0
- package/dist/commands/save-api-docs.d.ts.map +1 -0
- package/dist/commands/scaffold.d.ts +24 -0
- package/dist/commands/scaffold.d.ts.map +1 -0
- package/dist/commands/select.d.ts +22 -0
- package/dist/commands/select.d.ts.map +1 -0
- package/dist/commands/serve.d.ts +29 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/container-describer.d.ts +144 -0
- package/dist/container-describer.d.ts.map +1 -0
- package/dist/container.d.ts +451 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/endpoint.d.ts +113 -0
- package/dist/endpoint.d.ts.map +1 -0
- package/dist/feature.d.ts +47 -0
- package/dist/feature.d.ts.map +1 -0
- package/dist/graft.d.ts +29 -0
- package/dist/graft.d.ts.map +1 -0
- package/dist/hash-object.d.ts +8 -0
- package/dist/hash-object.d.ts.map +1 -0
- package/dist/helper.d.ts +209 -0
- package/dist/helper.d.ts.map +1 -0
- package/dist/introspection/generated.node.d.ts +44623 -0
- package/dist/introspection/generated.node.d.ts.map +1 -0
- package/dist/introspection/generated.web.d.ts +1412 -0
- package/dist/introspection/generated.web.d.ts.map +1 -0
- package/dist/introspection/index.d.ts +156 -0
- package/dist/introspection/index.d.ts.map +1 -0
- package/dist/introspection/scan.d.ts +147 -0
- package/dist/introspection/scan.d.ts.map +1 -0
- package/dist/node/container.d.ts +256 -0
- package/dist/node/container.d.ts.map +1 -0
- package/dist/node/feature.d.ts +9 -0
- package/dist/node/feature.d.ts.map +1 -0
- package/dist/node/features/container-link.d.ts +213 -0
- package/dist/node/features/container-link.d.ts.map +1 -0
- package/dist/node/features/content-db.d.ts +354 -0
- package/dist/node/features/content-db.d.ts.map +1 -0
- package/dist/node/features/disk-cache.d.ts +236 -0
- package/dist/node/features/disk-cache.d.ts.map +1 -0
- package/dist/node/features/dns.d.ts +511 -0
- package/dist/node/features/dns.d.ts.map +1 -0
- package/dist/node/features/docker.d.ts +485 -0
- package/dist/node/features/docker.d.ts.map +1 -0
- package/dist/node/features/downloader.d.ts +73 -0
- package/dist/node/features/downloader.d.ts.map +1 -0
- package/dist/node/features/figlet-fonts.d.ts +4 -0
- package/dist/node/features/figlet-fonts.d.ts.map +1 -0
- package/dist/node/features/file-manager.d.ts +177 -0
- package/dist/node/features/file-manager.d.ts.map +1 -0
- package/dist/node/features/fs.d.ts +635 -0
- package/dist/node/features/fs.d.ts.map +1 -0
- package/dist/node/features/git.d.ts +329 -0
- package/dist/node/features/git.d.ts.map +1 -0
- package/dist/node/features/google-auth.d.ts +200 -0
- package/dist/node/features/google-auth.d.ts.map +1 -0
- package/dist/node/features/google-calendar.d.ts +194 -0
- package/dist/node/features/google-calendar.d.ts.map +1 -0
- package/dist/node/features/google-docs.d.ts +138 -0
- package/dist/node/features/google-docs.d.ts.map +1 -0
- package/dist/node/features/google-drive.d.ts +202 -0
- package/dist/node/features/google-drive.d.ts.map +1 -0
- package/dist/node/features/google-mail.d.ts +221 -0
- package/dist/node/features/google-mail.d.ts.map +1 -0
- package/dist/node/features/google-sheets.d.ts +157 -0
- package/dist/node/features/google-sheets.d.ts.map +1 -0
- package/dist/node/features/grep.d.ts +207 -0
- package/dist/node/features/grep.d.ts.map +1 -0
- package/dist/node/features/helpers.d.ts +236 -0
- package/dist/node/features/helpers.d.ts.map +1 -0
- package/dist/node/features/ink.d.ts +332 -0
- package/dist/node/features/ink.d.ts.map +1 -0
- package/dist/node/features/ipc-socket.d.ts +298 -0
- package/dist/node/features/ipc-socket.d.ts.map +1 -0
- package/dist/node/features/json-tree.d.ts +140 -0
- package/dist/node/features/json-tree.d.ts.map +1 -0
- package/dist/node/features/networking.d.ts +373 -0
- package/dist/node/features/networking.d.ts.map +1 -0
- package/dist/node/features/nlp.d.ts +125 -0
- package/dist/node/features/nlp.d.ts.map +1 -0
- package/dist/node/features/opener.d.ts +93 -0
- package/dist/node/features/opener.d.ts.map +1 -0
- package/dist/node/features/os.d.ts +168 -0
- package/dist/node/features/os.d.ts.map +1 -0
- package/dist/node/features/package-finder.d.ts +419 -0
- package/dist/node/features/package-finder.d.ts.map +1 -0
- package/dist/node/features/postgres.d.ts +173 -0
- package/dist/node/features/postgres.d.ts.map +1 -0
- package/dist/node/features/proc.d.ts +285 -0
- package/dist/node/features/proc.d.ts.map +1 -0
- package/dist/node/features/process-manager.d.ts +427 -0
- package/dist/node/features/process-manager.d.ts.map +1 -0
- package/dist/node/features/python.d.ts +477 -0
- package/dist/node/features/python.d.ts.map +1 -0
- package/dist/node/features/redis.d.ts +247 -0
- package/dist/node/features/redis.d.ts.map +1 -0
- package/dist/node/features/repl.d.ts +84 -0
- package/dist/node/features/repl.d.ts.map +1 -0
- package/dist/node/features/runpod.d.ts +527 -0
- package/dist/node/features/runpod.d.ts.map +1 -0
- package/dist/node/features/secure-shell.d.ts +145 -0
- package/dist/node/features/secure-shell.d.ts.map +1 -0
- package/dist/node/features/semantic-search.d.ts +207 -0
- package/dist/node/features/semantic-search.d.ts.map +1 -0
- package/dist/node/features/sqlite.d.ts +180 -0
- package/dist/node/features/sqlite.d.ts.map +1 -0
- package/dist/node/features/telegram.d.ts +173 -0
- package/dist/node/features/telegram.d.ts.map +1 -0
- package/dist/node/features/transpiler.d.ts +51 -0
- package/dist/node/features/transpiler.d.ts.map +1 -0
- package/dist/node/features/tts.d.ts +108 -0
- package/dist/node/features/tts.d.ts.map +1 -0
- package/dist/node/features/ui.d.ts +562 -0
- package/dist/node/features/ui.d.ts.map +1 -0
- package/dist/node/features/vault.d.ts +90 -0
- package/dist/node/features/vault.d.ts.map +1 -0
- package/dist/node/features/vm.d.ts +285 -0
- package/dist/node/features/vm.d.ts.map +1 -0
- package/dist/node/features/yaml-tree.d.ts +118 -0
- package/dist/node/features/yaml-tree.d.ts.map +1 -0
- package/dist/node/features/yaml.d.ts +127 -0
- package/dist/node/features/yaml.d.ts.map +1 -0
- package/dist/node.d.ts +67 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/python/generated.d.ts +2 -0
- package/dist/python/generated.d.ts.map +1 -0
- package/dist/react/index.d.ts +36 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/registry.d.ts +97 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/scaffolds/generated.d.ts +13 -0
- package/dist/scaffolds/generated.d.ts.map +1 -0
- package/dist/scaffolds/template.d.ts +11 -0
- package/dist/scaffolds/template.d.ts.map +1 -0
- package/dist/schemas/base.d.ts +254 -0
- package/dist/schemas/base.d.ts.map +1 -0
- package/dist/selector.d.ts +130 -0
- package/dist/selector.d.ts.map +1 -0
- package/dist/server.d.ts +89 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/servers/express.d.ts +104 -0
- package/dist/servers/express.d.ts.map +1 -0
- package/dist/servers/mcp.d.ts +201 -0
- package/dist/servers/mcp.d.ts.map +1 -0
- package/dist/servers/socket.d.ts +121 -0
- package/dist/servers/socket.d.ts.map +1 -0
- package/dist/state.d.ts +24 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/web/clients/socket.d.ts +37 -0
- package/dist/web/clients/socket.d.ts.map +1 -0
- package/dist/web/container.d.ts +55 -0
- package/dist/web/container.d.ts.map +1 -0
- package/dist/web/extension.d.ts +4 -0
- package/dist/web/extension.d.ts.map +1 -0
- package/dist/web/feature.d.ts +8 -0
- package/dist/web/feature.d.ts.map +1 -0
- package/dist/web/features/asset-loader.d.ts +35 -0
- package/dist/web/features/asset-loader.d.ts.map +1 -0
- package/dist/web/features/container-link.d.ts +167 -0
- package/dist/web/features/container-link.d.ts.map +1 -0
- package/dist/web/features/esbuild.d.ts +51 -0
- package/dist/web/features/esbuild.d.ts.map +1 -0
- package/dist/web/features/helpers.d.ts +140 -0
- package/dist/web/features/helpers.d.ts.map +1 -0
- package/dist/web/features/network.d.ts +69 -0
- package/dist/web/features/network.d.ts.map +1 -0
- package/dist/web/features/speech.d.ts +71 -0
- package/dist/web/features/speech.d.ts.map +1 -0
- package/dist/web/features/vault.d.ts +62 -0
- package/dist/web/features/vault.d.ts.map +1 -0
- package/dist/web/features/vm.d.ts +48 -0
- package/dist/web/features/vm.d.ts.map +1 -0
- package/dist/web/features/voice-recognition.d.ts +96 -0
- package/dist/web/features/voice-recognition.d.ts.map +1 -0
- package/dist/web/shims/isomorphic-vm.d.ts +22 -0
- package/dist/web/shims/isomorphic-vm.d.ts.map +1 -0
- package/docs/apis/features/agi/assistant.md +1 -0
- package/docs/apis/features/agi/assistants-manager.md +62 -2
- package/docs/apis/features/agi/auto-assistant.md +11 -109
- package/docs/apis/features/agi/claude-code.md +138 -0
- package/docs/apis/features/agi/conversation.md +60 -31
- package/docs/apis/features/agi/luca-coder.md +407 -0
- package/docs/apis/features/agi/openapi.md +2 -2
- package/docs/apis/features/agi/skills-library.md +12 -0
- package/docs/apis/features/node/python.md +81 -11
- package/docs/apis/features/node/transpiler.md +74 -0
- package/docs/apis/features/web/esbuild.md +0 -6
- package/docs/apis/servers/mcp.md +2 -2
- package/docs/examples/entity.md +124 -0
- package/package.json +73 -21
- package/scripts/test-assistant-hooks.ts +13 -0
- package/src/agi/feature.ts +13 -0
- package/src/agi/features/assistant.ts +36 -25
- package/src/agi/features/assistants-manager.ts +70 -5
- package/src/agi/features/autonomous-assistant.ts +1 -5
- package/src/agi/features/browser-use.ts +2 -2
- package/src/agi/features/claude-code.ts +165 -1
- package/src/agi/features/conversation-history.ts +2 -6
- package/src/agi/features/conversation.ts +95 -3
- package/src/agi/features/docs-reader.ts +2 -1
- package/src/agi/features/file-tools.ts +2 -2
- package/src/agi/features/luca-coder.ts +1 -5
- package/src/agi/features/openai-codex.ts +1 -1
- package/src/agi/features/openapi.ts +3 -3
- package/src/agi/features/skills-library.ts +90 -2
- package/src/agi/lib/interceptor-chain.ts +10 -0
- package/src/agi/lib/token-counter.ts +1 -1
- package/src/bootstrap/generated.ts +126 -1
- package/src/bus.ts +27 -5
- package/src/cli/build-info.ts +2 -2
- package/src/client.ts +2 -2
- package/src/clients/elevenlabs/index.ts +5 -0
- package/src/commands/bootstrap.ts +2 -1
- package/src/commands/chat.ts +1 -0
- package/src/commands/code.ts +4 -2
- package/src/commands/prompt.ts +34 -34
- package/src/commands/sandbox-mcp.ts +69 -163
- package/src/commands/save-api-docs.ts +10 -8
- package/src/commands/select.ts +8 -3
- package/src/container-describer.ts +70 -84
- package/src/container.ts +93 -3
- package/src/endpoint.ts +1 -1
- package/src/entity.ts +173 -0
- package/src/feature.ts +3 -3
- package/src/helper.ts +8 -4
- package/src/introspection/generated.agi.ts +1403 -929
- package/src/introspection/generated.node.ts +127 -33
- package/src/introspection/generated.web.ts +95 -3
- package/src/introspection/scan.ts +1 -1
- package/src/node/container.ts +1 -1
- package/src/node/features/content-db.ts +3 -3
- package/src/node/features/file-manager.ts +10 -9
- package/src/node/features/git.ts +5 -5
- package/src/node/features/helpers.ts +1 -1
- package/src/node/features/json-tree.ts +1 -1
- package/src/node/features/os.ts +3 -3
- package/src/node/features/package-finder.ts +1 -1
- package/src/node/features/process-manager.ts +1 -1
- package/src/node/features/python.ts +3 -3
- package/src/node/features/redis.ts +1 -1
- package/src/node/features/repl.ts +2 -2
- package/src/node/features/transpiler.ts +34 -9
- package/src/node/features/ui.ts +1 -1
- package/src/node/features/vm.ts +6 -5
- package/src/node/features/yaml-tree.ts +1 -1
- package/src/node.ts +1 -0
- package/src/python/generated.ts +1 -1
- package/src/scaffolds/generated.ts +1 -1
- package/src/selector.ts +74 -4
- package/src/server.ts +2 -2
- package/src/servers/mcp.ts +6 -6
- package/src/web/features/helpers.ts +1 -1
- package/src/web/features/network.ts +1 -0
- package/test/assistant.test.ts +72 -0
- package/test/conversation.test.ts +220 -0
- package/test/vm-loadmodule.test.ts +213 -0
- package/tsconfig.build.json +12 -0
- package/tsconfig.json +1 -1
- package/scripts/examples/telegram-ink-ui.ts +0 -302
- package/scripts/examples/using-openai-codex.ts +0 -23
- package/scripts/examples/vm-loading-esm-modules.ts +0 -16
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Entity"
|
|
3
|
+
tags: [entity, state, events, tools, core]
|
|
4
|
+
lastTested: null
|
|
5
|
+
lastTestPassed: null
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# entity
|
|
9
|
+
|
|
10
|
+
Lightweight, composable objects with observable state, a typed event bus, and an optional tool interface.
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
An entity is a plain object — not a class — created via `container.entity(id, options?)`. Same id + options always returns the same underlying state and bus instance. Entities are designed to be extended with methods and getters via `.extend()`, and can expose those methods as AI tools via `.expose()`.
|
|
15
|
+
|
|
16
|
+
## Basic Entity with Observable State
|
|
17
|
+
|
|
18
|
+
Create an entity and read/write state through the observable `state` property.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
const counter = container.entity<{ count: number }>('counter')
|
|
22
|
+
counter.setState({ count: 0 })
|
|
23
|
+
|
|
24
|
+
counter.state.observe((next) => {
|
|
25
|
+
console.log('count changed to', next.count)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
counter.setState(s => ({ count: s.count + 1 }))
|
|
29
|
+
counter.setState(s => ({ count: s.count + 1 }))
|
|
30
|
+
console.log('final count:', counter.state.get('count'))
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`setState` accepts either a partial object or a function that receives the current state. Observers fire synchronously after each change.
|
|
34
|
+
|
|
35
|
+
## Typed Event Bus
|
|
36
|
+
|
|
37
|
+
Every entity has a built-in event bus. Declare the event map as the third type parameter.
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
type TimerEvents = {
|
|
41
|
+
tick: [elapsed: number]
|
|
42
|
+
done: []
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const timer = container.entity<{}, {}, TimerEvents>('timer')
|
|
46
|
+
|
|
47
|
+
timer.on('tick', (elapsed) => {
|
|
48
|
+
console.log('tick at', elapsed, 'ms')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
timer.once('done', () => {
|
|
52
|
+
console.log('timer finished')
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
timer.emit('tick', 100)
|
|
56
|
+
timer.emit('tick', 200)
|
|
57
|
+
timer.emit('done')
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`once` auto-detaches after the first fire. `waitFor` returns a promise that resolves on the next emit of that event.
|
|
61
|
+
|
|
62
|
+
## Extending with Methods
|
|
63
|
+
|
|
64
|
+
Use `.extend()` to graft methods and getters onto an entity. All base properties — `state`, `options`, `container`, and the event methods — are available via `this`.
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
const session = container.entity('session', { userId: '42' })
|
|
68
|
+
.extend({
|
|
69
|
+
greet() {
|
|
70
|
+
return `Hello user ${this.options.userId}`
|
|
71
|
+
},
|
|
72
|
+
get label() {
|
|
73
|
+
return `Session ${this.id} (user ${this.options.userId})`
|
|
74
|
+
},
|
|
75
|
+
bump() {
|
|
76
|
+
const visits = (this.state.get('visits') ?? 0) + 1
|
|
77
|
+
this.setState({ visits })
|
|
78
|
+
this.emit('visited', visits)
|
|
79
|
+
return visits
|
|
80
|
+
},
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
console.log(session.greet())
|
|
84
|
+
console.log(session.label)
|
|
85
|
+
console.log('visits:', session.bump())
|
|
86
|
+
console.log('visits:', session.bump())
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Extensions are chained via prototype delegation — each layer can see everything below it.
|
|
90
|
+
|
|
91
|
+
## Exposing Methods as AI Tools
|
|
92
|
+
|
|
93
|
+
Use `.expose(methodName, zodSchema)` to register methods as tools. `.toTools()` returns `{ schemas, handlers }` compatible with `assistant.addTools()`.
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
const search = container.entity('search', {})
|
|
97
|
+
.extend({
|
|
98
|
+
async lookup({ query }: { query: string }) {
|
|
99
|
+
return `Results for: ${query}`
|
|
100
|
+
},
|
|
101
|
+
async summarize({ text, maxWords }: { text: string; maxWords: number }) {
|
|
102
|
+
return text.split(' ').slice(0, maxWords).join(' ')
|
|
103
|
+
},
|
|
104
|
+
})
|
|
105
|
+
.expose('lookup', z.object({
|
|
106
|
+
query: z.string().describe('The search query'),
|
|
107
|
+
}))
|
|
108
|
+
.expose('summarize', z.object({
|
|
109
|
+
text: z.string().describe('Text to summarize'),
|
|
110
|
+
maxWords: z.number().describe('Maximum words in summary'),
|
|
111
|
+
}))
|
|
112
|
+
|
|
113
|
+
const { schemas, handlers } = search.toTools()
|
|
114
|
+
console.log('registered tools:', Object.keys(schemas))
|
|
115
|
+
|
|
116
|
+
// Pass directly to an assistant
|
|
117
|
+
// assistant.addTools(search)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`.expose()` is chainable and returns `this`, so you can stack as many as you need.
|
|
121
|
+
|
|
122
|
+
## Summary
|
|
123
|
+
|
|
124
|
+
Entities give you observable state, a typed event bus, and prototype-safe method extension — all as a plain object with no class overhead. The `.expose()` / `.toTools()` interface makes it straightforward to surface entity methods as AI tools.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soederpop/luca",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"website": "https://luca.soederpop.com",
|
|
5
5
|
"description": "lightweight universal conversational architecture AKA Le Ultimate Component Architecture AKA Last Universal Common Ancestor, part AI part Human",
|
|
6
6
|
"author": "jon soeder aka the people's champ <jon@soederpop.com>",
|
|
@@ -19,26 +19,77 @@
|
|
|
19
19
|
"coding assistant"
|
|
20
20
|
],
|
|
21
21
|
"main": "./src/node.ts",
|
|
22
|
-
"types": "./
|
|
22
|
+
"types": "./dist/node.d.ts",
|
|
23
23
|
"browser": "./src/browser.ts",
|
|
24
24
|
"exports": {
|
|
25
|
-
".":
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"./
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"./
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"./
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"./
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/node.d.ts",
|
|
27
|
+
"default": "./src/node.ts"
|
|
28
|
+
},
|
|
29
|
+
"./node": {
|
|
30
|
+
"types": "./dist/node.d.ts",
|
|
31
|
+
"default": "./src/node.ts"
|
|
32
|
+
},
|
|
33
|
+
"./node/*": {
|
|
34
|
+
"types": "./dist/node/*.d.ts",
|
|
35
|
+
"default": "./src/node/*"
|
|
36
|
+
},
|
|
37
|
+
"./web": {
|
|
38
|
+
"types": "./dist/browser.d.ts",
|
|
39
|
+
"default": "./src/browser.ts"
|
|
40
|
+
},
|
|
41
|
+
"./web/*": {
|
|
42
|
+
"types": "./dist/web/*.d.ts",
|
|
43
|
+
"default": "./src/web/*"
|
|
44
|
+
},
|
|
45
|
+
"./agi": {
|
|
46
|
+
"types": "./dist/agi/index.d.ts",
|
|
47
|
+
"default": "./src/agi/index.ts"
|
|
48
|
+
},
|
|
49
|
+
"./agi/*": {
|
|
50
|
+
"types": "./dist/agi/*.d.ts",
|
|
51
|
+
"default": "./src/agi/*"
|
|
52
|
+
},
|
|
53
|
+
"./schemas": {
|
|
54
|
+
"types": "./dist/schemas/base.d.ts",
|
|
55
|
+
"default": "./src/schemas/base.ts"
|
|
56
|
+
},
|
|
57
|
+
"./schemas/*": {
|
|
58
|
+
"types": "./dist/schemas/*.d.ts",
|
|
59
|
+
"default": "./src/schemas/*"
|
|
60
|
+
},
|
|
61
|
+
"./container": {
|
|
62
|
+
"types": "./dist/container.d.ts",
|
|
63
|
+
"default": "./src/container.ts"
|
|
64
|
+
},
|
|
65
|
+
"./client": {
|
|
66
|
+
"types": "./dist/client.d.ts",
|
|
67
|
+
"default": "./src/client.ts"
|
|
68
|
+
},
|
|
69
|
+
"./clients/*": {
|
|
70
|
+
"types": "./dist/clients/*.d.ts",
|
|
71
|
+
"default": "./src/clients/*"
|
|
72
|
+
},
|
|
73
|
+
"./server": {
|
|
74
|
+
"types": "./dist/server.d.ts",
|
|
75
|
+
"default": "./src/server.ts"
|
|
76
|
+
},
|
|
77
|
+
"./servers/*": {
|
|
78
|
+
"types": "./dist/servers/*.d.ts",
|
|
79
|
+
"default": "./src/servers/*"
|
|
80
|
+
},
|
|
81
|
+
"./feature": {
|
|
82
|
+
"types": "./dist/feature.d.ts",
|
|
83
|
+
"default": "./src/feature.ts"
|
|
84
|
+
},
|
|
85
|
+
"./react": {
|
|
86
|
+
"types": "./dist/react/index.d.ts",
|
|
87
|
+
"default": "./src/react/index.ts"
|
|
88
|
+
},
|
|
89
|
+
"./introspection": {
|
|
90
|
+
"types": "./dist/introspection/index.d.ts",
|
|
91
|
+
"default": "./src/introspection/index.ts"
|
|
92
|
+
}
|
|
42
93
|
},
|
|
43
94
|
"bin": {
|
|
44
95
|
"luca": "./src/cli/cli.ts"
|
|
@@ -51,13 +102,14 @@
|
|
|
51
102
|
"build:web": "bun run scripts/build-web.ts",
|
|
52
103
|
"build:introspection": "bun run src/cli/cli.ts introspect",
|
|
53
104
|
"compile": "bun run build:introspection && bun run build:scaffolds && bun run build:bootstrap && bun run build:python-bridge && bash scripts/stamp-build.sh && bun build ./src/cli/cli.ts --compile --outfile dist/luca --external node-llama-cpp",
|
|
105
|
+
"build:types": "tsc -p tsconfig.build.json",
|
|
54
106
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
55
107
|
"build:scaffolds": "bun run src/cli/cli.ts build-scaffolds",
|
|
56
108
|
"build:bootstrap": "bun run src/cli/cli.ts build-bootstrap",
|
|
57
109
|
"build:python-bridge": "bun run src/cli/cli.ts build-python-bridge",
|
|
58
110
|
"test": "bun test test/*.test.ts",
|
|
59
111
|
"update-all-docs": "bun run test && bun run build:introspection && bun run src/cli/cli.ts generate-api-docs && bun run build:scaffolds && bun run build:bootstrap && bun run build:python-bridge",
|
|
60
|
-
"precommit": "bun run update-all-docs && git add docs/apis/ src/introspection/generated.*.ts src/scaffolds/generated.ts src/bootstrap/generated.ts src/python/generated.ts && bun compile",
|
|
112
|
+
"precommit": "bun run typecheck && bun run update-all-docs && git add docs/apis/ src/introspection/generated.*.ts src/scaffolds/generated.ts src/bootstrap/generated.ts src/python/generated.ts && bun compile",
|
|
61
113
|
"test:integration": "bun test ./test-integration/"
|
|
62
114
|
},
|
|
63
115
|
"devDependencies": {
|
|
@@ -97,7 +149,7 @@
|
|
|
97
149
|
"@supabase/supabase-js": "^2.95.3",
|
|
98
150
|
"@types/marked": "^6.0.0",
|
|
99
151
|
"@types/marked-terminal": "^6.1.1",
|
|
100
|
-
"axios": "
|
|
152
|
+
"axios": "1.13.6",
|
|
101
153
|
"cacache": "^17.0.7",
|
|
102
154
|
"chalk": "^5.2.0",
|
|
103
155
|
"child-process-promise": "^2.2.1",
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import container from '@soederpop/luca/agi'
|
|
2
|
+
|
|
3
|
+
const coder = container.feature('assistant', { folder: 'assistants/codingAssistant' })
|
|
4
|
+
|
|
5
|
+
await coder.start()
|
|
6
|
+
console.log("Available Tools", coder.availableTools)
|
|
7
|
+
|
|
8
|
+
if (coder.state.get('startedHookRan')) {
|
|
9
|
+
console.log('Started Hook Ran')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AGIFeatures, AGIContainer } from './container.server.js'
|
|
2
|
+
import type { FeatureOptions, FeatureState } from '../feature.ts'
|
|
3
|
+
import { features, Feature as NodeFeature } from '../node/feature.ts'
|
|
4
|
+
|
|
5
|
+
export { features }
|
|
6
|
+
|
|
7
|
+
export type { FeatureState, FeatureOptions }
|
|
8
|
+
|
|
9
|
+
export class Feature<T extends FeatureState = FeatureState, K extends FeatureOptions = FeatureOptions> extends NodeFeature<T, K> {
|
|
10
|
+
override get container(): AGIContainer<AGIFeatures> {
|
|
11
|
+
return super.container as AGIContainer<AGIFeatures>
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
|
|
3
3
|
import { type AvailableFeatures } from '@soederpop/luca/feature'
|
|
4
|
-
import { Feature } from '
|
|
4
|
+
import { Feature } from '../feature.js'
|
|
5
5
|
import type { Conversation, ConversationTool, ContentPart, AskOptions, Message } from './conversation'
|
|
6
|
-
import type { AGIContainer } from '../container.server.js'
|
|
7
6
|
import type { ContentDb } from '@soederpop/luca/node'
|
|
8
7
|
import type { ConversationHistory, ConversationMeta } from './conversation-history'
|
|
9
8
|
import hashObject from '../../hash-object.js'
|
|
@@ -152,6 +151,10 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
|
|
|
152
151
|
* @returns this, for chaining
|
|
153
152
|
*/
|
|
154
153
|
intercept<K extends InterceptorPoint>(point: K, fn: InterceptorFn<InterceptorPoints[K]>): this {
|
|
154
|
+
if (!(point in this.interceptors)) {
|
|
155
|
+
const available = Object.keys(this.interceptors).join(', ')
|
|
156
|
+
throw new Error(`Unknown intercept point "${point}". Available points: ${available}`)
|
|
157
|
+
}
|
|
155
158
|
this.interceptors[point].add(fn as any)
|
|
156
159
|
return this
|
|
157
160
|
}
|
|
@@ -176,12 +179,9 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
|
|
|
176
179
|
}
|
|
177
180
|
}
|
|
178
181
|
|
|
179
|
-
override get container(): AGIContainer {
|
|
180
|
-
return super.container as AGIContainer
|
|
181
|
-
}
|
|
182
182
|
|
|
183
183
|
get name() {
|
|
184
|
-
return this.resolvedFolder.split('/').pop()
|
|
184
|
+
return this.options.name || this.resolvedFolder.split('/').pop()
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
/** The absolute resolved path to the assistant folder. */
|
|
@@ -213,11 +213,11 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
|
|
|
213
213
|
get voiceConfig(): Record<string, any> | undefined {
|
|
214
214
|
if (!this.hasVoice) return undefined
|
|
215
215
|
const yaml = this.container.feature('yaml')
|
|
216
|
-
return yaml.parse(this.container.fs.readFile(this.paths.resolve('voice.yaml')))
|
|
216
|
+
return yaml.parse(String(this.container.fs.readFile(this.paths.resolve('voice.yaml'))))
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
get resolvedDocsFolder() {
|
|
220
|
-
const { docsFolder = this.
|
|
220
|
+
const { docsFolder = this.effectiveOptions.docsFolder || 'docs' } = this.state.current
|
|
221
221
|
|
|
222
222
|
if (this.container.fs.exists(docsFolder)) {
|
|
223
223
|
return this.container.paths.resolve(docsFolder)
|
|
@@ -268,17 +268,17 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
|
|
|
268
268
|
let conv = this.state.get('conversation') as Conversation | null
|
|
269
269
|
if (!conv) {
|
|
270
270
|
conv = this.container.feature('conversation', {
|
|
271
|
-
model: this.
|
|
272
|
-
local: !!this.
|
|
271
|
+
model: this.effectiveOptions.model || 'gpt-5.4',
|
|
272
|
+
local: !!this.effectiveOptions.local,
|
|
273
273
|
tools: this.tools,
|
|
274
274
|
api: 'chat',
|
|
275
|
-
...(this.
|
|
276
|
-
...(this.
|
|
277
|
-
...(this.
|
|
278
|
-
...(this.
|
|
279
|
-
...(this.
|
|
280
|
-
...(this.
|
|
281
|
-
...(this.
|
|
275
|
+
...(this.effectiveOptions.maxTokens ? { maxTokens: this.effectiveOptions.maxTokens } : {}),
|
|
276
|
+
...(this.effectiveOptions.temperature != null ? { temperature: this.effectiveOptions.temperature } : {}),
|
|
277
|
+
...(this.effectiveOptions.topP != null ? { topP: this.effectiveOptions.topP } : {}),
|
|
278
|
+
...(this.effectiveOptions.topK != null ? { topK: this.effectiveOptions.topK } : {}),
|
|
279
|
+
...(this.effectiveOptions.frequencyPenalty != null ? { frequencyPenalty: this.effectiveOptions.frequencyPenalty } : {}),
|
|
280
|
+
...(this.effectiveOptions.presencePenalty != null ? { presencePenalty: this.effectiveOptions.presencePenalty } : {}),
|
|
281
|
+
...(this.effectiveOptions.stop ? { stop: this.effectiveOptions.stop } : {}),
|
|
282
282
|
history: [
|
|
283
283
|
{ role: 'system', content: this.effectiveSystemPrompt },
|
|
284
284
|
],
|
|
@@ -372,7 +372,7 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
|
|
|
372
372
|
* allowTools is applied first (strict allowlist), then forbidTools removes from whatever remains.
|
|
373
373
|
*/
|
|
374
374
|
private applyToolFilters(tools: Record<string, ConversationTool>): Record<string, ConversationTool> {
|
|
375
|
-
const { allowTools, forbidTools, toolNames } = this.
|
|
375
|
+
const { allowTools, forbidTools, toolNames } = this.effectiveOptions
|
|
376
376
|
if (!allowTools && !forbidTools && !toolNames) return tools
|
|
377
377
|
|
|
378
378
|
let names = Object.keys(tools)
|
|
@@ -395,7 +395,8 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
|
|
|
395
395
|
|
|
396
396
|
const result: Record<string, ConversationTool> = {}
|
|
397
397
|
for (const n of names) {
|
|
398
|
-
|
|
398
|
+
const tool = tools[n]
|
|
399
|
+
if (tool) result[n] = tool
|
|
399
400
|
}
|
|
400
401
|
return result
|
|
401
402
|
}
|
|
@@ -607,6 +608,15 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
|
|
|
607
608
|
return (this.state.get('meta') || {}) as Record<string, any>
|
|
608
609
|
}
|
|
609
610
|
|
|
611
|
+
/**
|
|
612
|
+
* Merged options where CORE.md frontmatter provides defaults and
|
|
613
|
+
* constructor options take precedence. Prefer this over `this.options`
|
|
614
|
+
* anywhere model parameters or runtime config is consumed.
|
|
615
|
+
*/
|
|
616
|
+
get effectiveOptions(): AssistantOptions & Record<string, any> {
|
|
617
|
+
return { ...this.meta, ...this.options }
|
|
618
|
+
}
|
|
619
|
+
|
|
610
620
|
/**
|
|
611
621
|
* Load the system prompt from CORE.md, applying any prepend/append options.
|
|
612
622
|
* YAML frontmatter (between --- fences) is stripped from the prompt and
|
|
@@ -831,8 +841,9 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
|
|
|
831
841
|
return `${stamp} ${content}`
|
|
832
842
|
}
|
|
833
843
|
|
|
834
|
-
|
|
835
|
-
|
|
844
|
+
const firstPart = content[0]
|
|
845
|
+
if (firstPart && firstPart.type === 'text') {
|
|
846
|
+
return [{ type: 'text' as const, text: `${stamp} ${firstPart.text}` }, ...content.slice(1)]
|
|
836
847
|
}
|
|
837
848
|
|
|
838
849
|
return [{ type: 'text' as const, text: stamp }, ...content]
|
|
@@ -919,7 +930,7 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
|
|
|
919
930
|
* Called from start() for non-lifecycle modes.
|
|
920
931
|
*/
|
|
921
932
|
private async loadConversationHistory(): Promise<void> {
|
|
922
|
-
const mode = this.
|
|
933
|
+
const mode = this.effectiveOptions.historyMode || 'lifecycle'
|
|
923
934
|
if (mode === 'lifecycle') return
|
|
924
935
|
|
|
925
936
|
const threadId = (this.state.get('resumeThreadId') as string | undefined) || this.buildThreadId(mode)
|
|
@@ -1104,7 +1115,7 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
|
|
|
1104
1115
|
await this.loadConversationHistory()
|
|
1105
1116
|
|
|
1106
1117
|
// Enable autoCompact for modes that accumulate history
|
|
1107
|
-
const mode = this.
|
|
1118
|
+
const mode = this.effectiveOptions.historyMode || 'lifecycle'
|
|
1108
1119
|
if (mode === 'daily' || mode === 'persistent') {
|
|
1109
1120
|
(this.conversation.options as any).autoCompact = true
|
|
1110
1121
|
}
|
|
@@ -1146,7 +1157,7 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
|
|
|
1146
1157
|
const count = (this.state.get('conversationCount') || 0) + 1
|
|
1147
1158
|
this.state.set('conversationCount', count)
|
|
1148
1159
|
|
|
1149
|
-
if (this.
|
|
1160
|
+
if (this.effectiveOptions.injectTimestamps) {
|
|
1150
1161
|
question = this.prependTimestamp(question)
|
|
1151
1162
|
}
|
|
1152
1163
|
|
|
@@ -1169,7 +1180,7 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
|
|
|
1169
1180
|
}
|
|
1170
1181
|
|
|
1171
1182
|
// Auto-save for non-lifecycle modes
|
|
1172
|
-
if (this.
|
|
1183
|
+
if (this.effectiveOptions.historyMode !== 'lifecycle' && this.state.get('threadId')) {
|
|
1173
1184
|
await this.conversation.save({ thread: this.state.get('threadId') })
|
|
1174
1185
|
}
|
|
1175
1186
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
|
|
3
3
|
import { type AvailableFeatures } from '@soederpop/luca/feature'
|
|
4
|
-
import { Feature } from '
|
|
5
|
-
import type { AGIContainer } from '../container.server.js'
|
|
4
|
+
import { Feature } from '../feature.js'
|
|
6
5
|
import type { Assistant } from './assistant.js'
|
|
6
|
+
import type { InterceptorFn, InterceptorPoint, InterceptorPoints } from '../lib/interceptor-chain.js'
|
|
7
7
|
|
|
8
8
|
declare module '@soederpop/luca/feature' {
|
|
9
9
|
interface AvailableFeatures {
|
|
@@ -47,6 +47,7 @@ export const AssistantsManagerStateSchema = FeatureStateSchema.extend({
|
|
|
47
47
|
entries: z.record(z.string(), z.any()).describe('Discovered assistant entries keyed by name'),
|
|
48
48
|
instances: z.record(z.string(), z.any()).describe('Active assistant instances keyed by name'),
|
|
49
49
|
factories: z.record(z.string(), z.any()).describe('Registered factory functions keyed by name'),
|
|
50
|
+
extraFolders: z.array(z.string()).describe('Additional folders to scan during discovery'),
|
|
50
51
|
})
|
|
51
52
|
|
|
52
53
|
export const AssistantsManagerOptionsSchema = FeatureOptionsSchema.extend({})
|
|
@@ -91,12 +92,10 @@ export class AssistantsManager extends Feature<AssistantsManagerState, Assistant
|
|
|
91
92
|
entries: {},
|
|
92
93
|
instances: {},
|
|
93
94
|
factories: {},
|
|
95
|
+
extraFolders: [],
|
|
94
96
|
}
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
override get container(): AGIContainer {
|
|
98
|
-
return super.container as AGIContainer
|
|
99
|
-
}
|
|
100
99
|
|
|
101
100
|
/** Discovered assistant entries keyed by name. */
|
|
102
101
|
get entries(): Record<string, AssistantEntry> {
|
|
@@ -113,12 +112,60 @@ export class AssistantsManager extends Feature<AssistantsManagerState, Assistant
|
|
|
113
112
|
return (this.state.get('factories') || {}) as Record<string, (options: Record<string, any>) => Assistant>
|
|
114
113
|
}
|
|
115
114
|
|
|
115
|
+
/** Interceptor registrations to be applied to every assistant this manager creates. */
|
|
116
|
+
private _interceptors: Array<{ point: InterceptorPoint; fn: InterceptorFn<any> }> = []
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Registers a pipeline interceptor that is applied to every assistant created by this manager.
|
|
120
|
+
* Interceptors are applied at the given interception point on each assistant at creation time.
|
|
121
|
+
* This mirrors the per-assistant `assistant.intercept(point, fn)` API, but scopes it globally
|
|
122
|
+
* across all assistants managed here — useful for cross-cutting concerns like logging, tracing,
|
|
123
|
+
* or policy enforcement.
|
|
124
|
+
*
|
|
125
|
+
* @param {InterceptorPoint} point - The interception point (beforeAsk, beforeTurn, beforeToolCall, afterToolCall, beforeResponse)
|
|
126
|
+
* @param {InterceptorFn<InterceptorPoints[K]>} fn - Middleware function receiving (ctx, next)
|
|
127
|
+
* @returns {this} This instance, for chaining
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```typescript
|
|
131
|
+
* manager.intercept('beforeAsk', async (ctx, next) => {
|
|
132
|
+
* console.log(`[${ctx.assistant.name}] asking: ${ctx.message}`)
|
|
133
|
+
* await next()
|
|
134
|
+
* })
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
intercept<K extends InterceptorPoint>(point: K, fn: InterceptorFn<InterceptorPoints[K]>): this {
|
|
138
|
+
this._interceptors.push({ point, fn })
|
|
139
|
+
return this
|
|
140
|
+
}
|
|
141
|
+
|
|
116
142
|
/**
|
|
117
143
|
* Discovers assistants by listing subdirectories in ~/.luca/assistants/
|
|
118
144
|
* and cwd/assistants/. Each subdirectory containing a CORE.md is an assistant.
|
|
119
145
|
*
|
|
120
146
|
* @returns {Promise<this>} This instance, for chaining
|
|
121
147
|
*/
|
|
148
|
+
/**
|
|
149
|
+
* Registers an additional folder to scan during assistant discovery and
|
|
150
|
+
* immediately triggers a new discovery pass.
|
|
151
|
+
*
|
|
152
|
+
* @param {string} folderPath - Absolute path to a folder containing assistant subdirectories
|
|
153
|
+
* @returns {Promise<this>} This instance, for chaining
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* await manager.addDiscoveryFolder('/path/to/more/assistants')
|
|
158
|
+
* console.log(manager.available) // includes assistants from the new folder
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
async addDiscoveryFolder(folderPath: string): Promise<this> {
|
|
162
|
+
const current = this.state.get('extraFolders') as string[]
|
|
163
|
+
if (!current.includes(folderPath)) {
|
|
164
|
+
this.state.set('extraFolders', [...current, folderPath])
|
|
165
|
+
}
|
|
166
|
+
return this.discover()
|
|
167
|
+
}
|
|
168
|
+
|
|
122
169
|
async discover(): Promise<this> {
|
|
123
170
|
const { fs, paths, os } = this.container
|
|
124
171
|
|
|
@@ -127,6 +174,7 @@ export class AssistantsManager extends Feature<AssistantsManagerState, Assistant
|
|
|
127
174
|
const locations = [
|
|
128
175
|
`${os.homedir}/.luca/assistants`,
|
|
129
176
|
paths.resolve('assistants'),
|
|
177
|
+
...(this.state.get('extraFolders') as string[]),
|
|
130
178
|
]
|
|
131
179
|
|
|
132
180
|
for (const location of locations) {
|
|
@@ -262,6 +310,7 @@ export class AssistantsManager extends Feature<AssistantsManagerState, Assistant
|
|
|
262
310
|
const factory = this.factories[name]
|
|
263
311
|
if (factory) {
|
|
264
312
|
const instance = factory(options)
|
|
313
|
+
this._bindAssistant(instance)
|
|
265
314
|
const updated = { ...this.instances, [name]: instance }
|
|
266
315
|
this.state.setState({ instances: updated, activeCount: Object.keys(updated).length })
|
|
267
316
|
this.emit('assistantCreated', name, instance)
|
|
@@ -281,6 +330,7 @@ export class AssistantsManager extends Feature<AssistantsManagerState, Assistant
|
|
|
281
330
|
...options,
|
|
282
331
|
})
|
|
283
332
|
|
|
333
|
+
this._bindAssistant(instance)
|
|
284
334
|
const updated = { ...this.instances, [name]: instance }
|
|
285
335
|
this.state.setState({ instances: updated, activeCount: Object.keys(updated).length })
|
|
286
336
|
this.emit('assistantCreated', name, instance)
|
|
@@ -288,6 +338,21 @@ export class AssistantsManager extends Feature<AssistantsManagerState, Assistant
|
|
|
288
338
|
return instance
|
|
289
339
|
}
|
|
290
340
|
|
|
341
|
+
/**
|
|
342
|
+
* Wires an assistant into the manager: bridges all assistant events up to the manager
|
|
343
|
+
* as `assistantEvent:<eventName>` with (assistant, ...originalArgs), and applies any
|
|
344
|
+
* globally registered interceptors.
|
|
345
|
+
*/
|
|
346
|
+
private _bindAssistant(instance: Assistant): void {
|
|
347
|
+
instance.on('*', (event: string, ...args: any[]) => {
|
|
348
|
+
this.emit(`assistantEvent:${event}` as any, instance, ...args)
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
for (const { point, fn } of this._interceptors) {
|
|
352
|
+
instance.intercept(point, fn)
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
291
356
|
/**
|
|
292
357
|
* Returns a previously created assistant instance by name.
|
|
293
358
|
*
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
|
|
3
|
-
import { Feature } from '
|
|
4
|
-
import type { AGIContainer } from '../container.server.js'
|
|
3
|
+
import { Feature } from '../feature.js'
|
|
5
4
|
import type { Assistant } from './assistant.js'
|
|
6
5
|
import type { ToolCallCtx } from '../lib/interceptor-chain.js'
|
|
7
6
|
|
|
@@ -158,9 +157,6 @@ export class AutonomousAssistant extends Feature<AutonomousAssistantState, Auton
|
|
|
158
157
|
}
|
|
159
158
|
}
|
|
160
159
|
|
|
161
|
-
override get container(): AGIContainer {
|
|
162
|
-
return super.container as AGIContainer
|
|
163
|
-
}
|
|
164
160
|
|
|
165
161
|
/** The inner assistant. Throws if not started. */
|
|
166
162
|
get assistant(): Assistant {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
|
|
3
|
-
import { Feature } from '
|
|
3
|
+
import { Feature } from '../feature.js'
|
|
4
4
|
|
|
5
5
|
declare module '@soederpop/luca/feature' {
|
|
6
6
|
interface AvailableFeatures {
|
|
@@ -61,7 +61,7 @@ export class BrowserUse extends Feature<BrowserUseState, BrowserUseOptions> {
|
|
|
61
61
|
static override optionsSchema = BrowserUseOptionsSchema
|
|
62
62
|
static override eventsSchema = BrowserUseEventsSchema
|
|
63
63
|
|
|
64
|
-
static tools = {
|
|
64
|
+
static override tools = {
|
|
65
65
|
browserOpen: {
|
|
66
66
|
description: 'Navigate the browser to a URL. Call this first to open a page before any interaction.',
|
|
67
67
|
schema: z.object({
|