@chanlerdev/scorel 0.0.5 → 0.0.7
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 +11 -2
- package/dist/index.js +440 -178
- package/dist/index.js.map +4 -4
- package/docs/CHANGELOG.md +59 -0
- package/docs/ROADMAP.md +6 -0
- package/docs/SHIP.md +1 -0
- package/docs/spec/channels.md +1 -1
- package/docs/spec/events.md +45 -11
- package/docs/spec/runtime.md +3 -3
- package/docs/spec/session.md +16 -4
- package/docs/spec/ship/S0106-snip-context-control.md +113 -0
- package/docs/spec/ship/S0107-system-reminder-unification.md +173 -0
- package/docs/spec/ship/S0108-gui-bundled-cli-runtime.md +108 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1746,6 +1746,7 @@ import { mkdir as mkdir2, readFile as readFile4, rename as rename2, rm, stat as
|
|
|
1746
1746
|
import { userInfo } from "node:os";
|
|
1747
1747
|
import { basename as basename2, dirname as dirname3, extname, isAbsolute, relative, resolve } from "node:path";
|
|
1748
1748
|
import { promisify } from "node:util";
|
|
1749
|
+
import { Type } from "@mariozechner/pi-ai";
|
|
1749
1750
|
var execFileAsync, DEFAULT_SEARCH_LIMIT, DEFAULT_GREP_LIMIT, DEFAULT_READ_LIMIT, DEFAULT_CONTEXT_WINDOW, READ_TOKEN_BUDGET_RATIO, FULL_READ_TOKEN_BUDGET_RATIO, createCodingTools, parseReadArgs, parseWriteArgs, parseEditArgs, parseBashArgs, parseGlobArgs, parseGrepArgs, parseTodoWriteArgs, parseTodoItem, expectRecord, expectPath, expectString, optionalString, optionalNumber, optionalBoolean, snapshotFile, sameSnapshot, exists, isWithin, linesOf, IMAGE_EXTENSIONS, DOCUMENT_EXTENSIONS, BINARY_EXTENSIONS, assertReadableFileKind, assertTextBuffer, selectCompleteLinesWithinBudget, estimateTokens, renderReadLines, readTokenBudget, completeRanges, hasCompleteCoverage, mergeRanges, countOccurrences, atomicWriteFile, bashResult, renderFullBashResult, writeBashArtifact, safeArtifactSegment, projectBashStreams, projectOutputStream, resolveDefaultShell, resolveRtkCommand, rtkRewriteResult, executableRewriteCommand, readRtkGain, rtkSavedTokenDelta, withRtkSavings, nonNegativeInteger, isRecord3, shellQuote, shellCommandArgs, userShell, truncate, sliceBytes, textResult, byteLength, isTimeoutError, isExecError, runRipgrep, splitOutput, vcsExcludes, grepArgs, splitGlobPatterns, paginate, toWorkspaceRelative, relativizeGrepLine, relativizeCountLine, sortPathsByMtime, formatPaginatedText, formatLimitSuffix, parseCountLines;
|
|
1750
1751
|
var init_coding_tools = __esm({
|
|
1751
1752
|
"packages/core/src/tools/coding-tools.ts"() {
|
|
@@ -1799,6 +1800,12 @@ var init_coding_tools = __esm({
|
|
|
1799
1800
|
defineTool({
|
|
1800
1801
|
name: "Read",
|
|
1801
1802
|
description: "Read a text file from the workspace. Long reads are truncated by complete lines; accumulated coverage unlocks Write/Edit.",
|
|
1803
|
+
parameters: Type.Object({
|
|
1804
|
+
file_path: Type.String(),
|
|
1805
|
+
offset: Type.Optional(Type.Number()),
|
|
1806
|
+
limit: Type.Optional(Type.Number()),
|
|
1807
|
+
full: Type.Optional(Type.Boolean())
|
|
1808
|
+
}),
|
|
1802
1809
|
execute: async (_toolCallId, args) => {
|
|
1803
1810
|
const input = parseReadArgs(args);
|
|
1804
1811
|
if (input.full && (input.offset !== void 0 || input.limit !== void 0)) {
|
|
@@ -1858,6 +1865,10 @@ var init_coding_tools = __esm({
|
|
|
1858
1865
|
defineTool({
|
|
1859
1866
|
name: "Write",
|
|
1860
1867
|
description: "Create a new file or fully overwrite an existing file. Existing files require complete read coverage of the current file.",
|
|
1868
|
+
parameters: Type.Object({
|
|
1869
|
+
file_path: Type.String(),
|
|
1870
|
+
content: Type.String()
|
|
1871
|
+
}),
|
|
1861
1872
|
execute: async (_toolCallId, args) => {
|
|
1862
1873
|
const input = parseWriteArgs(args);
|
|
1863
1874
|
const path = resolveWorkspacePath(input.path);
|
|
@@ -1879,6 +1890,12 @@ var init_coding_tools = __esm({
|
|
|
1879
1890
|
defineTool({
|
|
1880
1891
|
name: "Edit",
|
|
1881
1892
|
description: "Perform an exact string replacement in an existing file. Requires complete read coverage and a unique old_string unless replace_all is true.",
|
|
1893
|
+
parameters: Type.Object({
|
|
1894
|
+
file_path: Type.String(),
|
|
1895
|
+
old_string: Type.String(),
|
|
1896
|
+
new_string: Type.String(),
|
|
1897
|
+
replace_all: Type.Optional(Type.Boolean())
|
|
1898
|
+
}),
|
|
1882
1899
|
execute: async (_toolCallId, args) => {
|
|
1883
1900
|
const input = parseEditArgs(args);
|
|
1884
1901
|
const path = resolveWorkspacePath(input.path);
|
|
@@ -1914,6 +1931,13 @@ String: ${input.old_string}`
|
|
|
1914
1931
|
defineTool({
|
|
1915
1932
|
name: "Bash",
|
|
1916
1933
|
description: "Execute a shell command in the workspace with timeout and output truncation.",
|
|
1934
|
+
parameters: Type.Object({
|
|
1935
|
+
command: Type.String(),
|
|
1936
|
+
cwd: Type.Optional(Type.String()),
|
|
1937
|
+
timeout: Type.Optional(Type.Number()),
|
|
1938
|
+
description: Type.Optional(Type.String()),
|
|
1939
|
+
maxOutputBytes: Type.Optional(Type.Number())
|
|
1940
|
+
}),
|
|
1917
1941
|
execute: async (toolCallId, args, signal) => {
|
|
1918
1942
|
const input = parseBashArgs(args);
|
|
1919
1943
|
const commandCwd = input.cwd ? resolveWorkspacePath(input.cwd) : root;
|
|
@@ -1978,6 +2002,12 @@ String: ${input.old_string}`
|
|
|
1978
2002
|
defineTool({
|
|
1979
2003
|
name: "Glob",
|
|
1980
2004
|
description: "Find files by glob pattern using ripgrep file discovery.",
|
|
2005
|
+
parameters: Type.Object({
|
|
2006
|
+
pattern: Type.String(),
|
|
2007
|
+
path: Type.Optional(Type.String()),
|
|
2008
|
+
head_limit: Type.Optional(Type.Number()),
|
|
2009
|
+
offset: Type.Optional(Type.Number())
|
|
2010
|
+
}),
|
|
1981
2011
|
execute: async (_toolCallId, args, signal) => {
|
|
1982
2012
|
const input = parseGlobArgs(args);
|
|
1983
2013
|
const limit = input.head_limit ?? DEFAULT_SEARCH_LIMIT;
|
|
@@ -1998,6 +2028,22 @@ String: ${input.old_string}`
|
|
|
1998
2028
|
defineTool({
|
|
1999
2029
|
name: "Grep",
|
|
2000
2030
|
description: 'Search file contents with ripgrep. Default output_mode is "files" for matching paths; use "content" for matching lines or "count" for match counts.',
|
|
2031
|
+
parameters: Type.Object({
|
|
2032
|
+
pattern: Type.String(),
|
|
2033
|
+
path: Type.Optional(Type.String()),
|
|
2034
|
+
glob: Type.Optional(Type.String()),
|
|
2035
|
+
output_mode: Type.Optional(Type.Union([Type.Literal("files"), Type.Literal("content"), Type.Literal("count")])),
|
|
2036
|
+
"-B": Type.Optional(Type.Number()),
|
|
2037
|
+
"-A": Type.Optional(Type.Number()),
|
|
2038
|
+
"-C": Type.Optional(Type.Number()),
|
|
2039
|
+
context: Type.Optional(Type.Number()),
|
|
2040
|
+
"-n": Type.Optional(Type.Boolean()),
|
|
2041
|
+
"-i": Type.Optional(Type.Boolean()),
|
|
2042
|
+
type: Type.Optional(Type.String()),
|
|
2043
|
+
head_limit: Type.Optional(Type.Number()),
|
|
2044
|
+
offset: Type.Optional(Type.Number()),
|
|
2045
|
+
multiline: Type.Optional(Type.Boolean())
|
|
2046
|
+
}),
|
|
2001
2047
|
execute: async (_toolCallId, args, signal) => {
|
|
2002
2048
|
const input = parseGrepArgs(args);
|
|
2003
2049
|
const mode = input.output_mode ?? "files";
|
|
@@ -2051,6 +2097,15 @@ ${filenames.join("\n")}`,
|
|
|
2051
2097
|
defineTool({
|
|
2052
2098
|
name: "TodoWrite",
|
|
2053
2099
|
description: "Replace the current session todo list with a complete updated list.",
|
|
2100
|
+
parameters: Type.Object({
|
|
2101
|
+
todos: Type.Array(
|
|
2102
|
+
Type.Object({
|
|
2103
|
+
content: Type.String(),
|
|
2104
|
+
status: Type.Union([Type.Literal("pending"), Type.Literal("in_progress"), Type.Literal("completed")]),
|
|
2105
|
+
activeForm: Type.Optional(Type.String())
|
|
2106
|
+
})
|
|
2107
|
+
)
|
|
2108
|
+
}),
|
|
2054
2109
|
execute: async (_toolCallId, args) => {
|
|
2055
2110
|
const input = parseTodoWriteArgs(args);
|
|
2056
2111
|
const oldTodos = state.todos;
|
|
@@ -2682,17 +2737,53 @@ ${value}` };
|
|
|
2682
2737
|
});
|
|
2683
2738
|
|
|
2684
2739
|
// packages/core/src/tools/index.ts
|
|
2685
|
-
|
|
2740
|
+
import { Type as Type2 } from "@mariozechner/pi-ai";
|
|
2741
|
+
var defineTool, createSnipTool, parseSnipToolInput, isRecord4;
|
|
2686
2742
|
var init_tools = __esm({
|
|
2687
2743
|
"packages/core/src/tools/index.ts"() {
|
|
2688
2744
|
"use strict";
|
|
2689
2745
|
init_coding_tools();
|
|
2690
2746
|
defineTool = (tool) => tool;
|
|
2747
|
+
createSnipTool = (options) => defineTool({
|
|
2748
|
+
name: "snip",
|
|
2749
|
+
description: [
|
|
2750
|
+
"Hide a completed user turn from future model context.",
|
|
2751
|
+
"Use only when an earlier user turn is obsolete or noisy.",
|
|
2752
|
+
"The session JSONL evidence is preserved; the hidden turn disappears from the next context build.",
|
|
2753
|
+
"Input: { userMessageId: string, reason?: string }."
|
|
2754
|
+
].join(" "),
|
|
2755
|
+
parameters: Type2.Object({
|
|
2756
|
+
userMessageId: Type2.String(),
|
|
2757
|
+
reason: Type2.Optional(Type2.String())
|
|
2758
|
+
}),
|
|
2759
|
+
execute: async (_toolCallId, args) => {
|
|
2760
|
+
const input = parseSnipToolInput(args);
|
|
2761
|
+
const result = await options.snip(input);
|
|
2762
|
+
return {
|
|
2763
|
+
content: [{
|
|
2764
|
+
type: "text",
|
|
2765
|
+
text: "Snipped the selected user turn. It will be omitted from future model context."
|
|
2766
|
+
}],
|
|
2767
|
+
details: result
|
|
2768
|
+
};
|
|
2769
|
+
}
|
|
2770
|
+
});
|
|
2771
|
+
parseSnipToolInput = (args) => {
|
|
2772
|
+
if (!isRecord4(args) || typeof args.userMessageId !== "string") {
|
|
2773
|
+
throw new Error("snip requires { userMessageId: string }");
|
|
2774
|
+
}
|
|
2775
|
+
return {
|
|
2776
|
+
userMessageId: args.userMessageId,
|
|
2777
|
+
...typeof args.reason === "string" && args.reason.trim() ? { reason: args.reason.trim() } : {}
|
|
2778
|
+
};
|
|
2779
|
+
};
|
|
2780
|
+
isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2691
2781
|
}
|
|
2692
2782
|
});
|
|
2693
2783
|
|
|
2694
2784
|
// packages/core/src/channel/index.ts
|
|
2695
|
-
|
|
2785
|
+
import { Type as Type3 } from "@mariozechner/pi-ai";
|
|
2786
|
+
var createSendChannelMessageTool, parseSendChannelMessageInput, parseAttachments, optionalString2, isRecord5;
|
|
2696
2787
|
var init_channel = __esm({
|
|
2697
2788
|
"packages/core/src/channel/index.ts"() {
|
|
2698
2789
|
"use strict";
|
|
@@ -2700,6 +2791,18 @@ var init_channel = __esm({
|
|
|
2700
2791
|
createSendChannelMessageTool = (options) => defineTool({
|
|
2701
2792
|
name: "SendChannelMessage",
|
|
2702
2793
|
description: "Send a text reply to the current IM channel conversation. Do not provide raw platform user ids or group ids.",
|
|
2794
|
+
parameters: Type3.Object({
|
|
2795
|
+
text: Type3.Optional(Type3.String()),
|
|
2796
|
+
attachments: Type3.Optional(Type3.Array(Type3.Object({
|
|
2797
|
+
type: Type3.Union([Type3.Literal("image"), Type3.Literal("file")]),
|
|
2798
|
+
path: Type3.Optional(Type3.String()),
|
|
2799
|
+
url: Type3.Optional(Type3.String()),
|
|
2800
|
+
mimeType: Type3.Optional(Type3.String()),
|
|
2801
|
+
caption: Type3.Optional(Type3.String())
|
|
2802
|
+
}))),
|
|
2803
|
+
channel: Type3.Optional(Type3.String()),
|
|
2804
|
+
target: Type3.Optional(Type3.Literal("current"))
|
|
2805
|
+
}),
|
|
2703
2806
|
execute: async (_toolCallId, args) => {
|
|
2704
2807
|
const input = parseSendChannelMessageInput(args);
|
|
2705
2808
|
const result = await options.sendCurrent(input);
|
|
@@ -2710,7 +2813,7 @@ var init_channel = __esm({
|
|
|
2710
2813
|
}
|
|
2711
2814
|
});
|
|
2712
2815
|
parseSendChannelMessageInput = (value) => {
|
|
2713
|
-
if (!
|
|
2816
|
+
if (!isRecord5(value)) {
|
|
2714
2817
|
throw new Error("SendChannelMessage args must be an object");
|
|
2715
2818
|
}
|
|
2716
2819
|
const text = typeof value.text === "string" && value.text.trim().length > 0 ? value.text : void 0;
|
|
@@ -2739,7 +2842,7 @@ var init_channel = __esm({
|
|
|
2739
2842
|
throw new Error("SendChannelMessage.attachments must be an array");
|
|
2740
2843
|
}
|
|
2741
2844
|
return value.map((item, index) => {
|
|
2742
|
-
if (!
|
|
2845
|
+
if (!isRecord5(item)) {
|
|
2743
2846
|
throw new Error(`SendChannelMessage.attachments.${index} must be an object`);
|
|
2744
2847
|
}
|
|
2745
2848
|
if (item.type !== "image" && item.type !== "file") {
|
|
@@ -2768,14 +2871,14 @@ var init_channel = __esm({
|
|
|
2768
2871
|
}
|
|
2769
2872
|
return value;
|
|
2770
2873
|
};
|
|
2771
|
-
|
|
2874
|
+
isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2772
2875
|
}
|
|
2773
2876
|
});
|
|
2774
2877
|
|
|
2775
2878
|
// packages/core/src/extensions/index.ts
|
|
2776
2879
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
2777
2880
|
import { dirname as dirname4, resolve as resolve2 } from "node:path";
|
|
2778
|
-
var loadExtensionManifest, parseExtensionManifest, requireString2, requireIdentifier2, requireKind, requireRelativePath, optionalRelativePaths,
|
|
2881
|
+
var loadExtensionManifest, parseExtensionManifest, requireString2, requireIdentifier2, requireKind, requireRelativePath, optionalRelativePaths, isRecord6;
|
|
2779
2882
|
var init_extensions = __esm({
|
|
2780
2883
|
"packages/core/src/extensions/index.ts"() {
|
|
2781
2884
|
"use strict";
|
|
@@ -2788,7 +2891,7 @@ var init_extensions = __esm({
|
|
|
2788
2891
|
const message = cause instanceof Error ? cause.message : String(cause);
|
|
2789
2892
|
throw new Error(`Invalid extension manifest JSON at ${manifestPath}: ${message}`);
|
|
2790
2893
|
}
|
|
2791
|
-
if (!
|
|
2894
|
+
if (!isRecord6(value)) {
|
|
2792
2895
|
throw new Error(`Extension manifest at ${manifestPath} must be an object`);
|
|
2793
2896
|
}
|
|
2794
2897
|
const rootDir = dirname4(resolve2(manifestPath));
|
|
@@ -2844,7 +2947,7 @@ var init_extensions = __esm({
|
|
|
2844
2947
|
}
|
|
2845
2948
|
return value.map((item, index) => requireRelativePath(item, `${name}.${index}`, manifestPath));
|
|
2846
2949
|
};
|
|
2847
|
-
|
|
2950
|
+
isRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2848
2951
|
}
|
|
2849
2952
|
});
|
|
2850
2953
|
|
|
@@ -2988,7 +3091,8 @@ var init_instructions = __esm({
|
|
|
2988
3091
|
import { appendFile, mkdir as mkdir3, readFile as readFile7, writeFile as writeFile3 } from "node:fs/promises";
|
|
2989
3092
|
import { homedir as homedir3 } from "node:os";
|
|
2990
3093
|
import { join as join6 } from "node:path";
|
|
2991
|
-
|
|
3094
|
+
import { Type as Type4 } from "@mariozechner/pi-ai";
|
|
3095
|
+
var memoryDate, scorelMemoryPaths, scorelSessionMemoryPaths, buildMemoryContext, renderMemoryHarness, appendDailyEntry, createAppendDailyTool, renderDailyEntry, readMemoryDreamState, writeMemoryDreamState, readSessionMemory, writeSessionMemory, renderSessionMemory, ensureMemoryFiles, ensureFile, readOptional, trimForContext, compactLine, renderList, renderBullets, normalizeMarkdownFile, parseAppendDailyInput, validateAppendDailyInput, isLowSignalSummary, containsNormalizedDailyEntry, normalizeDailyText, requireString3, optionalStringArray, optionalNumber2, optionalString3, parseLastFailure, isRecord7, safeProjectId, isNodeErrorCode3;
|
|
2992
3096
|
var init_memory = __esm({
|
|
2993
3097
|
"packages/core/src/memory/index.ts"() {
|
|
2994
3098
|
"use strict";
|
|
@@ -3077,6 +3181,14 @@ var init_memory = __esm({
|
|
|
3077
3181
|
"Use this once near the end of a completed user turn when there is progress, a decision, or a follow-up worth preserving.",
|
|
3078
3182
|
"Do not include secrets, raw logs, speculation, or facts that should be re-read from the repository."
|
|
3079
3183
|
].join(" "),
|
|
3184
|
+
parameters: Type4.Object({
|
|
3185
|
+
summary: Type4.String(),
|
|
3186
|
+
completed: Type4.Optional(Type4.Array(Type4.String())),
|
|
3187
|
+
decisions: Type4.Optional(Type4.Array(Type4.String())),
|
|
3188
|
+
followUps: Type4.Optional(Type4.Array(Type4.String())),
|
|
3189
|
+
memoryCandidates: Type4.Optional(Type4.Array(Type4.String())),
|
|
3190
|
+
evidence: Type4.Optional(Type4.Array(Type4.String()))
|
|
3191
|
+
}),
|
|
3080
3192
|
execute: async (_toolCallId, args) => {
|
|
3081
3193
|
const input = parseAppendDailyInput(args);
|
|
3082
3194
|
validateAppendDailyInput(input);
|
|
@@ -3220,7 +3332,7 @@ var init_memory = __esm({
|
|
|
3220
3332
|
normalizeMarkdownFile = (value) => `${value.trimEnd()}
|
|
3221
3333
|
`;
|
|
3222
3334
|
parseAppendDailyInput = (value) => {
|
|
3223
|
-
if (!
|
|
3335
|
+
if (!isRecord7(value)) {
|
|
3224
3336
|
throw new Error("AppendDaily args must be an object");
|
|
3225
3337
|
}
|
|
3226
3338
|
const summary = requireString3(value.summary, "summary");
|
|
@@ -3286,12 +3398,12 @@ var init_memory = __esm({
|
|
|
3286
3398
|
optionalNumber2 = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
3287
3399
|
optionalString3 = (value) => typeof value === "string" && value.trim() ? value : void 0;
|
|
3288
3400
|
parseLastFailure = (value) => {
|
|
3289
|
-
if (!
|
|
3401
|
+
if (!isRecord7(value)) return void 0;
|
|
3290
3402
|
const at = optionalNumber2(value.at);
|
|
3291
3403
|
const message = optionalString3(value.message);
|
|
3292
3404
|
return at !== void 0 && message ? { at, message } : void 0;
|
|
3293
3405
|
};
|
|
3294
|
-
|
|
3406
|
+
isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3295
3407
|
safeProjectId = (projectId) => {
|
|
3296
3408
|
if (!/^[A-Za-z0-9_-]+$/.test(projectId)) {
|
|
3297
3409
|
throw new Error("projectId must contain only letters, numbers, underscores, or hyphens");
|
|
@@ -3302,16 +3414,65 @@ var init_memory = __esm({
|
|
|
3302
3414
|
}
|
|
3303
3415
|
});
|
|
3304
3416
|
|
|
3417
|
+
// packages/core/src/reminders/index.ts
|
|
3418
|
+
var createSystemReminderBlock, renderSystemReminderText, renderSystemReminder, systemReminderMessage, appendSystemReminderToToolResult, cloneSystemReminderBlock, isToolResultWithContent;
|
|
3419
|
+
var init_reminders = __esm({
|
|
3420
|
+
"packages/core/src/reminders/index.ts"() {
|
|
3421
|
+
"use strict";
|
|
3422
|
+
createSystemReminderBlock = (input) => ({
|
|
3423
|
+
type: "system_reminder",
|
|
3424
|
+
kind: input.kind,
|
|
3425
|
+
origin: input.origin,
|
|
3426
|
+
text: input.text,
|
|
3427
|
+
visibility: input.visibility,
|
|
3428
|
+
scope: input.scope,
|
|
3429
|
+
...input.data ? { data: { ...input.data } } : {}
|
|
3430
|
+
});
|
|
3431
|
+
renderSystemReminderText = (text) => `<system-reminder>
|
|
3432
|
+
${text}
|
|
3433
|
+
</system-reminder>`;
|
|
3434
|
+
renderSystemReminder = (input) => renderSystemReminderText(typeof input === "string" ? input : input.text);
|
|
3435
|
+
systemReminderMessage = (block, meta) => ({
|
|
3436
|
+
role: "user",
|
|
3437
|
+
content: [cloneSystemReminderBlock(block)],
|
|
3438
|
+
...meta ? { meta: { ...meta } } : {}
|
|
3439
|
+
});
|
|
3440
|
+
appendSystemReminderToToolResult = (message, block) => {
|
|
3441
|
+
for (let i = message.content.length - 1; i >= 0; i -= 1) {
|
|
3442
|
+
const candidate = message.content[i];
|
|
3443
|
+
if (candidate?.type !== "tool_result" || !isToolResultWithContent(candidate.result)) {
|
|
3444
|
+
continue;
|
|
3445
|
+
}
|
|
3446
|
+
const mergedResult = {
|
|
3447
|
+
...candidate.result,
|
|
3448
|
+
content: [...candidate.result.content, cloneSystemReminderBlock(block)]
|
|
3449
|
+
};
|
|
3450
|
+
message.content[i] = {
|
|
3451
|
+
...candidate,
|
|
3452
|
+
result: mergedResult
|
|
3453
|
+
};
|
|
3454
|
+
return true;
|
|
3455
|
+
}
|
|
3456
|
+
return false;
|
|
3457
|
+
};
|
|
3458
|
+
cloneSystemReminderBlock = (block) => ({
|
|
3459
|
+
...block,
|
|
3460
|
+
...block.data ? { data: { ...block.data } } : {}
|
|
3461
|
+
});
|
|
3462
|
+
isToolResultWithContent = (value) => typeof value === "object" && value !== null && "content" in value && Array.isArray(value.content);
|
|
3463
|
+
}
|
|
3464
|
+
});
|
|
3465
|
+
|
|
3305
3466
|
// packages/core/src/provider/pi-ai.ts
|
|
3306
3467
|
import {
|
|
3307
|
-
Type,
|
|
3308
3468
|
getModels,
|
|
3309
3469
|
streamSimple
|
|
3310
3470
|
} from "@mariozechner/pi-ai";
|
|
3311
|
-
var DEFAULT_CUSTOM_MODEL_CONTEXT_WINDOW, DEFAULT_CUSTOM_MODEL_MAX_TOKENS, createPiAiProvider, resolvePiAiModel, toPiContext, toPiMessage, toPiAssistantBlock, fromPiAssistant, fromPiContentBlock, toPiTool,
|
|
3471
|
+
var DEFAULT_CUSTOM_MODEL_CONTEXT_WINDOW, DEFAULT_CUSTOM_MODEL_MAX_TOKENS, createPiAiProvider, resolvePiAiModel, toPiContext, toPiMessage, toPiAssistantBlock, fromPiAssistant, fromPiContentBlock, toPiTool, textContent, toolResultText, isSystemReminderContentBlock, stringMeta, toPiStopReason, fromPiStopReason, fromPiUsage;
|
|
3312
3472
|
var init_pi_ai = __esm({
|
|
3313
3473
|
"packages/core/src/provider/pi-ai.ts"() {
|
|
3314
3474
|
"use strict";
|
|
3475
|
+
init_reminders();
|
|
3315
3476
|
DEFAULT_CUSTOM_MODEL_CONTEXT_WINDOW = 2e5;
|
|
3316
3477
|
DEFAULT_CUSTOM_MODEL_MAX_TOKENS = 64e3;
|
|
3317
3478
|
createPiAiProvider = (options) => ({
|
|
@@ -3410,6 +3571,9 @@ var init_pi_ai = __esm({
|
|
|
3410
3571
|
if (block.type === "text") {
|
|
3411
3572
|
return [{ type: "text", text: block.text }];
|
|
3412
3573
|
}
|
|
3574
|
+
if (block.type === "system_reminder") {
|
|
3575
|
+
return [{ type: "text", text: renderSystemReminder(block) }];
|
|
3576
|
+
}
|
|
3413
3577
|
if (block.type === "thinking") {
|
|
3414
3578
|
return [{ type: "thinking", thinking: block.text }];
|
|
3415
3579
|
}
|
|
@@ -3446,99 +3610,35 @@ var init_pi_ai = __esm({
|
|
|
3446
3610
|
toPiTool = (tool) => ({
|
|
3447
3611
|
name: tool.name,
|
|
3448
3612
|
description: tool.description,
|
|
3449
|
-
parameters:
|
|
3613
|
+
parameters: tool.parameters
|
|
3450
3614
|
});
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
return Type.Object({
|
|
3455
|
-
file_path: Type.String(),
|
|
3456
|
-
offset: Type.Optional(Type.Number()),
|
|
3457
|
-
limit: Type.Optional(Type.Number()),
|
|
3458
|
-
full: Type.Optional(Type.Boolean())
|
|
3459
|
-
});
|
|
3460
|
-
case "Write":
|
|
3461
|
-
return Type.Object({
|
|
3462
|
-
file_path: Type.String(),
|
|
3463
|
-
content: Type.String()
|
|
3464
|
-
});
|
|
3465
|
-
case "Edit":
|
|
3466
|
-
return Type.Object({
|
|
3467
|
-
file_path: Type.String(),
|
|
3468
|
-
old_string: Type.String(),
|
|
3469
|
-
new_string: Type.String(),
|
|
3470
|
-
replace_all: Type.Optional(Type.Boolean())
|
|
3471
|
-
});
|
|
3472
|
-
case "Bash":
|
|
3473
|
-
return Type.Object({
|
|
3474
|
-
command: Type.String(),
|
|
3475
|
-
cwd: Type.Optional(Type.String()),
|
|
3476
|
-
timeout: Type.Optional(Type.Number()),
|
|
3477
|
-
description: Type.Optional(Type.String()),
|
|
3478
|
-
maxOutputBytes: Type.Optional(Type.Number())
|
|
3479
|
-
});
|
|
3480
|
-
case "Glob":
|
|
3481
|
-
return Type.Object({
|
|
3482
|
-
pattern: Type.String(),
|
|
3483
|
-
path: Type.Optional(Type.String()),
|
|
3484
|
-
head_limit: Type.Optional(Type.Number()),
|
|
3485
|
-
offset: Type.Optional(Type.Number())
|
|
3486
|
-
});
|
|
3487
|
-
case "Grep":
|
|
3488
|
-
return Type.Object({
|
|
3489
|
-
pattern: Type.String(),
|
|
3490
|
-
path: Type.Optional(Type.String()),
|
|
3491
|
-
glob: Type.Optional(Type.String()),
|
|
3492
|
-
output_mode: Type.Optional(Type.Union([Type.Literal("files"), Type.Literal("content"), Type.Literal("count")])),
|
|
3493
|
-
"-B": Type.Optional(Type.Number()),
|
|
3494
|
-
"-A": Type.Optional(Type.Number()),
|
|
3495
|
-
"-C": Type.Optional(Type.Number()),
|
|
3496
|
-
context: Type.Optional(Type.Number()),
|
|
3497
|
-
"-n": Type.Optional(Type.Boolean()),
|
|
3498
|
-
"-i": Type.Optional(Type.Boolean()),
|
|
3499
|
-
type: Type.Optional(Type.String()),
|
|
3500
|
-
head_limit: Type.Optional(Type.Number()),
|
|
3501
|
-
offset: Type.Optional(Type.Number()),
|
|
3502
|
-
multiline: Type.Optional(Type.Boolean())
|
|
3503
|
-
});
|
|
3504
|
-
case "TodoWrite":
|
|
3505
|
-
return Type.Object({
|
|
3506
|
-
todos: Type.Array(
|
|
3507
|
-
Type.Object({
|
|
3508
|
-
content: Type.String(),
|
|
3509
|
-
status: Type.Union([Type.Literal("pending"), Type.Literal("in_progress"), Type.Literal("completed")]),
|
|
3510
|
-
activeForm: Type.Optional(Type.String())
|
|
3511
|
-
})
|
|
3512
|
-
)
|
|
3513
|
-
});
|
|
3514
|
-
case "AppendDaily":
|
|
3515
|
-
return Type.Object({
|
|
3516
|
-
summary: Type.String(),
|
|
3517
|
-
completed: Type.Optional(Type.Array(Type.String())),
|
|
3518
|
-
decisions: Type.Optional(Type.Array(Type.String())),
|
|
3519
|
-
followUps: Type.Optional(Type.Array(Type.String())),
|
|
3520
|
-
memoryCandidates: Type.Optional(Type.Array(Type.String())),
|
|
3521
|
-
evidence: Type.Optional(Type.Array(Type.String()))
|
|
3522
|
-
});
|
|
3523
|
-
case "Skill":
|
|
3524
|
-
return Type.Object({
|
|
3525
|
-
name: Type.String(),
|
|
3526
|
-
args: Type.Optional(Type.String())
|
|
3527
|
-
});
|
|
3528
|
-
default:
|
|
3529
|
-
return Type.Object({});
|
|
3615
|
+
textContent = (message) => message.content.flatMap((block) => {
|
|
3616
|
+
if (block.type === "text") {
|
|
3617
|
+
return [block.text];
|
|
3530
3618
|
}
|
|
3531
|
-
|
|
3532
|
-
|
|
3619
|
+
if (block.type === "system_reminder") {
|
|
3620
|
+
return [renderSystemReminder(block)];
|
|
3621
|
+
}
|
|
3622
|
+
return [];
|
|
3623
|
+
}).join("\n");
|
|
3533
3624
|
toolResultText = (result) => {
|
|
3534
3625
|
if (typeof result === "object" && result !== null && "content" in result) {
|
|
3535
3626
|
const content = result.content;
|
|
3536
3627
|
if (Array.isArray(content)) {
|
|
3537
|
-
return content.
|
|
3628
|
+
return content.flatMap((block) => {
|
|
3629
|
+
if (block?.type === "text" && typeof block.text === "string") {
|
|
3630
|
+
return [block.text];
|
|
3631
|
+
}
|
|
3632
|
+
if (isSystemReminderContentBlock(block)) {
|
|
3633
|
+
return [renderSystemReminder(block)];
|
|
3634
|
+
}
|
|
3635
|
+
return [];
|
|
3636
|
+
}).join("\n");
|
|
3538
3637
|
}
|
|
3539
3638
|
}
|
|
3540
3639
|
return JSON.stringify(result);
|
|
3541
3640
|
};
|
|
3641
|
+
isSystemReminderContentBlock = (value) => typeof value === "object" && value !== null && value.type === "system_reminder" && typeof value.text === "string";
|
|
3542
3642
|
stringMeta = (message, key) => {
|
|
3543
3643
|
const value = message.meta?.[key];
|
|
3544
3644
|
return typeof value === "string" ? value : void 0;
|
|
@@ -3776,22 +3876,23 @@ var init_runtime = __esm({
|
|
|
3776
3876
|
});
|
|
3777
3877
|
|
|
3778
3878
|
// packages/core/src/session/index.ts
|
|
3879
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
3779
3880
|
import { appendFile as appendFile2, mkdir as mkdir4, readFile as readFile8, writeFile as writeFile4 } from "node:fs/promises";
|
|
3780
3881
|
import { dirname as dirname6, join as join7 } from "node:path";
|
|
3781
3882
|
function assertTreeEvent(value) {
|
|
3782
|
-
if (!
|
|
3883
|
+
if (!isRecord8(value)) {
|
|
3783
3884
|
throw new SessionStoreError("invalid_event", "Event must be an object");
|
|
3784
3885
|
}
|
|
3785
3886
|
if (value.type === "session_header") {
|
|
3786
3887
|
throw new SessionStoreError("invalid_event", "Session header must be stored as the JSONL header line");
|
|
3787
3888
|
}
|
|
3788
|
-
if (value.type !== "user_message" && value.type !== "assistant_message" && value.type !== "tool_result" && value.type !== "session_title_updated" && value.type !== "instruction_snapshot" && value.type !== "harness_item" && value.type !== "compact" && value.type !== "queue_update" && value.type !== "skill_index_snapshot" && value.type !== "skill_index_delta") {
|
|
3889
|
+
if (value.type !== "user_message" && value.type !== "assistant_message" && value.type !== "tool_result" && value.type !== "session_title_updated" && value.type !== "instruction_snapshot" && value.type !== "harness_item" && value.type !== "compact" && value.type !== "context_control" && value.type !== "queue_update" && value.type !== "skill_index_snapshot" && value.type !== "skill_index_delta") {
|
|
3789
3890
|
throw new SessionStoreError("invalid_event", "Unsupported session event type");
|
|
3790
3891
|
}
|
|
3791
3892
|
if (typeof value.id !== "string" || value.parentId !== null && typeof value.parentId !== "string" || typeof value.seq !== "number" || typeof value.clientId !== "string" || typeof value.ts !== "number") {
|
|
3792
3893
|
throw new SessionStoreError("invalid_event", "Event is missing required base fields");
|
|
3793
3894
|
}
|
|
3794
|
-
if ((value.type === "user_message" || value.type === "assistant_message" || value.type === "tool_result") && !
|
|
3895
|
+
if ((value.type === "user_message" || value.type === "assistant_message" || value.type === "tool_result") && !isRecord8(value.message)) {
|
|
3795
3896
|
throw new SessionStoreError("invalid_event", "Message event is missing message payload");
|
|
3796
3897
|
}
|
|
3797
3898
|
if (value.type === "session_title_updated" && !isSessionTitleUpdated(value)) {
|
|
@@ -3806,6 +3907,9 @@ function assertTreeEvent(value) {
|
|
|
3806
3907
|
if (value.type === "compact" && !isCompactEvent(value)) {
|
|
3807
3908
|
throw new SessionStoreError("invalid_event", "compact is missing summary payload");
|
|
3808
3909
|
}
|
|
3910
|
+
if (value.type === "context_control" && !isContextControlEvent(value)) {
|
|
3911
|
+
throw new SessionStoreError("invalid_event", "context_control is missing hide_user_turn payload");
|
|
3912
|
+
}
|
|
3809
3913
|
if (value.type === "queue_update" && !isQueueUpdate(value)) {
|
|
3810
3914
|
throw new SessionStoreError("invalid_event", "queue_update is missing queue payload");
|
|
3811
3915
|
}
|
|
@@ -3816,11 +3920,13 @@ function assertTreeEvent(value) {
|
|
|
3816
3920
|
throw new SessionStoreError("invalid_event", "skill_index_delta is missing delta payload");
|
|
3817
3921
|
}
|
|
3818
3922
|
}
|
|
3819
|
-
var SessionStoreError, SessionTree, JsonlSession, sessionFilePath, sessionLogFilePath, sessionArtifactsDirPath, createSession, loadSession, buildContext, retainedMessagesBeforeCompact, isRetainedContextStart, parseJsonLine, parseHeader, parseSessionEvent, validateSessionMatch, isConversationEvent, isInstructionSnapshot, isHarnessItem, isCompactEvent, isQueueUpdate, isSessionTitleUpdated, isSkillIndexSnapshot, isSkillIndexDelta, isSkillIndexEntry, appendHarnessItemToContext,
|
|
3923
|
+
var snipUserMessageAlias, SessionStoreError, SessionTree, JsonlSession, sessionFilePath, sessionLogFilePath, sessionArtifactsDirPath, createSession, loadSession, buildContext, hiddenContextEventIds, retainedMessagesBeforeCompact, isRetainedContextStart, parseJsonLine, parseHeader, parseSessionEvent, validateSessionMatch, isConversationEvent, isInstructionSnapshot, isHarnessItem, isCompactEvent, isContextControlEvent, isQueueUpdate, isSessionTitleUpdated, isSkillIndexSnapshot, isSkillIndexDelta, isSkillIndexEntry, appendHarnessItemToContext, compactSummaryMessage, reminderKindFromHarness, reminderVisibilityFromHarness, reminderScopeFromHarness, cloneMessage, isRecord8;
|
|
3820
3924
|
var init_session = __esm({
|
|
3821
3925
|
"packages/core/src/session/index.ts"() {
|
|
3822
3926
|
"use strict";
|
|
3823
3927
|
init_src();
|
|
3928
|
+
init_reminders();
|
|
3929
|
+
snipUserMessageAlias = (eventId) => `u_${createHash2("sha256").update(eventId).digest("hex").slice(0, 8)}`;
|
|
3824
3930
|
SessionStoreError = class extends Error {
|
|
3825
3931
|
code;
|
|
3826
3932
|
line;
|
|
@@ -3844,7 +3950,8 @@ var init_session = __esm({
|
|
|
3844
3950
|
steer: []
|
|
3845
3951
|
},
|
|
3846
3952
|
skillIndexInitialized: false,
|
|
3847
|
-
skillIndex: {}
|
|
3953
|
+
skillIndex: {},
|
|
3954
|
+
hiddenUserTurnSpans: []
|
|
3848
3955
|
};
|
|
3849
3956
|
get rootId() {
|
|
3850
3957
|
return this.#rootId;
|
|
@@ -3964,6 +4071,16 @@ var init_session = __esm({
|
|
|
3964
4071
|
delete next[removed.name];
|
|
3965
4072
|
}
|
|
3966
4073
|
this.controlState.skillIndex = next;
|
|
4074
|
+
} else if (event.type === "context_control") {
|
|
4075
|
+
this.controlState.hiddenUserTurnSpans = [
|
|
4076
|
+
...this.controlState.hiddenUserTurnSpans.filter(
|
|
4077
|
+
(span) => span.anchorUserEventId !== event.anchorUserEventId
|
|
4078
|
+
),
|
|
4079
|
+
{
|
|
4080
|
+
anchorUserEventId: event.anchorUserEventId,
|
|
4081
|
+
throughEventId: event.throughEventId
|
|
4082
|
+
}
|
|
4083
|
+
];
|
|
3967
4084
|
}
|
|
3968
4085
|
}
|
|
3969
4086
|
};
|
|
@@ -4025,7 +4142,11 @@ var init_session = __esm({
|
|
|
4025
4142
|
};
|
|
4026
4143
|
buildContext = (tree, leafId) => {
|
|
4027
4144
|
const path = tree.getPath(leafId);
|
|
4145
|
+
const hiddenIds = hiddenContextEventIds(tree, path, leafId);
|
|
4028
4146
|
return path.reduce((messages, id, index) => {
|
|
4147
|
+
if (hiddenIds.has(id)) {
|
|
4148
|
+
return messages;
|
|
4149
|
+
}
|
|
4029
4150
|
const event = tree.get(id)?.event;
|
|
4030
4151
|
if (!event) {
|
|
4031
4152
|
return messages;
|
|
@@ -4038,7 +4159,7 @@ var init_session = __esm({
|
|
|
4038
4159
|
appendHarnessItemToContext(messages, event);
|
|
4039
4160
|
}
|
|
4040
4161
|
if (event.type === "compact") {
|
|
4041
|
-
const retained = retainedMessagesBeforeCompact(tree, path.slice(0, index), event.retainedEventCount);
|
|
4162
|
+
const retained = retainedMessagesBeforeCompact(tree, path.slice(0, index), event.retainedEventCount, hiddenIds);
|
|
4042
4163
|
messages.length = 0;
|
|
4043
4164
|
messages.push(compactSummaryMessage(event));
|
|
4044
4165
|
messages.push(...retained);
|
|
@@ -4046,7 +4167,29 @@ var init_session = __esm({
|
|
|
4046
4167
|
return messages;
|
|
4047
4168
|
}, []);
|
|
4048
4169
|
};
|
|
4049
|
-
|
|
4170
|
+
hiddenContextEventIds = (tree, path, leafId) => {
|
|
4171
|
+
const leaf = tree.get(leafId)?.event;
|
|
4172
|
+
if (!leaf) {
|
|
4173
|
+
return /* @__PURE__ */ new Set();
|
|
4174
|
+
}
|
|
4175
|
+
const pathIndexes = new Map(path.map((id, index) => [id, index]));
|
|
4176
|
+
const hidden = /* @__PURE__ */ new Set();
|
|
4177
|
+
for (const event of tree) {
|
|
4178
|
+
if (event.type !== "context_control" || Number(event.seq) > Number(leaf.seq)) {
|
|
4179
|
+
continue;
|
|
4180
|
+
}
|
|
4181
|
+
const start = pathIndexes.get(event.anchorUserEventId);
|
|
4182
|
+
const end = pathIndexes.get(event.throughEventId);
|
|
4183
|
+
if (start === void 0 || end === void 0 || end < start) {
|
|
4184
|
+
continue;
|
|
4185
|
+
}
|
|
4186
|
+
for (const id of path.slice(start, end + 1)) {
|
|
4187
|
+
hidden.add(id);
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4190
|
+
return hidden;
|
|
4191
|
+
};
|
|
4192
|
+
retainedMessagesBeforeCompact = (tree, pathBeforeCompact, retainedEventCount, hiddenIds = /* @__PURE__ */ new Set()) => {
|
|
4050
4193
|
if (retainedEventCount <= 0) {
|
|
4051
4194
|
return [];
|
|
4052
4195
|
}
|
|
@@ -4061,6 +4204,9 @@ var init_session = __esm({
|
|
|
4061
4204
|
}
|
|
4062
4205
|
const retained = [];
|
|
4063
4206
|
for (const id of pathBeforeCompact.slice(start)) {
|
|
4207
|
+
if (hiddenIds.has(id)) {
|
|
4208
|
+
continue;
|
|
4209
|
+
}
|
|
4064
4210
|
const event = tree.get(id)?.event;
|
|
4065
4211
|
if (!event) {
|
|
4066
4212
|
continue;
|
|
@@ -4085,13 +4231,13 @@ var init_session = __esm({
|
|
|
4085
4231
|
}
|
|
4086
4232
|
};
|
|
4087
4233
|
parseHeader = (value) => {
|
|
4088
|
-
if (!
|
|
4234
|
+
if (!isRecord8(value)) {
|
|
4089
4235
|
throw new SessionStoreError("invalid_header", "Session header must be an object");
|
|
4090
4236
|
}
|
|
4091
4237
|
if (value.version !== 1 || typeof value.sessionId !== "string" || typeof value.deviceId !== "string") {
|
|
4092
4238
|
throw new SessionStoreError("invalid_header", "Session header is missing required identity fields");
|
|
4093
4239
|
}
|
|
4094
|
-
if (typeof value.createdAt !== "number" || !
|
|
4240
|
+
if (typeof value.createdAt !== "number" || !isRecord8(value.meta)) {
|
|
4095
4241
|
throw new SessionStoreError("invalid_header", "Session header is missing createdAt or meta");
|
|
4096
4242
|
}
|
|
4097
4243
|
if (typeof value.meta.projectId !== "string" || value.meta.projectId.length === 0) {
|
|
@@ -4105,7 +4251,7 @@ var init_session = __esm({
|
|
|
4105
4251
|
return value;
|
|
4106
4252
|
};
|
|
4107
4253
|
validateSessionMatch = (header, value) => {
|
|
4108
|
-
if (!
|
|
4254
|
+
if (!isRecord8(value) || typeof value.sessionId !== "string") {
|
|
4109
4255
|
throw new SessionStoreError("invalid_header", "Event must be an object with a sessionId");
|
|
4110
4256
|
}
|
|
4111
4257
|
if (value.sessionId !== header.sessionId) {
|
|
@@ -4114,88 +4260,98 @@ var init_session = __esm({
|
|
|
4114
4260
|
};
|
|
4115
4261
|
isConversationEvent = (event) => event.type === "user_message" || event.type === "assistant_message" || event.type === "tool_result" || event.type === "harness_item" || event.type === "compact";
|
|
4116
4262
|
isInstructionSnapshot = (value) => {
|
|
4117
|
-
if (!
|
|
4263
|
+
if (!isRecord8(value) || value.version !== 1 || typeof value.cwd !== "string" || !Array.isArray(value.sections)) {
|
|
4118
4264
|
return false;
|
|
4119
4265
|
}
|
|
4120
4266
|
return value.sections.every(
|
|
4121
|
-
(section2) =>
|
|
4267
|
+
(section2) => isRecord8(section2) && typeof section2.kind === "string" && typeof section2.frozenAt === "number" && typeof section2.renderedBlock === "string"
|
|
4122
4268
|
);
|
|
4123
4269
|
};
|
|
4124
|
-
isHarnessItem = (value) =>
|
|
4270
|
+
isHarnessItem = (value) => isRecord8(value) && typeof value.kind === "string" && typeof value.origin === "string" && typeof value.content === "string" && (value.visibility === "display" || value.visibility === "hidden" || value.visibility === "compact");
|
|
4125
4271
|
isCompactEvent = (value) => typeof value.summary === "string" && typeof value.compactedThrough === "string" && typeof value.tokensBefore === "number" && typeof value.tokensAfter === "number" && typeof value.retainedEventCount === "number";
|
|
4272
|
+
isContextControlEvent = (value) => value.operation === "hide_user_turn" && typeof value.anchorUserEventId === "string" && typeof value.throughEventId === "string" && (value.actor === "agent" || value.actor === "user" || value.actor === "system") && (value.reason === void 0 || typeof value.reason === "string");
|
|
4126
4273
|
isQueueUpdate = (value) => (value.queue === "follow_up" || value.queue === "steer") && value.operation === "rewrite" && Array.isArray(value.items) && (value.anchorEventId === null || typeof value.anchorEventId === "string") && value.items.every(
|
|
4127
|
-
(item) =>
|
|
4274
|
+
(item) => isRecord8(item) && typeof item.id === "string" && Array.isArray(item.content) && typeof item.createdAt === "number" && typeof item.updatedAt === "number" && typeof item.clientId === "string"
|
|
4128
4275
|
);
|
|
4129
|
-
isSessionTitleUpdated = (value) => typeof value.title === "string" && value.title.length > 0 && (value.source === "model" || value.source === "user") && (value.derivedFrom === void 0 ||
|
|
4276
|
+
isSessionTitleUpdated = (value) => typeof value.title === "string" && value.title.length > 0 && (value.source === "model" || value.source === "user") && (value.derivedFrom === void 0 || isRecord8(value.derivedFrom) && typeof value.derivedFrom.eventId === "string" && typeof value.derivedFrom.seq === "number");
|
|
4130
4277
|
isSkillIndexSnapshot = (value) => (value.anchorEventId === null || typeof value.anchorEventId === "string") && Array.isArray(value.entries) && value.entries.every(isSkillIndexEntry);
|
|
4131
4278
|
isSkillIndexDelta = (value) => (value.anchorEventId === null || typeof value.anchorEventId === "string") && Array.isArray(value.added) && Array.isArray(value.changed) && Array.isArray(value.removed) && value.added.every(isSkillIndexEntry) && value.changed.every(isSkillIndexEntry) && value.removed.every(
|
|
4132
|
-
(item) =>
|
|
4279
|
+
(item) => isRecord8(item) && typeof item.name === "string" && typeof item.previousPath === "string"
|
|
4133
4280
|
);
|
|
4134
|
-
isSkillIndexEntry = (value) =>
|
|
4281
|
+
isSkillIndexEntry = (value) => isRecord8(value) && typeof value.name === "string" && typeof value.path === "string" && (value.scope === "user" || value.scope === "project" || value.scope === "extension") && typeof value.description === "string" && typeof value.mtimeMs === "number" && typeof value.size === "number" && typeof value.contentHash === "string" && typeof value.priority === "number";
|
|
4135
4282
|
appendHarnessItemToContext = (messages, event) => {
|
|
4136
|
-
const reminder =
|
|
4283
|
+
const reminder = createSystemReminderBlock({
|
|
4284
|
+
kind: reminderKindFromHarness(event.item.kind),
|
|
4285
|
+
origin: event.item.origin,
|
|
4286
|
+
text: event.item.content,
|
|
4287
|
+
visibility: reminderVisibilityFromHarness(event.item.visibility),
|
|
4288
|
+
scope: reminderScopeFromHarness(event.item.kind),
|
|
4289
|
+
...event.item.data ? { data: event.item.data } : {}
|
|
4290
|
+
});
|
|
4137
4291
|
const last = messages.at(-1);
|
|
4138
|
-
if (last?.role === "tool_result" &&
|
|
4292
|
+
if (last?.role === "tool_result" && appendSystemReminderToToolResult(last, reminder)) {
|
|
4139
4293
|
return;
|
|
4140
4294
|
}
|
|
4141
|
-
messages.push({
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
harnessKind: event.item.kind,
|
|
4147
|
-
harnessOrigin: event.item.origin
|
|
4148
|
-
}
|
|
4149
|
-
});
|
|
4295
|
+
messages.push(systemReminderMessage(reminder, {
|
|
4296
|
+
source: "harness_item",
|
|
4297
|
+
harnessKind: event.item.kind,
|
|
4298
|
+
harnessOrigin: event.item.origin
|
|
4299
|
+
}));
|
|
4150
4300
|
};
|
|
4151
|
-
appendReminderToToolResult = (message, reminder) => {
|
|
4152
|
-
for (let i = message.content.length - 1; i >= 0; i -= 1) {
|
|
4153
|
-
const block = message.content[i];
|
|
4154
|
-
if (block?.type !== "tool_result" || !isToolResultWithContent(block.result)) {
|
|
4155
|
-
continue;
|
|
4156
|
-
}
|
|
4157
|
-
const mergedResult = {
|
|
4158
|
-
...block.result,
|
|
4159
|
-
content: [...block.result.content, { type: "text", text: `
|
|
4160
|
-
|
|
4161
|
-
${reminder}` }]
|
|
4162
|
-
};
|
|
4163
|
-
message.content[i] = {
|
|
4164
|
-
...block,
|
|
4165
|
-
result: mergedResult
|
|
4166
|
-
};
|
|
4167
|
-
return true;
|
|
4168
|
-
}
|
|
4169
|
-
return false;
|
|
4170
|
-
};
|
|
4171
|
-
isToolResultWithContent = (value) => isRecord7(value) && Array.isArray(value.content);
|
|
4172
|
-
renderSystemReminder = (content) => `<system-reminder>
|
|
4173
|
-
${content}
|
|
4174
|
-
</system-reminder>`;
|
|
4175
4301
|
compactSummaryMessage = (event) => ({
|
|
4176
4302
|
role: "user",
|
|
4177
|
-
content: [{
|
|
4178
|
-
|
|
4179
|
-
|
|
4303
|
+
content: [createSystemReminderBlock({
|
|
4304
|
+
kind: "compact_summary",
|
|
4305
|
+
origin: "system",
|
|
4306
|
+
text: [
|
|
4180
4307
|
"Earlier session context has been compacted.",
|
|
4181
4308
|
"",
|
|
4182
4309
|
event.summary.trim(),
|
|
4183
4310
|
"",
|
|
4184
4311
|
"Use this summary as continuity context. Verify current repository facts before acting."
|
|
4185
|
-
].join("\n")
|
|
4186
|
-
|
|
4312
|
+
].join("\n"),
|
|
4313
|
+
visibility: "model",
|
|
4314
|
+
scope: "session"
|
|
4315
|
+
})],
|
|
4187
4316
|
meta: {
|
|
4188
4317
|
source: "compact",
|
|
4189
4318
|
compactedThrough: event.compactedThrough
|
|
4190
4319
|
}
|
|
4191
4320
|
});
|
|
4321
|
+
reminderKindFromHarness = (kind) => {
|
|
4322
|
+
if (kind === "attachment" || kind === "skill_listing" || kind === "skill_delta" || kind === "memory" || kind === "channel_context" || kind === "steer" || kind === "runtime_notice") {
|
|
4323
|
+
return kind;
|
|
4324
|
+
}
|
|
4325
|
+
if (kind === "date_change") {
|
|
4326
|
+
return "time";
|
|
4327
|
+
}
|
|
4328
|
+
return "runtime_notice";
|
|
4329
|
+
};
|
|
4330
|
+
reminderVisibilityFromHarness = (visibility) => {
|
|
4331
|
+
if (visibility === "hidden") {
|
|
4332
|
+
return "model";
|
|
4333
|
+
}
|
|
4334
|
+
return visibility;
|
|
4335
|
+
};
|
|
4336
|
+
reminderScopeFromHarness = (kind) => {
|
|
4337
|
+
if (kind === "steer" || kind === "skill_delta" || kind === "runtime_notice") {
|
|
4338
|
+
return "next_model_call";
|
|
4339
|
+
}
|
|
4340
|
+
if (kind === "channel_context" || kind === "attachment" || kind === "date_change") {
|
|
4341
|
+
return "turn";
|
|
4342
|
+
}
|
|
4343
|
+
return "session";
|
|
4344
|
+
};
|
|
4192
4345
|
cloneMessage = (message) => ({
|
|
4193
4346
|
...message,
|
|
4194
4347
|
content: message.content.map((block) => {
|
|
4195
|
-
if (block.type
|
|
4348
|
+
if (block.type === "system_reminder") {
|
|
4349
|
+
return cloneSystemReminderBlock(block);
|
|
4350
|
+
}
|
|
4351
|
+
if (block.type !== "tool_result" || !isRecord8(block.result)) {
|
|
4196
4352
|
return { ...block };
|
|
4197
4353
|
}
|
|
4198
|
-
const content = Array.isArray(block.result.content) ? { content: block.result.content.map((item) =>
|
|
4354
|
+
const content = Array.isArray(block.result.content) ? { content: block.result.content.map((item) => isRecord8(item) ? { ...item } : item) } : {};
|
|
4199
4355
|
return {
|
|
4200
4356
|
...block,
|
|
4201
4357
|
result: {
|
|
@@ -4205,16 +4361,17 @@ ${content}
|
|
|
4205
4361
|
}),
|
|
4206
4362
|
...message.meta ? { meta: { ...message.meta } } : {}
|
|
4207
4363
|
});
|
|
4208
|
-
|
|
4364
|
+
isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4209
4365
|
}
|
|
4210
4366
|
});
|
|
4211
4367
|
|
|
4212
4368
|
// packages/core/src/skills/index.ts
|
|
4213
|
-
import { createHash as
|
|
4369
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
4214
4370
|
import { existsSync as existsSync2 } from "node:fs";
|
|
4215
4371
|
import { readdir as readdir5, readFile as readFile9, stat as stat4 } from "node:fs/promises";
|
|
4216
4372
|
import { homedir as homedir4 } from "node:os";
|
|
4217
4373
|
import { dirname as dirname7, join as join8, resolve as resolve4 } from "node:path";
|
|
4374
|
+
import { Type as Type5 } from "@mariozechner/pi-ai";
|
|
4218
4375
|
var scanSkillIndex, diffSkillIndex, hasSkillIndexDelta, renderSkillListing, renderSkillDelta, createSkillTool, projectSkillRoots, readSkillEntry, parseSkillMetadata, firstParagraph, parseSkillArgs, findGitRoot2, isNodeErrorCode4;
|
|
4219
4376
|
var init_skills = __esm({
|
|
4220
4377
|
"packages/core/src/skills/index.ts"() {
|
|
@@ -4305,6 +4462,10 @@ var init_skills = __esm({
|
|
|
4305
4462
|
createSkillTool = (options) => defineTool({
|
|
4306
4463
|
name: "Skill",
|
|
4307
4464
|
description: "Load the full SKILL.md instructions for an available session-indexed skill by name.",
|
|
4465
|
+
parameters: Type5.Object({
|
|
4466
|
+
name: Type5.String(),
|
|
4467
|
+
args: Type5.Optional(Type5.String())
|
|
4468
|
+
}),
|
|
4308
4469
|
execute: async (_toolCallId, args) => {
|
|
4309
4470
|
const input = parseSkillArgs(args);
|
|
4310
4471
|
const entry = options.getEntry(input.name);
|
|
@@ -4369,7 +4530,7 @@ var init_skills = __esm({
|
|
|
4369
4530
|
...parsed.displayName ? { displayName: parsed.displayName } : {},
|
|
4370
4531
|
mtimeMs: fileStat.mtimeMs,
|
|
4371
4532
|
size: fileStat.size,
|
|
4372
|
-
contentHash:
|
|
4533
|
+
contentHash: createHash3("sha256").update(content).digest("hex"),
|
|
4373
4534
|
priority: options.priority
|
|
4374
4535
|
};
|
|
4375
4536
|
};
|
|
@@ -4446,6 +4607,7 @@ var init_src3 = __esm({
|
|
|
4446
4607
|
init_instructions();
|
|
4447
4608
|
init_memory();
|
|
4448
4609
|
init_pi_ai();
|
|
4610
|
+
init_reminders();
|
|
4449
4611
|
init_runtime();
|
|
4450
4612
|
init_session();
|
|
4451
4613
|
init_skills();
|
|
@@ -4785,7 +4947,7 @@ import { basename as basename3, dirname as dirname8, join as join10, resolve as
|
|
|
4785
4947
|
import { pathToFileURL } from "node:url";
|
|
4786
4948
|
import { promisify as promisify2 } from "node:util";
|
|
4787
4949
|
import { WebSocketServer } from "ws";
|
|
4788
|
-
var daemonPackageName, SESSION_MEMORY_COMPACT_WAIT_MS, AUTO_COMPACT_RETAINED_EVENTS, execFileAsync2, localDaemonStateFile, createLocalDaemonState, readLocalDaemonState, removeLocalDaemonState, markDaemonStopped, daemonStateLiveness, defaultIsPidAlive, startRemoteDaemonWebSocketServer, startScorelHostWebSocketServer, closeWebSocketServer, createRealRuntime, ScorelHost, isMissingConfigError, createEmbeddedTransport, isNodeErrorCode5, wireErrorCode, hasContinuousCoverage, countContentBlocks, normalizeContent, inputText, assistantText, messageText, estimateScorelMessagesTokens, estimateTextTokens, compactLine2, parseSessionMemoryJson, stringArray, disabledMemorySettings, detectRtk, ensureRtkAvailable, emptyRuntimeStats, readRuntimeStats, writeRuntimeStats, parseRuntimeStats, parseRuntimeStatsBuckets, addRtkSavings, addRuntimeStatsBucket, rtkSavingsFromToolResult, nonNegativeInteger2, resolveDefaultShell2, shellCommandArgs2, userShell2, runtimeChannelContextFromWire, parseQueuedChannelContext, parseQueuedModelSelection, imBindingKey, defaultBuiltinExtensionsDir, runtimeModuleDir, findBuiltinExtensionsDir, isSteerMessage, stripImCommandPrefix,
|
|
4950
|
+
var daemonPackageName, SESSION_MEMORY_COMPACT_WAIT_MS, AUTO_COMPACT_RETAINED_EVENTS, execFileAsync2, localDaemonStateFile, createLocalDaemonState, readLocalDaemonState, removeLocalDaemonState, markDaemonStopped, daemonStateLiveness, defaultIsPidAlive, startRemoteDaemonWebSocketServer, startScorelHostWebSocketServer, closeWebSocketServer, createRealRuntime, ScorelHost, isMissingConfigError, createEmbeddedTransport, isNodeErrorCode5, wireErrorCode, hasContinuousCoverage, countContentBlocks, normalizeContent, snipUserMessageIdBlock, inputText, assistantText, messageText, estimateScorelMessagesTokens, estimateTextTokens, compactLine2, parseSessionMemoryJson, stringArray, disabledMemorySettings, detectRtk, ensureRtkAvailable, emptyRuntimeStats, readRuntimeStats, writeRuntimeStats, parseRuntimeStats, parseRuntimeStatsBuckets, addRtkSavings, addRuntimeStatsBucket, rtkSavingsFromToolResult, nonNegativeInteger2, resolveDefaultShell2, shellCommandArgs2, userShell2, runtimeChannelContextFromWire, parseQueuedChannelContext, parseQueuedModelSelection, imBindingKey, defaultBuiltinExtensionsDir, runtimeModuleDir, findBuiltinExtensionsDir, isSteerMessage, stripImCommandPrefix, isRecord9, parseMemoryUpdate, normalizeMarkdownFile2, sanitizeSessionTitle, shortStack, formatDiagnosticLine, formatDiagnosticValue;
|
|
4789
4951
|
var init_src4 = __esm({
|
|
4790
4952
|
"packages/daemon/src/index.ts"() {
|
|
4791
4953
|
"use strict";
|
|
@@ -5502,7 +5664,7 @@ var init_src4 = __esm({
|
|
|
5502
5664
|
ts: this.#now(),
|
|
5503
5665
|
message: {
|
|
5504
5666
|
role: "user",
|
|
5505
|
-
content: input.content,
|
|
5667
|
+
content: [...input.content, snipUserMessageIdBlock(userEventId)],
|
|
5506
5668
|
...input.source === "follow_up" ? { meta: { source: "follow_up", queueItemId: input.queueItemId } } : {}
|
|
5507
5669
|
}
|
|
5508
5670
|
});
|
|
@@ -5522,6 +5684,7 @@ var init_src4 = __esm({
|
|
|
5522
5684
|
finalAssistantEventId: firstAssistantEventId
|
|
5523
5685
|
};
|
|
5524
5686
|
lane.channelContext = input.channelContext;
|
|
5687
|
+
lane.snipClientId = clientId;
|
|
5525
5688
|
try {
|
|
5526
5689
|
for await (const rawEvent of lane.runtime.executeTurn(
|
|
5527
5690
|
buildContext(lane.session.tree, userEvent.id),
|
|
@@ -5537,6 +5700,7 @@ var init_src4 = __esm({
|
|
|
5537
5700
|
}
|
|
5538
5701
|
} finally {
|
|
5539
5702
|
lane.channelContext = void 0;
|
|
5703
|
+
lane.snipClientId = void 0;
|
|
5540
5704
|
lane.runtime.unregisterTool("SendChannelMessage");
|
|
5541
5705
|
}
|
|
5542
5706
|
const result = { userEventId, assistantEventId: state.finalAssistantEventId };
|
|
@@ -6786,6 +6950,80 @@ var init_src4 = __esm({
|
|
|
6786
6950
|
listNames: () => Object.keys(lane.session.tree.controlState.skillIndex).sort()
|
|
6787
6951
|
})
|
|
6788
6952
|
);
|
|
6953
|
+
lane.runtime.registerTool(
|
|
6954
|
+
createSnipTool({
|
|
6955
|
+
snip: async (input) => this.#snipUserTurn(lane, input.userMessageId, input.reason)
|
|
6956
|
+
})
|
|
6957
|
+
);
|
|
6958
|
+
}
|
|
6959
|
+
async #snipUserTurn(lane, userMessageId, reason) {
|
|
6960
|
+
const leafId = lane.session.activeLeafId;
|
|
6961
|
+
if (!leafId) {
|
|
6962
|
+
throw new Error("snip requires an active conversation");
|
|
6963
|
+
}
|
|
6964
|
+
const path = lane.session.tree.getPath(leafId);
|
|
6965
|
+
const anchorUserEventId = this.#resolveSnipUserMessageId(lane, path, userMessageId);
|
|
6966
|
+
const anchorIndex = path.findIndex((id) => id === anchorUserEventId);
|
|
6967
|
+
if (anchorIndex < 0) {
|
|
6968
|
+
throw new Error(`snip target is not on the active conversation path: ${anchorUserEventId}`);
|
|
6969
|
+
}
|
|
6970
|
+
const anchor = lane.session.tree.get(anchorUserEventId)?.event;
|
|
6971
|
+
if (anchor?.type !== "user_message") {
|
|
6972
|
+
throw new Error(`snip target must be a user_message: ${anchorUserEventId}`);
|
|
6973
|
+
}
|
|
6974
|
+
const nextUserIndex = path.findIndex(
|
|
6975
|
+
(id, index) => index > anchorIndex && lane.session.tree.get(id)?.event.type === "user_message"
|
|
6976
|
+
);
|
|
6977
|
+
if (nextUserIndex < 0) {
|
|
6978
|
+
throw new Error("snip cannot hide the current user turn before the next user message exists");
|
|
6979
|
+
}
|
|
6980
|
+
const throughEventId = path[nextUserIndex - 1];
|
|
6981
|
+
if (!throughEventId || throughEventId === anchorUserEventId) {
|
|
6982
|
+
throw new Error(`snip target has no completed turn content: ${anchorUserEventId}`);
|
|
6983
|
+
}
|
|
6984
|
+
const clientId = lane.snipClientId;
|
|
6985
|
+
if (!clientId) {
|
|
6986
|
+
throw new Error("snip is only available while a user turn is running");
|
|
6987
|
+
}
|
|
6988
|
+
await this.#appendPersistent(lane, {
|
|
6989
|
+
type: "context_control",
|
|
6990
|
+
id: asEventId(this.#createId()),
|
|
6991
|
+
parentId: null,
|
|
6992
|
+
sessionId: lane.session.header.sessionId,
|
|
6993
|
+
clientId,
|
|
6994
|
+
ts: this.#now(),
|
|
6995
|
+
operation: "hide_user_turn",
|
|
6996
|
+
anchorUserEventId,
|
|
6997
|
+
throughEventId,
|
|
6998
|
+
actor: "agent",
|
|
6999
|
+
...reason ? { reason } : {}
|
|
7000
|
+
});
|
|
7001
|
+
await this.#appendDiagnostic(lane.session.header.sessionId, "context_snipped", {
|
|
7002
|
+
anchorUserEventId,
|
|
7003
|
+
throughEventId,
|
|
7004
|
+
hiddenEventCount: nextUserIndex - anchorIndex
|
|
7005
|
+
});
|
|
7006
|
+
return {
|
|
7007
|
+
anchorUserEventId,
|
|
7008
|
+
throughEventId,
|
|
7009
|
+
hiddenEventCount: nextUserIndex - anchorIndex
|
|
7010
|
+
};
|
|
7011
|
+
}
|
|
7012
|
+
#resolveSnipUserMessageId(lane, path, userMessageId) {
|
|
7013
|
+
if (path.includes(userMessageId)) {
|
|
7014
|
+
return userMessageId;
|
|
7015
|
+
}
|
|
7016
|
+
const matches = path.filter((id) => {
|
|
7017
|
+
const event = lane.session.tree.get(id)?.event;
|
|
7018
|
+
return event?.type === "user_message" && snipUserMessageAlias(id) === userMessageId;
|
|
7019
|
+
});
|
|
7020
|
+
if (matches.length === 1) {
|
|
7021
|
+
return matches[0];
|
|
7022
|
+
}
|
|
7023
|
+
if (matches.length > 1) {
|
|
7024
|
+
throw new Error(`snip target short id is ambiguous: ${userMessageId}`);
|
|
7025
|
+
}
|
|
7026
|
+
return asEventId(userMessageId);
|
|
6789
7027
|
}
|
|
6790
7028
|
async #selectChatRuntime(lane, modelSelection) {
|
|
6791
7029
|
if (!modelSelection) {
|
|
@@ -7548,7 +7786,17 @@ var init_src4 = __esm({
|
|
|
7548
7786
|
};
|
|
7549
7787
|
countContentBlocks = (message, type) => message.content.filter((block) => block.type === type).length;
|
|
7550
7788
|
normalizeContent = (content) => typeof content === "string" ? [{ type: "text", text: content }] : content;
|
|
7551
|
-
|
|
7789
|
+
snipUserMessageIdBlock = (userEventId) => ({
|
|
7790
|
+
...createSystemReminderBlock({
|
|
7791
|
+
kind: "message_ref",
|
|
7792
|
+
origin: "system",
|
|
7793
|
+
text: `snip.userMessageId: ${snipUserMessageAlias(userEventId)}`,
|
|
7794
|
+
visibility: "model",
|
|
7795
|
+
scope: "message",
|
|
7796
|
+
data: { userMessageId: snipUserMessageAlias(userEventId) }
|
|
7797
|
+
})
|
|
7798
|
+
});
|
|
7799
|
+
inputText = (message) => message.content.flatMap((block) => block.type === "text" && block.visibility !== "model" ? [block.text] : []).join("\n").trim();
|
|
7552
7800
|
assistantText = (message) => message.content.filter((block) => block.type === "text").map((block) => block.text).join("\n").trim();
|
|
7553
7801
|
messageText = (message) => {
|
|
7554
7802
|
const text = message.content.map((block) => {
|
|
@@ -7564,6 +7812,9 @@ var init_src4 = __esm({
|
|
|
7564
7812
|
if (block.type === "tool_result") {
|
|
7565
7813
|
return `[tool_result:${block.toolName}] ${JSON.stringify(block.result)}`;
|
|
7566
7814
|
}
|
|
7815
|
+
if (block.type === "system_reminder") {
|
|
7816
|
+
return `[system_reminder:${block.kind}] ${block.text}`;
|
|
7817
|
+
}
|
|
7567
7818
|
return "";
|
|
7568
7819
|
}).filter(Boolean).join("\n").trim();
|
|
7569
7820
|
return text || "(empty)";
|
|
@@ -7577,7 +7828,7 @@ var init_src4 = __esm({
|
|
|
7577
7828
|
return void 0;
|
|
7578
7829
|
}
|
|
7579
7830
|
const parsed = JSON.parse(text);
|
|
7580
|
-
if (!
|
|
7831
|
+
if (!isRecord9(parsed)) {
|
|
7581
7832
|
return void 0;
|
|
7582
7833
|
}
|
|
7583
7834
|
return {
|
|
@@ -7665,7 +7916,7 @@ var init_src4 = __esm({
|
|
|
7665
7916
|
}
|
|
7666
7917
|
};
|
|
7667
7918
|
parseRuntimeStats = (value) => {
|
|
7668
|
-
if (!
|
|
7919
|
+
if (!isRecord9(value) || !isRecord9(value.rtk)) {
|
|
7669
7920
|
return emptyRuntimeStats();
|
|
7670
7921
|
}
|
|
7671
7922
|
return {
|
|
@@ -7679,13 +7930,13 @@ var init_src4 = __esm({
|
|
|
7679
7930
|
};
|
|
7680
7931
|
};
|
|
7681
7932
|
parseRuntimeStatsBuckets = (value) => {
|
|
7682
|
-
if (!
|
|
7933
|
+
if (!isRecord9(value)) {
|
|
7683
7934
|
return {};
|
|
7684
7935
|
}
|
|
7685
7936
|
return Object.fromEntries(
|
|
7686
7937
|
Object.entries(value).map(([key, bucket]) => [
|
|
7687
7938
|
key,
|
|
7688
|
-
|
|
7939
|
+
isRecord9(bucket) ? {
|
|
7689
7940
|
outputTokens: nonNegativeInteger2(bucket.outputTokens),
|
|
7690
7941
|
savedTokens: nonNegativeInteger2(bucket.savedTokens)
|
|
7691
7942
|
} : { outputTokens: 0, savedTokens: 0 }
|
|
@@ -7703,11 +7954,11 @@ var init_src4 = __esm({
|
|
|
7703
7954
|
return bucket;
|
|
7704
7955
|
};
|
|
7705
7956
|
rtkSavingsFromToolResult = (result) => {
|
|
7706
|
-
if (!
|
|
7957
|
+
if (!isRecord9(result) || !isRecord9(result.details)) {
|
|
7707
7958
|
return void 0;
|
|
7708
7959
|
}
|
|
7709
7960
|
const rtk = result.details.rtk;
|
|
7710
|
-
if (!
|
|
7961
|
+
if (!isRecord9(rtk) || rtk.applied !== true) {
|
|
7711
7962
|
return void 0;
|
|
7712
7963
|
}
|
|
7713
7964
|
const outputTokens = nonNegativeInteger2(rtk.estimatedOutputTokens);
|
|
@@ -7752,7 +8003,7 @@ var init_src4 = __esm({
|
|
|
7752
8003
|
...context.data ? { data: context.data } : {}
|
|
7753
8004
|
});
|
|
7754
8005
|
parseQueuedChannelContext = (value) => {
|
|
7755
|
-
if (!
|
|
8006
|
+
if (!isRecord9(value)) {
|
|
7756
8007
|
return void 0;
|
|
7757
8008
|
}
|
|
7758
8009
|
if (typeof value.channel !== "string" || typeof value.externalConversationId !== "string") {
|
|
@@ -7764,11 +8015,11 @@ var init_src4 = __esm({
|
|
|
7764
8015
|
...typeof value.conversationType === "string" ? { conversationType: value.conversationType } : {},
|
|
7765
8016
|
...typeof value.senderDisplayName === "string" ? { senderDisplayName: value.senderDisplayName } : {},
|
|
7766
8017
|
...typeof value.mentionedBot === "boolean" ? { mentionedBot: value.mentionedBot } : {},
|
|
7767
|
-
...
|
|
8018
|
+
...isRecord9(value.data) ? { data: value.data } : {}
|
|
7768
8019
|
});
|
|
7769
8020
|
};
|
|
7770
8021
|
parseQueuedModelSelection = (value) => {
|
|
7771
|
-
if (!
|
|
8022
|
+
if (!isRecord9(value)) {
|
|
7772
8023
|
return void 0;
|
|
7773
8024
|
}
|
|
7774
8025
|
const selection = {};
|
|
@@ -7810,7 +8061,7 @@ var init_src4 = __esm({
|
|
|
7810
8061
|
};
|
|
7811
8062
|
isSteerMessage = (text) => /^\/(?:steer|interrupt)\b/i.test(text.trim());
|
|
7812
8063
|
stripImCommandPrefix = (text) => text.trim().replace(/^\/(?:steer|interrupt)\s*/i, "").trim() || text;
|
|
7813
|
-
|
|
8064
|
+
isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7814
8065
|
parseMemoryUpdate = (raw) => {
|
|
7815
8066
|
const text = raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
7816
8067
|
if (!text) {
|
|
@@ -8036,7 +8287,7 @@ var init_daemon_cli = __esm({
|
|
|
8036
8287
|
DEFAULT_PORT = 7777;
|
|
8037
8288
|
STOP_POLL_INTERVAL_MS = 200;
|
|
8038
8289
|
STOP_GRACE_MS = 5e3;
|
|
8039
|
-
START_READY_TIMEOUT_MS =
|
|
8290
|
+
START_READY_TIMEOUT_MS = 3e4;
|
|
8040
8291
|
AUTO_STARTED_IDLE_SHUTDOWN_MS = 15 * 60 * 1e3;
|
|
8041
8292
|
FOREGROUND_IDLE_SHUTDOWN_MS = 0;
|
|
8042
8293
|
defaultStateDir2 = () => join13(homedir6(), ".scorel");
|
|
@@ -9202,7 +9453,7 @@ var init_up_cli = __esm({
|
|
|
9202
9453
|
init_daemon_cli();
|
|
9203
9454
|
DEFAULT_DAEMON_PORT = 7777;
|
|
9204
9455
|
DEFAULT_WEBUI_PORT = 3e3;
|
|
9205
|
-
DEFAULT_DAEMON_READY_TIMEOUT_MS =
|
|
9456
|
+
DEFAULT_DAEMON_READY_TIMEOUT_MS = 3e4;
|
|
9206
9457
|
defaultStateDir3 = () => join16(homedir8(), ".scorel");
|
|
9207
9458
|
defaultAttachSigint = (listener) => {
|
|
9208
9459
|
process.on("SIGINT", listener);
|
|
@@ -9557,7 +9808,7 @@ __export(index_exports, {
|
|
|
9557
9808
|
runChat: () => runChat,
|
|
9558
9809
|
runCli: () => runCli
|
|
9559
9810
|
});
|
|
9560
|
-
import { createHash as
|
|
9811
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
9561
9812
|
import { appendFile as appendFile4, mkdir as mkdir8, readFile as readFile14, realpath as realpath3, readdir as readdir7, writeFile as writeFile8 } from "node:fs/promises";
|
|
9562
9813
|
import { createInterface } from "node:readline/promises";
|
|
9563
9814
|
import { homedir as homedir9 } from "node:os";
|
|
@@ -9879,11 +10130,11 @@ var init_index = __esm({
|
|
|
9879
10130
|
};
|
|
9880
10131
|
};
|
|
9881
10132
|
attachCacheFilePath = (stateDir, scope, sessionId) => {
|
|
9882
|
-
const scopeKey =
|
|
10133
|
+
const scopeKey = createHash4("sha256").update(`${scope.kind}\0${scope.locator}`).digest("hex").slice(0, 24);
|
|
9883
10134
|
return join17(stateDir, "attach-cache", scopeKey, `${sessionId}.json`);
|
|
9884
10135
|
};
|
|
9885
10136
|
attachDiagnosticsFilePath = (stateDir, scope, sessionId) => {
|
|
9886
|
-
const scopeKey =
|
|
10137
|
+
const scopeKey = createHash4("sha256").update(`${scope.kind}\0${scope.locator}`).digest("hex").slice(0, 24);
|
|
9887
10138
|
return join17(stateDir, "attach-cache", scopeKey, `${sessionId}.log`);
|
|
9888
10139
|
};
|
|
9889
10140
|
findAttachDiagnosticsFilePath = async (stateDir, sessionId, _remoteUrl) => {
|
|
@@ -10406,7 +10657,18 @@ ${text}
|
|
|
10406
10657
|
this.#atLineStart = text.endsWith("\n");
|
|
10407
10658
|
}
|
|
10408
10659
|
};
|
|
10409
|
-
blocksToText = (blocks) => blocks.
|
|
10660
|
+
blocksToText = (blocks) => blocks.flatMap((block) => {
|
|
10661
|
+
if (block.type === "text") {
|
|
10662
|
+
if (block.visibility === "model") {
|
|
10663
|
+
return [];
|
|
10664
|
+
}
|
|
10665
|
+
return [block.text];
|
|
10666
|
+
}
|
|
10667
|
+
if (block.type === "system_reminder" && block.visibility !== "model") {
|
|
10668
|
+
return [block.text];
|
|
10669
|
+
}
|
|
10670
|
+
return [];
|
|
10671
|
+
}).join("");
|
|
10410
10672
|
isCliEntrypoint = async () => {
|
|
10411
10673
|
if (!process.argv[1]) return false;
|
|
10412
10674
|
const [argvPath, modulePath] = await Promise.all([
|