@happyvertical/smrt-chat 0.30.0
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/AGENTS.md +35 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/README.md +163 -0
- package/dist/__smrt-register__.d.ts +2 -0
- package/dist/__smrt-register__.d.ts.map +1 -0
- package/dist/chunks/ChatService-Dpzc1Pa5.js +2044 -0
- package/dist/chunks/ChatService-Dpzc1Pa5.js.map +1 -0
- package/dist/collections/AgentSessionCollection.d.ts +57 -0
- package/dist/collections/AgentSessionCollection.d.ts.map +1 -0
- package/dist/collections/ChatMessageCollection.d.ts +79 -0
- package/dist/collections/ChatMessageCollection.d.ts.map +1 -0
- package/dist/collections/ChatParticipantCollection.d.ts +26 -0
- package/dist/collections/ChatParticipantCollection.d.ts.map +1 -0
- package/dist/collections/ChatReactionCollection.d.ts +23 -0
- package/dist/collections/ChatReactionCollection.d.ts.map +1 -0
- package/dist/collections/ChatRoomCollection.d.ts +43 -0
- package/dist/collections/ChatRoomCollection.d.ts.map +1 -0
- package/dist/collections/ChatThreadCollection.d.ts +9 -0
- package/dist/collections/ChatThreadCollection.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/agent-runtime.d.ts +16 -0
- package/dist/internal/agent-runtime.d.ts.map +1 -0
- package/dist/internal/agent-runtime.js +5 -0
- package/dist/internal/agent-runtime.js.map +1 -0
- package/dist/manifest.json +2811 -0
- package/dist/models/AgentSession.d.ts +70 -0
- package/dist/models/AgentSession.d.ts.map +1 -0
- package/dist/models/ChatMessage.d.ts +55 -0
- package/dist/models/ChatMessage.d.ts.map +1 -0
- package/dist/models/ChatParticipant.d.ts +32 -0
- package/dist/models/ChatParticipant.d.ts.map +1 -0
- package/dist/models/ChatReaction.d.ts +19 -0
- package/dist/models/ChatReaction.d.ts.map +1 -0
- package/dist/models/ChatRoom.d.ts +44 -0
- package/dist/models/ChatRoom.d.ts.map +1 -0
- package/dist/models/ChatThread.d.ts +24 -0
- package/dist/models/ChatThread.d.ts.map +1 -0
- package/dist/models/index.d.ts +7 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/playground.d.ts +2 -0
- package/dist/playground.d.ts.map +1 -0
- package/dist/playground.js +166 -0
- package/dist/playground.js.map +1 -0
- package/dist/services/ChatService.d.ts +390 -0
- package/dist/services/ChatService.d.ts.map +1 -0
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +1507 -0
- package/dist/svelte/components/agent/AgentChat.svelte +542 -0
- package/dist/svelte/components/agent/AgentChat.svelte.d.ts +21 -0
- package/dist/svelte/components/agent/AgentChat.svelte.d.ts.map +1 -0
- package/dist/svelte/components/agent/AgentSelector.svelte +175 -0
- package/dist/svelte/components/agent/AgentSelector.svelte.d.ts +11 -0
- package/dist/svelte/components/agent/AgentSelector.svelte.d.ts.map +1 -0
- package/dist/svelte/components/agent/AgentSessionPanel.svelte +322 -0
- package/dist/svelte/components/agent/AgentSessionPanel.svelte.d.ts +15 -0
- package/dist/svelte/components/agent/AgentSessionPanel.svelte.d.ts.map +1 -0
- package/dist/svelte/components/agent/ToolCallDisplay.svelte +335 -0
- package/dist/svelte/components/agent/ToolCallDisplay.svelte.d.ts +9 -0
- package/dist/svelte/components/agent/ToolCallDisplay.svelte.d.ts.map +1 -0
- package/dist/svelte/components/agent/message-blocks.d.ts +12 -0
- package/dist/svelte/components/agent/message-blocks.d.ts.map +1 -0
- package/dist/svelte/components/agent/message-blocks.js +41 -0
- package/dist/svelte/components/agent/message-blocks.test.js +31 -0
- package/dist/svelte/components/dialogs/RoomCreateDialog.svelte +403 -0
- package/dist/svelte/components/dialogs/RoomCreateDialog.svelte.d.ts +16 -0
- package/dist/svelte/components/dialogs/RoomCreateDialog.svelte.d.ts.map +1 -0
- package/dist/svelte/components/dialogs/SearchMessages.svelte +457 -0
- package/dist/svelte/components/dialogs/SearchMessages.svelte.d.ts +17 -0
- package/dist/svelte/components/dialogs/SearchMessages.svelte.d.ts.map +1 -0
- package/dist/svelte/components/layout/ChatLayout.svelte +150 -0
- package/dist/svelte/components/layout/ChatLayout.svelte.d.ts +18 -0
- package/dist/svelte/components/layout/ChatLayout.svelte.d.ts.map +1 -0
- package/dist/svelte/components/layout/MemberList.svelte +389 -0
- package/dist/svelte/components/layout/MemberList.svelte.d.ts +11 -0
- package/dist/svelte/components/layout/MemberList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/layout/RoomHeader.svelte +241 -0
- package/dist/svelte/components/layout/RoomHeader.svelte.d.ts +15 -0
- package/dist/svelte/components/layout/RoomHeader.svelte.d.ts.map +1 -0
- package/dist/svelte/components/layout/RoomList.svelte +471 -0
- package/dist/svelte/components/layout/RoomList.svelte.d.ts +15 -0
- package/dist/svelte/components/layout/RoomList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/messages/MessageInput.svelte +232 -0
- package/dist/svelte/components/messages/MessageInput.svelte.d.ts +20 -0
- package/dist/svelte/components/messages/MessageInput.svelte.d.ts.map +1 -0
- package/dist/svelte/components/messages/MessageItem.svelte +431 -0
- package/dist/svelte/components/messages/MessageItem.svelte.d.ts +19 -0
- package/dist/svelte/components/messages/MessageItem.svelte.d.ts.map +1 -0
- package/dist/svelte/components/messages/MessageList.svelte +129 -0
- package/dist/svelte/components/messages/MessageList.svelte.d.ts +17 -0
- package/dist/svelte/components/messages/MessageList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/messages/ThreadPanel.svelte +156 -0
- package/dist/svelte/components/messages/ThreadPanel.svelte.d.ts +17 -0
- package/dist/svelte/components/messages/ThreadPanel.svelte.d.ts.map +1 -0
- package/dist/svelte/components/messages/__tests__/MessageInput.test.js +38 -0
- package/dist/svelte/components/shared/Avatar.svelte +30 -0
- package/dist/svelte/components/shared/Avatar.svelte.d.ts +14 -0
- package/dist/svelte/components/shared/Avatar.svelte.d.ts.map +1 -0
- package/dist/svelte/components/shared/FileUpload.svelte +382 -0
- package/dist/svelte/components/shared/FileUpload.svelte.d.ts +14 -0
- package/dist/svelte/components/shared/FileUpload.svelte.d.ts.map +1 -0
- package/dist/svelte/components/shared/LinkPreview.svelte +108 -0
- package/dist/svelte/components/shared/LinkPreview.svelte.d.ts +18 -0
- package/dist/svelte/components/shared/LinkPreview.svelte.d.ts.map +1 -0
- package/dist/svelte/components/shared/MentionAutocomplete.svelte +168 -0
- package/dist/svelte/components/shared/MentionAutocomplete.svelte.d.ts +18 -0
- package/dist/svelte/components/shared/MentionAutocomplete.svelte.d.ts.map +1 -0
- package/dist/svelte/components/shared/MessageBubble.svelte +81 -0
- package/dist/svelte/components/shared/MessageBubble.svelte.d.ts +16 -0
- package/dist/svelte/components/shared/MessageBubble.svelte.d.ts.map +1 -0
- package/dist/svelte/components/shared/ReactionPicker.svelte +103 -0
- package/dist/svelte/components/shared/ReactionPicker.svelte.d.ts +10 -0
- package/dist/svelte/components/shared/ReactionPicker.svelte.d.ts.map +1 -0
- package/dist/svelte/components/shared/ReadReceipts.svelte +127 -0
- package/dist/svelte/components/shared/ReadReceipts.svelte.d.ts +13 -0
- package/dist/svelte/components/shared/ReadReceipts.svelte.d.ts.map +1 -0
- package/dist/svelte/components/shared/TypingIndicator.svelte +90 -0
- package/dist/svelte/components/shared/TypingIndicator.svelte.d.ts +12 -0
- package/dist/svelte/components/shared/TypingIndicator.svelte.d.ts.map +1 -0
- package/dist/svelte/components/shared/UserPresence.svelte +65 -0
- package/dist/svelte/components/shared/UserPresence.svelte.d.ts +13 -0
- package/dist/svelte/components/shared/UserPresence.svelte.d.ts.map +1 -0
- package/dist/svelte/components/shared/__tests__/Avatar.test.js +20 -0
- package/dist/svelte/components/shared/__tests__/LinkPreview.test.js +29 -0
- package/dist/svelte/components/shared/__tests__/MessageBubble.test.js +21 -0
- package/dist/svelte/components/shared/__tests__/ReactionPicker.test.js +35 -0
- package/dist/svelte/components/shared/__tests__/ReadReceipts.test.js +28 -0
- package/dist/svelte/components/shared/__tests__/TypingIndicator.test.js +27 -0
- package/dist/svelte/components/shared/__tests__/UserPresence.test.js +23 -0
- package/dist/svelte/components/tabs/ChatTab.svelte +240 -0
- package/dist/svelte/components/tabs/ChatTab.svelte.d.ts +21 -0
- package/dist/svelte/components/tabs/ChatTab.svelte.d.ts.map +1 -0
- package/dist/svelte/components/tabs/ChatTabList.svelte +158 -0
- package/dist/svelte/components/tabs/ChatTabList.svelte.d.ts +13 -0
- package/dist/svelte/components/tabs/ChatTabList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/tabs/ChatTabs.svelte +88 -0
- package/dist/svelte/components/tabs/ChatTabs.svelte.d.ts +21 -0
- package/dist/svelte/components/tabs/ChatTabs.svelte.d.ts.map +1 -0
- package/dist/svelte/components/tabs/MiniChat.svelte +253 -0
- package/dist/svelte/components/tabs/MiniChat.svelte.d.ts +15 -0
- package/dist/svelte/components/tabs/MiniChat.svelte.d.ts.map +1 -0
- package/dist/svelte/i18n.d.ts +51 -0
- package/dist/svelte/i18n.d.ts.map +1 -0
- package/dist/svelte/i18n.js +72 -0
- package/dist/svelte/i18n.messages.d.ts +50 -0
- package/dist/svelte/i18n.messages.d.ts.map +1 -0
- package/dist/svelte/i18n.messages.js +69 -0
- package/dist/svelte/index.d.ts +48 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +117 -0
- package/dist/svelte/playground.d.ts +171 -0
- package/dist/svelte/playground.d.ts.map +1 -0
- package/dist/svelte/playground.js +161 -0
- package/dist/svelte/types.d.ts +116 -0
- package/dist/svelte/types.d.ts.map +1 -0
- package/dist/svelte/types.js +1 -0
- package/dist/types.d.ts +99 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui.d.ts +4 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +92 -0
- package/dist/ui.js.map +1 -0
- package/package.json +95 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# @happyvertical/smrt-chat
|
|
2
|
+
|
|
3
|
+
Chat rooms, threads, and agent sessions with app-controlled tool whitelisting.
|
|
4
|
+
|
|
5
|
+
## Models
|
|
6
|
+
|
|
7
|
+
Internal models — all mutations go through the membership/owner-checked `ChatService` (S5 #1392). EVERY `@smrt()` model in this package (ChatRoom, ChatMessage, ChatParticipant, ChatThread, ChatReaction, AgentSession) has a READ-ONLY generated REST/MCP surface (`list`/`get` only); `create`/`update`/`delete` are intentionally NOT generated so the raw collection routes cannot skip the service-layer authorization. A structural regression test enumerates the registry to assert no chat model exposes a mutating op.
|
|
8
|
+
|
|
9
|
+
`ChatService` is a CLOSED FACADE (S5 #1392). The raw collections (`rooms`, `messages`, `participants`, `threads`, `agentSessions`, `reactions`) are ES `#private` fields — they are NOT on the public `ChatService` type and the package index does NOT export the collection classes, so a consumer cannot do `chat.messages.create({senderProfileId, role})` / `new ChatParticipantCollection(...)` to mutate around the authorization. The security-sensitive internals (`#writeMessage`, `#emitAgentReply`, `#enrollParticipant`, `#loadActiveSession`, `#requireActiveMembership`, `#requireRoomAdmin`, `#extractToolName`) are ES `#private` too, so they are unreachable at runtime — TypeScript `private` alone is erased and would leave them callable on the prototype. The agent-reply bridge is a `Symbol`-keyed static (not the old enumerable `_runAgentReply`), reachable only by the module-local `sendAgentReply` that holds the non-exported symbol.
|
|
10
|
+
|
|
11
|
+
- **ChatRoom**: `roomType` (public/private/dm/agent), `status`, `topic`, `maxParticipants`, `lastMessageAt`. Tenant-scoped (required).
|
|
12
|
+
- **ChatMessage**: shared by users + agents. `role` (user/assistant/system/tool), `messageType` (text/system/action/file/tool_call/tool_result), `toolCallData` JSON. Unified model — no separate agent message type. Tenant-scoped (required).
|
|
13
|
+
- **ChatParticipant**: `role` (owner/admin/member/viewer), `onlineStatus`, `lastReadMessageId`, `isMuted`. Tenant-scoped (required).
|
|
14
|
+
- **ChatThread**: `rootMessageId`, `isResolved`, `messageCount`. Created via `ChatService.startThread()` (member-checked). Tenant-scoped (required).
|
|
15
|
+
- **ChatReaction**: `messageId`, `profileId`, `emoji`. Added/removed via `ChatService.addReaction()`/`removeReaction()` (member-checked, self-keyed). Tenant-scoped (required).
|
|
16
|
+
- **AgentSession**: `agentId` (string ref, not FK), `allowedTools` (JSON string array), `sessionContext` (JSON), `systemPrompt`, limits (`maxTokens`/`maxMessages`/`expiresAt`). Optional tenancy.
|
|
17
|
+
|
|
18
|
+
## ChatService
|
|
19
|
+
|
|
20
|
+
Every public write takes an explicit server-supplied `actorProfileId` (the authenticated principal the route injects) — never a caller-controlled `senderProfileId`/`role` (S5 #1392).
|
|
21
|
+
|
|
22
|
+
Facade: `sendMessage()` (authors as the actor with `role: 'user'`; room-membership-checked; no caller-supplied sender/role and no public membership-skip), `createRoom()` (acting actor becomes owner — no caller-supplied `createdByProfileId`), `startThread()` (member-checked; optional `rootMessageId` bound to the same room+tenant), `addParticipant()`/`removeParticipant()` (owner/admin-checked; self-leave allowed), `updateRoom()` (owner/admin-checked), `addReaction()`/`removeReaction()` (member-checked, self-keyed), `getOrCreateDM()` (actor must be a DM participant), `createAgentSession()` (acting actor becomes the session participant — no caller-supplied `participantProfileId`; the existing-session room lookup is tenant-bound; optional `sessionKey` scopes session identity to a conversation subject so distinct keys get distinct sessions/rooms and a session opened for one subject is never reused/rewritten for another). Tenant-bound read facade (replaces raw-collection reach-ins; consumers apply their own ownership/context checks on the returned rows): `getAgentSession({agentSessionId, tenantId})`, `findActiveAgentSessions({tenantId, agentId, participantProfileId})`, `getThread({threadId, tenantId})`, `listRoomThreads({roomId, actorProfileId, tenantId})` (membership-gated), `getThreadMessages({threadId, actorProfileId, tenantId, limit?})` (membership-gated, chronological), `getRoomMessages({roomId, actorProfileId, tenantId})`/`getRoomForMember(roomId, actorProfileId, tenantId)` (membership-checked reads gated on the server-supplied `actorProfileId`, never a caller-controlled subject id — confused-deputy avoidance; `tenantId` required), `updateAgentSessionConfig()` (owner-checked; `tenantId` mandatory and bound into the lookup). Agent session messaging is split by authority: `sendAgentUserMessage()` (caller `actorProfileId` must be the session participant; always authored as the participant). The agent-authored reply path `sendAgentReply(service, params)` is an exported **function — NOT a `ChatService` method and NOT on the package index**; it is reachable only via the dedicated `@happyvertical/smrt-chat/internal/agent-runtime` subpath (S5 #1392), so only trusted in-process agent-runtime code that explicitly opts into that subpath can author as the agent. It authors as `session.agentId`, accepts an optional same-room/tenant `threadId`, and gates tool calls fail-closed against `allowedTools`. The shared internal persistence path (`writeMessage`) is private — it alone may author an arbitrary profile/role or skip the membership check, and is unreachable from any route; it also validates every supplied `threadId`/`agentSessionId`/`replyToMessageId` belongs to the SAME room AND tenant (tenant/room-bound lookups) before use, rejecting cross-room/cross-tenant references. Auto-creates rooms/sessions/participants via an internal `enrollParticipant`.
|
|
23
|
+
|
|
24
|
+
## Agent Tool Whitelisting
|
|
25
|
+
|
|
26
|
+
`allowedTools` is a JSON array controlled by the consuming app. Fail-closed: an empty/unparseable whitelist permits NO tools. The internal `sendAgentReply(service, params)` function enforces the whitelist before emitting any `tool`/`tool_call` message; a caller cannot supply a `senderProfileId`/`role` to post as the agent, and the function is not reachable from the package index.
|
|
27
|
+
|
|
28
|
+
## Gotchas
|
|
29
|
+
|
|
30
|
+
- **sessionContext, not context**: `context` is reserved for slug scoping. Use `getSessionContext()`/`updateSessionContext()` for agent memory.
|
|
31
|
+
- **Agent rooms auto-created**: `roomType: 'agent'`, `maxParticipants` defaults to 2; the agent is enrolled as a member so its replies pass the membership check. `createAgentSession()` re-enrolls the participant AND the agent on the existing-session path, so legacy sessions created before the agent was enrolled self-heal.
|
|
32
|
+
- **Per-subject sessions need `sessionKey`**: `createAgentSession()` reuses ANY active session for the same `(agentId, participantProfileId, tenantId)`. Callers that open separate conversations per subject (e.g. one content-editor session per content id) MUST pass a stable `sessionKey` (stored in `sessionContext.__sessionKey`, read via `AgentSession.getSessionKey()`); otherwise a session opened for one subject is reused and its context overwritten for another, surfacing the wrong room/threads (S5 #1392). A keyed create never reuses a keyless/legacy session.
|
|
33
|
+
- **Session expiry**: check `isActive()` before allowing messages (expiresAt or limit-based)
|
|
34
|
+
- **DM identity**: derived from the deterministic per-tenant `canonicalDmRoomId()` and the authoritative `chat_participants` join, not client metadata; concurrent creates upsert onto one row.
|
|
35
|
+
- **Tenant-bound lookups**: membership/session/DM lookups REQUIRE `tenantId` and always bind it into the WHERE clause (`findActiveMembership`/`isActiveMember`/`findActiveSession` take a required `tenantId`; AgentSession's `null` tenant is an explicit bound scope, not "any tenant") so they can never resolve a row from another tenant.
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright <2025> <Happy Vertical Corporation>
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @happyvertical/smrt-chat
|
|
2
|
+
|
|
3
|
+
Chat rooms, DMs, threads, and agent conversations for the SMRT framework. Supports public, private, DM, and agent-type rooms with threaded messages, reactions, and agent sessions with tool whitelisting.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @happyvertical/smrt-chat
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Rooms and messages
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { ChatService } from '@happyvertical/smrt-chat';
|
|
17
|
+
|
|
18
|
+
const chat = await ChatService.create({
|
|
19
|
+
persistence: { type: 'sql', url: 'chat.db' },
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// `actorProfileId` is the authenticated principal the route injects. Every
|
|
23
|
+
// write takes it explicitly; the caller never supplies a `senderProfileId`,
|
|
24
|
+
// `role`, or `createdByProfileId` (S5 #1392).
|
|
25
|
+
|
|
26
|
+
// Create a public room (the acting actor becomes the owner)
|
|
27
|
+
const room = await chat.createRoom({
|
|
28
|
+
tenantId: 'tenant-1',
|
|
29
|
+
name: 'General',
|
|
30
|
+
roomType: 'public',
|
|
31
|
+
actorProfileId: 'profile-1',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Send a message (always authored as the actor with role 'user')
|
|
35
|
+
const message = await chat.sendMessage({
|
|
36
|
+
tenantId: 'tenant-1',
|
|
37
|
+
roomId: room.id,
|
|
38
|
+
actorProfileId: 'profile-1',
|
|
39
|
+
content: 'Hello, world!',
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Start a threaded conversation from a message (member-checked)
|
|
43
|
+
const thread = await chat.startThread({
|
|
44
|
+
tenantId: 'tenant-1',
|
|
45
|
+
roomId: room.id,
|
|
46
|
+
actorProfileId: 'profile-1',
|
|
47
|
+
rootMessageId: message.id,
|
|
48
|
+
title: 'Follow-up discussion',
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Reply within the thread. The thread (and any reply-to message) must belong
|
|
52
|
+
// to the same room and tenant, or the write is rejected.
|
|
53
|
+
await chat.sendMessage({
|
|
54
|
+
tenantId: 'tenant-1',
|
|
55
|
+
roomId: room.id,
|
|
56
|
+
actorProfileId: 'profile-2',
|
|
57
|
+
content: 'Great point!',
|
|
58
|
+
threadId: thread.id,
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Agent sessions with tool whitelisting
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// Create an agent session (auto-creates an agent-type room). The acting actor
|
|
66
|
+
// becomes the owning participant; the caller cannot open a session for someone
|
|
67
|
+
// else by supplying a participant id.
|
|
68
|
+
const { session, room } = await chat.createAgentSession({
|
|
69
|
+
tenantId: 'tenant-1',
|
|
70
|
+
agentId: 'agent-summarizer',
|
|
71
|
+
actorProfileId: 'profile-1',
|
|
72
|
+
allowedTools: ['web-search', 'summarize'],
|
|
73
|
+
systemPrompt: 'You are a research assistant.',
|
|
74
|
+
maxMessages: 100,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Send a USER message within the agent session. The caller must be the
|
|
78
|
+
// session participant; the message is always authored as that participant.
|
|
79
|
+
await chat.sendAgentUserMessage({
|
|
80
|
+
tenantId: 'tenant-1',
|
|
81
|
+
agentSessionId: session.id,
|
|
82
|
+
actorProfileId: 'profile-1',
|
|
83
|
+
content: 'Summarize the latest news',
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Emit the agent's reply. This is the INTERNAL trusted authority that authors
|
|
87
|
+
// a message AS the agent, so it is intentionally NOT a public ChatService
|
|
88
|
+
// method and NOT on the package index. It is reachable only via the dedicated
|
|
89
|
+
// `./internal/agent-runtime` subpath, which a normal route/consumer importing
|
|
90
|
+
// from '@happyvertical/smrt-chat' cannot reach. Opting into this subpath
|
|
91
|
+
// signals the importer IS the trusted in-process agent runtime. Tool calls are
|
|
92
|
+
// gated fail-closed against the session's allowedTools.
|
|
93
|
+
import { sendAgentReply } from '@happyvertical/smrt-chat/internal/agent-runtime';
|
|
94
|
+
await sendAgentReply(chat, {
|
|
95
|
+
tenantId: 'tenant-1',
|
|
96
|
+
agentSessionId: session.id,
|
|
97
|
+
content: 'Here is the summary...',
|
|
98
|
+
kind: 'assistant',
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Check session limits before allowing more messages
|
|
102
|
+
if (session.isActive()) {
|
|
103
|
+
// Session has not expired or hit token/message limits
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Direct messages
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// Get or create a DM room between two profiles. The acting actor must be one
|
|
111
|
+
// of the two DM participants.
|
|
112
|
+
const dmRoom = await chat.getOrCreateDM({
|
|
113
|
+
tenantId: 'tenant-1',
|
|
114
|
+
actorProfileId: 'profile-1',
|
|
115
|
+
profileId1: 'profile-1',
|
|
116
|
+
profileId2: 'profile-2',
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## API
|
|
121
|
+
|
|
122
|
+
### Models
|
|
123
|
+
|
|
124
|
+
| Export | Description |
|
|
125
|
+
|--------|------------|
|
|
126
|
+
| `ChatRoom` | Room with type (`public`/`private`/`dm`/`agent`), status, topic, and metadata |
|
|
127
|
+
| `ChatMessage` | Message with `role` (user/assistant/system/tool), `messageType` (text/system/action/file/tool_call/tool_result), optional thread and reply references |
|
|
128
|
+
| `ChatParticipant` | Room member with `role` (owner/admin/member/viewer), online status, read tracking |
|
|
129
|
+
| `ChatThread` | Threaded conversation linked to a root message, with resolve/reopen lifecycle |
|
|
130
|
+
| `ChatReaction` | Emoji reaction on a message |
|
|
131
|
+
| `AgentSession` | AI agent session with `allowedTools` (JSON string array), `sessionContext` for multi-turn memory, `systemPrompt`, and usage limits (`maxTokens`/`maxMessages`/`expiresAt`) |
|
|
132
|
+
|
|
133
|
+
### Collections
|
|
134
|
+
|
|
135
|
+
| Export | Description |
|
|
136
|
+
|--------|------------|
|
|
137
|
+
| `ChatRoomCollection` | Room queries, `findOrCreateDM()` |
|
|
138
|
+
| `ChatMessageCollection` | Message queries and search filters |
|
|
139
|
+
| `ChatParticipantCollection` | Participant queries, `findMembership()` |
|
|
140
|
+
| `ChatThreadCollection` | Thread queries |
|
|
141
|
+
| `ChatReactionCollection` | Reaction queries |
|
|
142
|
+
| `AgentSessionCollection` | Session queries, `findActiveSession()`, `findOrCreate()` |
|
|
143
|
+
|
|
144
|
+
### Services
|
|
145
|
+
|
|
146
|
+
| Export | Description |
|
|
147
|
+
|--------|------------|
|
|
148
|
+
| `ChatService` | Facade: `createRoom()`, `sendMessage()`, `startThread()`, `addParticipant()`, `removeParticipant()`, `updateRoom()`, `addReaction()`, `removeReaction()`, `getOrCreateDM()`, `createAgentSession()`, `sendAgentUserMessage()`, `getRoomMessages()`, `getRoomForMember()`, `updateAgentSessionConfig()`. Every write takes a server-supplied `actorProfileId`. The agent-authored reply path (`sendAgentReply`) is intentionally NOT on this facade or the package index — it is an internal function in `services/ChatService.ts` for the trusted in-process agent runtime only (S5 #1392). |
|
|
149
|
+
|
|
150
|
+
### Types
|
|
151
|
+
|
|
152
|
+
`ChatRoomType`, `ChatRoomStatus`, `ChatRoomOptions`, `ChatMessageType`, `ChatMessageRole`, `ChatMessageOptions`, `ChatMessageSearchFilters`, `ChatParticipantRole`, `ChatParticipantStatus`, `ChatParticipantOptions`, `OnlineStatus`, `ChatThreadOptions`, `ChatReactionOptions`, `AgentSessionStatus`, `AgentSessionOptions`
|
|
153
|
+
|
|
154
|
+
### Constants
|
|
155
|
+
|
|
156
|
+
`CHAT_MODULE_META`, `CHAT_UI_SLOTS`
|
|
157
|
+
|
|
158
|
+
## Dependencies
|
|
159
|
+
|
|
160
|
+
- `@happyvertical/smrt-core` -- ORM and code generation
|
|
161
|
+
- `@happyvertical/smrt-tenancy` -- multi-tenant scoping
|
|
162
|
+
- `@happyvertical/smrt-types` -- shared type definitions
|
|
163
|
+
- Peer (optional): `@happyvertical/smrt-agents`, `@happyvertical/smrt-profiles`, `@happyvertical/smrt-svelte`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"__smrt-register__.d.ts","sourceRoot":"","sources":["../src/__smrt-register__.ts"],"names":[],"mappings":""}
|