niahere 0.2.40 → 0.2.41
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/package.json +1 -1
- package/src/db/models/message.ts +40 -1
- package/src/db/models/session.ts +29 -0
- package/src/mcp/server.ts +33 -0
- package/src/mcp/tools.ts +18 -0
- package/src/prompts/environment.md +13 -0
- package/src/types/index.ts +1 -1
- package/src/types/message.ts +16 -0
package/package.json
CHANGED
package/src/db/models/message.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getSql } from "../connection";
|
|
2
|
-
import type { SaveMessageParams, RoomStats, RecentMessage } from "../../types";
|
|
2
|
+
import type { SaveMessageParams, RoomStats, RecentMessage, SearchResult, SessionMessage } from "../../types";
|
|
3
3
|
|
|
4
4
|
export async function save(params: SaveMessageParams): Promise<void> {
|
|
5
5
|
const sql = getSql();
|
|
@@ -29,6 +29,45 @@ export async function getRecent(limit = 20, room?: string): Promise<RecentMessag
|
|
|
29
29
|
}));
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
export async function search(query: string, limit = 20, room?: string): Promise<SearchResult[]> {
|
|
33
|
+
const sql = getSql();
|
|
34
|
+
const pattern = `%${query}%`;
|
|
35
|
+
const rows = room
|
|
36
|
+
? await sql`
|
|
37
|
+
SELECT session_id, room, sender, content, created_at
|
|
38
|
+
FROM messages WHERE content ILIKE ${pattern} AND room = ${room}
|
|
39
|
+
ORDER BY created_at DESC LIMIT ${limit}
|
|
40
|
+
`
|
|
41
|
+
: await sql`
|
|
42
|
+
SELECT session_id, room, sender, content, created_at
|
|
43
|
+
FROM messages WHERE content ILIKE ${pattern}
|
|
44
|
+
ORDER BY created_at DESC LIMIT ${limit}
|
|
45
|
+
`;
|
|
46
|
+
return rows.map((r) => ({
|
|
47
|
+
sessionId: r.session_id,
|
|
48
|
+
room: r.room,
|
|
49
|
+
sender: r.sender,
|
|
50
|
+
content: r.content,
|
|
51
|
+
createdAt: String(r.created_at),
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function getBySession(sessionId: string): Promise<SessionMessage[]> {
|
|
56
|
+
const sql = getSql();
|
|
57
|
+
const rows = await sql`
|
|
58
|
+
SELECT room, sender, content, is_from_agent, created_at
|
|
59
|
+
FROM messages WHERE session_id = ${sessionId}
|
|
60
|
+
ORDER BY created_at ASC
|
|
61
|
+
`;
|
|
62
|
+
return rows.map((r) => ({
|
|
63
|
+
room: r.room,
|
|
64
|
+
sender: r.sender,
|
|
65
|
+
content: r.content,
|
|
66
|
+
isFromAgent: r.is_from_agent,
|
|
67
|
+
createdAt: String(r.created_at),
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
|
|
32
71
|
export async function getRoomStats(): Promise<RoomStats[]> {
|
|
33
72
|
const sql = getSql();
|
|
34
73
|
const rows = await sql`
|
package/src/db/models/session.ts
CHANGED
|
@@ -49,6 +49,35 @@ export async function getRecent(room: string, limit = 10): Promise<SessionSummar
|
|
|
49
49
|
}));
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
export async function listRecent(limit = 10, room?: string): Promise<SessionSummary[]> {
|
|
53
|
+
if (room) return getRecent(room, limit);
|
|
54
|
+
const sql = getSql();
|
|
55
|
+
const rows = await sql`
|
|
56
|
+
SELECT
|
|
57
|
+
s.id,
|
|
58
|
+
s.room,
|
|
59
|
+
s.created_at,
|
|
60
|
+
s.updated_at,
|
|
61
|
+
(
|
|
62
|
+
SELECT content FROM messages m
|
|
63
|
+
WHERE m.session_id = s.id AND m.sender = 'user'
|
|
64
|
+
ORDER BY m.created_at ASC LIMIT 1
|
|
65
|
+
) AS preview,
|
|
66
|
+
(SELECT COUNT(*)::int FROM messages m WHERE m.session_id = s.id) AS message_count
|
|
67
|
+
FROM sessions s
|
|
68
|
+
ORDER BY s.updated_at DESC
|
|
69
|
+
LIMIT ${limit}
|
|
70
|
+
`;
|
|
71
|
+
return rows.map((r) => ({
|
|
72
|
+
id: r.id,
|
|
73
|
+
room: r.room,
|
|
74
|
+
createdAt: String(r.created_at),
|
|
75
|
+
updatedAt: String(r.updated_at),
|
|
76
|
+
preview: r.preview ? String(r.preview) : null,
|
|
77
|
+
messageCount: r.message_count,
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
|
|
52
81
|
export async function create(id: string, room: string): Promise<void> {
|
|
53
82
|
const sql = getSql();
|
|
54
83
|
await sql`INSERT INTO sessions (id, room) VALUES (${id}, ${room})`;
|
package/src/mcp/server.ts
CHANGED
|
@@ -99,6 +99,39 @@ export function createNiaMcpServer() {
|
|
|
99
99
|
content: [{ type: "text" as const, text: await handlers.listMessages(args.limit, args.room) }],
|
|
100
100
|
}),
|
|
101
101
|
),
|
|
102
|
+
tool(
|
|
103
|
+
"list_sessions",
|
|
104
|
+
"Browse past conversation sessions with previews. Returns session IDs you can pass to read_session.",
|
|
105
|
+
{
|
|
106
|
+
room: z.string().optional().describe("Filter by room name"),
|
|
107
|
+
limit: z.number().default(10).describe("Number of sessions to return"),
|
|
108
|
+
},
|
|
109
|
+
async (args) => ({
|
|
110
|
+
content: [{ type: "text" as const, text: await handlers.listSessions(args.limit, args.room) }],
|
|
111
|
+
}),
|
|
112
|
+
),
|
|
113
|
+
tool(
|
|
114
|
+
"search_messages",
|
|
115
|
+
"Search across all past messages by keyword. Returns matching messages with session IDs for deeper reading.",
|
|
116
|
+
{
|
|
117
|
+
query: z.string().describe("Text to search for in message content"),
|
|
118
|
+
room: z.string().optional().describe("Filter by room name"),
|
|
119
|
+
limit: z.number().default(20).describe("Max results to return"),
|
|
120
|
+
},
|
|
121
|
+
async (args) => ({
|
|
122
|
+
content: [{ type: "text" as const, text: await handlers.searchMessages(args.query, args.limit, args.room) }],
|
|
123
|
+
}),
|
|
124
|
+
),
|
|
125
|
+
tool(
|
|
126
|
+
"read_session",
|
|
127
|
+
"Load the full transcript of a specific conversation session. Use list_sessions or search_messages to find session IDs.",
|
|
128
|
+
{
|
|
129
|
+
session_id: z.string().describe("Session ID to read"),
|
|
130
|
+
},
|
|
131
|
+
async (args) => ({
|
|
132
|
+
content: [{ type: "text" as const, text: await handlers.readSession(args.session_id) }],
|
|
133
|
+
}),
|
|
134
|
+
),
|
|
102
135
|
tool(
|
|
103
136
|
"add_watch_channel",
|
|
104
137
|
"Add or update a Slack watch channel. Watch channels receive ALL messages (not just @mentions) and act based on the behavior prompt. Takes effect on next message (hot-reloads).",
|
package/src/mcp/tools.ts
CHANGED
|
@@ -244,6 +244,24 @@ export async function listMessages(limit = 20, room?: string): Promise<string> {
|
|
|
244
244
|
return JSON.stringify(messages, null, 2);
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
+
export async function listSessions(limit = 10, room?: string): Promise<string> {
|
|
248
|
+
const sessions = await Session.listRecent(limit, room);
|
|
249
|
+
if (sessions.length === 0) return "No sessions found.";
|
|
250
|
+
return JSON.stringify(sessions, null, 2);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export async function searchMessages(query: string, limit = 20, room?: string): Promise<string> {
|
|
254
|
+
const results = await Message.search(query, limit, room);
|
|
255
|
+
if (results.length === 0) return "No matching messages found.";
|
|
256
|
+
return JSON.stringify(results, null, 2);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export async function readSession(sessionId: string): Promise<string> {
|
|
260
|
+
const messages = await Message.getBySession(sessionId);
|
|
261
|
+
if (messages.length === 0) return "Session not found or has no messages.";
|
|
262
|
+
return JSON.stringify(messages, null, 2);
|
|
263
|
+
}
|
|
264
|
+
|
|
247
265
|
export function addRule(rule: string): string {
|
|
248
266
|
const { selfDir } = getPaths();
|
|
249
267
|
const rulesPath = join(selfDir, "rules.md");
|
|
@@ -31,6 +31,9 @@ You have MCP tools for managing jobs directly (preferred over CLI for speed):
|
|
|
31
31
|
- **run_job** — trigger a job to run immediately
|
|
32
32
|
- **send_message** — send a message to the user (via telegram, slack, or default channel). Supports `media_path` to send images/files.
|
|
33
33
|
- **list_messages** — read recent chat history
|
|
34
|
+
- **list_sessions** — browse past conversation sessions with previews and message counts. Returns session IDs.
|
|
35
|
+
- **search_messages** — keyword search across all past messages. Find when something was discussed.
|
|
36
|
+
- **read_session** — load the full transcript of a specific session by ID.
|
|
34
37
|
- **add_watch_channel** — add a Slack channel for proactive monitoring. Specify channel key (`channel_id#name`) and behavior prompt. Hot-reloads.
|
|
35
38
|
- **remove_watch_channel** — stop watching a Slack channel. Hot-reloads.
|
|
36
39
|
- **enable_watch_channel** / **disable_watch_channel** — toggle a watch channel on/off without removing it. Hot-reloads.
|
|
@@ -73,6 +76,16 @@ Config reference:
|
|
|
73
76
|
- `channels.slack.watch` — per-channel proactive monitoring. Keys are `channel_id#channel_name` format.
|
|
74
77
|
{{slackWatch}}
|
|
75
78
|
|
|
79
|
+
## Conversation History
|
|
80
|
+
|
|
81
|
+
You have access to all prior conversations stored in the database:
|
|
82
|
+
|
|
83
|
+
- **list_sessions** — browse past sessions (with previews and message counts). Use to find a conversation.
|
|
84
|
+
- **search_messages** — search across all past messages by keyword. Returns session IDs for deeper reading.
|
|
85
|
+
- **read_session** — load the full transcript of a session by ID.
|
|
86
|
+
|
|
87
|
+
Use these when the user asks "did we talk about...", "what did I say about...", or when you need context from a prior conversation. Combine with `read_memory` for a complete picture.
|
|
88
|
+
|
|
76
89
|
## Persona & Memory
|
|
77
90
|
|
|
78
91
|
Your persona files live in {{selfDir}}/:
|
package/src/types/index.ts
CHANGED
|
@@ -7,5 +7,5 @@ export type { Channel, ChannelFactory } from "./channel";
|
|
|
7
7
|
export type { ChatState } from "./chat-state";
|
|
8
8
|
export type { Config, ChannelsConfig, TelegramConfig, SlackConfig } from "./config";
|
|
9
9
|
export type { Paths } from "./paths";
|
|
10
|
-
export type { SaveMessageParams, RoomStats, RecentMessage } from "./message";
|
|
10
|
+
export type { SaveMessageParams, RoomStats, RecentMessage, SearchResult, SessionMessage } from "./message";
|
|
11
11
|
export type { AgentInfo } from "./agent";
|
package/src/types/message.ts
CHANGED
|
@@ -19,3 +19,19 @@ export interface RecentMessage {
|
|
|
19
19
|
content: string;
|
|
20
20
|
createdAt: string;
|
|
21
21
|
}
|
|
22
|
+
|
|
23
|
+
export interface SearchResult {
|
|
24
|
+
sessionId: string;
|
|
25
|
+
room: string;
|
|
26
|
+
sender: string;
|
|
27
|
+
content: string;
|
|
28
|
+
createdAt: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface SessionMessage {
|
|
32
|
+
room: string;
|
|
33
|
+
sender: string;
|
|
34
|
+
content: string;
|
|
35
|
+
isFromAgent: boolean;
|
|
36
|
+
createdAt: string;
|
|
37
|
+
}
|