niahere 0.2.66 → 0.2.67
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/channels/slack.ts +21 -10
- package/src/chat/employee-prompt.ts +2 -2
- package/src/chat/engine.ts +10 -4
- package/src/chat/identity.ts +24 -0
- package/src/core/runner.ts +3 -3
- package/src/types/engine.ts +2 -0
package/package.json
CHANGED
package/src/channels/slack.ts
CHANGED
|
@@ -79,20 +79,26 @@ class SlackChannel implements Channel {
|
|
|
79
79
|
return `slack-${key}-${index}`;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
async function getState(key: string): Promise<ChatState> {
|
|
82
|
+
async function getState(key: string, watchBehavior?: { channel: string; behavior: string }): Promise<ChatState> {
|
|
83
83
|
let state = chats.get(key);
|
|
84
84
|
if (!state) {
|
|
85
85
|
const prefix = roomPrefix(key);
|
|
86
86
|
const idx = await Session.getLatestRoomIndex(prefix);
|
|
87
87
|
const room = roomName(key, idx);
|
|
88
|
-
const engine = await createChatEngine({
|
|
88
|
+
const engine = await createChatEngine({
|
|
89
|
+
room,
|
|
90
|
+
channel: "slack",
|
|
91
|
+
resume: true,
|
|
92
|
+
mcpServers: getMcpServers(),
|
|
93
|
+
watchBehavior,
|
|
94
|
+
});
|
|
89
95
|
state = { engine, roomIndex: idx, lock: Promise.resolve() };
|
|
90
96
|
chats.set(key, state);
|
|
91
97
|
}
|
|
92
98
|
return state;
|
|
93
99
|
}
|
|
94
100
|
|
|
95
|
-
async function restartChat(key: string): Promise<ChatState> {
|
|
101
|
+
async function restartChat(key: string, watchBehavior?: { channel: string; behavior: string }): Promise<ChatState> {
|
|
96
102
|
const old = chats.get(key);
|
|
97
103
|
if (old) old.engine.close();
|
|
98
104
|
|
|
@@ -106,7 +112,13 @@ class SlackChannel implements Channel {
|
|
|
106
112
|
await Session.create(`placeholder-${room}`, room);
|
|
107
113
|
|
|
108
114
|
log.info({ key, room }, "slack: creating chat engine");
|
|
109
|
-
const engine = await createChatEngine({
|
|
115
|
+
const engine = await createChatEngine({
|
|
116
|
+
room,
|
|
117
|
+
channel: "slack",
|
|
118
|
+
resume: false,
|
|
119
|
+
mcpServers: getMcpServers(),
|
|
120
|
+
watchBehavior,
|
|
121
|
+
});
|
|
110
122
|
const state: ChatState = { engine, roomIndex: newIdx, lock: Promise.resolve() };
|
|
111
123
|
chats.set(key, state);
|
|
112
124
|
log.info({ key, room, activeSessions: chats.size }, "slack: engine ready");
|
|
@@ -504,11 +516,10 @@ class SlackChannel implements Channel {
|
|
|
504
516
|
}
|
|
505
517
|
}
|
|
506
518
|
|
|
507
|
-
//
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
}
|
|
519
|
+
// Build watch behavior for system prompt injection (if watched channel)
|
|
520
|
+
const watchBehavior = watchConfig?.behavior
|
|
521
|
+
? { channel: watchConfig.name, behavior: watchConfig.behavior }
|
|
522
|
+
: undefined;
|
|
512
523
|
|
|
513
524
|
log.info(
|
|
514
525
|
{
|
|
@@ -524,7 +535,7 @@ class SlackChannel implements Channel {
|
|
|
524
535
|
|
|
525
536
|
let state: ChatState;
|
|
526
537
|
try {
|
|
527
|
-
state = await getState(key);
|
|
538
|
+
state = await getState(key, watchBehavior);
|
|
528
539
|
} catch (err) {
|
|
529
540
|
log.error({ err, key }, "slack: failed to create chat engine");
|
|
530
541
|
return;
|
|
@@ -12,7 +12,7 @@ function loadFile(dir: string, name: string): string {
|
|
|
12
12
|
return readFileSync(filePath, "utf8").trim();
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export function buildEmployeePrompt(name: string): string {
|
|
15
|
+
export function buildEmployeePrompt(name: string, mode: "chat" | "job" = "chat"): string {
|
|
16
16
|
const employee = getEmployee(name);
|
|
17
17
|
if (!employee) return "";
|
|
18
18
|
|
|
@@ -25,7 +25,7 @@ export function buildEmployeePrompt(name: string): string {
|
|
|
25
25
|
// Environment + mode + capabilities
|
|
26
26
|
parts.push(getEnvironmentPrompt());
|
|
27
27
|
|
|
28
|
-
const modePrompt = getModePrompt(
|
|
28
|
+
const modePrompt = getModePrompt(mode);
|
|
29
29
|
if (modePrompt) parts.push(modePrompt);
|
|
30
30
|
|
|
31
31
|
const skills = getSkillsSummary();
|
package/src/chat/engine.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { existsSync } from "fs";
|
|
|
5
5
|
import { join } from "path";
|
|
6
6
|
import { homedir } from "os";
|
|
7
7
|
import { randomUUID } from "crypto";
|
|
8
|
-
import { buildSystemPrompt, getSessionContext } from "./identity";
|
|
8
|
+
import { buildSystemPrompt, buildContextSuffix, getSessionContext } from "./identity";
|
|
9
9
|
import { buildEmployeePrompt } from "./employee-prompt";
|
|
10
10
|
import { getEmployee } from "../core/employees";
|
|
11
11
|
import { getAgentDefinitions, scanAgents } from "../core/agents";
|
|
@@ -146,7 +146,7 @@ export async function createChatEngine(opts: EngineOptions): Promise<ChatEngine>
|
|
|
146
146
|
} else if (opts.agent) {
|
|
147
147
|
const agents = scanAgents();
|
|
148
148
|
const agentDef = agents.find((a) => a.name === opts.agent);
|
|
149
|
-
if (agentDef) systemPrompt = agentDef.body;
|
|
149
|
+
if (agentDef) systemPrompt = agentDef.body + "\n\n" + buildContextSuffix("chat");
|
|
150
150
|
} else if (opts.job) {
|
|
151
151
|
// Job chat: load job and use its context
|
|
152
152
|
const jobData = await Job.get(opts.job);
|
|
@@ -158,15 +158,21 @@ export async function createChatEngine(opts: EngineOptions): Promise<ChatEngine>
|
|
|
158
158
|
const emp = getEmployee(jobData.employee);
|
|
159
159
|
if (emp?.repo && existsSync(emp.repo)) cwd = emp.repo;
|
|
160
160
|
} else if (jobData.agent) {
|
|
161
|
-
// If job has an agent, use agent prompt
|
|
161
|
+
// If job has an agent, use agent prompt + context
|
|
162
162
|
const agents = scanAgents();
|
|
163
163
|
const agentDef = agents.find((a) => a.name === jobData.agent);
|
|
164
|
-
if (agentDef) systemPrompt = agentDef.body;
|
|
164
|
+
if (agentDef) systemPrompt = agentDef.body + "\n\n" + buildContextSuffix("chat");
|
|
165
165
|
}
|
|
166
166
|
systemPrompt += `\n\n## Job Context\nYou are chatting in the context of job "${jobData.name}" (schedule: ${jobData.schedule}).\n\nJob prompt:\n${jobData.prompt}`;
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
// Watch mode: inject behavior into system prompt
|
|
171
|
+
if (opts.watchBehavior) {
|
|
172
|
+
const { channel: watchChannel, behavior } = opts.watchBehavior;
|
|
173
|
+
systemPrompt += `\n\n## Watch Mode — #${watchChannel}\n\nYou are monitoring this Slack channel. Follow the behavior instructions below.\nRespond with [NO_REPLY] if no action is needed — do not explain why.\n\n${behavior}`;
|
|
174
|
+
}
|
|
175
|
+
|
|
170
176
|
let sessionId: string | null = null;
|
|
171
177
|
if (typeof resume === "string") {
|
|
172
178
|
// Specific session ID provided
|
package/src/chat/identity.ts
CHANGED
|
@@ -52,6 +52,30 @@ export function buildSystemPrompt(mode: Mode = "chat", channel: string = "termin
|
|
|
52
52
|
return parts.join("\n\n");
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Build the context suffix (env + mode + skills + agents + employees) that should
|
|
57
|
+
* be appended to any custom system prompt (agent body, watch behavior, etc).
|
|
58
|
+
* Does NOT include Nia's identity — that's the caller's responsibility.
|
|
59
|
+
*/
|
|
60
|
+
export function buildContextSuffix(mode: Mode = "chat"): string {
|
|
61
|
+
const parts: string[] = [];
|
|
62
|
+
parts.push(getEnvironmentPrompt());
|
|
63
|
+
|
|
64
|
+
const modePrompt = getModePrompt(mode);
|
|
65
|
+
if (modePrompt) parts.push(modePrompt);
|
|
66
|
+
|
|
67
|
+
const skills = getSkillsSummary();
|
|
68
|
+
if (skills) parts.push(skills);
|
|
69
|
+
|
|
70
|
+
const agents = getAgentsSummary();
|
|
71
|
+
if (agents) parts.push(agents);
|
|
72
|
+
|
|
73
|
+
const employees = getEmployeesSummary();
|
|
74
|
+
if (employees) parts.push(employees);
|
|
75
|
+
|
|
76
|
+
return parts.join("\n\n");
|
|
77
|
+
}
|
|
78
|
+
|
|
55
79
|
/**
|
|
56
80
|
* Load recent session summaries for a room and format as a context block.
|
|
57
81
|
* Returns empty string if no summaries are available.
|
package/src/core/runner.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { JobInput, JobResult } from "../types";
|
|
|
7
7
|
import { appendAudit, readState, writeState } from "../utils/logger";
|
|
8
8
|
import type { AuditEntry, JobState } from "../types";
|
|
9
9
|
import { getConfig } from "../utils/config";
|
|
10
|
-
import { buildSystemPrompt } from "../chat/identity";
|
|
10
|
+
import { buildSystemPrompt, buildContextSuffix } from "../chat/identity";
|
|
11
11
|
import { buildEmployeePrompt } from "../chat/employee-prompt";
|
|
12
12
|
import { getEmployee } from "./employees";
|
|
13
13
|
import { scanAgents } from "./agents";
|
|
@@ -309,7 +309,7 @@ export async function runJob(job: JobInput, onActivity?: ActivityCallback): Prom
|
|
|
309
309
|
let systemPrompt: string;
|
|
310
310
|
let agentModel: string | undefined;
|
|
311
311
|
if (job.employee) {
|
|
312
|
-
const empPrompt = buildEmployeePrompt(job.employee);
|
|
312
|
+
const empPrompt = buildEmployeePrompt(job.employee, "job");
|
|
313
313
|
if (empPrompt) {
|
|
314
314
|
systemPrompt = empPrompt;
|
|
315
315
|
} else {
|
|
@@ -322,7 +322,7 @@ export async function runJob(job: JobInput, onActivity?: ActivityCallback): Prom
|
|
|
322
322
|
const agents = scanAgents();
|
|
323
323
|
const agentDef = agents.find((a) => a.name === job.agent);
|
|
324
324
|
if (agentDef) {
|
|
325
|
-
systemPrompt = agentDef.body;
|
|
325
|
+
systemPrompt = agentDef.body + "\n\n" + buildContextSuffix("job");
|
|
326
326
|
agentModel = agentDef.model;
|
|
327
327
|
} else {
|
|
328
328
|
systemPrompt = buildSystemPrompt("job");
|
package/src/types/engine.ts
CHANGED