@yoda.digital/iris-gateway 1.15.1 → 1.15.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/CHANGELOG.md +12 -0
- package/dist/bridge/routers/skills-context.d.ts +18 -0
- package/dist/bridge/routers/skills-context.d.ts.map +1 -0
- package/dist/bridge/routers/skills-context.js +91 -0
- package/dist/bridge/routers/skills-context.js.map +1 -0
- package/dist/bridge/routers/skills-handlers.d.ts +3 -17
- package/dist/bridge/routers/skills-handlers.d.ts.map +1 -1
- package/dist/bridge/routers/skills-handlers.js +11 -80
- package/dist/bridge/routers/skills-handlers.js.map +1 -1
- package/dist/governance/policy-audit.d.ts +4 -0
- package/dist/governance/policy-audit.d.ts.map +1 -0
- package/dist/governance/policy-audit.js +80 -0
- package/dist/governance/policy-audit.js.map +1 -0
- package/dist/governance/policy-types.d.ts +35 -0
- package/dist/governance/policy-types.d.ts.map +1 -0
- package/dist/governance/policy-types.js +12 -0
- package/dist/governance/policy-types.js.map +1 -0
- package/dist/governance/policy.d.ts +15 -48
- package/dist/governance/policy.d.ts.map +1 -1
- package/dist/governance/policy.js +13 -193
- package/dist/governance/policy.js.map +1 -1
- package/dist/proactive/engine.d.ts +8 -3
- package/dist/proactive/engine.d.ts.map +1 -1
- package/dist/proactive/engine.js +4 -65
- package/dist/proactive/engine.js.map +1 -1
- package/dist/proactive/pulse-prompts.d.ts +15 -0
- package/dist/proactive/pulse-prompts.d.ts.map +1 -0
- package/dist/proactive/pulse-prompts.js +61 -0
- package/dist/proactive/pulse-prompts.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,42 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { join, resolve } from "node:path";
|
|
3
|
-
/**
|
|
4
|
-
* PolicyEngine enforces the master policy — the structural ceiling
|
|
5
|
-
* for what agents, skills, and tools can exist and do.
|
|
6
|
-
*
|
|
7
|
-
* Three enforcement points:
|
|
8
|
-
* 1. Creation-time: validateAgent/validateSkill before writing files
|
|
9
|
-
* 2. Runtime: isToolAllowed before every tool call
|
|
10
|
-
* 3. Audit: auditAll scans existing agents/skills for violations
|
|
11
|
-
*
|
|
12
|
-
* Key invariant: agents can only NARROW within the policy, never widen.
|
|
13
|
-
*/
|
|
1
|
+
import { auditAll } from "./policy-audit.js";
|
|
14
2
|
export class PolicyEngine {
|
|
15
3
|
config;
|
|
16
4
|
constructor(config) {
|
|
17
5
|
this.config = config;
|
|
18
6
|
}
|
|
19
|
-
/** Whether the policy system is enabled. When disabled, everything is permitted. */
|
|
20
7
|
get enabled() {
|
|
21
8
|
return this.config.enabled;
|
|
22
9
|
}
|
|
23
|
-
/** Get the full policy config (for status endpoints). */
|
|
24
10
|
getConfig() {
|
|
25
11
|
return this.config;
|
|
26
12
|
}
|
|
27
13
|
// ── Tool enforcement (runtime) ──
|
|
28
|
-
/**
|
|
29
|
-
* Check if a tool call is allowed by master policy.
|
|
30
|
-
* Called in tool.execute.before BEFORE governance checks.
|
|
31
|
-
*/
|
|
32
14
|
isToolAllowed(toolName) {
|
|
33
15
|
if (!this.config.enabled)
|
|
34
16
|
return { allowed: true };
|
|
35
|
-
// Denied list always wins — belt and suspenders
|
|
36
17
|
if (this.config.tools.denied.length > 0 && this.config.tools.denied.includes(toolName)) {
|
|
37
18
|
return { allowed: false, reason: `Tool '${toolName}' is explicitly denied by master policy` };
|
|
38
19
|
}
|
|
39
|
-
// If allowlist is non-empty and enforcement is on, tool must be in it
|
|
40
20
|
if (this.config.enforcement.blockUnknownTools &&
|
|
41
21
|
this.config.tools.allowed.length > 0 &&
|
|
42
22
|
!this.config.tools.allowed.includes(toolName)) {
|
|
@@ -45,10 +25,6 @@ export class PolicyEngine {
|
|
|
45
25
|
return { allowed: true };
|
|
46
26
|
}
|
|
47
27
|
// ── Permission enforcement (runtime) ──
|
|
48
|
-
/**
|
|
49
|
-
* Check if a permission should be denied by master policy.
|
|
50
|
-
* Called in permission.ask hook.
|
|
51
|
-
*/
|
|
52
28
|
isPermissionDenied(permission) {
|
|
53
29
|
if (!this.config.enabled)
|
|
54
30
|
return false;
|
|
@@ -62,85 +38,45 @@ export class PolicyEngine {
|
|
|
62
38
|
return false;
|
|
63
39
|
}
|
|
64
40
|
// ── Agent creation validation ──
|
|
65
|
-
/**
|
|
66
|
-
* Validate an agent creation request against master policy.
|
|
67
|
-
* Returns violations (errors block creation, warnings are advisory).
|
|
68
|
-
*/
|
|
69
41
|
validateAgentCreation(req) {
|
|
70
42
|
if (!this.config.enabled)
|
|
71
43
|
return [];
|
|
72
44
|
const violations = [];
|
|
73
45
|
const agentPolicy = this.config.agents;
|
|
74
|
-
// Mode check
|
|
75
46
|
const mode = req.mode ?? "subagent";
|
|
76
47
|
if (!agentPolicy.allowedModes.includes(mode)) {
|
|
77
|
-
violations.push({
|
|
78
|
-
level: "error",
|
|
79
|
-
code: "AGENT_MODE_DENIED",
|
|
80
|
-
message: `Mode '${mode}' is not allowed. Allowed: ${agentPolicy.allowedModes.join(", ")}`,
|
|
81
|
-
});
|
|
48
|
+
violations.push({ level: "error", code: "AGENT_MODE_DENIED", message: `Mode '${mode}' is not allowed. Allowed: ${agentPolicy.allowedModes.join(", ")}` });
|
|
82
49
|
}
|
|
83
|
-
// Primary creation check
|
|
84
50
|
if (mode === "primary" && !agentPolicy.allowPrimaryCreation) {
|
|
85
|
-
violations.push({
|
|
86
|
-
level: "error",
|
|
87
|
-
code: "AGENT_PRIMARY_DENIED",
|
|
88
|
-
message: "Creating primary agents is not allowed by policy",
|
|
89
|
-
});
|
|
51
|
+
violations.push({ level: "error", code: "AGENT_PRIMARY_DENIED", message: "Creating primary agents is not allowed by policy" });
|
|
90
52
|
}
|
|
91
|
-
// Description required
|
|
92
53
|
if (agentPolicy.requireDescription && !req.description?.trim()) {
|
|
93
|
-
violations.push({
|
|
94
|
-
level: "error",
|
|
95
|
-
code: "AGENT_DESCRIPTION_REQUIRED",
|
|
96
|
-
message: "Agent description is required by policy",
|
|
97
|
-
});
|
|
54
|
+
violations.push({ level: "error", code: "AGENT_DESCRIPTION_REQUIRED", message: "Agent description is required by policy" });
|
|
98
55
|
}
|
|
99
|
-
// Steps limit
|
|
100
56
|
if (agentPolicy.maxSteps > 0 && req.steps && req.steps > agentPolicy.maxSteps) {
|
|
101
|
-
violations.push({
|
|
102
|
-
level: "error",
|
|
103
|
-
code: "AGENT_STEPS_EXCEEDED",
|
|
104
|
-
message: `Steps ${req.steps} exceeds policy limit of ${agentPolicy.maxSteps}`,
|
|
105
|
-
});
|
|
57
|
+
violations.push({ level: "error", code: "AGENT_STEPS_EXCEEDED", message: `Steps ${req.steps} exceeds policy limit of ${agentPolicy.maxSteps}` });
|
|
106
58
|
}
|
|
107
|
-
// Tool validation: each declared tool must be in master allowlist
|
|
108
59
|
if (req.tools?.length && this.config.tools.allowed.length > 0) {
|
|
109
60
|
for (const tool of req.tools) {
|
|
110
61
|
if (!this.config.tools.allowed.includes(tool)) {
|
|
111
|
-
violations.push({
|
|
112
|
-
level: "error",
|
|
113
|
-
code: "AGENT_TOOL_NOT_ALLOWED",
|
|
114
|
-
message: `Tool '${tool}' is not in master policy allowlist`,
|
|
115
|
-
});
|
|
62
|
+
violations.push({ level: "error", code: "AGENT_TOOL_NOT_ALLOWED", message: `Tool '${tool}' is not in master policy allowlist` });
|
|
116
63
|
}
|
|
117
64
|
}
|
|
118
65
|
}
|
|
119
|
-
// Denied tools check
|
|
120
66
|
if (req.tools?.length && this.config.tools.denied.length > 0) {
|
|
121
67
|
for (const tool of req.tools) {
|
|
122
68
|
if (this.config.tools.denied.includes(tool)) {
|
|
123
|
-
violations.push({
|
|
124
|
-
level: "error",
|
|
125
|
-
code: "AGENT_TOOL_DENIED",
|
|
126
|
-
message: `Tool '${tool}' is explicitly denied by master policy`,
|
|
127
|
-
});
|
|
69
|
+
violations.push({ level: "error", code: "AGENT_TOOL_DENIED", message: `Tool '${tool}' is explicitly denied by master policy` });
|
|
128
70
|
}
|
|
129
71
|
}
|
|
130
72
|
}
|
|
131
|
-
// Skill validation: restricted skills can't be assigned
|
|
132
73
|
if (req.skills?.length && this.config.skills.restricted.length > 0) {
|
|
133
74
|
for (const skill of req.skills) {
|
|
134
75
|
if (this.config.skills.restricted.includes(skill)) {
|
|
135
|
-
violations.push({
|
|
136
|
-
level: "error",
|
|
137
|
-
code: "AGENT_SKILL_RESTRICTED",
|
|
138
|
-
message: `Skill '${skill}' is restricted by master policy`,
|
|
139
|
-
});
|
|
76
|
+
violations.push({ level: "error", code: "AGENT_SKILL_RESTRICTED", message: `Skill '${skill}' is restricted by master policy` });
|
|
140
77
|
}
|
|
141
78
|
}
|
|
142
79
|
}
|
|
143
|
-
// Permission weakening check: agent permission can't grant what master denies
|
|
144
80
|
if (req.permission) {
|
|
145
81
|
this.checkPermissionWeakening(req.permission, violations);
|
|
146
82
|
}
|
|
@@ -151,130 +87,19 @@ export class PolicyEngine {
|
|
|
151
87
|
if (!this.config.enabled)
|
|
152
88
|
return [];
|
|
153
89
|
const violations = [];
|
|
154
|
-
// Restricted skill names
|
|
155
90
|
if (this.config.skills.restricted.includes(req.name)) {
|
|
156
|
-
violations.push({
|
|
157
|
-
level: "error",
|
|
158
|
-
code: "SKILL_RESTRICTED",
|
|
159
|
-
message: `Skill name '${req.name}' is restricted by master policy`,
|
|
160
|
-
});
|
|
91
|
+
violations.push({ level: "error", code: "SKILL_RESTRICTED", message: `Skill name '${req.name}' is restricted by master policy` });
|
|
161
92
|
}
|
|
162
|
-
// Trigger requirement
|
|
163
93
|
if (this.config.skills.requireTriggers && !req.triggers?.trim()) {
|
|
164
|
-
violations.push({
|
|
165
|
-
level: "warning",
|
|
166
|
-
code: "SKILL_NO_TRIGGERS",
|
|
167
|
-
message: "Policy recommends triggers for proactive skill suggestion",
|
|
168
|
-
});
|
|
94
|
+
violations.push({ level: "warning", code: "SKILL_NO_TRIGGERS", message: "Policy recommends triggers for proactive skill suggestion" });
|
|
169
95
|
}
|
|
170
96
|
return violations;
|
|
171
97
|
}
|
|
172
|
-
// ── Audit
|
|
98
|
+
// ── Audit (delegates to policy-audit.ts) ──
|
|
173
99
|
auditAll() {
|
|
174
|
-
|
|
175
|
-
const agentsDir = resolve(process.cwd(), ".opencode", "agents");
|
|
176
|
-
const skillsDir = resolve(process.cwd(), ".opencode", "skills");
|
|
177
|
-
// Audit agents
|
|
178
|
-
if (existsSync(agentsDir)) {
|
|
179
|
-
for (const entry of readdirSync(agentsDir, { withFileTypes: true })) {
|
|
180
|
-
if (!entry.isFile() || !entry.name.endsWith(".md"))
|
|
181
|
-
continue;
|
|
182
|
-
const name = entry.name.replace(/\.md$/, "");
|
|
183
|
-
const raw = readFileSync(join(agentsDir, entry.name), "utf-8");
|
|
184
|
-
const violations = this.auditAgent(name, raw);
|
|
185
|
-
results.push({ name, type: "agent", violations, compliant: !violations.some((v) => v.level === "error") });
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
// Audit skills
|
|
189
|
-
if (existsSync(skillsDir)) {
|
|
190
|
-
for (const entry of readdirSync(skillsDir, { withFileTypes: true })) {
|
|
191
|
-
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
192
|
-
continue;
|
|
193
|
-
const skillFile = join(skillsDir, entry.name, "SKILL.md");
|
|
194
|
-
if (!existsSync(skillFile))
|
|
195
|
-
continue;
|
|
196
|
-
const raw = readFileSync(skillFile, "utf-8");
|
|
197
|
-
const violations = this.auditSkill(entry.name, raw);
|
|
198
|
-
results.push({ name: entry.name, type: "skill", violations, compliant: !violations.some((v) => v.level === "error") });
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return results;
|
|
100
|
+
return auditAll(this.config);
|
|
202
101
|
}
|
|
203
102
|
// ── Private helpers ──
|
|
204
|
-
auditAgent(name, raw) {
|
|
205
|
-
if (!this.config.enabled)
|
|
206
|
-
return [];
|
|
207
|
-
const violations = [];
|
|
208
|
-
// Extract mode
|
|
209
|
-
const modeMatch = raw.match(/mode:\s*(\w+)/);
|
|
210
|
-
const mode = modeMatch?.[1] ?? "unknown";
|
|
211
|
-
if (!this.config.agents.allowedModes.includes(mode) && mode !== "primary") {
|
|
212
|
-
violations.push({
|
|
213
|
-
level: "error",
|
|
214
|
-
code: "AGENT_MODE_DENIED",
|
|
215
|
-
message: `Agent '${name}' has mode '${mode}' not in policy allowlist`,
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
// Extract tools
|
|
219
|
-
const toolMatches = raw.matchAll(/^\s+(\w+):\s*true/gm);
|
|
220
|
-
for (const match of toolMatches) {
|
|
221
|
-
const tool = match[1];
|
|
222
|
-
if (this.config.tools.denied.includes(tool)) {
|
|
223
|
-
violations.push({
|
|
224
|
-
level: "error",
|
|
225
|
-
code: "AGENT_TOOL_DENIED",
|
|
226
|
-
message: `Agent '${name}' uses denied tool '${tool}'`,
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
if (this.config.tools.allowed.length > 0 && !this.config.tools.allowed.includes(tool) && tool !== "skill") {
|
|
230
|
-
violations.push({
|
|
231
|
-
level: "warning",
|
|
232
|
-
code: "AGENT_TOOL_NOT_ALLOWED",
|
|
233
|
-
message: `Agent '${name}' uses tool '${tool}' not in master allowlist`,
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
// Check description
|
|
238
|
-
if (this.config.agents.requireDescription && !/description:\s*.+/.test(raw)) {
|
|
239
|
-
violations.push({
|
|
240
|
-
level: "warning",
|
|
241
|
-
code: "AGENT_NO_DESCRIPTION",
|
|
242
|
-
message: `Agent '${name}' has no description (required by policy)`,
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
// Check skills against restricted
|
|
246
|
-
const skillMatches = raw.matchAll(/^\s+-\s+(\S+)/gm);
|
|
247
|
-
for (const match of skillMatches) {
|
|
248
|
-
if (this.config.skills.restricted.includes(match[1])) {
|
|
249
|
-
violations.push({
|
|
250
|
-
level: "error",
|
|
251
|
-
code: "AGENT_SKILL_RESTRICTED",
|
|
252
|
-
message: `Agent '${name}' uses restricted skill '${match[1]}'`,
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
return violations;
|
|
257
|
-
}
|
|
258
|
-
auditSkill(name, raw) {
|
|
259
|
-
if (!this.config.enabled)
|
|
260
|
-
return [];
|
|
261
|
-
const violations = [];
|
|
262
|
-
if (this.config.skills.restricted.includes(name)) {
|
|
263
|
-
violations.push({
|
|
264
|
-
level: "error",
|
|
265
|
-
code: "SKILL_RESTRICTED",
|
|
266
|
-
message: `Skill '${name}' is restricted by master policy`,
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
if (this.config.skills.requireTriggers && !/triggers:/.test(raw)) {
|
|
270
|
-
violations.push({
|
|
271
|
-
level: "warning",
|
|
272
|
-
code: "SKILL_NO_TRIGGERS",
|
|
273
|
-
message: `Skill '${name}' has no trigger keywords`,
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
return violations;
|
|
277
|
-
}
|
|
278
103
|
checkPermissionWeakening(agentPerm, violations) {
|
|
279
104
|
const masterPerms = this.config.permissions;
|
|
280
105
|
const permMap = {
|
|
@@ -282,16 +107,11 @@ export class PolicyEngine {
|
|
|
282
107
|
edit: masterPerms.edit,
|
|
283
108
|
read: masterPerms.read,
|
|
284
109
|
};
|
|
285
|
-
// Flatten: check allow.bash, allow.edit, etc.
|
|
286
110
|
const allow = agentPerm["allow"];
|
|
287
111
|
if (allow && typeof allow === "object") {
|
|
288
112
|
for (const [key, val] of Object.entries(allow)) {
|
|
289
113
|
if (permMap[key] === "deny" && val !== "deny") {
|
|
290
|
-
violations.push({
|
|
291
|
-
level: "error",
|
|
292
|
-
code: "AGENT_PERM_WEAKENING",
|
|
293
|
-
message: `Agent permission allows '${key}' but master policy denies it`,
|
|
294
|
-
});
|
|
114
|
+
violations.push({ level: "error", code: "AGENT_PERM_WEAKENING", message: `Agent permission allows '${key}' but master policy denies it` });
|
|
295
115
|
}
|
|
296
116
|
}
|
|
297
117
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/governance/policy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/governance/policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* engine.ts — PulseEngine: scheduling and proactive execution loop.
|
|
3
|
+
*
|
|
4
|
+
* @decomposition-plan (issue #235 — VISION.md §1 pre-emption at 341 lines)
|
|
5
|
+
* Prompt builders and quiet-hours logic extracted to pulse-prompts.ts:
|
|
6
|
+
* - pulse-prompts.ts → buildIntentPrompt, buildTriggerPrompt, isQuietHours
|
|
7
|
+
* - engine.ts → PulseEngine class — scheduling + execution (this file, ~200 lines)
|
|
8
|
+
*/
|
|
1
9
|
import type { IntentStore } from "./store.js";
|
|
2
10
|
import type { ProactiveConfig } from "./types.js";
|
|
3
11
|
import type { OpenCodeBridge } from "../bridge/opencode-client.js";
|
|
@@ -38,9 +46,6 @@ export declare class PulseEngine {
|
|
|
38
46
|
private executeIntent;
|
|
39
47
|
private executeTrigger;
|
|
40
48
|
private executeProactive;
|
|
41
|
-
private buildIntentPrompt;
|
|
42
|
-
private buildTriggerPrompt;
|
|
43
|
-
private isQuietHours;
|
|
44
49
|
}
|
|
45
50
|
export {};
|
|
46
51
|
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/proactive/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAqC,MAAM,YAAY,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/proactive/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAqC,MAAM,YAAY,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAGtE,UAAU,eAAe;IACvB,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,CAAC;IACxB,WAAW,CAAC,EAAE,mBAAmB,CAAC;CACnC;AAKD,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IAEzC,OAAO,CAAC,SAAS,CAA+C;IAChE,OAAO,CAAC,SAAS,CAA+C;IAChE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAsB;gBAEvC,IAAI,EAAE,eAAe;IAYjC,KAAK,IAAI,IAAI;IAoBb,IAAI,IAAI,IAAI;IAYN,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBrB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;YAoBpB,aAAa;YAoCb,cAAc;YAmCd,gBAAgB;CA+C/B"}
|
package/dist/proactive/engine.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { buildIntentPrompt, buildTriggerPrompt, isQuietHours } from "./pulse-prompts.js";
|
|
1
2
|
const SKIP_MARKER = "[SKIP]";
|
|
2
3
|
const DEFER_REGEX = /^\[DEFER\s+(\d+)h\]$/i;
|
|
3
4
|
export class PulseEngine {
|
|
@@ -102,14 +103,12 @@ export class PulseEngine {
|
|
|
102
103
|
this.logger.debug({ id: intent.id }, "Skipped: global quota exceeded");
|
|
103
104
|
return;
|
|
104
105
|
}
|
|
105
|
-
// Intents are created during active conversations — don't gate by quiet hours.
|
|
106
|
-
// Quiet hours only apply to system-initiated triggers (dormancy, etc.).
|
|
107
106
|
const result = await this.executeProactive({
|
|
108
107
|
channelId: intent.channelId,
|
|
109
108
|
chatId: intent.chatId,
|
|
110
109
|
senderId: intent.senderId,
|
|
111
110
|
chatType: "dm",
|
|
112
|
-
prompt:
|
|
111
|
+
prompt: buildIntentPrompt(intent, this.vaultStore, quota.engagementRate, quota.sentToday, quota.limit),
|
|
113
112
|
sourceId: intent.id,
|
|
114
113
|
sourceType: "intent",
|
|
115
114
|
});
|
|
@@ -131,7 +130,7 @@ export class PulseEngine {
|
|
|
131
130
|
this.logger.debug({ id: trigger.id }, "Trigger skipped: global quota exceeded");
|
|
132
131
|
return;
|
|
133
132
|
}
|
|
134
|
-
if (
|
|
133
|
+
if (isQuietHours(trigger.senderId, trigger.channelId, this.vaultStore, this.config)) {
|
|
135
134
|
this.logger.debug({ id: trigger.id }, "Trigger skipped: quiet hours");
|
|
136
135
|
return;
|
|
137
136
|
}
|
|
@@ -140,7 +139,7 @@ export class PulseEngine {
|
|
|
140
139
|
chatId: trigger.chatId,
|
|
141
140
|
senderId: trigger.senderId,
|
|
142
141
|
chatType: "dm",
|
|
143
|
-
prompt:
|
|
142
|
+
prompt: buildTriggerPrompt(trigger, this.vaultStore, quota.engagementRate, quota.sentToday, quota.limit),
|
|
144
143
|
sourceId: trigger.id,
|
|
145
144
|
sourceType: "trigger",
|
|
146
145
|
});
|
|
@@ -174,65 +173,5 @@ export class PulseEngine {
|
|
|
174
173
|
this.logger.info({ senderId: params.senderId, channelId: params.channelId, sourceType: params.sourceType }, "Proactive message sent");
|
|
175
174
|
return "sent";
|
|
176
175
|
}
|
|
177
|
-
buildIntentPrompt(intent, engagementRate, sentToday, limit) {
|
|
178
|
-
const elapsed = Date.now() - intent.createdAt;
|
|
179
|
-
const hoursAgo = Math.floor(elapsed / 3_600_000);
|
|
180
|
-
const timeAgo = hoursAgo >= 24
|
|
181
|
-
? `${Math.floor(hoursAgo / 24)} days ago`
|
|
182
|
-
: `${hoursAgo} hours ago`;
|
|
183
|
-
const profile = this.vaultStore.getProfile(intent.senderId, intent.channelId);
|
|
184
|
-
const profileBlock = profile
|
|
185
|
-
? `User: ${profile.name ?? "unknown"} | ${profile.timezone ?? "no timezone"} | ${profile.language ?? ""}`
|
|
186
|
-
: "User: unknown";
|
|
187
|
-
return `[PROACTIVE FOLLOW-UP]
|
|
188
|
-
You registered an intent ${timeAgo}: "${intent.what}"
|
|
189
|
-
${intent.why ? `Reason: "${intent.why}"` : ""}
|
|
190
|
-
|
|
191
|
-
${profileBlock}
|
|
192
|
-
Your quota: ${limit - sentToday}/${limit} proactive messages remaining today
|
|
193
|
-
Your engagement rate: ${Math.round(engagementRate * 100)}% of proactive messages get replies
|
|
194
|
-
|
|
195
|
-
Decide: Should you follow up now? If yes, compose a natural, helpful message.
|
|
196
|
-
Use any tools you need (send_message, vault_remember, canvas_update, etc.).
|
|
197
|
-
If not worth it, respond with just: [SKIP]
|
|
198
|
-
If you want to try later, respond with: [DEFER Xh] (replace X with hours)`;
|
|
199
|
-
}
|
|
200
|
-
buildTriggerPrompt(trigger, engagementRate, sentToday, limit) {
|
|
201
|
-
const profile = this.vaultStore.getProfile(trigger.senderId, trigger.channelId);
|
|
202
|
-
const profileBlock = profile
|
|
203
|
-
? `User: ${profile.name ?? "unknown"} | ${profile.timezone ?? "no timezone"} | ${profile.language ?? ""}`
|
|
204
|
-
: "User: unknown";
|
|
205
|
-
return `[PROACTIVE OUTREACH — ${trigger.type.replace(/_/g, " ").toUpperCase()}]
|
|
206
|
-
${trigger.context}
|
|
207
|
-
|
|
208
|
-
${profileBlock}
|
|
209
|
-
Your quota: ${limit - sentToday}/${limit} proactive messages remaining today
|
|
210
|
-
Your engagement rate: ${Math.round(engagementRate * 100)}% of proactive messages get replies
|
|
211
|
-
|
|
212
|
-
Decide: Should you reach out? If yes, compose a natural, warm message.
|
|
213
|
-
If not appropriate, respond with just: [SKIP]
|
|
214
|
-
If you want to try later, respond with: [DEFER Xh]`;
|
|
215
|
-
}
|
|
216
|
-
isQuietHours(senderId, channelId) {
|
|
217
|
-
const profile = this.vaultStore.getProfile(senderId, channelId);
|
|
218
|
-
const tz = profile?.timezone;
|
|
219
|
-
let hour;
|
|
220
|
-
if (tz) {
|
|
221
|
-
try {
|
|
222
|
-
hour = parseInt(new Date().toLocaleString("en-US", { timeZone: tz, hour: "numeric", hour12: false }), 10);
|
|
223
|
-
}
|
|
224
|
-
catch {
|
|
225
|
-
hour = new Date().getHours();
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
hour = new Date().getHours();
|
|
230
|
-
}
|
|
231
|
-
const { start, end } = this.config.quietHours;
|
|
232
|
-
if (start > end) {
|
|
233
|
-
return hour >= start || hour < end;
|
|
234
|
-
}
|
|
235
|
-
return hour >= start && hour < end;
|
|
236
|
-
}
|
|
237
176
|
}
|
|
238
177
|
//# sourceMappingURL=engine.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/proactive/engine.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/proactive/engine.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAczF,MAAM,WAAW,GAAG,QAAQ,CAAC;AAC7B,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAE5C,MAAM,OAAO,WAAW;IACL,KAAK,CAAc;IACnB,MAAM,CAAiB;IACvB,MAAM,CAAgB;IACtB,UAAU,CAAa;IACvB,UAAU,CAAa;IACvB,QAAQ,CAAkB;IAC1B,MAAM,CAAS;IACf,MAAM,CAAkB;IAEjC,SAAS,GAA0C,IAAI,CAAC;IACxD,SAAS,GAA0C,IAAI,CAAC;IAC/C,WAAW,CAAuB;IAEnD,YAAY,IAAqB;QAC/B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACtC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;YAChC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,kBAAkB,CAAC,CAAC;YACjD,CAAC,CAAC,CAAC;QACL,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAC/B,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QAEvB,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YACjC,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;gBAChC,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;oBAC/B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,oBAAoB,CAAC,CAAC;gBACnD,CAAC,CAAC,CAAC;YACL,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;YACtC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IACrD,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACxB,CAAC;QACD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACxB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM;YAAE,OAAO;QACzD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC5E,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,gCAAgC,CAAC,CAAC;QACjE,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;QAClD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;QACpD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,WAAW;QACf,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM;YAAE,OAAO;QACzD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO;YAAE,OAAO;QAE1C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAElF,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YAC3B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC;YAC3E,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;gBACpB,IAAI,EAAE,cAAc;gBACpB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,MAAM,EAAE,IAAI,CAAC,QAAQ;gBACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,OAAO,EAAE,SAAS,IAAI,CAAC,IAAI,IAAI,SAAS,kBAAkB,YAAY,QAAQ;gBAC9E,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;aAClC,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,8BAA8B,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,MAAuB;QACjD,IAAI,CAAC;YACH,IAAI,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,mBAAmB,EAAE,CAAC;gBACvE,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;gBAC3D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,EAAE,+BAA+B,CAAC,CAAC;gBACrG,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;YACjH,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;gBACnB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,yBAAyB,CAAC,CAAC;gBAC5F,OAAO;YACT,CAAC;YAED,IAAI,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC;gBAC5E,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,gCAAgC,CAAC,CAAC;gBACvE,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC;gBACzC,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC;gBACtG,QAAQ,EAAE,MAAM,CAAC,EAAE;gBACnB,UAAU,EAAE,QAAQ;aACrB,CAAC,CAAC;YAEH,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,yBAAyB,CAAC,CAAC;YACrE,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,OAAyB;QACpD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;YACnH,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;gBACnB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,iCAAiC,CAAC,CAAC;gBACzE,OAAO;YACT,CAAC;YAED,IAAI,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC;gBAC5E,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,wCAAwC,CAAC,CAAC;gBAChF,OAAO;YACT,CAAC;YAED,IAAI,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACpF,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,8BAA8B,CAAC,CAAC;gBACtE,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC;gBACzC,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC;gBACxG,QAAQ,EAAE,OAAO,CAAC,EAAE;gBACpB,UAAU,EAAE,SAAS;aACtB,CAAC,CAAC;YAEH,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,0BAA0B,CAAC,CAAC;YACvE,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,MAQ9B;QACC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CACzC,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,QAAQ,EACf,IAAI,CAAC,MAAM,CACZ,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAEvF,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,WAAW,EAAE,CAAC;YACjD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,kBAAkB,CAAC,CAAC;YACpE,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACtD,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,aAAa,CAAC,CAAC;YACtE,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAE1E,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC;YAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,IAAI,EAAE,MAAM,CAAC,UAAU;YACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;SAC1B,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,EACzF,wBAAwB,CACzB,CAAC;QAEF,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pulse-prompts.ts — Prompt builders for the PulseEngine.
|
|
3
|
+
* Extracted from engine.ts (VISION.md §1 — 500-line hard limit pre-emption, issue #235).
|
|
4
|
+
*
|
|
5
|
+
* @decomposition-plan
|
|
6
|
+
* engine.ts split at 341 lines:
|
|
7
|
+
* - pulse-prompts.ts → buildIntentPrompt, buildTriggerPrompt, isQuietHours (this file)
|
|
8
|
+
* - engine.ts → PulseEngine class — scheduling + execution loop (~220 lines)
|
|
9
|
+
*/
|
|
10
|
+
import type { ProactiveConfig, ProactiveIntent, ProactiveTrigger } from "./types.js";
|
|
11
|
+
import type { VaultStore } from "../vault/store.js";
|
|
12
|
+
export declare function buildIntentPrompt(intent: ProactiveIntent, vaultStore: VaultStore, engagementRate: number, sentToday: number, limit: number): string;
|
|
13
|
+
export declare function buildTriggerPrompt(trigger: ProactiveTrigger, vaultStore: VaultStore, engagementRate: number, sentToday: number, limit: number): string;
|
|
14
|
+
export declare function isQuietHours(senderId: string, channelId: string, vaultStore: VaultStore, config: ProactiveConfig): boolean;
|
|
15
|
+
//# sourceMappingURL=pulse-prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pulse-prompts.d.ts","sourceRoot":"","sources":["../../src/proactive/pulse-prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,MAAM,CAwBR;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,gBAAgB,EACzB,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,MAAM,CAgBR;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,eAAe,GACtB,OAAO,CAuBT"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export function buildIntentPrompt(intent, vaultStore, engagementRate, sentToday, limit) {
|
|
2
|
+
const elapsed = Date.now() - intent.createdAt;
|
|
3
|
+
const hoursAgo = Math.floor(elapsed / 3_600_000);
|
|
4
|
+
const timeAgo = hoursAgo >= 24
|
|
5
|
+
? `${Math.floor(hoursAgo / 24)} days ago`
|
|
6
|
+
: `${hoursAgo} hours ago`;
|
|
7
|
+
const profile = vaultStore.getProfile(intent.senderId, intent.channelId);
|
|
8
|
+
const profileBlock = profile
|
|
9
|
+
? `User: ${profile.name ?? "unknown"} | ${profile.timezone ?? "no timezone"} | ${profile.language ?? ""}`
|
|
10
|
+
: "User: unknown";
|
|
11
|
+
return `[PROACTIVE FOLLOW-UP]
|
|
12
|
+
You registered an intent ${timeAgo}: "${intent.what}"
|
|
13
|
+
${intent.why ? `Reason: "${intent.why}"` : ""}
|
|
14
|
+
|
|
15
|
+
${profileBlock}
|
|
16
|
+
Your quota: ${limit - sentToday}/${limit} proactive messages remaining today
|
|
17
|
+
Your engagement rate: ${Math.round(engagementRate * 100)}% of proactive messages get replies
|
|
18
|
+
|
|
19
|
+
Decide: Should you follow up now? If yes, compose a natural, helpful message.
|
|
20
|
+
Use any tools you need (send_message, vault_remember, canvas_update, etc.).
|
|
21
|
+
If not worth it, respond with just: [SKIP]
|
|
22
|
+
If you want to try later, respond with: [DEFER Xh] (replace X with hours)`;
|
|
23
|
+
}
|
|
24
|
+
export function buildTriggerPrompt(trigger, vaultStore, engagementRate, sentToday, limit) {
|
|
25
|
+
const profile = vaultStore.getProfile(trigger.senderId, trigger.channelId);
|
|
26
|
+
const profileBlock = profile
|
|
27
|
+
? `User: ${profile.name ?? "unknown"} | ${profile.timezone ?? "no timezone"} | ${profile.language ?? ""}`
|
|
28
|
+
: "User: unknown";
|
|
29
|
+
return `[PROACTIVE OUTREACH — ${trigger.type.replace(/_/g, " ").toUpperCase()}]
|
|
30
|
+
${trigger.context}
|
|
31
|
+
|
|
32
|
+
${profileBlock}
|
|
33
|
+
Your quota: ${limit - sentToday}/${limit} proactive messages remaining today
|
|
34
|
+
Your engagement rate: ${Math.round(engagementRate * 100)}% of proactive messages get replies
|
|
35
|
+
|
|
36
|
+
Decide: Should you reach out? If yes, compose a natural, warm message.
|
|
37
|
+
If not appropriate, respond with just: [SKIP]
|
|
38
|
+
If you want to try later, respond with: [DEFER Xh]`;
|
|
39
|
+
}
|
|
40
|
+
export function isQuietHours(senderId, channelId, vaultStore, config) {
|
|
41
|
+
const profile = vaultStore.getProfile(senderId, channelId);
|
|
42
|
+
const tz = profile?.timezone;
|
|
43
|
+
let hour;
|
|
44
|
+
if (tz) {
|
|
45
|
+
try {
|
|
46
|
+
hour = parseInt(new Date().toLocaleString("en-US", { timeZone: tz, hour: "numeric", hour12: false }), 10);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
hour = new Date().getHours();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
hour = new Date().getHours();
|
|
54
|
+
}
|
|
55
|
+
const { start, end } = config.quietHours;
|
|
56
|
+
if (start > end) {
|
|
57
|
+
return hour >= start || hour < end;
|
|
58
|
+
}
|
|
59
|
+
return hour >= start && hour < end;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=pulse-prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pulse-prompts.js","sourceRoot":"","sources":["../../src/proactive/pulse-prompts.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED