gsd-pi 2.75.0-dev.b6ad8c5f7 → 2.75.0-dev.e41b70b10
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/resources/extensions/gsd/auto/phases.js +2 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +22 -1
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +8 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +11 -11
- package/dist/resources/extensions/gsd/auto-model-selection.js +3 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +19 -9
- package/dist/resources/extensions/gsd/auto-worktree.js +16 -1
- package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +128 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +17 -4
- package/dist/resources/extensions/gsd/commands/handlers/onboarding.js +52 -92
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/commands-memory.js +462 -0
- package/dist/resources/extensions/gsd/doctor-git-checks.js +22 -2
- package/dist/resources/extensions/gsd/gsd-db.js +237 -4
- package/dist/resources/extensions/gsd/memory-embeddings.js +219 -0
- package/dist/resources/extensions/gsd/memory-extractor.js +78 -27
- package/dist/resources/extensions/gsd/memory-ingest.js +218 -0
- package/dist/resources/extensions/gsd/memory-relations.js +189 -0
- package/dist/resources/extensions/gsd/memory-source-store.js +113 -0
- package/dist/resources/extensions/gsd/memory-store.js +299 -6
- package/dist/resources/extensions/gsd/pre-execution-checks.js +12 -8
- package/dist/resources/extensions/gsd/prompts/add-tests.md +1 -0
- package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/dist/resources/extensions/gsd/tools/memory-tools.js +306 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +14 -0
- package/dist/resources/extensions/search-the-web/command-search-provider.js +4 -1
- package/dist/resources/extensions/search-the-web/native-search.js +13 -2
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +12 -10
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
- package/packages/mcp-server/dist/session-manager.js +8 -1
- package/packages/mcp-server/dist/session-manager.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +1 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +207 -71
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/mcp-server.test.ts +40 -4
- package/packages/mcp-server/src/server.ts +12 -10
- package/packages/mcp-server/src/session-manager.ts +10 -3
- package/packages/mcp-server/src/workflow-tools.test.ts +346 -1
- package/packages/mcp-server/src/workflow-tools.ts +228 -75
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +1 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/api-family.d.ts +27 -0
- package/packages/pi-ai/dist/providers/api-family.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/api-family.js +47 -0
- package/packages/pi-ai/dist/providers/api-family.js.map +1 -0
- package/packages/pi-ai/dist/providers/api-family.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/api-family.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/api-family.test.js +101 -0
- package/packages/pi-ai/dist/providers/api-family.test.js.map +1 -0
- package/packages/pi-ai/src/index.ts +1 -0
- package/packages/pi-ai/src/providers/api-family.test.ts +129 -0
- package/packages/pi-ai/src/providers/api-family.ts +57 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/cli/args.d.ts +6 -0
- package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/cli/args.js +14 -4
- package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
- package/packages/pi-coding-agent/dist/cli/args.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/cli/args.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/cli/args.test.js +38 -0
- package/packages/pi-coding-agent/dist/cli/args.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +4 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +7 -1
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +3 -0
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/src/cli/args.test.ts +44 -0
- package/packages/pi-coding-agent/src/cli/args.ts +21 -6
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +4 -1
- package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -2
- package/packages/pi-coding-agent/src/core/retry-handler.ts +4 -1
- package/packages/pi-coding-agent/src/core/sdk.ts +17 -1
- package/packages/pi-coding-agent/src/main.ts +4 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -10
- package/src/resources/extensions/gsd/auto/phases.ts +3 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +25 -1
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +15 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +21 -7
- package/src/resources/extensions/gsd/auto-model-selection.ts +3 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +33 -9
- package/src/resources/extensions/gsd/auto-worktree.ts +16 -1
- package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +158 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +20 -4
- package/src/resources/extensions/gsd/commands/handlers/onboarding.ts +65 -131
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/commands-memory.ts +551 -0
- package/src/resources/extensions/gsd/doctor-git-checks.ts +23 -2
- package/src/resources/extensions/gsd/gsd-db.ts +273 -4
- package/src/resources/extensions/gsd/memory-embeddings.ts +235 -0
- package/src/resources/extensions/gsd/memory-extractor.ts +100 -34
- package/src/resources/extensions/gsd/memory-ingest.ts +286 -0
- package/src/resources/extensions/gsd/memory-relations.ts +240 -0
- package/src/resources/extensions/gsd/memory-source-store.ts +138 -0
- package/src/resources/extensions/gsd/memory-store.ts +351 -7
- package/src/resources/extensions/gsd/pre-execution-checks.ts +12 -8
- package/src/resources/extensions/gsd/prompts/add-tests.md +1 -0
- package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/escalation.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/doctor-git-symlink-cwd.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-embeddings.test.ts +213 -0
- package/src/resources/extensions/gsd/tests/memory-ingest.test.ts +153 -0
- package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/memory-relations.test.ts +175 -0
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/memory-tools.test.ts +295 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +132 -8
- package/src/resources/extensions/gsd/tests/prompts-no-gitignored-test-refs.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +97 -0
- package/src/resources/extensions/gsd/tools/memory-tools.ts +380 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +14 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +3 -1
- package/src/resources/extensions/search-the-web/command-search-provider.ts +4 -1
- package/src/resources/extensions/search-the-web/native-search.ts +13 -3
- package/src/resources/extensions/gsd/tests/onboarding-handler-loader.test.ts +0 -41
- /package/dist/web/standalone/.next/static/{J2z3GMC9QtSLr7gyoM38c → By_yegSJ-AA1OP0QjYbSl}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{J2z3GMC9QtSLr7gyoM38c → By_yegSJ-AA1OP0QjYbSl}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
// GSD Memory Tools — Phase 1 executors for capture_thought, memory_query, gsd_graph
|
|
2
|
+
//
|
|
3
|
+
// These executors back the three memory-layer tools the LLM can call at any
|
|
4
|
+
// point in a session. They build on the existing `memory-store.ts` layer
|
|
5
|
+
// (SQLite memories table) and degrade gracefully when the DB is unavailable.
|
|
6
|
+
//
|
|
7
|
+
// Phase 1 scope:
|
|
8
|
+
// - capture_thought → create a memory with the caller-supplied category/content
|
|
9
|
+
// - memory_query → keyword-filtered, score-ranked listing of active memories
|
|
10
|
+
// - gsd_graph → returns a memory and its supersedes edges only (Phase 4 adds memory_relations)
|
|
11
|
+
import { _getAdapter, isDbAvailable } from "../gsd-db.js";
|
|
12
|
+
import { createMemory, getActiveMemoriesRanked, queryMemoriesRanked, reinforceMemory, } from "../memory-store.js";
|
|
13
|
+
import { traverseGraph } from "../memory-relations.js";
|
|
14
|
+
function dbUnavailable(operation) {
|
|
15
|
+
return {
|
|
16
|
+
content: [
|
|
17
|
+
{
|
|
18
|
+
type: "text",
|
|
19
|
+
text: "Error: GSD database is not available. Memory tools require an initialized .gsd/ project.",
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
details: { operation, error: "db_unavailable" },
|
|
23
|
+
isError: true,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const VALID_CATEGORIES = new Set([
|
|
27
|
+
"architecture",
|
|
28
|
+
"convention",
|
|
29
|
+
"gotcha",
|
|
30
|
+
"preference",
|
|
31
|
+
"environment",
|
|
32
|
+
"pattern",
|
|
33
|
+
]);
|
|
34
|
+
export function executeMemoryCapture(params) {
|
|
35
|
+
if (!isDbAvailable())
|
|
36
|
+
return dbUnavailable("memory_capture");
|
|
37
|
+
const category = (params.category ?? "").trim().toLowerCase();
|
|
38
|
+
const content = (params.content ?? "").trim();
|
|
39
|
+
if (!category || !content) {
|
|
40
|
+
return {
|
|
41
|
+
content: [{ type: "text", text: "Error: category and content are required." }],
|
|
42
|
+
details: { operation: "memory_capture", error: "missing_fields" },
|
|
43
|
+
isError: true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (!VALID_CATEGORIES.has(category)) {
|
|
47
|
+
return {
|
|
48
|
+
content: [
|
|
49
|
+
{
|
|
50
|
+
type: "text",
|
|
51
|
+
text: `Error: invalid category "${category}". Must be one of: ${[...VALID_CATEGORIES].join(", ")}.`,
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
details: { operation: "memory_capture", error: "invalid_category" },
|
|
55
|
+
isError: true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const confidence = clampConfidence(params.confidence);
|
|
59
|
+
const scope = normalizeScope(params.scope);
|
|
60
|
+
const tags = normalizeTags(params.tags);
|
|
61
|
+
const id = createMemory({ category, content, confidence, scope, tags });
|
|
62
|
+
if (!id) {
|
|
63
|
+
return {
|
|
64
|
+
content: [{ type: "text", text: "Error: failed to create memory." }],
|
|
65
|
+
details: { operation: "memory_capture", error: "create_failed" },
|
|
66
|
+
isError: true,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
content: [{ type: "text", text: `Captured ${id} (${category}): ${content}` }],
|
|
71
|
+
details: { operation: "memory_capture", id, category, confidence, scope, tags },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function normalizeScope(value) {
|
|
75
|
+
if (typeof value !== "string")
|
|
76
|
+
return "project";
|
|
77
|
+
const trimmed = value.trim();
|
|
78
|
+
return trimmed.length === 0 ? "project" : trimmed;
|
|
79
|
+
}
|
|
80
|
+
function normalizeTags(value) {
|
|
81
|
+
if (!Array.isArray(value))
|
|
82
|
+
return [];
|
|
83
|
+
return value.filter((t) => typeof t === "string" && t.trim().length > 0).slice(0, 10);
|
|
84
|
+
}
|
|
85
|
+
function clampConfidence(value) {
|
|
86
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
87
|
+
return 0.8;
|
|
88
|
+
if (value < 0.1)
|
|
89
|
+
return 0.1;
|
|
90
|
+
if (value > 0.99)
|
|
91
|
+
return 0.99;
|
|
92
|
+
return value;
|
|
93
|
+
}
|
|
94
|
+
export function executeMemoryQuery(params) {
|
|
95
|
+
if (!isDbAvailable())
|
|
96
|
+
return dbUnavailable("memory_query");
|
|
97
|
+
const query = (params.query ?? "").trim();
|
|
98
|
+
const k = clampTopK(params.k, 10);
|
|
99
|
+
const includeSuperseded = params.include_superseded === true;
|
|
100
|
+
const category = params.category?.trim().toLowerCase() || undefined;
|
|
101
|
+
const scopeFilter = params.scope?.trim() || undefined;
|
|
102
|
+
const tagFilter = params.tag?.trim().toLowerCase() || undefined;
|
|
103
|
+
try {
|
|
104
|
+
let ranked = [];
|
|
105
|
+
if (query) {
|
|
106
|
+
ranked = queryMemoriesRanked({
|
|
107
|
+
query,
|
|
108
|
+
k,
|
|
109
|
+
category,
|
|
110
|
+
scope: scopeFilter,
|
|
111
|
+
tag: tagFilter,
|
|
112
|
+
include_superseded: includeSuperseded,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
const candidates = includeSuperseded
|
|
117
|
+
? includeSupersededMemories(getActiveMemoriesRanked(200))
|
|
118
|
+
: getActiveMemoriesRanked(200);
|
|
119
|
+
ranked = candidates
|
|
120
|
+
.filter((m) => {
|
|
121
|
+
if (category && m.category.toLowerCase() !== category)
|
|
122
|
+
return false;
|
|
123
|
+
if (scopeFilter && m.scope !== scopeFilter)
|
|
124
|
+
return false;
|
|
125
|
+
if (tagFilter && !m.tags.map((t) => t.toLowerCase()).includes(tagFilter))
|
|
126
|
+
return false;
|
|
127
|
+
return true;
|
|
128
|
+
})
|
|
129
|
+
.slice(0, k)
|
|
130
|
+
.map((memory) => ({
|
|
131
|
+
memory,
|
|
132
|
+
score: memory.confidence * (1 + memory.hit_count * 0.1),
|
|
133
|
+
keywordRank: null,
|
|
134
|
+
semanticRank: null,
|
|
135
|
+
confidenceBoost: memory.confidence * (1 + memory.hit_count * 0.1),
|
|
136
|
+
reason: "ranked",
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
const hits = ranked.map((r) => ({
|
|
140
|
+
id: r.memory.id,
|
|
141
|
+
category: r.memory.category,
|
|
142
|
+
content: r.memory.content,
|
|
143
|
+
confidence: r.memory.confidence,
|
|
144
|
+
hit_count: r.memory.hit_count,
|
|
145
|
+
score: r.score,
|
|
146
|
+
reason: r.reason,
|
|
147
|
+
keyword_rank: r.keywordRank,
|
|
148
|
+
semantic_rank: r.semanticRank,
|
|
149
|
+
}));
|
|
150
|
+
if (params.reinforce_hits) {
|
|
151
|
+
for (const h of hits)
|
|
152
|
+
reinforceMemory(h.id);
|
|
153
|
+
}
|
|
154
|
+
const summary = hits.length === 0
|
|
155
|
+
? "No matching memories."
|
|
156
|
+
: hits.map((h) => `- [${h.id}] (${h.category}) ${h.content}`).join("\n");
|
|
157
|
+
return {
|
|
158
|
+
content: [{ type: "text", text: summary }],
|
|
159
|
+
details: {
|
|
160
|
+
operation: "memory_query",
|
|
161
|
+
query,
|
|
162
|
+
k,
|
|
163
|
+
returned: hits.length,
|
|
164
|
+
hits,
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
return {
|
|
170
|
+
content: [{ type: "text", text: `Error: memory query failed: ${err.message}` }],
|
|
171
|
+
details: { operation: "memory_query", error: err.message },
|
|
172
|
+
isError: true,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function clampTopK(value, fallback) {
|
|
177
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
178
|
+
return fallback;
|
|
179
|
+
if (value < 1)
|
|
180
|
+
return 1;
|
|
181
|
+
if (value > 50)
|
|
182
|
+
return 50;
|
|
183
|
+
return Math.floor(value);
|
|
184
|
+
}
|
|
185
|
+
function includeSupersededMemories(rankedActive) {
|
|
186
|
+
const adapter = _getAdapter();
|
|
187
|
+
if (!adapter)
|
|
188
|
+
return rankedActive;
|
|
189
|
+
try {
|
|
190
|
+
const rows = adapter.prepare("SELECT * FROM memories").all();
|
|
191
|
+
return rows.map((row) => {
|
|
192
|
+
let tags = [];
|
|
193
|
+
if (typeof row["tags"] === "string") {
|
|
194
|
+
try {
|
|
195
|
+
const parsed = JSON.parse(row["tags"]);
|
|
196
|
+
if (Array.isArray(parsed))
|
|
197
|
+
tags = parsed.filter((t) => typeof t === "string");
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
/* leave empty */
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
seq: row["seq"],
|
|
205
|
+
id: row["id"],
|
|
206
|
+
category: row["category"],
|
|
207
|
+
content: row["content"],
|
|
208
|
+
confidence: row["confidence"],
|
|
209
|
+
source_unit_type: row["source_unit_type"] ?? null,
|
|
210
|
+
source_unit_id: row["source_unit_id"] ?? null,
|
|
211
|
+
created_at: row["created_at"],
|
|
212
|
+
updated_at: row["updated_at"],
|
|
213
|
+
superseded_by: row["superseded_by"] ?? null,
|
|
214
|
+
hit_count: row["hit_count"],
|
|
215
|
+
scope: row["scope"] ?? "project",
|
|
216
|
+
tags,
|
|
217
|
+
};
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return rankedActive;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
export function executeGsdGraph(params) {
|
|
225
|
+
if (!isDbAvailable())
|
|
226
|
+
return dbUnavailable("gsd_graph");
|
|
227
|
+
if (params.mode === "build") {
|
|
228
|
+
// The extractor emits LINK actions incrementally (Phase 4). There is no
|
|
229
|
+
// batch rebuild step to run today — ingest artifacts via `/gsd memory
|
|
230
|
+
// extract <SRC-...>` and the next extraction turn will add edges.
|
|
231
|
+
return {
|
|
232
|
+
content: [
|
|
233
|
+
{
|
|
234
|
+
type: "text",
|
|
235
|
+
text: "gsd_graph build acknowledged. Graph edges are populated incrementally by memory " +
|
|
236
|
+
"extraction (including LINK actions). Use `/gsd memory extract <SRC-...>` to trigger " +
|
|
237
|
+
"extraction against a specific ingested source.",
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
details: { operation: "gsd_graph", mode: "build", built: 0 },
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
if (params.mode !== "query") {
|
|
244
|
+
return {
|
|
245
|
+
content: [{ type: "text", text: `Error: unknown mode "${params.mode}". Must be "build" or "query".` }],
|
|
246
|
+
details: { operation: "gsd_graph", error: "invalid_mode" },
|
|
247
|
+
isError: true,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
const memoryId = params.memoryId?.trim();
|
|
251
|
+
if (!memoryId) {
|
|
252
|
+
return {
|
|
253
|
+
content: [{ type: "text", text: "Error: memoryId is required for mode=query." }],
|
|
254
|
+
details: { operation: "gsd_graph", error: "missing_memory_id" },
|
|
255
|
+
isError: true,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
const graph = traverseGraph(memoryId, clampDepth(params.depth));
|
|
260
|
+
const rel = params.rel?.trim().toLowerCase() || null;
|
|
261
|
+
const edges = rel ? graph.edges.filter((e) => e.rel === rel) : graph.edges;
|
|
262
|
+
const relevantIds = new Set([memoryId]);
|
|
263
|
+
for (const e of edges) {
|
|
264
|
+
relevantIds.add(e.from);
|
|
265
|
+
relevantIds.add(e.to);
|
|
266
|
+
}
|
|
267
|
+
const nodes = graph.nodes.filter((n) => relevantIds.has(n.id));
|
|
268
|
+
if (nodes.length === 0) {
|
|
269
|
+
return {
|
|
270
|
+
content: [{ type: "text", text: `No memory found with id ${memoryId}.` }],
|
|
271
|
+
details: { operation: "gsd_graph", mode: "query", memoryId, nodes: [], edges: [] },
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
const summary = [
|
|
275
|
+
`Memory ${memoryId} — ${nodes.length} node(s), ${edges.length} edge(s).`,
|
|
276
|
+
...nodes.map((n) => ` [${n.id}] (${n.category}) ${n.content}`),
|
|
277
|
+
...edges.map((e) => ` ${e.from} --${e.rel}-> ${e.to}`),
|
|
278
|
+
].join("\n");
|
|
279
|
+
return {
|
|
280
|
+
content: [{ type: "text", text: summary }],
|
|
281
|
+
details: {
|
|
282
|
+
operation: "gsd_graph",
|
|
283
|
+
mode: "query",
|
|
284
|
+
memoryId,
|
|
285
|
+
nodes: nodes.map((n) => ({ id: n.id, category: n.category, content: n.content })),
|
|
286
|
+
edges: edges.map((e) => ({ from: e.from, to: e.to, rel: e.rel })),
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
catch (err) {
|
|
291
|
+
return {
|
|
292
|
+
content: [{ type: "text", text: `Error: graph query failed: ${err.message}` }],
|
|
293
|
+
details: { operation: "gsd_graph", error: err.message },
|
|
294
|
+
isError: true,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function clampDepth(value) {
|
|
299
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
300
|
+
return 1;
|
|
301
|
+
if (value < 0)
|
|
302
|
+
return 0;
|
|
303
|
+
if (value > 5)
|
|
304
|
+
return 5;
|
|
305
|
+
return Math.floor(value);
|
|
306
|
+
}
|
|
@@ -4,6 +4,8 @@ import { loadWriteGateSnapshot, shouldBlockContextArtifactSaveInSnapshot } from
|
|
|
4
4
|
import { getMilestone, getSliceStatusSummary, getSliceTaskCounts, readTransaction, saveGateResult, } from "../gsd-db.js";
|
|
5
5
|
import { GATE_REGISTRY } from "../gate-registry.js";
|
|
6
6
|
import { saveArtifactToDb } from "../db-writer.js";
|
|
7
|
+
import { resolveMilestoneFile, resolveSliceFile } from "../paths.js";
|
|
8
|
+
import { unlinkSync } from "node:fs";
|
|
7
9
|
import { handleCompleteMilestone } from "./complete-milestone.js";
|
|
8
10
|
import { handleCompleteTask } from "./complete-task.js";
|
|
9
11
|
import { handleCompleteSlice } from "./complete-slice.js";
|
|
@@ -61,6 +63,18 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
|
|
|
61
63
|
slice_id: params.slice_id,
|
|
62
64
|
task_id: params.task_id,
|
|
63
65
|
}, basePath);
|
|
66
|
+
if (params.artifact_type === "CONTEXT" && !params.task_id) {
|
|
67
|
+
try {
|
|
68
|
+
const draftFile = params.slice_id
|
|
69
|
+
? resolveSliceFile(basePath, params.milestone_id, params.slice_id, "CONTEXT-DRAFT")
|
|
70
|
+
: resolveMilestoneFile(basePath, params.milestone_id, "CONTEXT-DRAFT");
|
|
71
|
+
if (draftFile)
|
|
72
|
+
unlinkSync(draftFile);
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
logWarning("tool", `CONTEXT-DRAFT.md unlink failed: ${e.message}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
64
78
|
return {
|
|
65
79
|
content: [{ type: "text", text: `Saved ${params.artifact_type} artifact to ${relativePath}` }],
|
|
66
80
|
details: { operation: "save_summary", path: relativePath, artifact_type: params.artifact_type },
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* All provider logic lives in provider.ts (S01) — this is pure UI wiring.
|
|
9
9
|
*/
|
|
10
|
+
import { isAnthropicApi } from '@gsd/pi-ai';
|
|
10
11
|
import { getTavilyApiKey, getBraveApiKey, getOllamaApiKey, getSearchProviderPreference, setSearchProviderPreference, resolveSearchProvider, } from './provider.js';
|
|
11
12
|
const VALID_PREFERENCES = ['tavily', 'brave', 'ollama', 'auto'];
|
|
12
13
|
function keyStatus(provider) {
|
|
@@ -71,7 +72,9 @@ export function registerSearchProviderCommand(pi) {
|
|
|
71
72
|
}
|
|
72
73
|
setSearchProviderPreference(chosen);
|
|
73
74
|
const effective = resolveSearchProvider();
|
|
74
|
-
|
|
75
|
+
// Gate on api (#4478 / ADR-012): covers claude-code, anthropic-vertex, and
|
|
76
|
+
// other Anthropic-fronting transports — not just the plain `anthropic` provider.
|
|
77
|
+
const isAnthropic = isAnthropicApi(ctx.model);
|
|
75
78
|
const nativeNote = isAnthropic ? '\nNote: Native Anthropic web search is also active (automatic, no API key needed).' : '';
|
|
76
79
|
ctx.ui.notify(`Search provider set to ${chosen}. Effective provider: ${effective ?? 'none (no API keys)'}${nativeNote}`, 'info');
|
|
77
80
|
},
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Extracted from index.ts so it can be unit-tested without importing
|
|
5
5
|
* the heavy tool-registration modules.
|
|
6
6
|
*/
|
|
7
|
+
import { isAnthropicApi } from "@gsd/pi-ai";
|
|
7
8
|
import { resolveSearchProviderFromPreferences } from "../gsd/preferences.js";
|
|
8
9
|
/** Tool names for the Brave-backed custom search tools */
|
|
9
10
|
export const BRAVE_TOOL_NAMES = ["search-the-web", "search_and_read"];
|
|
@@ -75,7 +76,10 @@ export function registerNativeSearchHooks(pi) {
|
|
|
75
76
|
pi.on("model_select", async (event, ctx) => {
|
|
76
77
|
modelSelectFired = true;
|
|
77
78
|
const wasAnthropic = isAnthropicProvider;
|
|
78
|
-
|
|
79
|
+
// Gate on `api` not `provider` (#4478 / ADR-012): covers claude-code OAuth,
|
|
80
|
+
// anthropic-vertex, and Vercel-gateway-hosted Anthropic — all serve the
|
|
81
|
+
// Messages API and accept the native web_search tool.
|
|
82
|
+
isAnthropicProvider = isAnthropicApi(event.model);
|
|
79
83
|
const hasBrave = !!process.env.BRAVE_API_KEY;
|
|
80
84
|
// When Anthropic (and not preferring Brave): disable custom search tools —
|
|
81
85
|
// native web_search is server-side and more reliable.
|
|
@@ -116,7 +120,14 @@ export function registerNativeSearchHooks(pi) {
|
|
|
116
120
|
// modelsAreEqual suppresses model_select AND the SDK doesn't pass model.
|
|
117
121
|
const eventModel = event.model;
|
|
118
122
|
let isAnthropic;
|
|
119
|
-
if (eventModel?.
|
|
123
|
+
if (eventModel?.api) {
|
|
124
|
+
// Preferred path: gate on wire protocol (#4478 / ADR-012).
|
|
125
|
+
isAnthropic = isAnthropicApi(eventModel);
|
|
126
|
+
}
|
|
127
|
+
else if (eventModel?.provider) {
|
|
128
|
+
// Fallback for event shapes that carry provider but not api — only plain
|
|
129
|
+
// `anthropic` maps unambiguously without the api field. Other Anthropic
|
|
130
|
+
// transports will arrive via the modelSelectFired or model-name branch.
|
|
120
131
|
isAnthropic = eventModel.provider === "anthropic";
|
|
121
132
|
}
|
|
122
133
|
else if (modelSelectFired) {
|