opencodekit 0.23.1 → 0.23.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/dist/index.js +354 -825
- package/dist/template/.opencode/AGENTS.md +15 -2
- package/dist/template/.opencode/command/init.md +198 -34
- package/dist/template/.opencode/context/fallow.md +137 -0
- package/dist/template/.opencode/opencode.json +12 -315
- package/dist/template/.opencode/plugin/codesearch.ts +730 -0
- package/dist/template/.opencode/plugin/memory/compile.ts +171 -186
- package/dist/template/.opencode/plugin/memory/index-generator.ts +118 -133
- package/dist/template/.opencode/plugin/memory/lint.ts +253 -275
- package/dist/template/.opencode/plugin/memory/tools.ts +224 -268
- package/dist/template/.opencode/plugin/memory/validate.ts +154 -164
- package/dist/template/.opencode/plugin/sdk/copilot/responses/tool/web-search-preview.ts +13 -30
- package/dist/template/.opencode/plugin/sdk/copilot/responses/tool/web-search-shared.ts +25 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/tool/web-search.ts +17 -34
- package/dist/template/.opencode/plugin/session-summary.ts +0 -2
- package/dist/template/.opencode/plugin/srcwalk.ts +646 -667
- package/dist/template/.opencode/skill/code-navigation/SKILL.md +10 -10
- package/dist/template/.opencode/skill/code-review-and-quality/SKILL.md +1 -1
- package/dist/template/.opencode/skill/condition-based-waiting/example.ts +15 -2
- package/dist/template/.opencode/skill/debugging-and-error-recovery/SKILL.md +1 -1
- package/dist/template/.opencode/skill/deep-module-design/SKILL.md +1 -1
- package/dist/template/.opencode/skill/fallow/SKILL.md +409 -0
- package/dist/template/.opencode/skill/fallow/references/cli-reference.md +1905 -0
- package/dist/template/.opencode/skill/fallow/references/gotchas.md +644 -0
- package/dist/template/.opencode/skill/fallow/references/patterns.md +791 -0
- package/dist/template/.opencode/skill/planning-and-task-breakdown/SKILL.md +1 -1
- package/dist/template/.opencode/skill/srcwalk/SKILL.md +10 -13
- package/dist/template/.opencode/skill/ubiquitous-language/SKILL.md +1 -1
- package/dist/template/.opencode/tool/grepsearch.ts +92 -103
- package/package.json +1 -1
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import type { ObservationInput, ObservationRow } from "./db/types.js";
|
|
17
|
-
import { getMemoryDB } from "./db.js";
|
|
17
|
+
import { getMemoryDB } from "./db/schema.js";
|
|
18
18
|
import { hasWord } from "./helpers.js";
|
|
19
19
|
import { appendOperationLog } from "./operation-log.js";
|
|
20
20
|
|
|
@@ -25,17 +25,17 @@ import { appendOperationLog } from "./operation-log.js";
|
|
|
25
25
|
export type ValidationVerdict = "pass" | "warn" | "reject";
|
|
26
26
|
|
|
27
27
|
export interface ValidationResult {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
verdict: ValidationVerdict;
|
|
29
|
+
issues: ValidationIssue[];
|
|
30
|
+
/** If a near-duplicate was found, its ID */
|
|
31
|
+
duplicateOf?: number;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export interface ValidationIssue {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
type: "duplicate" | "near-duplicate" | "contradiction" | "low-quality";
|
|
36
|
+
severity: "high" | "medium" | "low";
|
|
37
|
+
message: string;
|
|
38
|
+
relatedId?: number;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// ============================================================================
|
|
@@ -47,87 +47,82 @@ export interface ValidationIssue {
|
|
|
47
47
|
* Returns verdict (pass/warn/reject) with issues.
|
|
48
48
|
*/
|
|
49
49
|
export function validateObservation(input: ObservationInput): ValidationResult {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
summary: `Validated [${input.type}] "${input.title}" — ${verdict}${issues.length > 0 ? ` (${issues.length} issues)` : ""}`,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return { verdict, issues };
|
|
50
|
+
const issues: ValidationIssue[] = [];
|
|
51
|
+
|
|
52
|
+
// Check 1: Exact title duplicate
|
|
53
|
+
const exactDup = findExactDuplicate(input);
|
|
54
|
+
if (exactDup) {
|
|
55
|
+
// If it's explicitly superseding, that's fine
|
|
56
|
+
if (input.supersedes === exactDup.id) {
|
|
57
|
+
// Intentional supersede — pass
|
|
58
|
+
} else {
|
|
59
|
+
issues.push({
|
|
60
|
+
type: "duplicate",
|
|
61
|
+
severity: "high",
|
|
62
|
+
message: `Exact duplicate of #${exactDup.id}: "${exactDup.title}"`,
|
|
63
|
+
relatedId: exactDup.id,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
appendOperationLog({
|
|
67
|
+
operation: "observation-duplicate-warning",
|
|
68
|
+
targets: [`#${exactDup.id}`],
|
|
69
|
+
summary: `Duplicate warning: "${input.title}" (matches #${exactDup.id})`,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
verdict: "warn",
|
|
74
|
+
issues,
|
|
75
|
+
duplicateOf: exactDup.id,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check 2: Near-duplicate via FTS5
|
|
81
|
+
const nearDup = findNearDuplicate(input);
|
|
82
|
+
if (nearDup) {
|
|
83
|
+
issues.push({
|
|
84
|
+
type: "near-duplicate",
|
|
85
|
+
severity: "medium",
|
|
86
|
+
message: `Similar to #${nearDup.id}: "${nearDup.title}" (consider superseding)`,
|
|
87
|
+
relatedId: nearDup.id,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Check 3: Contradiction with existing decisions
|
|
92
|
+
if (input.type === "decision") {
|
|
93
|
+
const contradiction = findContradiction(input);
|
|
94
|
+
if (contradiction) {
|
|
95
|
+
issues.push({
|
|
96
|
+
type: "contradiction",
|
|
97
|
+
severity: "medium",
|
|
98
|
+
message: `May contradict #${contradiction.id}: "${contradiction.title}"`,
|
|
99
|
+
relatedId: contradiction.id,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check 4: Low quality (no narrative, no concepts)
|
|
105
|
+
if (!input.narrative && !input.concepts) {
|
|
106
|
+
issues.push({
|
|
107
|
+
type: "low-quality",
|
|
108
|
+
severity: "low",
|
|
109
|
+
message: "Observation has no narrative and no concepts — low knowledge value",
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Determine verdict
|
|
114
|
+
const hasHigh = issues.some((i) => i.severity === "high");
|
|
115
|
+
const verdict: ValidationVerdict = hasHigh ? "reject" : issues.length > 0 ? "warn" : "pass";
|
|
116
|
+
|
|
117
|
+
if (verdict === "pass" || verdict === "warn") {
|
|
118
|
+
appendOperationLog({
|
|
119
|
+
operation: "observation-validated",
|
|
120
|
+
targets: [input.title],
|
|
121
|
+
summary: `Validated [${input.type}] "${input.title}" — ${verdict}${issues.length > 0 ? ` (${issues.length} issues)` : ""}`,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return { verdict, issues };
|
|
131
126
|
}
|
|
132
127
|
|
|
133
128
|
// ============================================================================
|
|
@@ -138,106 +133,101 @@ export function validateObservation(input: ObservationInput): ValidationResult {
|
|
|
138
133
|
* Check for exact title match (same type, active).
|
|
139
134
|
*/
|
|
140
135
|
function findExactDuplicate(input: ObservationInput): ObservationRow | null {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
136
|
+
const db = getMemoryDB();
|
|
137
|
+
return db
|
|
138
|
+
.query(
|
|
139
|
+
`SELECT * FROM observations
|
|
145
140
|
WHERE type = ? AND LOWER(title) = LOWER(?) AND superseded_by IS NULL
|
|
146
141
|
LIMIT 1`,
|
|
147
|
-
|
|
148
|
-
|
|
142
|
+
)
|
|
143
|
+
.get(input.type, input.title) as ObservationRow | null;
|
|
149
144
|
}
|
|
150
145
|
|
|
151
146
|
/**
|
|
152
147
|
* Check for near-duplicate via FTS5 title search.
|
|
153
148
|
*/
|
|
154
149
|
function findNearDuplicate(input: ObservationInput): ObservationRow | null {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
150
|
+
const db = getMemoryDB();
|
|
151
|
+
|
|
152
|
+
// Build FTS query from title words
|
|
153
|
+
// Strip FTS5 special operators and characters to prevent query syntax errors
|
|
154
|
+
const FTS5_OPERATORS = /\b(AND|OR|NOT|NEAR)\b/gi;
|
|
155
|
+
const words = input.title
|
|
156
|
+
.replace(FTS5_OPERATORS, "")
|
|
157
|
+
.replace(/['"*^+(){}]/g, "")
|
|
158
|
+
.split(/\s+/)
|
|
159
|
+
.filter((w) => w.length > 2)
|
|
160
|
+
.map((w) => `"${w}"*`)
|
|
161
|
+
.join(" AND ");
|
|
162
|
+
|
|
163
|
+
if (!words) return null;
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
const result = db
|
|
167
|
+
.query(
|
|
168
|
+
`SELECT o.* FROM observations o
|
|
174
169
|
JOIN observations_fts fts ON fts.rowid = o.id
|
|
175
170
|
WHERE observations_fts MATCH ?
|
|
176
171
|
AND o.type = ?
|
|
177
172
|
AND o.superseded_by IS NULL
|
|
178
173
|
AND o.id != COALESCE(?, -1)
|
|
179
174
|
ORDER BY bm25(observations_fts) LIMIT 1`,
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return result;
|
|
188
|
-
} catch {
|
|
189
|
-
return null;
|
|
190
|
-
}
|
|
175
|
+
)
|
|
176
|
+
.get(words, input.type, input.supersedes ?? null) as ObservationRow | null;
|
|
177
|
+
|
|
178
|
+
return result;
|
|
179
|
+
} catch {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
191
182
|
}
|
|
192
183
|
|
|
193
184
|
/**
|
|
194
185
|
* Check for contradictions with existing decisions.
|
|
195
186
|
*/
|
|
196
187
|
function findContradiction(input: ObservationInput): ObservationRow | null {
|
|
197
|
-
|
|
188
|
+
if (!input.concepts || input.concepts.length === 0) return null;
|
|
198
189
|
|
|
199
|
-
|
|
190
|
+
const db = getMemoryDB();
|
|
200
191
|
|
|
201
|
-
|
|
202
|
-
|
|
192
|
+
// Search for decisions with overlapping concepts
|
|
193
|
+
const conceptQuery = input.concepts.map((c) => `"${c}"*`).join(" OR ");
|
|
203
194
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
195
|
+
try {
|
|
196
|
+
const candidates = db
|
|
197
|
+
.query(
|
|
198
|
+
`SELECT o.* FROM observations o
|
|
208
199
|
JOIN observations_fts fts ON fts.rowid = o.id
|
|
209
200
|
WHERE observations_fts MATCH ?
|
|
210
201
|
AND o.type = 'decision'
|
|
211
202
|
AND o.superseded_by IS NULL
|
|
212
203
|
ORDER BY bm25(observations_fts) LIMIT 5`,
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
return null;
|
|
204
|
+
)
|
|
205
|
+
.all(conceptQuery) as ObservationRow[];
|
|
206
|
+
|
|
207
|
+
// Check for opposing signals
|
|
208
|
+
const inputText = `${input.title} ${input.narrative ?? ""}`.toLowerCase();
|
|
209
|
+
const contradictionPairs = [
|
|
210
|
+
["use", "don't use"],
|
|
211
|
+
["enable", "disable"],
|
|
212
|
+
["add", "remove"],
|
|
213
|
+
["prefer", "avoid"],
|
|
214
|
+
["always", "never"],
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
for (const candidate of candidates) {
|
|
218
|
+
const candidateText = `${candidate.title} ${candidate.narrative ?? ""}`.toLowerCase();
|
|
219
|
+
for (const [wordA, wordB] of contradictionPairs) {
|
|
220
|
+
if (
|
|
221
|
+
(hasWord(inputText, wordA) && hasWord(candidateText, wordB)) ||
|
|
222
|
+
(hasWord(inputText, wordB) && hasWord(candidateText, wordA))
|
|
223
|
+
) {
|
|
224
|
+
return candidate;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
} catch {
|
|
229
|
+
// FTS5 query failed
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return null;
|
|
243
233
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { createProviderToolFactory } from "@ai-sdk/provider-utils"
|
|
2
|
-
import { z } from "zod/v4"
|
|
1
|
+
import { createProviderToolFactory } from "@ai-sdk/provider-utils";
|
|
2
|
+
import { z } from "zod/v4";
|
|
3
|
+
import { webSearchInputSchema } from "./web-search-shared.js";
|
|
3
4
|
|
|
4
5
|
// Args validation schema
|
|
5
6
|
export const webSearchPreviewArgsSchema = z.object({
|
|
@@ -38,7 +39,7 @@ export const webSearchPreviewArgsSchema = z.object({
|
|
|
38
39
|
timezone: z.string().optional(),
|
|
39
40
|
})
|
|
40
41
|
.optional(),
|
|
41
|
-
})
|
|
42
|
+
});
|
|
42
43
|
|
|
43
44
|
export const webSearchPreview = createProviderToolFactory<
|
|
44
45
|
{
|
|
@@ -51,7 +52,7 @@ export const webSearchPreview = createProviderToolFactory<
|
|
|
51
52
|
* - medium: Balanced context, cost, and latency (default)
|
|
52
53
|
* - low: Least context, lowest cost, fastest response
|
|
53
54
|
*/
|
|
54
|
-
searchContextSize?: "low" | "medium" | "high"
|
|
55
|
+
searchContextSize?: "low" | "medium" | "high";
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
58
|
* User location information to provide geographically relevant search results.
|
|
@@ -60,44 +61,26 @@ export const webSearchPreview = createProviderToolFactory<
|
|
|
60
61
|
/**
|
|
61
62
|
* Type of location (always 'approximate')
|
|
62
63
|
*/
|
|
63
|
-
type: "approximate"
|
|
64
|
+
type: "approximate";
|
|
64
65
|
/**
|
|
65
66
|
* Two-letter ISO country code (e.g., 'US', 'GB')
|
|
66
67
|
*/
|
|
67
|
-
country?: string
|
|
68
|
+
country?: string;
|
|
68
69
|
/**
|
|
69
70
|
* City name (free text, e.g., 'Minneapolis')
|
|
70
71
|
*/
|
|
71
|
-
city?: string
|
|
72
|
+
city?: string;
|
|
72
73
|
/**
|
|
73
74
|
* Region name (free text, e.g., 'Minnesota')
|
|
74
75
|
*/
|
|
75
|
-
region?: string
|
|
76
|
+
region?: string;
|
|
76
77
|
/**
|
|
77
78
|
* IANA timezone (e.g., 'America/Chicago')
|
|
78
79
|
*/
|
|
79
|
-
timezone?: string
|
|
80
|
-
}
|
|
80
|
+
timezone?: string;
|
|
81
|
+
};
|
|
81
82
|
}
|
|
82
83
|
>({
|
|
83
84
|
id: "openai.web_search_preview",
|
|
84
|
-
inputSchema:
|
|
85
|
-
|
|
86
|
-
.discriminatedUnion("type", [
|
|
87
|
-
z.object({
|
|
88
|
-
type: z.literal("search"),
|
|
89
|
-
query: z.string().nullish(),
|
|
90
|
-
}),
|
|
91
|
-
z.object({
|
|
92
|
-
type: z.literal("open_page"),
|
|
93
|
-
url: z.string(),
|
|
94
|
-
}),
|
|
95
|
-
z.object({
|
|
96
|
-
type: z.literal("find"),
|
|
97
|
-
url: z.string(),
|
|
98
|
-
pattern: z.string(),
|
|
99
|
-
}),
|
|
100
|
-
])
|
|
101
|
-
.nullish(),
|
|
102
|
-
}),
|
|
103
|
-
})
|
|
85
|
+
inputSchema: webSearchInputSchema,
|
|
86
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared input schema for web search tool actions.
|
|
5
|
+
* Both search and search-preview tools use the same action types.
|
|
6
|
+
*/
|
|
7
|
+
export const webSearchInputSchema = z.object({
|
|
8
|
+
action: z
|
|
9
|
+
.discriminatedUnion("type", [
|
|
10
|
+
z.object({
|
|
11
|
+
type: z.literal("search"),
|
|
12
|
+
query: z.string().nullish(),
|
|
13
|
+
}),
|
|
14
|
+
z.object({
|
|
15
|
+
type: z.literal("open_page"),
|
|
16
|
+
url: z.string(),
|
|
17
|
+
}),
|
|
18
|
+
z.object({
|
|
19
|
+
type: z.literal("find"),
|
|
20
|
+
url: z.string(),
|
|
21
|
+
pattern: z.string(),
|
|
22
|
+
}),
|
|
23
|
+
])
|
|
24
|
+
.nullish(),
|
|
25
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { createProviderToolFactory } from "@ai-sdk/provider-utils"
|
|
2
|
-
import { z } from "zod/v4"
|
|
1
|
+
import { createProviderToolFactory } from "@ai-sdk/provider-utils";
|
|
2
|
+
import { z } from "zod/v4";
|
|
3
|
+
import { webSearchInputSchema } from "./web-search-shared.js";
|
|
3
4
|
|
|
4
5
|
export const webSearchArgsSchema = z.object({
|
|
5
6
|
filters: z
|
|
@@ -19,7 +20,7 @@ export const webSearchArgsSchema = z.object({
|
|
|
19
20
|
timezone: z.string().optional(),
|
|
20
21
|
})
|
|
21
22
|
.optional(),
|
|
22
|
-
})
|
|
23
|
+
});
|
|
23
24
|
|
|
24
25
|
export const webSearchToolFactory = createProviderToolFactory<
|
|
25
26
|
{
|
|
@@ -35,8 +36,8 @@ export const webSearchToolFactory = createProviderToolFactory<
|
|
|
35
36
|
* If not provided, all domains are allowed.
|
|
36
37
|
* Subdomains of the provided domains are allowed as well.
|
|
37
38
|
*/
|
|
38
|
-
allowedDomains?: string[]
|
|
39
|
-
}
|
|
39
|
+
allowedDomains?: string[];
|
|
40
|
+
};
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
43
|
* Search context size to use for the web search.
|
|
@@ -44,7 +45,7 @@ export const webSearchToolFactory = createProviderToolFactory<
|
|
|
44
45
|
* - medium: Balanced context, cost, and latency (default)
|
|
45
46
|
* - low: Least context, lowest cost, fastest response
|
|
46
47
|
*/
|
|
47
|
-
searchContextSize?: "low" | "medium" | "high"
|
|
48
|
+
searchContextSize?: "low" | "medium" | "high";
|
|
48
49
|
|
|
49
50
|
/**
|
|
50
51
|
* User location information to provide geographically relevant search results.
|
|
@@ -53,50 +54,32 @@ export const webSearchToolFactory = createProviderToolFactory<
|
|
|
53
54
|
/**
|
|
54
55
|
* Type of location (always 'approximate')
|
|
55
56
|
*/
|
|
56
|
-
type: "approximate"
|
|
57
|
+
type: "approximate";
|
|
57
58
|
/**
|
|
58
59
|
* Two-letter ISO country code (e.g., 'US', 'GB')
|
|
59
60
|
*/
|
|
60
|
-
country?: string
|
|
61
|
+
country?: string;
|
|
61
62
|
/**
|
|
62
63
|
* City name (free text, e.g., 'Minneapolis')
|
|
63
64
|
*/
|
|
64
|
-
city?: string
|
|
65
|
+
city?: string;
|
|
65
66
|
/**
|
|
66
67
|
* Region name (free text, e.g., 'Minnesota')
|
|
67
68
|
*/
|
|
68
|
-
region?: string
|
|
69
|
+
region?: string;
|
|
69
70
|
/**
|
|
70
71
|
* IANA timezone (e.g., 'America/Chicago')
|
|
71
72
|
*/
|
|
72
|
-
timezone?: string
|
|
73
|
-
}
|
|
73
|
+
timezone?: string;
|
|
74
|
+
};
|
|
74
75
|
}
|
|
75
76
|
>({
|
|
76
77
|
id: "openai.web_search",
|
|
77
|
-
inputSchema:
|
|
78
|
-
|
|
79
|
-
.discriminatedUnion("type", [
|
|
80
|
-
z.object({
|
|
81
|
-
type: z.literal("search"),
|
|
82
|
-
query: z.string().nullish(),
|
|
83
|
-
}),
|
|
84
|
-
z.object({
|
|
85
|
-
type: z.literal("open_page"),
|
|
86
|
-
url: z.string(),
|
|
87
|
-
}),
|
|
88
|
-
z.object({
|
|
89
|
-
type: z.literal("find"),
|
|
90
|
-
url: z.string(),
|
|
91
|
-
pattern: z.string(),
|
|
92
|
-
}),
|
|
93
|
-
])
|
|
94
|
-
.nullish(),
|
|
95
|
-
}),
|
|
96
|
-
})
|
|
78
|
+
inputSchema: webSearchInputSchema,
|
|
79
|
+
});
|
|
97
80
|
|
|
98
81
|
export const webSearch = (
|
|
99
82
|
args: Parameters<typeof webSearchToolFactory>[0] = {}, // default
|
|
100
83
|
) => {
|
|
101
|
-
return webSearchToolFactory(args)
|
|
102
|
-
}
|
|
84
|
+
return webSearchToolFactory(args);
|
|
85
|
+
};
|
|
@@ -454,9 +454,7 @@ export const SessionSummaryPlugin: Plugin = async ({ client, directory }) => {
|
|
|
454
454
|
addRead(summary, normalized, "Code navigation");
|
|
455
455
|
break;
|
|
456
456
|
case "grep":
|
|
457
|
-
case "srcwalk_search":
|
|
458
457
|
case "glob":
|
|
459
|
-
case "srcwalk_files":
|
|
460
458
|
// Search tools — not tracking individual files
|
|
461
459
|
break;
|
|
462
460
|
}
|