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,380 @@
|
|
|
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
|
+
|
|
12
|
+
import { _getAdapter, isDbAvailable } from "../gsd-db.js";
|
|
13
|
+
import {
|
|
14
|
+
createMemory,
|
|
15
|
+
getActiveMemoriesRanked,
|
|
16
|
+
queryMemoriesRanked,
|
|
17
|
+
reinforceMemory,
|
|
18
|
+
} from "../memory-store.js";
|
|
19
|
+
import type { Memory, RankedMemory } from "../memory-store.js";
|
|
20
|
+
import { traverseGraph } from "../memory-relations.js";
|
|
21
|
+
|
|
22
|
+
// ─── Shared result shape (matches tools/workflow-tool-executors.ts) ─────────
|
|
23
|
+
|
|
24
|
+
export interface ToolExecutionResult {
|
|
25
|
+
content: Array<{ type: "text"; text: string }>;
|
|
26
|
+
details: Record<string, unknown>;
|
|
27
|
+
isError?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function dbUnavailable(operation: string): ToolExecutionResult {
|
|
31
|
+
return {
|
|
32
|
+
content: [
|
|
33
|
+
{
|
|
34
|
+
type: "text",
|
|
35
|
+
text: "Error: GSD database is not available. Memory tools require an initialized .gsd/ project.",
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
details: { operation, error: "db_unavailable" },
|
|
39
|
+
isError: true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ─── capture_thought ────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
export interface MemoryCaptureParams {
|
|
46
|
+
category: string;
|
|
47
|
+
content: string;
|
|
48
|
+
confidence?: number;
|
|
49
|
+
tags?: string[];
|
|
50
|
+
scope?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const VALID_CATEGORIES = new Set([
|
|
54
|
+
"architecture",
|
|
55
|
+
"convention",
|
|
56
|
+
"gotcha",
|
|
57
|
+
"preference",
|
|
58
|
+
"environment",
|
|
59
|
+
"pattern",
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
export function executeMemoryCapture(params: MemoryCaptureParams): ToolExecutionResult {
|
|
63
|
+
if (!isDbAvailable()) return dbUnavailable("memory_capture");
|
|
64
|
+
|
|
65
|
+
const category = (params.category ?? "").trim().toLowerCase();
|
|
66
|
+
const content = (params.content ?? "").trim();
|
|
67
|
+
if (!category || !content) {
|
|
68
|
+
return {
|
|
69
|
+
content: [{ type: "text", text: "Error: category and content are required." }],
|
|
70
|
+
details: { operation: "memory_capture", error: "missing_fields" },
|
|
71
|
+
isError: true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (!VALID_CATEGORIES.has(category)) {
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: "text",
|
|
79
|
+
text: `Error: invalid category "${category}". Must be one of: ${[...VALID_CATEGORIES].join(", ")}.`,
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
details: { operation: "memory_capture", error: "invalid_category" },
|
|
83
|
+
isError: true,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const confidence = clampConfidence(params.confidence);
|
|
87
|
+
const scope = normalizeScope(params.scope);
|
|
88
|
+
const tags = normalizeTags(params.tags);
|
|
89
|
+
|
|
90
|
+
const id = createMemory({ category, content, confidence, scope, tags });
|
|
91
|
+
if (!id) {
|
|
92
|
+
return {
|
|
93
|
+
content: [{ type: "text", text: "Error: failed to create memory." }],
|
|
94
|
+
details: { operation: "memory_capture", error: "create_failed" },
|
|
95
|
+
isError: true,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
content: [{ type: "text", text: `Captured ${id} (${category}): ${content}` }],
|
|
101
|
+
details: { operation: "memory_capture", id, category, confidence, scope, tags },
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function normalizeScope(value: unknown): string {
|
|
106
|
+
if (typeof value !== "string") return "project";
|
|
107
|
+
const trimmed = value.trim();
|
|
108
|
+
return trimmed.length === 0 ? "project" : trimmed;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function normalizeTags(value: unknown): string[] {
|
|
112
|
+
if (!Array.isArray(value)) return [];
|
|
113
|
+
return value.filter((t): t is string => typeof t === "string" && t.trim().length > 0).slice(0, 10);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function clampConfidence(value: unknown): number {
|
|
117
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return 0.8;
|
|
118
|
+
if (value < 0.1) return 0.1;
|
|
119
|
+
if (value > 0.99) return 0.99;
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ─── memory_query ───────────────────────────────────────────────────────────
|
|
124
|
+
|
|
125
|
+
export interface MemoryQueryParams {
|
|
126
|
+
query: string;
|
|
127
|
+
k?: number;
|
|
128
|
+
category?: string;
|
|
129
|
+
scope?: string;
|
|
130
|
+
tag?: string;
|
|
131
|
+
include_superseded?: boolean;
|
|
132
|
+
reinforce_hits?: boolean;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface MemoryQueryHit {
|
|
136
|
+
id: string;
|
|
137
|
+
category: string;
|
|
138
|
+
content: string;
|
|
139
|
+
confidence: number;
|
|
140
|
+
hit_count: number;
|
|
141
|
+
score: number;
|
|
142
|
+
reason: "keyword" | "semantic" | "both" | "ranked";
|
|
143
|
+
keyword_rank: number | null;
|
|
144
|
+
semantic_rank: number | null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function executeMemoryQuery(params: MemoryQueryParams): ToolExecutionResult {
|
|
148
|
+
if (!isDbAvailable()) return dbUnavailable("memory_query");
|
|
149
|
+
|
|
150
|
+
const query = (params.query ?? "").trim();
|
|
151
|
+
const k = clampTopK(params.k, 10);
|
|
152
|
+
const includeSuperseded = params.include_superseded === true;
|
|
153
|
+
const category = params.category?.trim().toLowerCase() || undefined;
|
|
154
|
+
const scopeFilter = params.scope?.trim() || undefined;
|
|
155
|
+
const tagFilter = params.tag?.trim().toLowerCase() || undefined;
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
let ranked: RankedMemory[] = [];
|
|
159
|
+
if (query) {
|
|
160
|
+
ranked = queryMemoriesRanked({
|
|
161
|
+
query,
|
|
162
|
+
k,
|
|
163
|
+
category,
|
|
164
|
+
scope: scopeFilter,
|
|
165
|
+
tag: tagFilter,
|
|
166
|
+
include_superseded: includeSuperseded,
|
|
167
|
+
});
|
|
168
|
+
} else {
|
|
169
|
+
const candidates: Memory[] = includeSuperseded
|
|
170
|
+
? includeSupersededMemories(getActiveMemoriesRanked(200))
|
|
171
|
+
: getActiveMemoriesRanked(200);
|
|
172
|
+
ranked = candidates
|
|
173
|
+
.filter((m) => {
|
|
174
|
+
if (category && m.category.toLowerCase() !== category) return false;
|
|
175
|
+
if (scopeFilter && m.scope !== scopeFilter) return false;
|
|
176
|
+
if (tagFilter && !m.tags.map((t) => t.toLowerCase()).includes(tagFilter)) return false;
|
|
177
|
+
return true;
|
|
178
|
+
})
|
|
179
|
+
.slice(0, k)
|
|
180
|
+
.map((memory) => ({
|
|
181
|
+
memory,
|
|
182
|
+
score: memory.confidence * (1 + memory.hit_count * 0.1),
|
|
183
|
+
keywordRank: null,
|
|
184
|
+
semanticRank: null,
|
|
185
|
+
confidenceBoost: memory.confidence * (1 + memory.hit_count * 0.1),
|
|
186
|
+
reason: "ranked" as const,
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const hits: MemoryQueryHit[] = ranked.map((r) => ({
|
|
191
|
+
id: r.memory.id,
|
|
192
|
+
category: r.memory.category,
|
|
193
|
+
content: r.memory.content,
|
|
194
|
+
confidence: r.memory.confidence,
|
|
195
|
+
hit_count: r.memory.hit_count,
|
|
196
|
+
score: r.score,
|
|
197
|
+
reason: r.reason,
|
|
198
|
+
keyword_rank: r.keywordRank,
|
|
199
|
+
semantic_rank: r.semanticRank,
|
|
200
|
+
}));
|
|
201
|
+
|
|
202
|
+
if (params.reinforce_hits) {
|
|
203
|
+
for (const h of hits) reinforceMemory(h.id);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const summary = hits.length === 0
|
|
207
|
+
? "No matching memories."
|
|
208
|
+
: hits.map((h) => `- [${h.id}] (${h.category}) ${h.content}`).join("\n");
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
content: [{ type: "text", text: summary }],
|
|
212
|
+
details: {
|
|
213
|
+
operation: "memory_query",
|
|
214
|
+
query,
|
|
215
|
+
k,
|
|
216
|
+
returned: hits.length,
|
|
217
|
+
hits,
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
} catch (err) {
|
|
221
|
+
return {
|
|
222
|
+
content: [{ type: "text", text: `Error: memory query failed: ${(err as Error).message}` }],
|
|
223
|
+
details: { operation: "memory_query", error: (err as Error).message },
|
|
224
|
+
isError: true,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function clampTopK(value: unknown, fallback: number): number {
|
|
230
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
|
231
|
+
if (value < 1) return 1;
|
|
232
|
+
if (value > 50) return 50;
|
|
233
|
+
return Math.floor(value);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function includeSupersededMemories(rankedActive: Memory[]): Memory[] {
|
|
237
|
+
const adapter = _getAdapter();
|
|
238
|
+
if (!adapter) return rankedActive;
|
|
239
|
+
try {
|
|
240
|
+
const rows = adapter.prepare("SELECT * FROM memories").all();
|
|
241
|
+
return rows.map((row) => {
|
|
242
|
+
let tags: string[] = [];
|
|
243
|
+
if (typeof row["tags"] === "string") {
|
|
244
|
+
try {
|
|
245
|
+
const parsed = JSON.parse(row["tags"] as string);
|
|
246
|
+
if (Array.isArray(parsed)) tags = parsed.filter((t): t is string => typeof t === "string");
|
|
247
|
+
} catch {
|
|
248
|
+
/* leave empty */
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
seq: row["seq"] as number,
|
|
253
|
+
id: row["id"] as string,
|
|
254
|
+
category: row["category"] as string,
|
|
255
|
+
content: row["content"] as string,
|
|
256
|
+
confidence: row["confidence"] as number,
|
|
257
|
+
source_unit_type: (row["source_unit_type"] as string) ?? null,
|
|
258
|
+
source_unit_id: (row["source_unit_id"] as string) ?? null,
|
|
259
|
+
created_at: row["created_at"] as string,
|
|
260
|
+
updated_at: row["updated_at"] as string,
|
|
261
|
+
superseded_by: (row["superseded_by"] as string) ?? null,
|
|
262
|
+
hit_count: row["hit_count"] as number,
|
|
263
|
+
scope: (row["scope"] as string) ?? "project",
|
|
264
|
+
tags,
|
|
265
|
+
};
|
|
266
|
+
});
|
|
267
|
+
} catch {
|
|
268
|
+
return rankedActive;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// ─── gsd_graph ──────────────────────────────────────────────────────────────
|
|
273
|
+
|
|
274
|
+
export interface GsdGraphParams {
|
|
275
|
+
mode: "build" | "query";
|
|
276
|
+
memoryId?: string;
|
|
277
|
+
depth?: number;
|
|
278
|
+
rel?: string;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export interface GraphNode {
|
|
282
|
+
id: string;
|
|
283
|
+
category: string;
|
|
284
|
+
content: string;
|
|
285
|
+
confidence: number;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export interface GraphEdge {
|
|
289
|
+
from: string;
|
|
290
|
+
to: string;
|
|
291
|
+
rel: string;
|
|
292
|
+
confidence: number;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export function executeGsdGraph(params: GsdGraphParams): ToolExecutionResult {
|
|
296
|
+
if (!isDbAvailable()) return dbUnavailable("gsd_graph");
|
|
297
|
+
|
|
298
|
+
if (params.mode === "build") {
|
|
299
|
+
// The extractor emits LINK actions incrementally (Phase 4). There is no
|
|
300
|
+
// batch rebuild step to run today — ingest artifacts via `/gsd memory
|
|
301
|
+
// extract <SRC-...>` and the next extraction turn will add edges.
|
|
302
|
+
return {
|
|
303
|
+
content: [
|
|
304
|
+
{
|
|
305
|
+
type: "text",
|
|
306
|
+
text:
|
|
307
|
+
"gsd_graph build acknowledged. Graph edges are populated incrementally by memory " +
|
|
308
|
+
"extraction (including LINK actions). Use `/gsd memory extract <SRC-...>` to trigger " +
|
|
309
|
+
"extraction against a specific ingested source.",
|
|
310
|
+
},
|
|
311
|
+
],
|
|
312
|
+
details: { operation: "gsd_graph", mode: "build", built: 0 },
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (params.mode !== "query") {
|
|
317
|
+
return {
|
|
318
|
+
content: [{ type: "text", text: `Error: unknown mode "${params.mode}". Must be "build" or "query".` }],
|
|
319
|
+
details: { operation: "gsd_graph", error: "invalid_mode" },
|
|
320
|
+
isError: true,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const memoryId = params.memoryId?.trim();
|
|
325
|
+
if (!memoryId) {
|
|
326
|
+
return {
|
|
327
|
+
content: [{ type: "text", text: "Error: memoryId is required for mode=query." }],
|
|
328
|
+
details: { operation: "gsd_graph", error: "missing_memory_id" },
|
|
329
|
+
isError: true,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
const graph = traverseGraph(memoryId, clampDepth(params.depth));
|
|
335
|
+
const rel = params.rel?.trim().toLowerCase() || null;
|
|
336
|
+
const edges = rel ? graph.edges.filter((e) => e.rel === rel) : graph.edges;
|
|
337
|
+
const relevantIds = new Set<string>([memoryId]);
|
|
338
|
+
for (const e of edges) {
|
|
339
|
+
relevantIds.add(e.from);
|
|
340
|
+
relevantIds.add(e.to);
|
|
341
|
+
}
|
|
342
|
+
const nodes = graph.nodes.filter((n) => relevantIds.has(n.id));
|
|
343
|
+
|
|
344
|
+
if (nodes.length === 0) {
|
|
345
|
+
return {
|
|
346
|
+
content: [{ type: "text", text: `No memory found with id ${memoryId}.` }],
|
|
347
|
+
details: { operation: "gsd_graph", mode: "query", memoryId, nodes: [], edges: [] },
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const summary = [
|
|
352
|
+
`Memory ${memoryId} — ${nodes.length} node(s), ${edges.length} edge(s).`,
|
|
353
|
+
...nodes.map((n) => ` [${n.id}] (${n.category}) ${n.content}`),
|
|
354
|
+
...edges.map((e) => ` ${e.from} --${e.rel}-> ${e.to}`),
|
|
355
|
+
].join("\n");
|
|
356
|
+
return {
|
|
357
|
+
content: [{ type: "text", text: summary }],
|
|
358
|
+
details: {
|
|
359
|
+
operation: "gsd_graph",
|
|
360
|
+
mode: "query",
|
|
361
|
+
memoryId,
|
|
362
|
+
nodes: nodes.map((n) => ({ id: n.id, category: n.category, content: n.content })),
|
|
363
|
+
edges: edges.map((e) => ({ from: e.from, to: e.to, rel: e.rel })),
|
|
364
|
+
},
|
|
365
|
+
};
|
|
366
|
+
} catch (err) {
|
|
367
|
+
return {
|
|
368
|
+
content: [{ type: "text", text: `Error: graph query failed: ${(err as Error).message}` }],
|
|
369
|
+
details: { operation: "gsd_graph", error: (err as Error).message },
|
|
370
|
+
isError: true,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function clampDepth(value: unknown): number {
|
|
376
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return 1;
|
|
377
|
+
if (value < 0) return 0;
|
|
378
|
+
if (value > 5) return 5;
|
|
379
|
+
return Math.floor(value);
|
|
380
|
+
}
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
} from "../gsd-db.js";
|
|
11
11
|
import { GATE_REGISTRY } from "../gate-registry.js";
|
|
12
12
|
import { saveArtifactToDb } from "../db-writer.js";
|
|
13
|
+
import { resolveMilestoneFile, resolveSliceFile } from "../paths.js";
|
|
14
|
+
import { unlinkSync } from "node:fs";
|
|
13
15
|
import type { CompleteMilestoneParams } from "./complete-milestone.js";
|
|
14
16
|
import { handleCompleteMilestone } from "./complete-milestone.js";
|
|
15
17
|
import { handleCompleteTask } from "./complete-task.js";
|
|
@@ -103,6 +105,18 @@ export async function executeSummarySave(
|
|
|
103
105
|
},
|
|
104
106
|
basePath,
|
|
105
107
|
);
|
|
108
|
+
|
|
109
|
+
if (params.artifact_type === "CONTEXT" && !params.task_id) {
|
|
110
|
+
try {
|
|
111
|
+
const draftFile = params.slice_id
|
|
112
|
+
? resolveSliceFile(basePath, params.milestone_id, params.slice_id, "CONTEXT-DRAFT")
|
|
113
|
+
: resolveMilestoneFile(basePath, params.milestone_id, "CONTEXT-DRAFT");
|
|
114
|
+
if (draftFile) unlinkSync(draftFile);
|
|
115
|
+
} catch (e) {
|
|
116
|
+
logWarning("tool", `CONTEXT-DRAFT.md unlink failed: ${(e as Error).message}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
106
120
|
return {
|
|
107
121
|
content: [{ type: "text", text: `Saved ${params.artifact_type} artifact to ${relativePath}` }],
|
|
108
122
|
details: { operation: "save_summary", path: relativePath, artifact_type: params.artifact_type },
|
|
@@ -54,7 +54,9 @@ export type LogComponent =
|
|
|
54
54
|
| "registry" // Rule registry hook state
|
|
55
55
|
| "renderer" // Markdown renderer and projections
|
|
56
56
|
| "safety" // LLM safety harness
|
|
57
|
-
| "ecosystem"
|
|
57
|
+
| "ecosystem" // GSD ecosystem extension loader and dispatch
|
|
58
|
+
| "memory-embeddings" // Memory layer embedding generation
|
|
59
|
+
| "memory-ingest"; // Memory layer ingestion pipeline
|
|
58
60
|
|
|
59
61
|
export interface LogEntry {
|
|
60
62
|
ts: string;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* All provider logic lives in provider.ts (S01) — this is pure UI wiring.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
import { isAnthropicApi } from '@gsd/pi-ai'
|
|
11
12
|
import type { ExtensionAPI } from '@gsd/pi-coding-agent'
|
|
12
13
|
import type { AutocompleteItem } from '@gsd/pi-tui'
|
|
13
14
|
import {
|
|
@@ -90,7 +91,9 @@ export function registerSearchProviderCommand(pi: ExtensionAPI): void {
|
|
|
90
91
|
|
|
91
92
|
setSearchProviderPreference(chosen)
|
|
92
93
|
const effective = resolveSearchProvider()
|
|
93
|
-
|
|
94
|
+
// Gate on api (#4478 / ADR-012): covers claude-code, anthropic-vertex, and
|
|
95
|
+
// other Anthropic-fronting transports — not just the plain `anthropic` provider.
|
|
96
|
+
const isAnthropic = isAnthropicApi(ctx.model)
|
|
94
97
|
const nativeNote = isAnthropic ? '\nNote: Native Anthropic web search is also active (automatic, no API key needed).' : ''
|
|
95
98
|
ctx.ui.notify(
|
|
96
99
|
`Search provider set to ${chosen}. Effective provider: ${effective ?? 'none (no API keys)'}${nativeNote}`,
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* the heavy tool-registration modules.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { isAnthropicApi } from "@gsd/pi-ai";
|
|
8
9
|
import { resolveSearchProviderFromPreferences } from "../gsd/preferences.js";
|
|
9
10
|
|
|
10
11
|
/** Tool names for the Brave-backed custom search tools */
|
|
@@ -94,7 +95,10 @@ export function registerNativeSearchHooks(pi: NativeSearchPI): { getIsAnthropic:
|
|
|
94
95
|
pi.on("model_select", async (event: any, ctx: any) => {
|
|
95
96
|
modelSelectFired = true;
|
|
96
97
|
const wasAnthropic = isAnthropicProvider;
|
|
97
|
-
|
|
98
|
+
// Gate on `api` not `provider` (#4478 / ADR-012): covers claude-code OAuth,
|
|
99
|
+
// anthropic-vertex, and Vercel-gateway-hosted Anthropic — all serve the
|
|
100
|
+
// Messages API and accept the native web_search tool.
|
|
101
|
+
isAnthropicProvider = isAnthropicApi(event.model);
|
|
98
102
|
|
|
99
103
|
const hasBrave = !!process.env.BRAVE_API_KEY;
|
|
100
104
|
|
|
@@ -139,9 +143,15 @@ export function registerNativeSearchHooks(pi: NativeSearchPI): { getIsAnthropic:
|
|
|
139
143
|
// the model_select flag, then to the model name heuristic (last resort).
|
|
140
144
|
// The model name heuristic is needed for session restores where
|
|
141
145
|
// modelsAreEqual suppresses model_select AND the SDK doesn't pass model.
|
|
142
|
-
const eventModel = event.model as { provider
|
|
146
|
+
const eventModel = event.model as { provider?: string; api?: string } | undefined;
|
|
143
147
|
let isAnthropic: boolean;
|
|
144
|
-
if (eventModel?.
|
|
148
|
+
if (eventModel?.api) {
|
|
149
|
+
// Preferred path: gate on wire protocol (#4478 / ADR-012).
|
|
150
|
+
isAnthropic = isAnthropicApi(eventModel);
|
|
151
|
+
} else if (eventModel?.provider) {
|
|
152
|
+
// Fallback for event shapes that carry provider but not api — only plain
|
|
153
|
+
// `anthropic` maps unambiguously without the api field. Other Anthropic
|
|
154
|
+
// transports will arrive via the modelSelectFired or model-name branch.
|
|
145
155
|
isAnthropic = eventModel.provider === "anthropic";
|
|
146
156
|
} else if (modelSelectFired) {
|
|
147
157
|
isAnthropic = isAnthropicProvider;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import test from "node:test"
|
|
2
|
-
import assert from "node:assert/strict"
|
|
3
|
-
import { readFileSync } from "node:fs"
|
|
4
|
-
import { join } from "node:path"
|
|
5
|
-
|
|
6
|
-
test("onboarding handler resolves wizard module from deployed runtime paths", () => {
|
|
7
|
-
const source = readFileSync(
|
|
8
|
-
join(import.meta.dirname, "..", "commands", "handlers", "onboarding.ts"),
|
|
9
|
-
"utf-8",
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
assert.match(
|
|
13
|
-
source,
|
|
14
|
-
/process\.env\.GSD_PKG_ROOT/,
|
|
15
|
-
"handler should probe GSD_PKG_ROOT for deployed dist\/onboarding.js",
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
assert.match(
|
|
19
|
-
source,
|
|
20
|
-
/process\.argv\[1\]/,
|
|
21
|
-
"handler should fall back to argv-derived package root when env is missing",
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
assert.match(
|
|
25
|
-
source,
|
|
26
|
-
/candidates\.push\("\.\.\/\.\.\/\.\.\/\.\.\/\.\.\/onboarding\.js"\)/,
|
|
27
|
-
"handler must keep the relative source\/dist fallback",
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
assert.match(
|
|
31
|
-
source,
|
|
32
|
-
/for \(const specifier of candidates\)/,
|
|
33
|
-
"handler should try candidates in order",
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
assert.match(
|
|
37
|
-
source,
|
|
38
|
-
/Failed to load onboarding wizard module/,
|
|
39
|
-
"handler should throw a diagnostic error when no candidate resolves",
|
|
40
|
-
)
|
|
41
|
-
})
|
|
File without changes
|
|
File without changes
|