@martian-engineering/lossless-claw 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -25,7 +25,7 @@ function formatDisplayTime(
25
25
  const LcmGrepSchema = Type.Object({
26
26
  pattern: Type.String({
27
27
  description:
28
- "Search pattern. Interpreted as regex when mode is 'regex', or as a text query for 'full_text' mode.",
28
+ 'Search pattern. Interpreted as regex when mode is "regex", or as a text query for "full_text" mode. In full_text mode, wrap exact multi-word phrases in quotes to preserve phrase matching.',
29
29
  }),
30
30
  mode: Type.Optional(
31
31
  Type.String({
@@ -70,6 +70,13 @@ const LcmGrepSchema = Type.Object({
70
70
  maximum: 200,
71
71
  }),
72
72
  ),
73
+ sort: Type.Optional(
74
+ Type.String({
75
+ description:
76
+ 'Sort order: "recency" (newest first, default), "relevance" (best FTS5 match first, full_text mode only), or "hybrid" (full_text mode only; balances relevance with recency). Applied before limit is enforced.',
77
+ enum: ["recency", "relevance", "hybrid"],
78
+ }),
79
+ ),
73
80
  });
74
81
 
75
82
  function truncateSnippet(content: string, maxLen: number = 200): string {
@@ -82,7 +89,8 @@ function truncateSnippet(content: string, maxLen: number = 200): string {
82
89
 
83
90
  export function createLcmGrepTool(input: {
84
91
  deps: LcmDependencies;
85
- lcm: LcmContextEngine;
92
+ lcm?: LcmContextEngine;
93
+ getLcm?: () => Promise<LcmContextEngine>;
86
94
  sessionId?: string;
87
95
  sessionKey?: string;
88
96
  }): AnyAgentTool {
@@ -93,18 +101,24 @@ export function createLcmGrepTool(input: {
93
101
  "Search compacted conversation history using regex or full-text search. " +
94
102
  "Searches across messages and/or summaries stored by LCM. " +
95
103
  "Use this to find specific content that may have been compacted away from " +
96
- "active context. Returns matching snippets with their summary/message IDs " +
104
+ "active context. In full_text mode, quoted phrases stay intact and optional sort modes can prioritize relevance for older topics. Returns matching snippets with their summary/message IDs " +
97
105
  "for follow-up with lcm_expand or lcm_describe.",
98
106
  parameters: LcmGrepSchema,
99
107
  async execute(_toolCallId, params) {
100
- const retrieval = input.lcm.getRetrieval();
101
- const timezone = input.lcm.timezone;
108
+ const lcm = input.lcm ?? (await input.getLcm?.());
109
+ if (!lcm) {
110
+ throw new Error("LCM engine is unavailable.");
111
+ }
112
+ const retrieval = lcm.getRetrieval();
113
+ const timezone = lcm.timezone;
102
114
 
103
115
  const p = params as Record<string, unknown>;
104
116
  const pattern = (p.pattern as string).trim();
105
117
  const mode = (p.mode as "regex" | "full_text") ?? "regex";
106
118
  const scope = (p.scope as "messages" | "summaries" | "both") ?? "both";
107
119
  const limit = typeof p.limit === "number" ? Math.trunc(p.limit) : 50;
120
+ const requestedSort = (p.sort as "recency" | "relevance" | "hybrid") ?? "recency";
121
+ const effectiveSort = mode === "full_text" ? requestedSort : "recency";
108
122
  let since: Date | undefined;
109
123
  let before: Date | undefined;
110
124
  try {
@@ -121,7 +135,7 @@ export function createLcmGrepTool(input: {
121
135
  });
122
136
  }
123
137
  const conversationScope = await resolveLcmConversationScope({
124
- lcm: input.lcm,
138
+ lcm,
125
139
  deps: input.deps,
126
140
  sessionId: input.sessionId,
127
141
  sessionKey: input.sessionKey,
@@ -133,7 +147,6 @@ export function createLcmGrepTool(input: {
133
147
  "No LCM conversation found for this session. Provide conversationId or set allConversations=true.",
134
148
  });
135
149
  }
136
-
137
150
  const result = await retrieval.grep({
138
151
  query: pattern,
139
152
  mode,
@@ -142,12 +155,13 @@ export function createLcmGrepTool(input: {
142
155
  limit,
143
156
  since,
144
157
  before,
158
+ sort: effectiveSort,
145
159
  });
146
160
 
147
161
  const lines: string[] = [];
148
162
  lines.push("## LCM Grep Results");
149
163
  lines.push(`**Pattern:** \`${pattern}\``);
150
- lines.push(`**Mode:** ${mode} | **Scope:** ${scope}`);
164
+ lines.push(`**Mode:** ${mode} | **Scope:** ${scope} | **Sort:** ${effectiveSort}`);
151
165
  if (conversationScope.allConversations) {
152
166
  lines.push("**Conversation scope:** all conversations");
153
167
  } else if (conversationScope.conversationId != null) {
package/src/types.ts CHANGED
@@ -39,6 +39,7 @@ export type CompleteFn = (params: {
39
39
  authProfileId?: string;
40
40
  agentDir?: string;
41
41
  runtimeConfig?: unknown;
42
+ skipModelAuth?: boolean;
42
43
  messages: Array<{ role: string; content: unknown }>;
43
44
  system?: string;
44
45
  maxTokens: number;