@oyasmi/pipiclaw 0.5.1 → 0.5.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/README.md +308 -209
- package/dist/agent/channel-runner.d.ts +47 -0
- package/dist/agent/channel-runner.js +441 -0
- package/dist/agent/index.d.ts +3 -0
- package/dist/agent/index.js +2 -0
- package/dist/agent/progress-formatter.d.ts +4 -0
- package/dist/agent/progress-formatter.js +52 -0
- package/dist/agent/run-queue.d.ts +7 -0
- package/dist/agent/run-queue.js +26 -0
- package/dist/agent/runner-factory.d.ts +3 -0
- package/dist/agent/runner-factory.js +10 -0
- package/dist/agent/session-events.d.ts +14 -0
- package/dist/agent/session-events.js +215 -0
- package/dist/agent/session-resource-gate.d.ts +10 -0
- package/dist/agent/session-resource-gate.js +44 -0
- package/dist/agent/type-guards.d.ts +22 -0
- package/dist/agent/type-guards.js +106 -0
- package/dist/agent/types.d.ts +160 -0
- package/dist/agent/types.js +22 -0
- package/dist/agent.d.ts +2 -16
- package/dist/agent.js +1 -782
- package/dist/command-extension.d.ts +0 -1
- package/dist/command-extension.js +0 -1
- package/dist/commands.d.ts +0 -1
- package/dist/commands.js +0 -1
- package/dist/config-loader.d.ts +0 -1
- package/dist/config-loader.js +1 -2
- package/dist/context.d.ts +58 -15
- package/dist/context.js +50 -8
- package/dist/index.d.ts +12 -13
- package/dist/index.js +12 -13
- package/dist/log.d.ts +0 -1
- package/dist/log.js +0 -1
- package/dist/main.d.ts +0 -1
- package/dist/main.js +5 -405
- package/dist/memory/bootstrap.d.ts +6 -0
- package/dist/memory/bootstrap.js +46 -0
- package/dist/{memory-candidates.d.ts → memory/candidates.d.ts} +1 -1
- package/dist/{memory-candidates.js → memory/candidates.js} +33 -21
- package/dist/memory/chinese-words.d.ts +1 -0
- package/dist/memory/chinese-words.js +273 -0
- package/dist/{memory-consolidation.d.ts → memory/consolidation.d.ts} +0 -1
- package/dist/{memory-consolidation.js → memory/consolidation.js} +26 -35
- package/dist/{memory-files.d.ts → memory/files.d.ts} +0 -6
- package/dist/{memory-files.js → memory/files.js} +11 -36
- package/dist/{memory-lifecycle.d.ts → memory/lifecycle.d.ts} +23 -6
- package/dist/memory/lifecycle.js +246 -0
- package/dist/{memory-recall.d.ts → memory/recall.d.ts} +2 -2
- package/dist/memory/recall.js +501 -0
- package/dist/{session-memory.d.ts → memory/session.d.ts} +1 -1
- package/dist/{session-memory.js → memory/session.js} +31 -62
- package/dist/model-utils.d.ts +0 -1
- package/dist/model-utils.js +0 -1
- package/dist/paths.d.ts +0 -1
- package/dist/paths.js +0 -1
- package/dist/prompt-builder.d.ts +0 -1
- package/dist/prompt-builder.js +0 -1
- package/dist/runtime/bootstrap.d.ts +47 -0
- package/dist/runtime/bootstrap.js +450 -0
- package/dist/{delivery.d.ts → runtime/delivery.d.ts} +0 -1
- package/dist/{delivery.js → runtime/delivery.js} +1 -2
- package/dist/{dingtalk.d.ts → runtime/dingtalk.d.ts} +10 -1
- package/dist/{dingtalk.js → runtime/dingtalk.js} +87 -28
- package/dist/{events.d.ts → runtime/events.d.ts} +0 -1
- package/dist/{events.js → runtime/events.js} +1 -2
- package/dist/{store.d.ts → runtime/store.d.ts} +5 -1
- package/dist/{store.js → runtime/store.js} +60 -20
- package/dist/sandbox.d.ts +0 -1
- package/dist/sandbox.js +1 -2
- package/dist/{llm-json.d.ts → shared/llm-json.d.ts} +0 -1
- package/dist/{llm-json.js → shared/llm-json.js} +0 -1
- package/dist/shared/markdown-sections.d.ts +6 -0
- package/dist/{markdown-sections.js → shared/markdown-sections.js} +10 -4
- package/dist/{shell-escape.d.ts → shared/shell-escape.d.ts} +0 -1
- package/dist/{shell-escape.js → shared/shell-escape.js} +0 -1
- package/dist/shared/text-utils.d.ts +9 -0
- package/dist/shared/text-utils.js +36 -0
- package/dist/shared/type-guards.d.ts +5 -0
- package/dist/shared/type-guards.js +12 -0
- package/dist/shared/types.d.ts +14 -0
- package/dist/shared/types.js +1 -0
- package/dist/sidecar-worker.d.ts +0 -1
- package/dist/sidecar-worker.js +1 -8
- package/dist/{sub-agents.d.ts → subagents/discovery.d.ts} +0 -1
- package/dist/{sub-agents.js → subagents/discovery.js} +2 -3
- package/dist/{tools/subagent.d.ts → subagents/tool.d.ts} +2 -16
- package/dist/{tools/subagent.js → subagents/tool.js} +16 -38
- package/dist/tools/attach.d.ts +0 -1
- package/dist/tools/attach.js +0 -1
- package/dist/tools/bash.d.ts +0 -1
- package/dist/tools/bash.js +0 -1
- package/dist/tools/edit.d.ts +0 -1
- package/dist/tools/edit.js +1 -2
- package/dist/tools/index.d.ts +1 -2
- package/dist/tools/index.js +1 -2
- package/dist/tools/read.d.ts +0 -1
- package/dist/tools/read.js +1 -2
- package/dist/tools/truncate.d.ts +0 -1
- package/dist/tools/truncate.js +0 -1
- package/dist/tools/write-content.d.ts +0 -1
- package/dist/tools/write-content.js +1 -2
- package/dist/tools/write.d.ts +0 -1
- package/dist/tools/write.js +0 -1
- package/package.json +9 -3
- package/CHANGELOG.md +0 -47
- package/dist/agent.d.ts.map +0 -1
- package/dist/agent.js.map +0 -1
- package/dist/command-extension.d.ts.map +0 -1
- package/dist/command-extension.js.map +0 -1
- package/dist/commands.d.ts.map +0 -1
- package/dist/commands.js.map +0 -1
- package/dist/config-loader.d.ts.map +0 -1
- package/dist/config-loader.js.map +0 -1
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js.map +0 -1
- package/dist/delivery.d.ts.map +0 -1
- package/dist/delivery.js.map +0 -1
- package/dist/dingtalk.d.ts.map +0 -1
- package/dist/dingtalk.js.map +0 -1
- package/dist/events.d.ts.map +0 -1
- package/dist/events.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/llm-json.d.ts.map +0 -1
- package/dist/llm-json.js.map +0 -1
- package/dist/log.d.ts.map +0 -1
- package/dist/log.js.map +0 -1
- package/dist/main.d.ts.map +0 -1
- package/dist/main.js.map +0 -1
- package/dist/markdown-sections.d.ts +0 -6
- package/dist/markdown-sections.d.ts.map +0 -1
- package/dist/markdown-sections.js.map +0 -1
- package/dist/memory-candidates.d.ts.map +0 -1
- package/dist/memory-candidates.js.map +0 -1
- package/dist/memory-consolidation.d.ts.map +0 -1
- package/dist/memory-consolidation.js.map +0 -1
- package/dist/memory-files.d.ts.map +0 -1
- package/dist/memory-files.js.map +0 -1
- package/dist/memory-lifecycle.d.ts.map +0 -1
- package/dist/memory-lifecycle.js +0 -150
- package/dist/memory-lifecycle.js.map +0 -1
- package/dist/memory-recall.d.ts.map +0 -1
- package/dist/memory-recall.js +0 -218
- package/dist/memory-recall.js.map +0 -1
- package/dist/model-utils.d.ts.map +0 -1
- package/dist/model-utils.js.map +0 -1
- package/dist/paths.d.ts.map +0 -1
- package/dist/paths.js.map +0 -1
- package/dist/prompt-builder.d.ts.map +0 -1
- package/dist/prompt-builder.js.map +0 -1
- package/dist/sandbox.d.ts.map +0 -1
- package/dist/sandbox.js.map +0 -1
- package/dist/session-memory-files.d.ts +0 -2
- package/dist/session-memory-files.d.ts.map +0 -1
- package/dist/session-memory-files.js +0 -2
- package/dist/session-memory-files.js.map +0 -1
- package/dist/session-memory.d.ts.map +0 -1
- package/dist/session-memory.js.map +0 -1
- package/dist/shell-escape.d.ts.map +0 -1
- package/dist/shell-escape.js.map +0 -1
- package/dist/sidecar-worker.d.ts.map +0 -1
- package/dist/sidecar-worker.js.map +0 -1
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js.map +0 -1
- package/dist/sub-agents.d.ts.map +0 -1
- package/dist/sub-agents.js.map +0 -1
- package/dist/tools/attach.d.ts.map +0 -1
- package/dist/tools/attach.js.map +0 -1
- package/dist/tools/bash.d.ts.map +0 -1
- package/dist/tools/bash.js.map +0 -1
- package/dist/tools/edit.d.ts.map +0 -1
- package/dist/tools/edit.js.map +0 -1
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/read.d.ts.map +0 -1
- package/dist/tools/read.js.map +0 -1
- package/dist/tools/subagent.d.ts.map +0 -1
- package/dist/tools/subagent.js.map +0 -1
- package/dist/tools/truncate.d.ts.map +0 -1
- package/dist/tools/truncate.js.map +0 -1
- package/dist/tools/write-content.d.ts.map +0 -1
- package/dist/tools/write-content.js.map +0 -1
- package/dist/tools/write.d.ts.map +0 -1
- package/dist/tools/write.js.map +0 -1
- package/docs/improve-memory/design.md +0 -537
- package/docs/improve-memory/interfaces-and-tests.md +0 -473
- package/docs/improve-memory/spec.md +0 -357
- package/docs/memory-rfc.md +0 -297
- package/docs/proj-review.md +0 -188
- package/docs/subagent/pi-subagent-analyse.txt +0 -190
- package/docs/subagent/pi-subagent-design.txt +0 -266
- package/docs/subagent/pi-subagent-phase1-plan.txt +0 -529
- package/docs/test-supplementation-plan.md +0 -553
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
import { parseJsonObject } from "../shared/llm-json.js";
|
|
2
|
+
import { HAN_REGEX } from "../shared/text-utils.js";
|
|
3
|
+
import { runSidecarTask } from "../sidecar-worker.js";
|
|
4
|
+
import { buildMemoryCandidates } from "./candidates.js";
|
|
5
|
+
import { COMMON_CHINESE_WORDS } from "./chinese-words.js";
|
|
6
|
+
const RERANK_SYSTEM_PROMPT = `You are selecting which memory snippets are most relevant to the current user turn.
|
|
7
|
+
|
|
8
|
+
Return strict JSON only:
|
|
9
|
+
{
|
|
10
|
+
"selectedIds": ["candidate-id"]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
Rules:
|
|
14
|
+
- Select only snippets that are clearly useful for answering the current turn.
|
|
15
|
+
- Prefer current work state, constraints, active files, recent corrections, and durable decisions.
|
|
16
|
+
- If nothing is clearly useful, return an empty array.
|
|
17
|
+
- Do not rewrite the candidates. Only return candidate ids.`;
|
|
18
|
+
const TOKEN_PART_REGEX = /[\p{Script=Han}]+|[\p{L}\p{N}_./-]+/gu;
|
|
19
|
+
const ASCII_SPLIT_REGEX = /[._/-]+/g;
|
|
20
|
+
const MEMORY_RECALL_RERANK_TIMEOUT_MS = 8_000;
|
|
21
|
+
const RERANK_CONTENT_CLIP = 800;
|
|
22
|
+
const MAX_HAN_WORD_LENGTH = Array.from(COMMON_CHINESE_WORDS).reduce((max, word) => Math.max(max, word.length), 2);
|
|
23
|
+
const LATIN_STOP_WORDS = new Set([
|
|
24
|
+
"a",
|
|
25
|
+
"an",
|
|
26
|
+
"and",
|
|
27
|
+
"are",
|
|
28
|
+
"as",
|
|
29
|
+
"at",
|
|
30
|
+
"be",
|
|
31
|
+
"been",
|
|
32
|
+
"being",
|
|
33
|
+
"by",
|
|
34
|
+
"can",
|
|
35
|
+
"could",
|
|
36
|
+
"did",
|
|
37
|
+
"do",
|
|
38
|
+
"does",
|
|
39
|
+
"doing",
|
|
40
|
+
"for",
|
|
41
|
+
"from",
|
|
42
|
+
"had",
|
|
43
|
+
"has",
|
|
44
|
+
"have",
|
|
45
|
+
"here",
|
|
46
|
+
"how",
|
|
47
|
+
"i",
|
|
48
|
+
"in",
|
|
49
|
+
"is",
|
|
50
|
+
"it",
|
|
51
|
+
"its",
|
|
52
|
+
"me",
|
|
53
|
+
"my",
|
|
54
|
+
"of",
|
|
55
|
+
"on",
|
|
56
|
+
"or",
|
|
57
|
+
"our",
|
|
58
|
+
"please",
|
|
59
|
+
"should",
|
|
60
|
+
"that",
|
|
61
|
+
"the",
|
|
62
|
+
"their",
|
|
63
|
+
"them",
|
|
64
|
+
"there",
|
|
65
|
+
"these",
|
|
66
|
+
"they",
|
|
67
|
+
"this",
|
|
68
|
+
"to",
|
|
69
|
+
"was",
|
|
70
|
+
"we",
|
|
71
|
+
"were",
|
|
72
|
+
"what",
|
|
73
|
+
"when",
|
|
74
|
+
"where",
|
|
75
|
+
"which",
|
|
76
|
+
"who",
|
|
77
|
+
"why",
|
|
78
|
+
"with",
|
|
79
|
+
"would",
|
|
80
|
+
"you",
|
|
81
|
+
"your",
|
|
82
|
+
]);
|
|
83
|
+
const CHINESE_STOP_CHARS = new Set([
|
|
84
|
+
"的",
|
|
85
|
+
"了",
|
|
86
|
+
"在",
|
|
87
|
+
"是",
|
|
88
|
+
"有",
|
|
89
|
+
"不",
|
|
90
|
+
"和",
|
|
91
|
+
"与",
|
|
92
|
+
"个",
|
|
93
|
+
"把",
|
|
94
|
+
"被",
|
|
95
|
+
"从",
|
|
96
|
+
"对",
|
|
97
|
+
"而",
|
|
98
|
+
"给",
|
|
99
|
+
"将",
|
|
100
|
+
"就",
|
|
101
|
+
"让",
|
|
102
|
+
"向",
|
|
103
|
+
"也",
|
|
104
|
+
"以",
|
|
105
|
+
"因",
|
|
106
|
+
"又",
|
|
107
|
+
"于",
|
|
108
|
+
"则",
|
|
109
|
+
"之",
|
|
110
|
+
"这",
|
|
111
|
+
"那",
|
|
112
|
+
"其",
|
|
113
|
+
"它",
|
|
114
|
+
"他",
|
|
115
|
+
"她",
|
|
116
|
+
"们",
|
|
117
|
+
"都",
|
|
118
|
+
"要",
|
|
119
|
+
"会",
|
|
120
|
+
"能",
|
|
121
|
+
"很",
|
|
122
|
+
"得",
|
|
123
|
+
"地",
|
|
124
|
+
"着",
|
|
125
|
+
"过",
|
|
126
|
+
"吗",
|
|
127
|
+
"呢",
|
|
128
|
+
"吧",
|
|
129
|
+
"啊",
|
|
130
|
+
"哦",
|
|
131
|
+
"嗯",
|
|
132
|
+
"呀",
|
|
133
|
+
]);
|
|
134
|
+
function containsHanText(text) {
|
|
135
|
+
return HAN_REGEX.test(text);
|
|
136
|
+
}
|
|
137
|
+
function tokenizeHanPart(part) {
|
|
138
|
+
const chars = Array.from(part);
|
|
139
|
+
const covered = new Uint8Array(chars.length);
|
|
140
|
+
const tokens = [];
|
|
141
|
+
for (let index = 0; index < chars.length; index++) {
|
|
142
|
+
let matchedLength = 0;
|
|
143
|
+
const maxLength = Math.min(MAX_HAN_WORD_LENGTH, chars.length - index);
|
|
144
|
+
for (let size = maxLength; size >= 2; size--) {
|
|
145
|
+
const candidate = chars.slice(index, index + size).join("");
|
|
146
|
+
if (COMMON_CHINESE_WORDS.has(candidate)) {
|
|
147
|
+
tokens.push(candidate);
|
|
148
|
+
matchedLength = size;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (matchedLength > 0) {
|
|
153
|
+
for (let coveredIndex = index; coveredIndex < index + matchedLength; coveredIndex++) {
|
|
154
|
+
covered[coveredIndex] = 1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
for (let index = 0; index <= chars.length - 2; index++) {
|
|
159
|
+
if (covered[index] || covered[index + 1]) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
tokens.push(chars.slice(index, index + 2).join(""));
|
|
163
|
+
}
|
|
164
|
+
for (let index = 0; index < chars.length; index++) {
|
|
165
|
+
if (covered[index]) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
const char = chars[index];
|
|
169
|
+
if (!CHINESE_STOP_CHARS.has(char)) {
|
|
170
|
+
tokens.push(char);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return Array.from(new Set(tokens));
|
|
174
|
+
}
|
|
175
|
+
function tokenizeAsciiPart(part) {
|
|
176
|
+
const tokens = [];
|
|
177
|
+
const normalized = part.toLowerCase();
|
|
178
|
+
const segments = normalized.split(ASCII_SPLIT_REGEX).filter(Boolean);
|
|
179
|
+
if (normalized.length >= 2 && !LATIN_STOP_WORDS.has(normalized)) {
|
|
180
|
+
tokens.push(normalized);
|
|
181
|
+
}
|
|
182
|
+
for (const segment of segments) {
|
|
183
|
+
if (segment.length >= 2 && !LATIN_STOP_WORDS.has(segment)) {
|
|
184
|
+
tokens.push(segment);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return tokens;
|
|
188
|
+
}
|
|
189
|
+
function tokenize(text) {
|
|
190
|
+
const parts = text.toLowerCase().match(TOKEN_PART_REGEX) ?? [];
|
|
191
|
+
const tokens = [];
|
|
192
|
+
for (const part of parts) {
|
|
193
|
+
if (containsHanText(part)) {
|
|
194
|
+
tokens.push(...tokenizeHanPart(part));
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
tokens.push(...tokenizeAsciiPart(part));
|
|
198
|
+
}
|
|
199
|
+
return Array.from(new Set(tokens));
|
|
200
|
+
}
|
|
201
|
+
export function tokenizeRecallText(text) {
|
|
202
|
+
return tokenize(text);
|
|
203
|
+
}
|
|
204
|
+
function buildTokenSet(text) {
|
|
205
|
+
return new Set(tokenize(text));
|
|
206
|
+
}
|
|
207
|
+
function computeTokenMatchStats(queryTokens, text) {
|
|
208
|
+
if (queryTokens.length === 0 || !text.trim()) {
|
|
209
|
+
return { matchedCount: 0, coverage: 0 };
|
|
210
|
+
}
|
|
211
|
+
const haystack = buildTokenSet(text);
|
|
212
|
+
let matchedCount = 0;
|
|
213
|
+
for (const token of queryTokens) {
|
|
214
|
+
if (haystack.has(token)) {
|
|
215
|
+
matchedCount++;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
matchedCount,
|
|
220
|
+
coverage: matchedCount / queryTokens.length,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function collectMatchingQueryTokens(queryTokens, texts) {
|
|
224
|
+
const haystack = new Set();
|
|
225
|
+
for (const text of texts) {
|
|
226
|
+
for (const token of tokenize(text)) {
|
|
227
|
+
haystack.add(token);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const matches = new Set();
|
|
231
|
+
for (const token of queryTokens) {
|
|
232
|
+
if (haystack.has(token)) {
|
|
233
|
+
matches.add(token);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return matches;
|
|
237
|
+
}
|
|
238
|
+
function computeExactMatchBoost(query, candidate) {
|
|
239
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
240
|
+
if (!normalizedQuery) {
|
|
241
|
+
return 0;
|
|
242
|
+
}
|
|
243
|
+
const minLength = containsHanText(normalizedQuery) ? 2 : 4;
|
|
244
|
+
if (normalizedQuery.length < minLength) {
|
|
245
|
+
return 0;
|
|
246
|
+
}
|
|
247
|
+
let boost = 0;
|
|
248
|
+
const scoringFields = [
|
|
249
|
+
[candidate.title, 12],
|
|
250
|
+
[candidate.searchText ?? candidate.content, 8],
|
|
251
|
+
[candidate.path, 4],
|
|
252
|
+
];
|
|
253
|
+
for (const [field, value] of scoringFields) {
|
|
254
|
+
if (field.toLowerCase().includes(normalizedQuery)) {
|
|
255
|
+
boost += value;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return boost;
|
|
259
|
+
}
|
|
260
|
+
function computeRecencyBoost(timestamp) {
|
|
261
|
+
if (!timestamp)
|
|
262
|
+
return 0;
|
|
263
|
+
const timestampMs = Date.parse(timestamp);
|
|
264
|
+
if (!Number.isFinite(timestampMs))
|
|
265
|
+
return 0;
|
|
266
|
+
const ageMs = Date.now() - timestampMs;
|
|
267
|
+
const dayMs = 24 * 60 * 60 * 1000;
|
|
268
|
+
if (ageMs <= dayMs)
|
|
269
|
+
return 6;
|
|
270
|
+
if (ageMs <= 7 * dayMs)
|
|
271
|
+
return 4;
|
|
272
|
+
if (ageMs <= 30 * dayMs)
|
|
273
|
+
return 2;
|
|
274
|
+
return 0;
|
|
275
|
+
}
|
|
276
|
+
function detectQueryIntents(query) {
|
|
277
|
+
const intents = new Set();
|
|
278
|
+
if (/\b(now|current|currently|status)\b/i.test(query) || /(现在|当前|目前|正在|状态)/u.test(query)) {
|
|
279
|
+
intents.add("current-state");
|
|
280
|
+
}
|
|
281
|
+
if (/\b(next|follow-?up|todo|plan)\b/i.test(query) || /(下一步|接下来|后续|怎么办|怎么做|该查什么)/u.test(query)) {
|
|
282
|
+
intents.add("next-steps");
|
|
283
|
+
}
|
|
284
|
+
if (/\b(constraint|requirement|guardrail|compatible|compatibility)\b/i.test(query) ||
|
|
285
|
+
/(约束|限制|要求|兼容|注意事项)/u.test(query)) {
|
|
286
|
+
intents.add("constraints");
|
|
287
|
+
}
|
|
288
|
+
if (/\b(decision|decided|why)\b/i.test(query) || /(决策|决定|方案|为什么)/u.test(query)) {
|
|
289
|
+
intents.add("decisions");
|
|
290
|
+
}
|
|
291
|
+
if (/\b(error|bug|failure|issue|regression)\b/i.test(query) || /(错误|异常|失败|问题|缺陷|回归)/u.test(query)) {
|
|
292
|
+
intents.add("errors");
|
|
293
|
+
}
|
|
294
|
+
if (/\b(history|previous|before|earlier|past)\b/i.test(query) || /(历史|之前|以前|过去|早先|曾经)/u.test(query)) {
|
|
295
|
+
intents.add("history");
|
|
296
|
+
}
|
|
297
|
+
return intents;
|
|
298
|
+
}
|
|
299
|
+
function computeSectionIntentBoost(intents, candidate) {
|
|
300
|
+
const kind = candidate.sectionKind ?? "";
|
|
301
|
+
let boost = 0;
|
|
302
|
+
if (intents.has("current-state") && kind === "current state")
|
|
303
|
+
boost += 10;
|
|
304
|
+
if (intents.has("next-steps") && kind === "next steps")
|
|
305
|
+
boost += 10;
|
|
306
|
+
if (intents.has("constraints") && kind.includes("constraint"))
|
|
307
|
+
boost += 8;
|
|
308
|
+
if (intents.has("decisions") && kind.includes("decision"))
|
|
309
|
+
boost += 8;
|
|
310
|
+
if (intents.has("errors") && kind === "errors & corrections")
|
|
311
|
+
boost += 8;
|
|
312
|
+
if (intents.has("history") && candidate.source === "channel-history")
|
|
313
|
+
boost += 8;
|
|
314
|
+
return boost;
|
|
315
|
+
}
|
|
316
|
+
function compareScoredCandidates(a, b) {
|
|
317
|
+
return (b.score - a.score ||
|
|
318
|
+
b.lexicalMatchCount - a.lexicalMatchCount ||
|
|
319
|
+
b.candidate.priority - a.candidate.priority ||
|
|
320
|
+
a.candidate.title.localeCompare(b.candidate.title));
|
|
321
|
+
}
|
|
322
|
+
function scoreCandidate(query, queryTokens, intents, candidate) {
|
|
323
|
+
const searchText = candidate.searchText ?? candidate.content;
|
|
324
|
+
const titleStats = computeTokenMatchStats(queryTokens, candidate.title);
|
|
325
|
+
const contentStats = computeTokenMatchStats(queryTokens, searchText);
|
|
326
|
+
const pathStats = computeTokenMatchStats(queryTokens, candidate.path);
|
|
327
|
+
const matchedTokens = collectMatchingQueryTokens(queryTokens, [candidate.title, searchText, candidate.path]);
|
|
328
|
+
const exactBoost = computeExactMatchBoost(query, candidate);
|
|
329
|
+
const intentBoost = computeSectionIntentBoost(intents, candidate);
|
|
330
|
+
const overallCoverage = queryTokens.length > 0 ? matchedTokens.size / queryTokens.length : 0;
|
|
331
|
+
const lexicalScore = overallCoverage * 48 +
|
|
332
|
+
titleStats.coverage * 18 +
|
|
333
|
+
contentStats.coverage * 22 +
|
|
334
|
+
pathStats.coverage * 8 +
|
|
335
|
+
exactBoost;
|
|
336
|
+
const structuralScore = candidate.priority + intentBoost + computeRecencyBoost(candidate.timestamp);
|
|
337
|
+
if (matchedTokens.size === 0 && exactBoost === 0) {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
return {
|
|
341
|
+
candidate,
|
|
342
|
+
score: lexicalScore * (1 + structuralScore / 100),
|
|
343
|
+
lexicalMatchCount: matchedTokens.size,
|
|
344
|
+
intentBoost,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
function seedIntentCandidates(request, candidates, existing, intents, queryTokens) {
|
|
348
|
+
if (intents.size === 0) {
|
|
349
|
+
return existing;
|
|
350
|
+
}
|
|
351
|
+
const seen = new Set(existing.map(({ candidate }) => candidate.id));
|
|
352
|
+
const seeded = [...existing];
|
|
353
|
+
const limit = Math.max(request.maxCandidates, request.maxInjected);
|
|
354
|
+
const intentCandidates = candidates
|
|
355
|
+
.map((candidate) => ({
|
|
356
|
+
candidate,
|
|
357
|
+
intentBoost: computeSectionIntentBoost(intents, candidate),
|
|
358
|
+
}))
|
|
359
|
+
.filter(({ candidate, intentBoost }) => intentBoost > 0 && !seen.has(candidate.id))
|
|
360
|
+
.sort((a, b) => b.intentBoost - a.intentBoost ||
|
|
361
|
+
b.candidate.priority - a.candidate.priority ||
|
|
362
|
+
a.candidate.title.localeCompare(b.candidate.title));
|
|
363
|
+
for (const { candidate, intentBoost } of intentCandidates) {
|
|
364
|
+
const matchedTokens = collectMatchingQueryTokens(queryTokens, [
|
|
365
|
+
candidate.title,
|
|
366
|
+
candidate.searchText ?? candidate.content,
|
|
367
|
+
]);
|
|
368
|
+
if (matchedTokens.size === 0) {
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
seeded.push({
|
|
372
|
+
candidate,
|
|
373
|
+
score: (intentBoost + matchedTokens.size * 8) *
|
|
374
|
+
(1 + (candidate.priority + computeRecencyBoost(candidate.timestamp)) / 100),
|
|
375
|
+
lexicalMatchCount: matchedTokens.size,
|
|
376
|
+
intentBoost,
|
|
377
|
+
});
|
|
378
|
+
seen.add(candidate.id);
|
|
379
|
+
if (seeded.length >= limit) {
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return seeded;
|
|
384
|
+
}
|
|
385
|
+
async function rerankCandidates(request, candidates) {
|
|
386
|
+
if ((!request.rerankWithModel && !request.autoRerank) || candidates.length <= request.maxInjected) {
|
|
387
|
+
return candidates;
|
|
388
|
+
}
|
|
389
|
+
const renderedCandidates = candidates
|
|
390
|
+
.map(({ candidate, score, lexicalMatchCount, intentBoost }) => {
|
|
391
|
+
const clippedContent = candidate.content.length > RERANK_CONTENT_CLIP
|
|
392
|
+
? `${candidate.content.slice(0, RERANK_CONTENT_CLIP)}...`
|
|
393
|
+
: candidate.content;
|
|
394
|
+
return [
|
|
395
|
+
`id: ${candidate.id}`,
|
|
396
|
+
`source: ${candidate.source}`,
|
|
397
|
+
`title: ${candidate.title}`,
|
|
398
|
+
`path: ${candidate.path}`,
|
|
399
|
+
`score: ${score}`,
|
|
400
|
+
`lexicalMatchCount: ${lexicalMatchCount}`,
|
|
401
|
+
`intentBoost: ${intentBoost}`,
|
|
402
|
+
`content: ${clippedContent}`,
|
|
403
|
+
].join("\n");
|
|
404
|
+
})
|
|
405
|
+
.join("\n\n---\n\n");
|
|
406
|
+
try {
|
|
407
|
+
const result = await runSidecarTask({
|
|
408
|
+
name: "memory-recall-rerank",
|
|
409
|
+
model: request.model,
|
|
410
|
+
resolveApiKey: request.resolveApiKey,
|
|
411
|
+
systemPrompt: RERANK_SYSTEM_PROMPT,
|
|
412
|
+
prompt: `User turn:\n${request.query.trim()}\n\nCandidates:\n${renderedCandidates}`,
|
|
413
|
+
timeoutMs: MEMORY_RECALL_RERANK_TIMEOUT_MS,
|
|
414
|
+
parse: (text) => {
|
|
415
|
+
const parsed = parseJsonObject(text);
|
|
416
|
+
return Array.isArray(parsed.selectedIds)
|
|
417
|
+
? parsed.selectedIds.filter((id) => typeof id === "string" && id.trim().length > 0)
|
|
418
|
+
: [];
|
|
419
|
+
},
|
|
420
|
+
});
|
|
421
|
+
const selectedIds = new Set(result.output);
|
|
422
|
+
if (selectedIds.size === 0) {
|
|
423
|
+
return candidates;
|
|
424
|
+
}
|
|
425
|
+
const selected = candidates.filter(({ candidate }) => selectedIds.has(candidate.id));
|
|
426
|
+
return selected.length > 0 ? selected : candidates;
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
return candidates;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function renderRecallResult(items, maxChars) {
|
|
433
|
+
if (items.length === 0) {
|
|
434
|
+
return "";
|
|
435
|
+
}
|
|
436
|
+
const lines = ["<runtime_context>", "Relevant context for this turn:"];
|
|
437
|
+
for (const item of items) {
|
|
438
|
+
lines.push("");
|
|
439
|
+
lines.push(`[${item.source}/${item.title}]`);
|
|
440
|
+
lines.push(`Path: ${item.path}`);
|
|
441
|
+
lines.push(item.content);
|
|
442
|
+
}
|
|
443
|
+
lines.push("</runtime_context>");
|
|
444
|
+
const rendered = lines.join("\n");
|
|
445
|
+
if (rendered.length <= maxChars) {
|
|
446
|
+
return rendered;
|
|
447
|
+
}
|
|
448
|
+
const clippedLines = ["<runtime_context>", "Relevant context for this turn:"];
|
|
449
|
+
let usedChars = clippedLines.join("\n").length + "</runtime_context>".length + 2;
|
|
450
|
+
for (const item of items) {
|
|
451
|
+
const block = ["", `[${item.source}/${item.title}]`, `Path: ${item.path}`, item.content].join("\n");
|
|
452
|
+
if (usedChars + block.length > maxChars) {
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
clippedLines.push("", `[${item.source}/${item.title}]`, `Path: ${item.path}`, item.content);
|
|
456
|
+
usedChars += block.length;
|
|
457
|
+
}
|
|
458
|
+
clippedLines.push("</runtime_context>");
|
|
459
|
+
return clippedLines.join("\n");
|
|
460
|
+
}
|
|
461
|
+
export async function recallRelevantMemory(request) {
|
|
462
|
+
const query = request.query.trim();
|
|
463
|
+
if (!query) {
|
|
464
|
+
return { items: [], renderedText: "" };
|
|
465
|
+
}
|
|
466
|
+
const candidates = await buildMemoryCandidates({
|
|
467
|
+
workspaceDir: request.workspaceDir,
|
|
468
|
+
channelDir: request.channelDir,
|
|
469
|
+
cache: request.candidateCache,
|
|
470
|
+
});
|
|
471
|
+
const filteredCandidates = request.allowedSources?.length
|
|
472
|
+
? candidates.filter((candidate) => request.allowedSources?.includes(candidate.source))
|
|
473
|
+
: candidates;
|
|
474
|
+
if (filteredCandidates.length === 0) {
|
|
475
|
+
return { items: [], renderedText: "" };
|
|
476
|
+
}
|
|
477
|
+
const queryTokens = tokenize(query);
|
|
478
|
+
const queryIntents = detectQueryIntents(query);
|
|
479
|
+
const scored = filteredCandidates
|
|
480
|
+
.map((candidate) => scoreCandidate(query, queryTokens, queryIntents, candidate))
|
|
481
|
+
.filter((candidate) => candidate !== null)
|
|
482
|
+
.sort(compareScoredCandidates);
|
|
483
|
+
const shortlist = seedIntentCandidates(request, filteredCandidates, scored, queryIntents, queryTokens)
|
|
484
|
+
.sort(compareScoredCandidates)
|
|
485
|
+
.slice(0, Math.max(request.maxCandidates, request.maxInjected));
|
|
486
|
+
if (shortlist.length === 0) {
|
|
487
|
+
return { items: [], renderedText: "" };
|
|
488
|
+
}
|
|
489
|
+
const reranked = await rerankCandidates(request, shortlist);
|
|
490
|
+
const items = reranked.slice(0, request.maxInjected).map(({ candidate, score }) => ({
|
|
491
|
+
source: candidate.source,
|
|
492
|
+
path: candidate.path,
|
|
493
|
+
title: candidate.title,
|
|
494
|
+
content: candidate.content,
|
|
495
|
+
score,
|
|
496
|
+
}));
|
|
497
|
+
return {
|
|
498
|
+
items,
|
|
499
|
+
renderedText: renderRecallResult(items, request.maxChars),
|
|
500
|
+
};
|
|
501
|
+
}
|
|
@@ -16,7 +16,7 @@ export interface SessionMemoryUpdateOptions {
|
|
|
16
16
|
messages: AgentMessage[];
|
|
17
17
|
model: Model<Api>;
|
|
18
18
|
resolveApiKey: (model: Model<Api>) => Promise<string>;
|
|
19
|
+
timeoutMs?: number;
|
|
19
20
|
}
|
|
20
21
|
export declare function renderSessionMemory(state: SessionMemoryState): string;
|
|
21
22
|
export declare function updateChannelSessionMemory(options: SessionMemoryUpdateOptions): Promise<SessionMemoryState>;
|
|
22
|
-
//# sourceMappingURL=session-memory.d.ts.map
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { serializeConversation } from "@mariozechner/pi-coding-agent";
|
|
2
2
|
import { writeFile } from "fs/promises";
|
|
3
3
|
import { join } from "path";
|
|
4
|
-
import { parseJsonObject } from "
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { runSidecarTask, SidecarParseError } from "
|
|
4
|
+
import { parseJsonObject } from "../shared/llm-json.js";
|
|
5
|
+
import { splitH1Sections } from "../shared/markdown-sections.js";
|
|
6
|
+
import { clipText } from "../shared/text-utils.js";
|
|
7
|
+
import { buildStandardMessages, isRecord } from "../shared/type-guards.js";
|
|
8
|
+
import { runSidecarTask, SidecarParseError } from "../sidecar-worker.js";
|
|
9
|
+
import { readChannelMemory, readChannelSession, rewriteChannelSession } from "./files.js";
|
|
9
10
|
const SESSION_TRANSCRIPT_MAX_CHARS = 20_000;
|
|
10
11
|
const SESSION_MEMORY_MAX_CHARS = 4_000;
|
|
11
12
|
const SESSION_ITEM_LIMIT = 12;
|
|
12
13
|
const SESSION_ITEM_MAX_CHARS = 300;
|
|
13
|
-
const
|
|
14
|
+
const DEFAULT_SESSION_MEMORY_TIMEOUT_MS = 30_000;
|
|
14
15
|
const SESSION_MEMORY_SYSTEM_PROMPT = `You maintain a Pipiclaw SESSION.md file.
|
|
15
16
|
|
|
16
17
|
Return strict JSON only. Do not use Markdown fences.
|
|
@@ -37,15 +38,6 @@ Rules:
|
|
|
37
38
|
- "nextSteps" should reflect the most likely immediate follow-up actions.
|
|
38
39
|
- "worklog" must stay terse and recent.
|
|
39
40
|
- If a field has nothing useful, return an empty string or empty array.`;
|
|
40
|
-
function clipText(text, maxChars) {
|
|
41
|
-
const normalized = text.replace(/\r/g, "").trim();
|
|
42
|
-
if (normalized.length <= maxChars) {
|
|
43
|
-
return normalized;
|
|
44
|
-
}
|
|
45
|
-
const headChars = Math.floor(maxChars * 0.45);
|
|
46
|
-
const tailChars = maxChars - headChars;
|
|
47
|
-
return `${normalized.slice(0, headChars)}\n\n[... omitted middle section ...]\n\n${normalized.slice(-tailChars)}`;
|
|
48
|
-
}
|
|
49
41
|
function normalizeItem(value) {
|
|
50
42
|
if (typeof value !== "string") {
|
|
51
43
|
return null;
|
|
@@ -70,33 +62,22 @@ function normalizeItems(value) {
|
|
|
70
62
|
function normalizeTitle(value) {
|
|
71
63
|
return typeof value === "string" ? value.trim().slice(0, 120) : "";
|
|
72
64
|
}
|
|
73
|
-
function isRecord(value) {
|
|
74
|
-
return typeof value === "object" && value !== null;
|
|
75
|
-
}
|
|
76
65
|
function parseStateUpdate(text) {
|
|
77
66
|
const parsed = parseJsonObject(text);
|
|
78
67
|
if (!isRecord(parsed)) {
|
|
79
68
|
throw new Error("Session memory response was not a JSON object");
|
|
80
69
|
}
|
|
81
|
-
const next = {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if ("constraints" in parsed)
|
|
93
|
-
next.constraints = normalizeItems(parsed.constraints);
|
|
94
|
-
if ("errorsAndCorrections" in parsed)
|
|
95
|
-
next.errorsAndCorrections = normalizeItems(parsed.errorsAndCorrections);
|
|
96
|
-
if ("nextSteps" in parsed)
|
|
97
|
-
next.nextSteps = normalizeItems(parsed.nextSteps);
|
|
98
|
-
if ("worklog" in parsed)
|
|
99
|
-
next.worklog = normalizeItems(parsed.worklog);
|
|
70
|
+
const next = {
|
|
71
|
+
title: normalizeTitle(parsed.title),
|
|
72
|
+
currentState: normalizeItems(parsed.currentState),
|
|
73
|
+
userIntent: normalizeItems(parsed.userIntent),
|
|
74
|
+
activeFiles: normalizeItems(parsed.activeFiles),
|
|
75
|
+
decisions: normalizeItems(parsed.decisions),
|
|
76
|
+
constraints: normalizeItems(parsed.constraints),
|
|
77
|
+
errorsAndCorrections: normalizeItems(parsed.errorsAndCorrections),
|
|
78
|
+
nextSteps: normalizeItems(parsed.nextSteps),
|
|
79
|
+
worklog: normalizeItems(parsed.worklog),
|
|
80
|
+
};
|
|
100
81
|
return next;
|
|
101
82
|
}
|
|
102
83
|
function createEmptySessionMemoryState() {
|
|
@@ -138,7 +119,7 @@ function parseSectionItems(content) {
|
|
|
138
119
|
}
|
|
139
120
|
function parseRenderedSessionMemory(markdown) {
|
|
140
121
|
const state = createEmptySessionMemoryState();
|
|
141
|
-
for (const section of
|
|
122
|
+
for (const section of splitH1Sections(markdown)) {
|
|
142
123
|
switch (section.heading.toLowerCase()) {
|
|
143
124
|
case "session title":
|
|
144
125
|
state.title = stripHtmlComments(section.content).split("\n")[0]?.trim().slice(0, 120) || "";
|
|
@@ -171,19 +152,17 @@ function parseRenderedSessionMemory(markdown) {
|
|
|
171
152
|
}
|
|
172
153
|
return state;
|
|
173
154
|
}
|
|
174
|
-
function mergeSessionMemoryState(
|
|
155
|
+
function mergeSessionMemoryState(_current, update) {
|
|
175
156
|
return {
|
|
176
|
-
title: typeof update.title === "string" ? update.title :
|
|
177
|
-
currentState: Array.isArray(update.currentState) ? update.currentState :
|
|
178
|
-
userIntent: Array.isArray(update.userIntent) ? update.userIntent :
|
|
179
|
-
activeFiles: Array.isArray(update.activeFiles) ? update.activeFiles :
|
|
180
|
-
decisions: Array.isArray(update.decisions) ? update.decisions :
|
|
181
|
-
constraints: Array.isArray(update.constraints) ? update.constraints :
|
|
182
|
-
errorsAndCorrections: Array.isArray(update.errorsAndCorrections)
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
nextSteps: Array.isArray(update.nextSteps) ? update.nextSteps : current.nextSteps,
|
|
186
|
-
worklog: Array.isArray(update.worklog) ? update.worklog : current.worklog,
|
|
157
|
+
title: typeof update.title === "string" ? update.title : "",
|
|
158
|
+
currentState: Array.isArray(update.currentState) ? update.currentState : [],
|
|
159
|
+
userIntent: Array.isArray(update.userIntent) ? update.userIntent : [],
|
|
160
|
+
activeFiles: Array.isArray(update.activeFiles) ? update.activeFiles : [],
|
|
161
|
+
decisions: Array.isArray(update.decisions) ? update.decisions : [],
|
|
162
|
+
constraints: Array.isArray(update.constraints) ? update.constraints : [],
|
|
163
|
+
errorsAndCorrections: Array.isArray(update.errorsAndCorrections) ? update.errorsAndCorrections : [],
|
|
164
|
+
nextSteps: Array.isArray(update.nextSteps) ? update.nextSteps : [],
|
|
165
|
+
worklog: Array.isArray(update.worklog) ? update.worklog : [],
|
|
187
166
|
};
|
|
188
167
|
}
|
|
189
168
|
async function writeSessionMemoryDebugFile(channelDir, error, rawText) {
|
|
@@ -200,15 +179,6 @@ async function writeSessionMemoryDebugFile(channelDir, error, rawText) {
|
|
|
200
179
|
function renderSection(heading, items) {
|
|
201
180
|
return [`# ${heading}`, "", ...items.map((item) => `- ${item}`)].join("\n");
|
|
202
181
|
}
|
|
203
|
-
function isStandardAgentMessage(message) {
|
|
204
|
-
return (typeof message === "object" &&
|
|
205
|
-
message !== null &&
|
|
206
|
-
"role" in message &&
|
|
207
|
-
(message.role === "user" || message.role === "assistant" || message.role === "toolResult"));
|
|
208
|
-
}
|
|
209
|
-
function buildMessagesForSessionMemory(messages) {
|
|
210
|
-
return messages.filter(isStandardAgentMessage);
|
|
211
|
-
}
|
|
212
182
|
export function renderSessionMemory(state) {
|
|
213
183
|
const sections = [];
|
|
214
184
|
if (state.title.trim()) {
|
|
@@ -246,7 +216,7 @@ ${transcript || "(empty)"}`;
|
|
|
246
216
|
export async function updateChannelSessionMemory(options) {
|
|
247
217
|
const currentSession = await readChannelSession(options.channelDir);
|
|
248
218
|
const currentMemory = await readChannelMemory(options.channelDir);
|
|
249
|
-
const messages =
|
|
219
|
+
const messages = buildStandardMessages(options.messages);
|
|
250
220
|
const currentState = parseRenderedSessionMemory(currentSession);
|
|
251
221
|
let update;
|
|
252
222
|
try {
|
|
@@ -257,7 +227,7 @@ export async function updateChannelSessionMemory(options) {
|
|
|
257
227
|
systemPrompt: SESSION_MEMORY_SYSTEM_PROMPT,
|
|
258
228
|
prompt: buildSessionPrompt(currentSession, currentMemory, messages),
|
|
259
229
|
parse: parseStateUpdate,
|
|
260
|
-
timeoutMs:
|
|
230
|
+
timeoutMs: options.timeoutMs ?? DEFAULT_SESSION_MEMORY_TIMEOUT_MS,
|
|
261
231
|
});
|
|
262
232
|
update = result.output;
|
|
263
233
|
}
|
|
@@ -271,4 +241,3 @@ export async function updateChannelSessionMemory(options) {
|
|
|
271
241
|
await rewriteChannelSession(options.channelDir, rendered);
|
|
272
242
|
return parseRenderedSessionMemory(rendered);
|
|
273
243
|
}
|
|
274
|
-
//# sourceMappingURL=session-memory.js.map
|
package/dist/model-utils.d.ts
CHANGED
|
@@ -8,4 +8,3 @@ export declare function findExactModelReferenceMatch(modelReference: string, ava
|
|
|
8
8
|
};
|
|
9
9
|
export declare function formatModelList(models: Model<Api>[], currentModel: Model<Api> | undefined, limit?: number): string;
|
|
10
10
|
export declare function resolveInitialModel(modelRegistry: ModelRegistry, settingsManager: PipiclawSettingsManager): Model<Api>;
|
|
11
|
-
//# sourceMappingURL=model-utils.d.ts.map
|
package/dist/model-utils.js
CHANGED
package/dist/paths.d.ts
CHANGED