@keyoku/openclaw 1.0.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/dist/capture.d.ts +23 -0
- package/dist/capture.d.ts.map +1 -0
- package/dist/capture.js +114 -0
- package/dist/capture.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +71 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +19 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +22 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +136 -0
- package/dist/context.js.map +1 -0
- package/dist/heartbeat-setup.d.ts +10 -0
- package/dist/heartbeat-setup.d.ts.map +1 -0
- package/dist/heartbeat-setup.js +49 -0
- package/dist/heartbeat-setup.js.map +1 -0
- package/dist/hooks.d.ts +10 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +152 -0
- package/dist/hooks.js.map +1 -0
- package/dist/incremental-capture.d.ts +24 -0
- package/dist/incremental-capture.d.ts.map +1 -0
- package/dist/incremental-capture.js +81 -0
- package/dist/incremental-capture.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/migration.d.ts +29 -0
- package/dist/migration.d.ts.map +1 -0
- package/dist/migration.js +203 -0
- package/dist/migration.js.map +1 -0
- package/dist/service.d.ts +7 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +133 -0
- package/dist/service.js.map +1 -0
- package/dist/tools.d.ts +11 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +188 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +31 -0
- package/src/capture.ts +116 -0
- package/src/cli.ts +95 -0
- package/src/config.ts +43 -0
- package/src/context.ts +164 -0
- package/src/heartbeat-setup.ts +53 -0
- package/src/hooks.ts +175 -0
- package/src/incremental-capture.ts +88 -0
- package/src/index.ts +68 -0
- package/src/migration.ts +241 -0
- package/src/service.ts +145 -0
- package/src/tools.ts +239 -0
- package/src/types.ts +40 -0
- package/test/capture.test.ts +139 -0
- package/test/context.test.ts +273 -0
- package/test/hooks.test.ts +137 -0
- package/test/tools.test.ts +174 -0
- package/tsconfig.json +8 -0
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw lifecycle hook registrations.
|
|
3
|
+
* - before_prompt_build: auto-recall + heartbeat context fusion
|
|
4
|
+
* - agent_end: auto-capture memorable facts
|
|
5
|
+
*/
|
|
6
|
+
import { formatMemoryContext, formatHeartbeatContext } from './context.js';
|
|
7
|
+
/**
|
|
8
|
+
* Extract a summary of recent activity from conversation messages.
|
|
9
|
+
* Takes the last N user and assistant messages and builds a query string
|
|
10
|
+
* that represents what the agent has been doing.
|
|
11
|
+
*/
|
|
12
|
+
function summarizeRecentActivity(messages, maxMessages = 6) {
|
|
13
|
+
if (!Array.isArray(messages) || messages.length === 0)
|
|
14
|
+
return '';
|
|
15
|
+
const recent = messages.slice(-maxMessages);
|
|
16
|
+
const parts = [];
|
|
17
|
+
for (const msg of recent) {
|
|
18
|
+
const m = msg;
|
|
19
|
+
if (!m.role || !m.content)
|
|
20
|
+
continue;
|
|
21
|
+
let text = '';
|
|
22
|
+
if (typeof m.content === 'string') {
|
|
23
|
+
text = m.content;
|
|
24
|
+
}
|
|
25
|
+
else if (Array.isArray(m.content)) {
|
|
26
|
+
// Anthropic format: content blocks
|
|
27
|
+
text = m.content
|
|
28
|
+
.filter((b) => b.type === 'text' && b.text)
|
|
29
|
+
.map((b) => b.text)
|
|
30
|
+
.join(' ');
|
|
31
|
+
}
|
|
32
|
+
if (!text)
|
|
33
|
+
continue;
|
|
34
|
+
// Truncate long messages to keep the query focused
|
|
35
|
+
const truncated = text.length > 300 ? text.slice(0, 300) : text;
|
|
36
|
+
if (m.role === 'user') {
|
|
37
|
+
parts.push(`User: ${truncated}`);
|
|
38
|
+
}
|
|
39
|
+
else if (m.role === 'assistant') {
|
|
40
|
+
parts.push(`Assistant: ${truncated}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return parts.join('\n');
|
|
44
|
+
}
|
|
45
|
+
// Idle check-in: track consecutive quiet heartbeats.
|
|
46
|
+
// After N quiet beats, force the LLM to engage with the user.
|
|
47
|
+
const IDLE_CHECK_IN_INTERVAL = 3; // every 3 quiet beats (~15 min with 5m heartbeat)
|
|
48
|
+
let quietHeartbeatCount = 0;
|
|
49
|
+
export function registerHooks(api, client, entityId, agentId, config) {
|
|
50
|
+
// before_prompt_build: auto-recall + heartbeat context injection
|
|
51
|
+
if (config.autoRecall || config.heartbeat) {
|
|
52
|
+
api.on('before_prompt_build', async (event) => {
|
|
53
|
+
const ev = event;
|
|
54
|
+
if (!ev.prompt || ev.prompt.length < 5)
|
|
55
|
+
return;
|
|
56
|
+
const isHeartbeat = ev.prompt.includes('HEARTBEAT');
|
|
57
|
+
// Heartbeat path: use heartbeat context endpoint with LLM analysis
|
|
58
|
+
if (isHeartbeat && config.heartbeat) {
|
|
59
|
+
const activitySummary = summarizeRecentActivity(ev.messages ?? []);
|
|
60
|
+
try {
|
|
61
|
+
const ctx = await client.heartbeatContext(entityId, {
|
|
62
|
+
query: activitySummary || undefined,
|
|
63
|
+
top_k: config.topK,
|
|
64
|
+
min_score: 0.1,
|
|
65
|
+
agent_id: agentId,
|
|
66
|
+
max_results: 10,
|
|
67
|
+
analyze: true,
|
|
68
|
+
activity_summary: activitySummary || undefined,
|
|
69
|
+
autonomy: config.autonomy,
|
|
70
|
+
});
|
|
71
|
+
// Idle check-in: if nothing to act on, count quiet beats
|
|
72
|
+
if (!ctx.should_act) {
|
|
73
|
+
quietHeartbeatCount++;
|
|
74
|
+
api.logger.info?.(`keyoku: quiet heartbeat ${quietHeartbeatCount}/${IDLE_CHECK_IN_INTERVAL}`);
|
|
75
|
+
if (quietHeartbeatCount >= IDLE_CHECK_IN_INTERVAL) {
|
|
76
|
+
quietHeartbeatCount = 0;
|
|
77
|
+
// Build a check-in signal with any known memories
|
|
78
|
+
const memoryHints = ctx.relevant_memories
|
|
79
|
+
.slice(0, 3)
|
|
80
|
+
.map((r) => r.memory.content)
|
|
81
|
+
.join('; ');
|
|
82
|
+
const checkInBlock = [
|
|
83
|
+
'<heartbeat-signals>',
|
|
84
|
+
'## Action Brief',
|
|
85
|
+
'It has been a while since you last reached out. Send the user a brief, friendly message right now.',
|
|
86
|
+
'',
|
|
87
|
+
'## Tell the User',
|
|
88
|
+
memoryHints
|
|
89
|
+
? `Hey! Just checking in. Reference what you know about them: ${memoryHints}`
|
|
90
|
+
: 'Hey! Just wanted to check in — how are things going?',
|
|
91
|
+
'',
|
|
92
|
+
'## Execute These Actions',
|
|
93
|
+
'- Send a short, warm greeting to the user',
|
|
94
|
+
'',
|
|
95
|
+
'should_act: true',
|
|
96
|
+
`Urgency: low | Mode: ${config.autonomy}`,
|
|
97
|
+
'</heartbeat-signals>',
|
|
98
|
+
];
|
|
99
|
+
api.logger.info?.('keyoku: idle check-in triggered — forcing engagement');
|
|
100
|
+
return { prependContext: checkInBlock.join('\n') };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
// Active heartbeat resets the quiet counter
|
|
105
|
+
quietHeartbeatCount = 0;
|
|
106
|
+
}
|
|
107
|
+
const formatted = formatHeartbeatContext(ctx);
|
|
108
|
+
if (formatted) {
|
|
109
|
+
const analyzed = ctx.analysis ? ` [${ctx.analysis.autonomy}/${ctx.analysis.urgency}]` : '';
|
|
110
|
+
api.logger.info?.(`keyoku: heartbeat context injected (should_act: ${ctx.should_act}, memories: ${ctx.relevant_memories.length}${analyzed})`);
|
|
111
|
+
return { prependContext: formatted };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
api.logger.warn(`keyoku: heartbeat context failed: ${String(err)}`);
|
|
116
|
+
}
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// Auto-recall path: search memories relevant to user's prompt + recent context
|
|
120
|
+
if (config.autoRecall && !isHeartbeat) {
|
|
121
|
+
try {
|
|
122
|
+
// Build a richer query: user prompt + last assistant message for context
|
|
123
|
+
const recentContext = summarizeRecentActivity(ev.messages ?? [], 2);
|
|
124
|
+
const query = recentContext
|
|
125
|
+
? `${ev.prompt}\n\nRecent context:\n${recentContext}`
|
|
126
|
+
: ev.prompt;
|
|
127
|
+
api.logger.info?.(`keyoku: auto-recall searching (query: ${query.slice(0, 80)}...)`);
|
|
128
|
+
const results = await client.search(entityId, query, {
|
|
129
|
+
limit: config.topK,
|
|
130
|
+
min_score: 0.15,
|
|
131
|
+
});
|
|
132
|
+
if (results.length > 0) {
|
|
133
|
+
const formatted = formatMemoryContext(results);
|
|
134
|
+
api.logger.info?.(`keyoku: auto-recall injected ${results.length} memories`);
|
|
135
|
+
return { prependContext: formatted };
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
api.logger.info?.('keyoku: auto-recall found 0 matching memories');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
api.logger.warn(`keyoku: auto-recall failed: ${String(err)}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
// NOTE: agent_end capture removed — incremental capture (incremental-capture.ts)
|
|
148
|
+
// now handles both user and assistant messages in real-time, making the
|
|
149
|
+
// session-end batch capture redundant. This also eliminates the only source
|
|
150
|
+
// of duplicate /remember calls.
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Incremental per-message memory capture.
|
|
3
|
+
*
|
|
4
|
+
* Strategy: capture the user+assistant exchange as a PAIR, not separately.
|
|
5
|
+
* This gives Keyoku the full context to extract meaningful memories:
|
|
6
|
+
* "User asked about X → Agent decided Y because Z"
|
|
7
|
+
* instead of fragmented, context-free snippets.
|
|
8
|
+
*
|
|
9
|
+
* Flow:
|
|
10
|
+
* 1. `before_prompt_build` — stash the user's prompt (no /remember call yet)
|
|
11
|
+
* 2. `message_sent` — pair the stashed prompt with the assistant's response,
|
|
12
|
+
* send the combined exchange to Keyoku's /remember endpoint ONCE.
|
|
13
|
+
*
|
|
14
|
+
* Keyoku's engine then:
|
|
15
|
+
* - Extracts discrete facts from the full exchange
|
|
16
|
+
* - Deduplicates against existing memories (hash + semantic)
|
|
17
|
+
* - Detects and resolves conflicts
|
|
18
|
+
* - Stores only genuinely new information
|
|
19
|
+
*/
|
|
20
|
+
import type { KeyokuClient } from '@keyoku/memory';
|
|
21
|
+
import type { KeyokuConfig } from './config.js';
|
|
22
|
+
import type { PluginApi } from './types.js';
|
|
23
|
+
export declare function registerIncrementalCapture(api: PluginApi, client: KeyokuClient, entityId: string, agentId: string, config: Required<KeyokuConfig>): void;
|
|
24
|
+
//# sourceMappingURL=incremental-capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incremental-capture.d.ts","sourceRoot":"","sources":["../src/incremental-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,GAC7B,IAAI,CAwDN"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Incremental per-message memory capture.
|
|
3
|
+
*
|
|
4
|
+
* Strategy: capture the user+assistant exchange as a PAIR, not separately.
|
|
5
|
+
* This gives Keyoku the full context to extract meaningful memories:
|
|
6
|
+
* "User asked about X → Agent decided Y because Z"
|
|
7
|
+
* instead of fragmented, context-free snippets.
|
|
8
|
+
*
|
|
9
|
+
* Flow:
|
|
10
|
+
* 1. `before_prompt_build` — stash the user's prompt (no /remember call yet)
|
|
11
|
+
* 2. `message_sent` — pair the stashed prompt with the assistant's response,
|
|
12
|
+
* send the combined exchange to Keyoku's /remember endpoint ONCE.
|
|
13
|
+
*
|
|
14
|
+
* Keyoku's engine then:
|
|
15
|
+
* - Extracts discrete facts from the full exchange
|
|
16
|
+
* - Deduplicates against existing memories (hash + semantic)
|
|
17
|
+
* - Detects and resolves conflicts
|
|
18
|
+
* - Stores only genuinely new information
|
|
19
|
+
*/
|
|
20
|
+
import { looksLikePromptInjection } from './capture.js';
|
|
21
|
+
export function registerIncrementalCapture(api, client, entityId, agentId, config) {
|
|
22
|
+
// Stash for the most recent user prompt, paired with the next assistant response
|
|
23
|
+
let pendingUserPrompt = null;
|
|
24
|
+
// Step 1: Stash user prompt (no API call yet)
|
|
25
|
+
api.on('before_prompt_build', async (event) => {
|
|
26
|
+
const ev = event;
|
|
27
|
+
if (!ev.prompt || ev.prompt.length < 10)
|
|
28
|
+
return;
|
|
29
|
+
// Don't stash heartbeat prompts or injected blocks
|
|
30
|
+
if (ev.prompt.includes('HEARTBEAT'))
|
|
31
|
+
return;
|
|
32
|
+
if (ev.prompt.includes('<your-memories>') || ev.prompt.includes('<heartbeat-signals>'))
|
|
33
|
+
return;
|
|
34
|
+
if (ev.prompt.length > config.captureMaxChars)
|
|
35
|
+
return;
|
|
36
|
+
if (looksLikePromptInjection(ev.prompt))
|
|
37
|
+
return;
|
|
38
|
+
pendingUserPrompt = ev.prompt;
|
|
39
|
+
}, { priority: -10 }); // Low priority — runs after auto-recall
|
|
40
|
+
// Step 2: Pair with assistant response and send to Keyoku
|
|
41
|
+
api.on('message_sent', async (event) => {
|
|
42
|
+
const ev = event;
|
|
43
|
+
if (!ev.success || !ev.content)
|
|
44
|
+
return;
|
|
45
|
+
const assistantContent = ev.content;
|
|
46
|
+
// Skip noise
|
|
47
|
+
if (assistantContent.length < 20)
|
|
48
|
+
return;
|
|
49
|
+
if (assistantContent === 'HEARTBEAT_OK' || assistantContent === 'NO_REPLY')
|
|
50
|
+
return;
|
|
51
|
+
if (assistantContent.includes('<heartbeat-signals>') || assistantContent.includes('<your-memories>'))
|
|
52
|
+
return;
|
|
53
|
+
if (looksLikePromptInjection(assistantContent))
|
|
54
|
+
return;
|
|
55
|
+
// Build the exchange: user prompt + assistant response
|
|
56
|
+
let exchange;
|
|
57
|
+
if (pendingUserPrompt) {
|
|
58
|
+
exchange = `User: ${pendingUserPrompt}\n\nAssistant: ${assistantContent}`;
|
|
59
|
+
pendingUserPrompt = null; // consumed
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// No user prompt stashed (e.g., tool-triggered response) — just capture assistant
|
|
63
|
+
exchange = assistantContent;
|
|
64
|
+
}
|
|
65
|
+
// Truncate if the combined exchange is too long
|
|
66
|
+
if (exchange.length > config.captureMaxChars) {
|
|
67
|
+
exchange = exchange.slice(0, config.captureMaxChars);
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
await client.remember(entityId, exchange, {
|
|
71
|
+
agent_id: agentId,
|
|
72
|
+
source: 'conversation',
|
|
73
|
+
});
|
|
74
|
+
api.logger.debug?.(`keyoku: captured exchange (${exchange.length} chars)`);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
api.logger.warn(`keyoku: capture failed: ${String(err)}`);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=incremental-capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incremental-capture.js","sourceRoot":"","sources":["../src/incremental-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAGxD,MAAM,UAAU,0BAA0B,CACxC,GAAc,EACd,MAAoB,EACpB,QAAgB,EAChB,OAAe,EACf,MAA8B;IAE9B,iFAAiF;IACjF,IAAI,iBAAiB,GAAkB,IAAI,CAAC;IAE5C,8CAA8C;IAC9C,GAAG,CAAC,EAAE,CAAC,qBAAqB,EAAE,KAAK,EAAE,KAAc,EAAE,EAAE;QACrD,MAAM,EAAE,GAAG,KAA4B,CAAC;QACxC,IAAI,CAAC,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE;YAAE,OAAO;QAEhD,mDAAmD;QACnD,IAAI,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,OAAO;QAC5C,IAAI,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC;YAAE,OAAO;QAC/F,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,eAAe;YAAE,OAAO;QACtD,IAAI,wBAAwB,CAAC,EAAE,CAAC,MAAM,CAAC;YAAE,OAAO;QAEhD,iBAAiB,GAAG,EAAE,CAAC,MAAM,CAAC;IAChC,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,wCAAwC;IAE/D,0DAA0D;IAC1D,GAAG,CAAC,EAAE,CAAC,cAAc,EAAE,KAAK,EAAE,KAAc,EAAE,EAAE;QAC9C,MAAM,EAAE,GAAG,KAAgD,CAAC;QAC5D,IAAI,CAAC,EAAE,CAAC,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO;YAAE,OAAO;QAEvC,MAAM,gBAAgB,GAAG,EAAE,CAAC,OAAO,CAAC;QAEpC,aAAa;QACb,IAAI,gBAAgB,CAAC,MAAM,GAAG,EAAE;YAAE,OAAO;QACzC,IAAI,gBAAgB,KAAK,cAAc,IAAI,gBAAgB,KAAK,UAAU;YAAE,OAAO;QACnF,IAAI,gBAAgB,CAAC,QAAQ,CAAC,qBAAqB,CAAC,IAAI,gBAAgB,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YAAE,OAAO;QAC7G,IAAI,wBAAwB,CAAC,gBAAgB,CAAC;YAAE,OAAO;QAEvD,uDAAuD;QACvD,IAAI,QAAgB,CAAC;QACrB,IAAI,iBAAiB,EAAE,CAAC;YACtB,QAAQ,GAAG,SAAS,iBAAiB,kBAAkB,gBAAgB,EAAE,CAAC;YAC1E,iBAAiB,GAAG,IAAI,CAAC,CAAC,WAAW;QACvC,CAAC;aAAM,CAAC;YACN,kFAAkF;YAClF,QAAQ,GAAG,gBAAgB,CAAC;QAC9B,CAAC;QAED,gDAAgD;QAChD,IAAI,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;YAC7C,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;QACvD,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE;gBACxC,QAAQ,EAAE,OAAO;gBACjB,MAAM,EAAE,cAAc;aACvB,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,8BAA8B,QAAQ,CAAC,MAAM,SAAS,CAAC,CAAC;QAC7E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @keyoku/openclaw — Keyoku Memory Plugin for OpenClaw
|
|
3
|
+
*
|
|
4
|
+
* Gives any OpenClaw agent persistent memory, proactive heartbeat behavior,
|
|
5
|
+
* and scheduling — powered by the Keyoku memory engine.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* import keyokuMemory from '@keyoku/openclaw';
|
|
9
|
+
* // In openclaw config:
|
|
10
|
+
* plugins: { 'keyoku-memory': keyokuMemory({ autoRecall: true }) }
|
|
11
|
+
* slots: { memory: 'keyoku-memory' }
|
|
12
|
+
*/
|
|
13
|
+
import { type KeyokuConfig } from './config.js';
|
|
14
|
+
import type { PluginApi } from './types.js';
|
|
15
|
+
export type { KeyokuConfig } from './config.js';
|
|
16
|
+
export { KeyokuClient } from '@keyoku/memory';
|
|
17
|
+
export default function keyokuMemory(config?: KeyokuConfig): {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
kind: "memory";
|
|
22
|
+
register(api: PluginApi): void;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,KAAK,YAAY,EAAiB,MAAM,aAAa,CAAC;AAO/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,MAAM,CAAC,EAAE,YAAY;;;;;kBAOxC,SAAS;EAkC1B"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @keyoku/openclaw — Keyoku Memory Plugin for OpenClaw
|
|
3
|
+
*
|
|
4
|
+
* Gives any OpenClaw agent persistent memory, proactive heartbeat behavior,
|
|
5
|
+
* and scheduling — powered by the Keyoku memory engine.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* import keyokuMemory from '@keyoku/openclaw';
|
|
9
|
+
* // In openclaw config:
|
|
10
|
+
* plugins: { 'keyoku-memory': keyokuMemory({ autoRecall: true }) }
|
|
11
|
+
* slots: { memory: 'keyoku-memory' }
|
|
12
|
+
*/
|
|
13
|
+
import { KeyokuClient } from '@keyoku/memory';
|
|
14
|
+
import { resolveConfig } from './config.js';
|
|
15
|
+
import { registerTools } from './tools.js';
|
|
16
|
+
import { registerHooks } from './hooks.js';
|
|
17
|
+
import { registerService } from './service.js';
|
|
18
|
+
import { registerCli } from './cli.js';
|
|
19
|
+
import { registerIncrementalCapture } from './incremental-capture.js';
|
|
20
|
+
import { ensureHeartbeatMd } from './heartbeat-setup.js';
|
|
21
|
+
export { KeyokuClient } from '@keyoku/memory';
|
|
22
|
+
export default function keyokuMemory(config) {
|
|
23
|
+
return {
|
|
24
|
+
id: 'keyoku-memory',
|
|
25
|
+
name: 'Keyoku Memory',
|
|
26
|
+
description: 'Persistent memory, heartbeat enhancement, and scheduling powered by Keyoku',
|
|
27
|
+
kind: 'memory',
|
|
28
|
+
register(api) {
|
|
29
|
+
const cfg = resolveConfig(config);
|
|
30
|
+
// Resolve entity/agent IDs — fall back to plugin API id
|
|
31
|
+
const entityId = cfg.entityId || api.id || 'default';
|
|
32
|
+
const agentId = cfg.agentId || api.id || 'default';
|
|
33
|
+
const client = new KeyokuClient({ baseUrl: cfg.keyokuUrl });
|
|
34
|
+
api.logger.info(`keyoku: plugin registered (url: ${cfg.keyokuUrl}, entity: ${entityId})`);
|
|
35
|
+
// Register 6 memory/schedule tools
|
|
36
|
+
registerTools(api, client, entityId, agentId);
|
|
37
|
+
// Register lifecycle hooks (auto-recall, heartbeat, auto-capture)
|
|
38
|
+
registerHooks(api, client, entityId, agentId, cfg);
|
|
39
|
+
// Register Keyoku binary lifecycle service
|
|
40
|
+
registerService(api, cfg.keyokuUrl);
|
|
41
|
+
// Register CLI subcommands
|
|
42
|
+
registerCli(api, client, entityId);
|
|
43
|
+
// Register incremental per-message capture
|
|
44
|
+
if (cfg.incrementalCapture) {
|
|
45
|
+
registerIncrementalCapture(api, client, entityId, agentId, cfg);
|
|
46
|
+
}
|
|
47
|
+
// Auto-generate HEARTBEAT.md if heartbeat is enabled and file doesn't exist
|
|
48
|
+
if (cfg.heartbeat) {
|
|
49
|
+
ensureHeartbeatMd(api);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAqB,aAAa,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAIzD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,MAAqB;IACxD,OAAO;QACL,EAAE,EAAE,eAAe;QACnB,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,4EAA4E;QACzF,IAAI,EAAE,QAAiB;QAEvB,QAAQ,CAAC,GAAc;YACrB,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;YAElC,wDAAwD;YACxD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,EAAE,IAAI,SAAS,CAAC;YACrD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,EAAE,IAAI,SAAS,CAAC;YAEnD,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;YAE5D,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,mCAAmC,GAAG,CAAC,SAAS,aAAa,QAAQ,GAAG,CAAC,CAAC;YAE1F,mCAAmC;YACnC,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;YAE9C,kEAAkE;YAClE,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;YAEnD,2CAA2C;YAC3C,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;YAEpC,2BAA2B;YAC3B,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;YAEnC,2CAA2C;YAC3C,IAAI,GAAG,CAAC,kBAAkB,EAAE,CAAC;gBAC3B,0BAA0B,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;YAClE,CAAC;YAED,4EAA4E;YAC5E,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;gBAClB,iBAAiB,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration utility — imports OpenClaw's file-based memories into Keyoku.
|
|
3
|
+
*
|
|
4
|
+
* Reads MEMORY.md and memory/*.md files, chunks them by heading sections,
|
|
5
|
+
* deduplicates against existing Keyoku memories, and stores each chunk.
|
|
6
|
+
*
|
|
7
|
+
* Usage: `openclaw memory import --dir /path/to/workspace`
|
|
8
|
+
*/
|
|
9
|
+
import type { KeyokuClient } from '@keyoku/memory';
|
|
10
|
+
export interface ImportResult {
|
|
11
|
+
imported: number;
|
|
12
|
+
skipped: number;
|
|
13
|
+
errors: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Import OpenClaw memory files into Keyoku.
|
|
17
|
+
*/
|
|
18
|
+
export declare function importMemoryFiles(params: {
|
|
19
|
+
client: KeyokuClient;
|
|
20
|
+
entityId: string;
|
|
21
|
+
workspaceDir: string;
|
|
22
|
+
agentId?: string;
|
|
23
|
+
dryRun?: boolean;
|
|
24
|
+
logger?: {
|
|
25
|
+
info: (msg: string) => void;
|
|
26
|
+
warn: (msg: string) => void;
|
|
27
|
+
};
|
|
28
|
+
}): Promise<ImportResult>;
|
|
29
|
+
//# sourceMappingURL=migration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../src/migration.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAoHD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE;IAC9C,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACvE,GAAG,OAAO,CAAC,YAAY,CAAC,CAiGxB"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration utility — imports OpenClaw's file-based memories into Keyoku.
|
|
3
|
+
*
|
|
4
|
+
* Reads MEMORY.md and memory/*.md files, chunks them by heading sections,
|
|
5
|
+
* deduplicates against existing Keyoku memories, and stores each chunk.
|
|
6
|
+
*
|
|
7
|
+
* Usage: `openclaw memory import --dir /path/to/workspace`
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync, readdirSync, existsSync, statSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
/**
|
|
12
|
+
* Split markdown content by ## or ### headings.
|
|
13
|
+
* Each heading section becomes one chunk.
|
|
14
|
+
* If no headings, split by --- separators or paragraphs.
|
|
15
|
+
*/
|
|
16
|
+
function chunkByHeadings(content, maxChunkChars = 1000) {
|
|
17
|
+
const chunks = [];
|
|
18
|
+
// Try splitting by headings first
|
|
19
|
+
const headingPattern = /^#{2,3}\s+(.+)$/gm;
|
|
20
|
+
const headings = [];
|
|
21
|
+
let match;
|
|
22
|
+
while ((match = headingPattern.exec(content)) !== null) {
|
|
23
|
+
headings.push({ index: match.index, title: match[1].trim() });
|
|
24
|
+
}
|
|
25
|
+
if (headings.length > 0) {
|
|
26
|
+
for (let i = 0; i < headings.length; i++) {
|
|
27
|
+
const start = headings[i].index;
|
|
28
|
+
const end = i + 1 < headings.length ? headings[i + 1].index : content.length;
|
|
29
|
+
const sectionText = content.slice(start, end).trim();
|
|
30
|
+
if (sectionText.length < 10)
|
|
31
|
+
continue;
|
|
32
|
+
// If section is too long, split by paragraphs
|
|
33
|
+
if (sectionText.length > maxChunkChars) {
|
|
34
|
+
const paragraphs = splitByParagraphs(sectionText, maxChunkChars);
|
|
35
|
+
for (const p of paragraphs) {
|
|
36
|
+
chunks.push({ content: p, source: '', section: headings[i].title });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
chunks.push({ content: sectionText, source: '', section: headings[i].title });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Content before the first heading
|
|
44
|
+
const preamble = content.slice(0, headings[0].index).trim();
|
|
45
|
+
if (preamble.length >= 10) {
|
|
46
|
+
const paragraphs = splitByParagraphs(preamble, maxChunkChars);
|
|
47
|
+
for (const p of paragraphs) {
|
|
48
|
+
chunks.push({ content: p, source: '' });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
// No headings — try --- separators
|
|
54
|
+
const sections = content.split(/^---+$/m);
|
|
55
|
+
if (sections.length > 1) {
|
|
56
|
+
for (const section of sections) {
|
|
57
|
+
const trimmed = section.trim();
|
|
58
|
+
if (trimmed.length < 10)
|
|
59
|
+
continue;
|
|
60
|
+
const paragraphs = splitByParagraphs(trimmed, maxChunkChars);
|
|
61
|
+
for (const p of paragraphs) {
|
|
62
|
+
chunks.push({ content: p, source: '' });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// No structure — split by paragraphs
|
|
68
|
+
const paragraphs = splitByParagraphs(content, maxChunkChars);
|
|
69
|
+
for (const p of paragraphs) {
|
|
70
|
+
chunks.push({ content: p, source: '' });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return chunks;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Split text by double-newline (paragraphs), merging small paragraphs
|
|
78
|
+
* and splitting oversized ones.
|
|
79
|
+
*/
|
|
80
|
+
function splitByParagraphs(text, maxChars = 1000) {
|
|
81
|
+
const rawParagraphs = text.split(/\n\n+/);
|
|
82
|
+
const results = [];
|
|
83
|
+
let buffer = '';
|
|
84
|
+
for (const para of rawParagraphs) {
|
|
85
|
+
const trimmed = para.trim();
|
|
86
|
+
if (!trimmed)
|
|
87
|
+
continue;
|
|
88
|
+
if (buffer.length + trimmed.length + 2 <= maxChars) {
|
|
89
|
+
buffer = buffer ? `${buffer}\n\n${trimmed}` : trimmed;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
if (buffer)
|
|
93
|
+
results.push(buffer);
|
|
94
|
+
if (trimmed.length > maxChars) {
|
|
95
|
+
// Hard split at maxChars boundary
|
|
96
|
+
for (let i = 0; i < trimmed.length; i += maxChars) {
|
|
97
|
+
results.push(trimmed.slice(i, i + maxChars));
|
|
98
|
+
}
|
|
99
|
+
buffer = '';
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
buffer = trimmed;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (buffer && buffer.length >= 10)
|
|
107
|
+
results.push(buffer);
|
|
108
|
+
return results;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Small delay helper for rate limiting.
|
|
112
|
+
*/
|
|
113
|
+
function delay(ms) {
|
|
114
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Import OpenClaw memory files into Keyoku.
|
|
118
|
+
*/
|
|
119
|
+
export async function importMemoryFiles(params) {
|
|
120
|
+
const { client, entityId, workspaceDir, agentId, dryRun = false, logger = console } = params;
|
|
121
|
+
const result = { imported: 0, skipped: 0, errors: 0 };
|
|
122
|
+
// Discover memory files
|
|
123
|
+
const files = [];
|
|
124
|
+
// Check for MEMORY.md
|
|
125
|
+
const memoryMdPath = join(workspaceDir, 'MEMORY.md');
|
|
126
|
+
if (existsSync(memoryMdPath)) {
|
|
127
|
+
files.push({ path: memoryMdPath, name: 'MEMORY.md' });
|
|
128
|
+
}
|
|
129
|
+
// Check for memory/ directory
|
|
130
|
+
const memoryDir = join(workspaceDir, 'memory');
|
|
131
|
+
if (existsSync(memoryDir) && statSync(memoryDir).isDirectory()) {
|
|
132
|
+
const entries = readdirSync(memoryDir)
|
|
133
|
+
.filter((f) => f.endsWith('.md'))
|
|
134
|
+
.sort(); // chronological for dated files
|
|
135
|
+
for (const entry of entries) {
|
|
136
|
+
files.push({ path: join(memoryDir, entry), name: `memory/${entry}` });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (files.length === 0) {
|
|
140
|
+
logger.info('No memory files found in workspace.');
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
logger.info(`Found ${files.length} memory file(s) to import.`);
|
|
144
|
+
// Process each file
|
|
145
|
+
for (const file of files) {
|
|
146
|
+
let content;
|
|
147
|
+
try {
|
|
148
|
+
content = readFileSync(file.path, 'utf-8');
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
logger.warn(`Failed to read ${file.name}: ${String(err)}`);
|
|
152
|
+
result.errors++;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (content.trim().length < 10) {
|
|
156
|
+
logger.info(`Skipping ${file.name} (too short)`);
|
|
157
|
+
result.skipped++;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const chunks = chunkByHeadings(content);
|
|
161
|
+
for (const chunk of chunks) {
|
|
162
|
+
chunk.source = file.name;
|
|
163
|
+
// Build the content to store — include source context
|
|
164
|
+
const taggedContent = chunk.section
|
|
165
|
+
? `[Imported from ${file.name} — ${chunk.section}]\n${chunk.content}`
|
|
166
|
+
: `[Imported from ${file.name}]\n${chunk.content}`;
|
|
167
|
+
if (dryRun) {
|
|
168
|
+
logger.info(`[dry-run] Would import: ${taggedContent.slice(0, 80)}...`);
|
|
169
|
+
result.imported++;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
// Dedup check: search for similar content
|
|
173
|
+
try {
|
|
174
|
+
const queryText = chunk.content.slice(0, 100);
|
|
175
|
+
const existing = await client.search(entityId, queryText, { limit: 1, min_score: 0.95 });
|
|
176
|
+
if (existing.length > 0) {
|
|
177
|
+
result.skipped++;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// Search failed — proceed with import anyway
|
|
183
|
+
}
|
|
184
|
+
// Store the memory
|
|
185
|
+
try {
|
|
186
|
+
await client.remember(entityId, taggedContent, {
|
|
187
|
+
agent_id: agentId,
|
|
188
|
+
source: 'migration',
|
|
189
|
+
});
|
|
190
|
+
result.imported++;
|
|
191
|
+
logger.info(`Imported: ${chunk.content.slice(0, 60)}...`);
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
logger.warn(`Failed to store chunk from ${file.name}: ${String(err)}`);
|
|
195
|
+
result.errors++;
|
|
196
|
+
}
|
|
197
|
+
// Rate limit
|
|
198
|
+
await delay(50);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.js","sourceRoot":"","sources":["../src/migration.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyoku binary lifecycle management.
|
|
3
|
+
* Starts/stops the Keyoku Go binary as a child process.
|
|
4
|
+
*/
|
|
5
|
+
import type { PluginApi } from './types.js';
|
|
6
|
+
export declare function registerService(api: PluginApi, keyokuUrl: string): void;
|
|
7
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA0D5C,wBAAgB,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CA6EvE"}
|