oscar64-mcp-docs 1.0.7 → 1.0.8
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/stdio.js +148 -302
- package/package.json +1 -1
package/dist/stdio.js
CHANGED
|
@@ -394,67 +394,30 @@ var toolErrorSchema = z.object({
|
|
|
394
394
|
})
|
|
395
395
|
).optional().describe("Optional follow-up tool calls that can recover the workflow.")
|
|
396
396
|
});
|
|
397
|
-
var classificationEvidenceSchema = z.object({
|
|
398
|
-
label: z.string().describe("Label supported by this evidence item."),
|
|
399
|
-
facet: z.enum(["primary_track", "domain", "hardware", "technique", "abstraction", "artifact"]).describe("Facet channel that this evidence contributes to."),
|
|
400
|
-
reason: z.string().describe("Human-readable explanation for why this rule matched."),
|
|
401
|
-
weight: z.number().describe("Weighted contribution from this evidence match."),
|
|
402
|
-
matched_on: z.string().describe("Stable rule identifier that produced the evidence."),
|
|
403
|
-
source_field: z.enum(["title", "rel_path", "text", "files", "asset_refs", "derived"]).describe("Artifact field where the match was detected."),
|
|
404
|
-
matched_text: z.string().describe("Concrete snippet/text token that matched the rule."),
|
|
405
|
-
direct: z.boolean().describe("True when this is a direct artifact signal (API include/symbol) instead of a weak heuristic mention.")
|
|
406
|
-
});
|
|
407
|
-
var classificationDetailsSchema = z.object({
|
|
408
|
-
primary_track: z.string().describe("Selected primary track after evidence gating and fallback handling."),
|
|
409
|
-
primary_track_status: z.enum(["asserted", "neutral_fallback"]).describe("Whether the primary track is directly asserted or forced to a neutral fallback."),
|
|
410
|
-
facets: z.object({
|
|
411
|
-
domain: z.array(z.string()).describe("Functional domains covered by this result."),
|
|
412
|
-
hardware: z.array(z.string()).describe("Hardware domains referenced by this result."),
|
|
413
|
-
technique: z.array(z.string()).describe("Implementation techniques shown in this result."),
|
|
414
|
-
abstraction: z.array(z.string()).describe("Abstraction styles represented in this result."),
|
|
415
|
-
artifact: z.array(z.string()).describe("Artifact kinds used or produced in this result."),
|
|
416
|
-
systems: z.array(systemFamilySchema).describe("Detected target systems for this result; empty means shared/common."),
|
|
417
|
-
scope: z.enum(["tutorial", "sample", "manual"]).describe("Content scope of this result.")
|
|
418
|
-
}),
|
|
419
|
-
confidence: z.number().describe("Calibrated numeric confidence for the primary track decision."),
|
|
420
|
-
confidence_bucket: z.enum(["low", "medium", "high"]).describe("Confidence band intended for policy decisions and quality monitoring."),
|
|
421
|
-
evidence: z.array(classificationEvidenceSchema).describe("Inspectable evidence records used to derive primary track and facets.")
|
|
422
|
-
});
|
|
423
397
|
var classificationSummarySchema = z.object({
|
|
424
398
|
track: z.string().describe("Primary track summary value for routing and filtering."),
|
|
425
399
|
track_status: z.enum(["asserted", "neutral_fallback"]).describe("Whether the summary track was asserted or neutralized by fallback policy."),
|
|
426
|
-
confidence_bucket: z.enum(["low", "medium", "high"]).describe("Coarse confidence bucket for this classification summary.")
|
|
427
|
-
confidence: z.number().describe("Calibrated numeric confidence for summary consumers."),
|
|
428
|
-
domains: z.array(z.string()).describe("Top-level functional domains admitted after evidence gating."),
|
|
429
|
-
hardware: z.array(z.string()).describe("Relevant hardware domains admitted by evidence."),
|
|
430
|
-
techniques: z.array(z.string()).describe("Top techniques surfaced for this result."),
|
|
431
|
-
systems: z.array(systemFamilySchema).describe("Detected target systems for this result; empty means shared/common."),
|
|
432
|
-
scope: z.enum(["tutorial", "sample", "manual"]).describe("Content scope of this result.")
|
|
400
|
+
confidence_bucket: z.enum(["low", "medium", "high"]).describe("Coarse confidence bucket for this classification summary.")
|
|
433
401
|
});
|
|
434
402
|
var searchPreviewSchema = z.object({
|
|
435
403
|
summary: z.string().describe("Compact preview summary for quick relevance checks."),
|
|
436
404
|
signature: z.string().optional().describe("Declaration-like line extracted from content when available."),
|
|
437
|
-
include_path: z.string().optional().describe("Header include path context when relevant.")
|
|
438
|
-
declaration_context: z.string().optional().describe("Nearby declaration context that helps disambiguate similar APIs.")
|
|
405
|
+
include_path: z.string().optional().describe("Header include path context when relevant.")
|
|
439
406
|
});
|
|
440
407
|
var searchHitSchema = z.object({
|
|
441
|
-
source: z.enum(["manual", "code"]).describe("Where the result came from."),
|
|
442
408
|
result_type: z.enum(["topics", "tutorials", "samples", "headers"]).describe("Artifact type for this result."),
|
|
443
409
|
uri: z.string().describe("URI to pass into `read_uri` for full content."),
|
|
444
410
|
title: z.string().describe("Short title for the matched result."),
|
|
445
411
|
preview: searchPreviewSchema.describe("Structured preview fields for relevance evaluation."),
|
|
446
|
-
score: z.number().describe("Relative relevance score; higher means better match."),
|
|
447
412
|
referenced_files: z.array(z.string()).optional().describe("Referenced `code://...` URIs that can be read with `read_uri` (for example from #embed or #include)."),
|
|
448
|
-
classification_summary: classificationSummarySchema.describe("Compact classification metadata always returned.")
|
|
449
|
-
classification_details: classificationDetailsSchema.optional().describe("Detailed classification, included when `include_details=true`.")
|
|
413
|
+
classification_summary: classificationSummarySchema.describe("Compact classification metadata always returned.")
|
|
450
414
|
});
|
|
451
415
|
var searchInputSchema = z.object({
|
|
452
416
|
query: z.string().min(1).describe("Query text, symbol, API name, or error phrase to search for."),
|
|
453
417
|
limit: z.number().int().min(1).max(80).default(20).describe("Maximum number of results to return."),
|
|
454
418
|
type: searchTypeSchema.default("all").describe("Filter results by artifact type. Defaults to `all`."),
|
|
455
|
-
system: systemFilterSchema.default("c64").describe("Target system filter. Defaults to `c64`; use `all` for cross-system search.")
|
|
456
|
-
|
|
457
|
-
});
|
|
419
|
+
system: systemFilterSchema.default("c64").describe("Target system filter. Defaults to `c64`; use `all` for cross-system search.")
|
|
420
|
+
}).strict();
|
|
458
421
|
var searchDataSchema = z.object({
|
|
459
422
|
results: z.array(searchHitSchema).describe("Ranked search hits.")
|
|
460
423
|
});
|
|
@@ -1820,30 +1783,10 @@ var readUriTool = createTool2({
|
|
|
1820
1783
|
// src/mcp/tools/search.tool.ts
|
|
1821
1784
|
import { createTool as createTool3 } from "@mastra/core/tools";
|
|
1822
1785
|
import path9 from "path";
|
|
1823
|
-
var INTENT_SYNONYMS = {
|
|
1824
|
-
screenmem: ["screen", "memory", "screen memory"],
|
|
1825
|
-
charset: ["character set", "font", "d018"],
|
|
1826
|
-
d018: ["charset", "screen memory", "vic"],
|
|
1827
|
-
bank: ["banking", "vic_setbank", "memmap", "bank switch"],
|
|
1828
|
-
banking: ["bank", "vic_setbank", "memmap"],
|
|
1829
|
-
rasterirq: ["raster irq", "rirq", "interrupt"],
|
|
1830
|
-
sprite: ["sprites", "spr_", "vic"],
|
|
1831
|
-
sprites: ["sprite", "spr_", "vic"],
|
|
1832
|
-
charwin: ["cwin", "window", "text window"],
|
|
1833
|
-
joystick: ["joy", "input", "cia"],
|
|
1834
|
-
memmap: ["memory map", "banking", "mmap_"],
|
|
1835
|
-
vic: ["vic_ii", "d018", "screen memory"]
|
|
1836
|
-
};
|
|
1837
1786
|
function parseCodeUri(uri) {
|
|
1838
|
-
if (uri.startsWith("code://oscar/")) {
|
|
1839
|
-
|
|
1840
|
-
}
|
|
1841
|
-
if (uri.startsWith("code://sample/")) {
|
|
1842
|
-
return { scope: "sample", relPath: uri.replace("code://sample/", "") };
|
|
1843
|
-
}
|
|
1844
|
-
if (uri.startsWith("code://tutorial/")) {
|
|
1845
|
-
return { scope: "tutorial", relPath: uri.replace("code://tutorial/", "") };
|
|
1846
|
-
}
|
|
1787
|
+
if (uri.startsWith("code://oscar/")) return { scope: "oscar", relPath: uri.replace("code://oscar/", "") };
|
|
1788
|
+
if (uri.startsWith("code://sample/")) return { scope: "sample", relPath: uri.replace("code://sample/", "") };
|
|
1789
|
+
if (uri.startsWith("code://tutorial/")) return { scope: "tutorial", relPath: uri.replace("code://tutorial/", "") };
|
|
1847
1790
|
return null;
|
|
1848
1791
|
}
|
|
1849
1792
|
async function resolveReferencedUris(state, sourceUri, refs) {
|
|
@@ -1894,6 +1837,12 @@ async function resolveReferencedUris(state, sourceUri, refs) {
|
|
|
1894
1837
|
function escapeRegExp(value) {
|
|
1895
1838
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1896
1839
|
}
|
|
1840
|
+
function tokenizeQuery(query) {
|
|
1841
|
+
return query.toLowerCase().split(/[^a-z0-9_]+/).map((token) => token.trim()).filter((token) => token.length >= 3);
|
|
1842
|
+
}
|
|
1843
|
+
function isExactSymbolQuery(query) {
|
|
1844
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(query.trim());
|
|
1845
|
+
}
|
|
1897
1846
|
function looksLikeDeclarationLine(line) {
|
|
1898
1847
|
const trimmed = line.trim();
|
|
1899
1848
|
if (!trimmed) return false;
|
|
@@ -1913,286 +1862,171 @@ function inferResultType(result) {
|
|
|
1913
1862
|
if (uri.startsWith("code://oscar/include/") && uri.toLowerCase().endsWith(".h")) return "headers";
|
|
1914
1863
|
return "samples";
|
|
1915
1864
|
}
|
|
1916
|
-
function
|
|
1865
|
+
function extractSignatureFromBody(body, query) {
|
|
1866
|
+
if (!body || !query.trim()) return void 0;
|
|
1867
|
+
const symbol = query.trim().toLowerCase();
|
|
1868
|
+
const exactSymbol = isExactSymbolQuery(query) ? new RegExp(`\\b${escapeRegExp(symbol)}\\b`) : null;
|
|
1869
|
+
const queryTokens = tokenizeQuery(query);
|
|
1870
|
+
const lines = body.split(/\r?\n/);
|
|
1871
|
+
for (const line of lines) {
|
|
1872
|
+
const trimmed = line.trim();
|
|
1873
|
+
if (!trimmed || !looksLikeDeclarationLine(trimmed)) continue;
|
|
1874
|
+
const lower = trimmed.toLowerCase();
|
|
1875
|
+
if (exactSymbol && exactSymbol.test(lower)) return trimmed;
|
|
1876
|
+
if (queryTokens.some((token) => lower.includes(token))) return trimmed;
|
|
1877
|
+
}
|
|
1878
|
+
return void 0;
|
|
1879
|
+
}
|
|
1880
|
+
function buildPreview(result, query, resultType) {
|
|
1917
1881
|
const uri = String(result?.uri ?? "");
|
|
1918
1882
|
const body = String(result?.body ?? "");
|
|
1919
1883
|
const fallbackSummary = makeExcerpt(String(result?.snippet ?? ""), 700);
|
|
1920
1884
|
const basePreview = typeof result?.preview === "object" && result.preview ? result.preview : { summary: fallbackSummary };
|
|
1921
|
-
|
|
1922
|
-
let declarationContext = typeof basePreview.declarationContext === "string" && basePreview.declarationContext.trim().length > 0 ? basePreview.declarationContext.trim() : void 0;
|
|
1923
|
-
if (body && query.trim()) {
|
|
1924
|
-
const queryWord = query.trim().toLowerCase();
|
|
1925
|
-
const matcher = new RegExp(`\\b${escapeRegExp(queryWord)}\\b`);
|
|
1926
|
-
const lines = body.split(/\r?\n/);
|
|
1927
|
-
for (let i = 0; i < lines.length; i += 1) {
|
|
1928
|
-
const line = String(lines[i] ?? "");
|
|
1929
|
-
const lower = line.toLowerCase();
|
|
1930
|
-
if (!lower.includes(queryWord)) continue;
|
|
1931
|
-
if (!matcher.test(lower) || !looksLikeDeclarationLine(line)) continue;
|
|
1932
|
-
signature = signature ?? line.trim();
|
|
1933
|
-
const prev = lines.slice(Math.max(0, i - 1), i).find((v) => String(v).trim().length > 0)?.trim();
|
|
1934
|
-
const next = lines.slice(i + 1, i + 3).find((v) => String(v).trim().length > 0)?.trim();
|
|
1935
|
-
declarationContext = declarationContext ?? [prev, line.trim(), next].filter(Boolean).join(" | ");
|
|
1936
|
-
break;
|
|
1937
|
-
}
|
|
1938
|
-
}
|
|
1885
|
+
const signature = (typeof basePreview.signature === "string" && basePreview.signature.trim().length > 0 ? basePreview.signature.trim() : void 0) ?? extractSignatureFromBody(body, query);
|
|
1939
1886
|
const includePathFromUri = uri.startsWith("code://oscar/include/") ? uri.replace("code://oscar/include/", "") : void 0;
|
|
1940
|
-
const includePath = typeof basePreview.includePath === "string" && basePreview.includePath.trim().length > 0 ? basePreview.includePath.trim() : includePathFromUri;
|
|
1887
|
+
const includePath = resultType === "headers" ? typeof basePreview.includePath === "string" && basePreview.includePath.trim().length > 0 ? basePreview.includePath.trim() : includePathFromUri : void 0;
|
|
1941
1888
|
const summaryCandidate = typeof basePreview.summary === "string" && basePreview.summary.trim().length > 0 ? basePreview.summary : fallbackSummary;
|
|
1942
1889
|
return {
|
|
1943
1890
|
summary: summaryCandidate || makeExcerpt(body || String(result?.title ?? ""), 700),
|
|
1944
1891
|
...signature ? { signature } : {},
|
|
1945
|
-
...includePath ? { include_path: includePath } : {}
|
|
1946
|
-
...declarationContext ? { declaration_context: declarationContext } : {}
|
|
1892
|
+
...includePath ? { include_path: includePath } : {}
|
|
1947
1893
|
};
|
|
1948
1894
|
}
|
|
1949
|
-
function
|
|
1950
|
-
const
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
const body = String(result?.body ?? "");
|
|
1958
|
-
if (body) {
|
|
1959
|
-
const exactWord = new RegExp(`\\b${escapeRegExp(symbolLower)}\\b`);
|
|
1960
|
-
const lines = body.split(/\r?\n/);
|
|
1961
|
-
for (const line of lines) {
|
|
1962
|
-
const lower = line.toLowerCase();
|
|
1963
|
-
if (!lower.includes(symbolLower)) continue;
|
|
1964
|
-
if (exactWord.test(lower)) {
|
|
1965
|
-
boost = Math.max(boost, looksLikeDeclarationLine(line) ? 70 : 28);
|
|
1966
|
-
break;
|
|
1967
|
-
}
|
|
1968
|
-
boost = Math.max(boost, 10);
|
|
1895
|
+
function normalizeSearchResults(raw) {
|
|
1896
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1897
|
+
for (const result of raw) {
|
|
1898
|
+
const uri = String(result?.uri ?? "");
|
|
1899
|
+
if (!uri) continue;
|
|
1900
|
+
const prev = seen.get(uri);
|
|
1901
|
+
if (!prev || Number(result?.score ?? 0) > Number(prev?.score ?? 0)) {
|
|
1902
|
+
seen.set(uri, result);
|
|
1969
1903
|
}
|
|
1970
1904
|
}
|
|
1971
|
-
|
|
1972
|
-
if (boost > 0 && uri.startsWith("code://oscar/include/")) boost += 12;
|
|
1973
|
-
return boost;
|
|
1974
|
-
}
|
|
1975
|
-
function isExactSymbolQuery(query) {
|
|
1976
|
-
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(query.trim());
|
|
1905
|
+
return [...seen.values()];
|
|
1977
1906
|
}
|
|
1978
|
-
function
|
|
1979
|
-
|
|
1907
|
+
function toClassificationSummary(classification) {
|
|
1908
|
+
const confidence = Number(classification?.confidence ?? 0.25);
|
|
1909
|
+
const confidenceBucket = classification?.confidenceBucket === "high" || classification?.confidenceBucket === "medium" || classification?.confidenceBucket === "low" ? classification.confidenceBucket : confidence >= 0.8 ? "high" : confidence >= 0.55 ? "medium" : "low";
|
|
1910
|
+
const scope = classification?.facets?.scope === "manual" ? "manual" : "code";
|
|
1911
|
+
const neutralTrack = scope === "manual" ? "compiler_language" : "fundamentals";
|
|
1912
|
+
const track = String(classification?.primaryTrack ?? neutralTrack);
|
|
1913
|
+
const status = classification?.primaryTrackStatus === "asserted" || classification?.primaryTrackStatus === "neutral_fallback" ? classification.primaryTrackStatus : confidence >= 0.62 ? "asserted" : "neutral_fallback";
|
|
1914
|
+
return {
|
|
1915
|
+
track,
|
|
1916
|
+
track_status: status,
|
|
1917
|
+
confidence_bucket: confidenceBucket
|
|
1918
|
+
};
|
|
1980
1919
|
}
|
|
1981
|
-
function
|
|
1982
|
-
|
|
1920
|
+
function extractSystems(classification) {
|
|
1921
|
+
if (!Array.isArray(classification?.facets?.systems)) return [];
|
|
1983
1922
|
const out = /* @__PURE__ */ new Set();
|
|
1984
|
-
for (const
|
|
1985
|
-
|
|
1986
|
-
|
|
1923
|
+
for (const item of classification.facets.systems) {
|
|
1924
|
+
const normalized = normalizeSystemToken(String(item ?? ""));
|
|
1925
|
+
if (normalized) out.add(normalized);
|
|
1987
1926
|
}
|
|
1988
|
-
if (tokens.includes("vic") && tokens.includes("bank")) out.add("vic_setbank");
|
|
1989
|
-
if (tokens.includes("screenmem")) out.add("d018");
|
|
1990
1927
|
return [...out];
|
|
1991
1928
|
}
|
|
1992
|
-
function
|
|
1993
|
-
const
|
|
1994
|
-
if (
|
|
1995
|
-
return terms.join(" ");
|
|
1996
|
-
}
|
|
1997
|
-
function hasApiIntent(query) {
|
|
1998
|
-
const tokens = tokenizeQuery(query);
|
|
1999
|
-
return tokens.some(
|
|
2000
|
-
(token) => ["vic", "d018", "bank", "banking", "charset", "screenmem", "memmap", "charwin", "rasterirq", "sprite"].includes(
|
|
2001
|
-
token
|
|
2002
|
-
)
|
|
2003
|
-
);
|
|
2004
|
-
}
|
|
2005
|
-
function hasImplementationIntent(query) {
|
|
2006
|
-
const tokens = tokenizeQuery(query);
|
|
2007
|
-
return tokens.some((token) => ["setup", "init", "move", "print", "poll", "wait", "split"].includes(token));
|
|
2008
|
-
}
|
|
2009
|
-
function isActionableResult(result) {
|
|
2010
|
-
const uri = String(result?.uri ?? "");
|
|
2011
|
-
if (uri.startsWith("code://oscar/include/")) return uri.toLowerCase().endsWith(".h");
|
|
2012
|
-
const signature = String(result?.preview?.signature ?? "");
|
|
2013
|
-
if (signature.trim().length > 0) return true;
|
|
2014
|
-
return uri.startsWith("code://tutorial/") || uri.startsWith("code://sample/");
|
|
2015
|
-
}
|
|
2016
|
-
function isLowConfidenceResultSet(rawResults, query) {
|
|
2017
|
-
if (rawResults.length === 0) return true;
|
|
2018
|
-
const top = Number(rawResults[0]?.score ?? 0);
|
|
2019
|
-
const second = Number(rawResults[1]?.score ?? 0);
|
|
2020
|
-
if (top < 0.6) return true;
|
|
2021
|
-
if (second > 0 && top / second < 1.12) return true;
|
|
2022
|
-
if (hasApiIntent(query) && !rawResults.slice(0, 3).some((entry) => isActionableResult(entry))) return true;
|
|
2023
|
-
return false;
|
|
2024
|
-
}
|
|
2025
|
-
function computeIntentBoost(result, query) {
|
|
2026
|
-
const uri = String(result?.uri ?? "");
|
|
1929
|
+
function hasQuerySignal(result, query) {
|
|
1930
|
+
const queryTokens = tokenizeQuery(query);
|
|
1931
|
+
if (queryTokens.length === 0) return false;
|
|
2027
1932
|
const title = String(result?.title ?? "").toLowerCase();
|
|
1933
|
+
const snippet = String(result?.snippet ?? "").toLowerCase();
|
|
2028
1934
|
const body = String(result?.body ?? "").toLowerCase();
|
|
2029
|
-
|
|
2030
|
-
if (hasApiIntent(query) && uri.startsWith("code://oscar/include/")) boost += 14;
|
|
2031
|
-
if (hasImplementationIntent(query) && (uri.startsWith("code://tutorial/") || uri.startsWith("code://sample/"))) {
|
|
2032
|
-
boost += 8;
|
|
2033
|
-
}
|
|
2034
|
-
const expandedTerms = expandQueryTerms(query);
|
|
2035
|
-
for (const term of expandedTerms) {
|
|
2036
|
-
if (term.length < 3) continue;
|
|
2037
|
-
if (title.includes(term)) boost += 1.2;
|
|
2038
|
-
else if (body.includes(term)) boost += 0.5;
|
|
2039
|
-
}
|
|
2040
|
-
if (uri.includes("vic.h") && /\b(vic|d018|screenmem|charset|bank)\b/i.test(query)) boost += 10;
|
|
2041
|
-
if (uri.includes("memmap.h") && /\b(memmap|bank|banking|rom|ram)\b/i.test(query)) boost += 9;
|
|
2042
|
-
if (uri.toLowerCase().includes("screenmem") && /\b(screenmem|screen memory|charset|d018)\b/i.test(query)) boost += 11;
|
|
2043
|
-
return boost;
|
|
1935
|
+
return queryTokens.some((token) => title.includes(token) || snippet.includes(token) || body.includes(token));
|
|
2044
1936
|
}
|
|
2045
|
-
function
|
|
2046
|
-
|
|
2047
|
-
if (
|
|
2048
|
-
if (
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
}
|
|
1937
|
+
function hasClearCodingValue(hit) {
|
|
1938
|
+
if (typeof hit.preview.signature === "string" && hit.preview.signature.trim().length > 0) return true;
|
|
1939
|
+
if (hit.resultType === "headers" && typeof hit.preview.include_path === "string" && hit.preview.include_path.length > 0) return true;
|
|
1940
|
+
if ((hit.referencedUris?.length ?? 0) > 0) return true;
|
|
1941
|
+
if ((hit.resultType === "tutorials" || hit.resultType === "samples" || hit.resultType === "topics") && String(hit.preview.summary ?? "").trim().length > 0) {
|
|
1942
|
+
return true;
|
|
1943
|
+
}
|
|
1944
|
+
if (hit.hasQuerySignal && (hit.resultType === "tutorials" || hit.resultType === "samples" || hit.resultType === "topics")) {
|
|
1945
|
+
return true;
|
|
1946
|
+
}
|
|
1947
|
+
return false;
|
|
2055
1948
|
}
|
|
2056
|
-
function
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
1949
|
+
function computeRankingBoost(hit) {
|
|
1950
|
+
let boost = 0;
|
|
1951
|
+
if (hit.resultType === "headers") boost += 20;
|
|
1952
|
+
if (hit.resultType === "tutorials" || hit.resultType === "samples") boost += 6;
|
|
1953
|
+
if (hit.preview.signature) boost += 16;
|
|
1954
|
+
if ((hit.referencedUris?.length ?? 0) > 0) boost += 8;
|
|
1955
|
+
if (hit.hasQuerySignal) boost += 5;
|
|
1956
|
+
const symbol = hit.query.trim().toLowerCase();
|
|
1957
|
+
if (isExactSymbolQuery(hit.query)) {
|
|
1958
|
+
const signature = String(hit.preview.signature ?? "").toLowerCase();
|
|
1959
|
+
if (signature.includes(symbol)) boost += 42;
|
|
1960
|
+
if (hit.resultType === "headers" && hit.uri.toLowerCase().includes(`${symbol}.h`)) boost += 18;
|
|
1961
|
+
}
|
|
1962
|
+
if (hit.classificationSummary.track === "fundamentals" && hit.classificationSummary.confidence_bucket === "low") {
|
|
1963
|
+
boost -= 8;
|
|
2065
1964
|
}
|
|
2066
|
-
return
|
|
1965
|
+
return boost;
|
|
2067
1966
|
}
|
|
2068
1967
|
async function executeSearch(context) {
|
|
2069
|
-
const { query, limit
|
|
1968
|
+
const { query, limit } = context;
|
|
2070
1969
|
const requestedType = context.type ?? "all";
|
|
2071
1970
|
const system = context.system ?? "c64";
|
|
2072
1971
|
const state = await getStateSnapshot();
|
|
2073
|
-
const
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
{
|
|
2089
|
-
label: "fundamentals",
|
|
2090
|
-
facet: "primary_track",
|
|
2091
|
-
reason: "Fallback classification due to missing source metadata",
|
|
2092
|
-
weight: 3,
|
|
2093
|
-
matched_on: "fallback",
|
|
2094
|
-
source_field: "derived",
|
|
2095
|
-
matched_text: "fallback",
|
|
2096
|
-
direct: true
|
|
2097
|
-
}
|
|
2098
|
-
]
|
|
2099
|
-
});
|
|
2100
|
-
const toDetails = (classification) => {
|
|
2101
|
-
const fallback = toFallbackClassification();
|
|
2102
|
-
const normalizeSystems = (systems) => {
|
|
2103
|
-
if (!Array.isArray(systems)) return [];
|
|
2104
|
-
const out = /* @__PURE__ */ new Set();
|
|
2105
|
-
for (const entry of systems) {
|
|
2106
|
-
const normalized = normalizeSystemToken(String(entry ?? ""));
|
|
2107
|
-
if (normalized) out.add(normalized);
|
|
2108
|
-
}
|
|
2109
|
-
return [...out];
|
|
2110
|
-
};
|
|
2111
|
-
if (!classification || typeof classification !== "object") return fallback;
|
|
2112
|
-
return normalizePrimaryTrackForConfidence({
|
|
2113
|
-
primary_track: String(classification.primaryTrack ?? fallback.primary_track),
|
|
2114
|
-
primary_track_status: classification.primaryTrackStatus === "asserted" || classification.primaryTrackStatus === "neutral_fallback" ? classification.primaryTrackStatus : fallback.primary_track_status,
|
|
2115
|
-
facets: {
|
|
2116
|
-
domain: Array.isArray(classification.facets?.domain) ? classification.facets.domain.map(String) : [],
|
|
2117
|
-
hardware: Array.isArray(classification.facets?.hardware) ? classification.facets.hardware.map(String) : [],
|
|
2118
|
-
technique: Array.isArray(classification.facets?.technique) ? classification.facets.technique.map(String) : [],
|
|
2119
|
-
abstraction: Array.isArray(classification.facets?.abstraction) ? classification.facets.abstraction.map(String) : [],
|
|
2120
|
-
artifact: Array.isArray(classification.facets?.artifact) ? classification.facets.artifact.map(String) : [],
|
|
2121
|
-
systems: normalizeSystems(classification.facets?.systems),
|
|
2122
|
-
scope: classification.facets?.scope === "tutorial" || classification.facets?.scope === "sample" || classification.facets?.scope === "manual" ? classification.facets.scope : fallback.facets.scope
|
|
2123
|
-
},
|
|
2124
|
-
confidence: Number(classification.confidence ?? fallback.confidence),
|
|
2125
|
-
confidence_bucket: classification.confidenceBucket === "low" || classification.confidenceBucket === "medium" || classification.confidenceBucket === "high" ? classification.confidenceBucket : fallback.confidence_bucket,
|
|
2126
|
-
evidence: Array.isArray(classification.evidence) ? classification.evidence.map((item) => ({
|
|
2127
|
-
label: String(item?.label ?? ""),
|
|
2128
|
-
facet: item?.facet === "primary_track" || item?.facet === "domain" || item?.facet === "hardware" || item?.facet === "technique" || item?.facet === "abstraction" || item?.facet === "artifact" ? item.facet : "primary_track",
|
|
2129
|
-
reason: String(item?.reason ?? ""),
|
|
2130
|
-
weight: Number(item?.weight ?? 0),
|
|
2131
|
-
matched_on: String(item?.matchedOn ?? item?.matched_on ?? ""),
|
|
2132
|
-
source_field: item?.sourceField === "title" || item?.sourceField === "rel_path" || item?.sourceField === "text" || item?.sourceField === "files" || item?.sourceField === "asset_refs" || item?.sourceField === "derived" ? item.sourceField : item?.source_field === "title" || item?.source_field === "rel_path" || item?.source_field === "text" || item?.source_field === "files" || item?.source_field === "asset_refs" || item?.source_field === "derived" ? item.source_field : "derived",
|
|
2133
|
-
matched_text: String(item?.matchedText ?? item?.matched_text ?? ""),
|
|
2134
|
-
direct: Boolean(item?.direct)
|
|
2135
|
-
})) : []
|
|
2136
|
-
});
|
|
2137
|
-
};
|
|
2138
|
-
const toSummary = (details) => ({
|
|
2139
|
-
track: details.primary_track,
|
|
2140
|
-
track_status: details.primary_track_status,
|
|
2141
|
-
confidence_bucket: details.confidence_bucket,
|
|
2142
|
-
confidence: details.confidence,
|
|
2143
|
-
domains: details.facets.domain,
|
|
2144
|
-
hardware: details.facets.hardware,
|
|
2145
|
-
techniques: details.facets.technique,
|
|
2146
|
-
systems: details.facets.systems,
|
|
2147
|
-
scope: details.facets.scope
|
|
2148
|
-
});
|
|
2149
|
-
const primaryResults = state.searchIndex.search(query, {
|
|
2150
|
-
combineWith: inferCombineMode(query),
|
|
2151
|
-
prefix: true,
|
|
2152
|
-
fuzzy: 0.12
|
|
2153
|
-
});
|
|
2154
|
-
const symbolQuery = isExactSymbolQuery(query);
|
|
2155
|
-
const expandedQuery = buildExpandedQuery(query);
|
|
2156
|
-
const useFallback = !symbolQuery && (isLowConfidenceResultSet(primaryResults, query) || expandedQuery !== query);
|
|
2157
|
-
const expandedResults = useFallback ? state.searchIndex.search(expandedQuery, {
|
|
2158
|
-
combineWith: "OR",
|
|
2159
|
-
prefix: true,
|
|
2160
|
-
fuzzy: 0.16
|
|
2161
|
-
}) : [];
|
|
2162
|
-
const rawResults = normalizeSearchResults([
|
|
2163
|
-
...primaryResults,
|
|
2164
|
-
...expandedResults.map((item) => ({
|
|
2165
|
-
...item,
|
|
2166
|
-
score: Number(item?.score ?? 0) * 0.82
|
|
2167
|
-
}))
|
|
2168
|
-
]);
|
|
1972
|
+
const rawResults = normalizeSearchResults(
|
|
1973
|
+
state.searchIndex.search(query, {
|
|
1974
|
+
combineWith: inferCombineMode(query),
|
|
1975
|
+
prefix: true,
|
|
1976
|
+
fuzzy: 0.12
|
|
1977
|
+
})
|
|
1978
|
+
);
|
|
1979
|
+
const fallbackResults = rawResults.length === 0 ? normalizeSearchResults(
|
|
1980
|
+
state.searchIndex.search(query, {
|
|
1981
|
+
combineWith: "OR",
|
|
1982
|
+
prefix: true,
|
|
1983
|
+
fuzzy: 0.16
|
|
1984
|
+
})
|
|
1985
|
+
) : [];
|
|
1986
|
+
const mergedResults = normalizeSearchResults([...rawResults, ...fallbackResults]);
|
|
2169
1987
|
const mapped = await Promise.all(
|
|
2170
|
-
|
|
2171
|
-
const details = toDetails(result.classification);
|
|
2172
|
-
const referencedUris = await resolveReferencedUris(state, String(result.uri ?? ""), result.referencedFiles);
|
|
1988
|
+
mergedResults.map(async (result) => {
|
|
2173
1989
|
const resultType = inferResultType(result);
|
|
2174
|
-
const
|
|
1990
|
+
const preview = buildPreview(result, query, resultType);
|
|
1991
|
+
const referencedUris = await resolveReferencedUris(state, String(result.uri ?? ""), result.referencedFiles);
|
|
1992
|
+
const classificationSummary = toClassificationSummary(result.classification);
|
|
1993
|
+
const systems = extractSystems(result.classification);
|
|
1994
|
+
const hasSignal = hasQuerySignal(result, query);
|
|
1995
|
+
const baseScore = Number(result?.score ?? 0);
|
|
1996
|
+
const rankScore = baseScore + computeRankingBoost({
|
|
1997
|
+
uri: String(result.uri ?? ""),
|
|
1998
|
+
resultType,
|
|
1999
|
+
preview,
|
|
2000
|
+
query,
|
|
2001
|
+
referencedUris,
|
|
2002
|
+
classificationSummary,
|
|
2003
|
+
hasQuerySignal: hasSignal
|
|
2004
|
+
});
|
|
2175
2005
|
return {
|
|
2176
|
-
|
|
2006
|
+
rankScore,
|
|
2007
|
+
systems,
|
|
2008
|
+
keep: hasClearCodingValue({
|
|
2009
|
+
resultType,
|
|
2010
|
+
preview,
|
|
2011
|
+
referencedUris,
|
|
2012
|
+
hasQuerySignal: hasSignal
|
|
2013
|
+
}),
|
|
2177
2014
|
hit: {
|
|
2178
|
-
source: result.source === "manual" ? "manual" : "code",
|
|
2179
2015
|
result_type: resultType,
|
|
2180
2016
|
uri: String(result.uri ?? ""),
|
|
2181
2017
|
title: String(result.title ?? ""),
|
|
2182
|
-
preview
|
|
2183
|
-
score: (result.score ?? 0) + rerankBoost,
|
|
2018
|
+
preview,
|
|
2184
2019
|
...referencedUris ? { referenced_files: referencedUris } : {},
|
|
2185
|
-
classification_summary:
|
|
2186
|
-
...include_details ? { classification_details: details } : {}
|
|
2020
|
+
classification_summary: classificationSummary
|
|
2187
2021
|
}
|
|
2188
2022
|
};
|
|
2189
2023
|
})
|
|
2190
2024
|
);
|
|
2191
|
-
const hits = mapped.filter((entry) => {
|
|
2025
|
+
const hits = mapped.filter((entry) => entry.keep).filter((entry) => {
|
|
2192
2026
|
const uri = String(entry.hit.uri ?? "");
|
|
2193
2027
|
if (uri.startsWith("code://oscar/include/") && !uri.toLowerCase().endsWith(".h")) return false;
|
|
2194
2028
|
return true;
|
|
2195
|
-
}).filter((entry) => requestedType === "all" || entry.hit.result_type === requestedType).filter((entry) => matchesSystemFilter(entry.
|
|
2029
|
+
}).filter((entry) => requestedType === "all" || entry.hit.result_type === requestedType).filter((entry) => matchesSystemFilter(entry.systems, system)).sort((a, b) => b.rankScore - a.rankScore || a.hit.uri.localeCompare(b.hit.uri)).slice(0, limit);
|
|
2196
2030
|
return {
|
|
2197
2031
|
ok: true,
|
|
2198
2032
|
data: {
|
|
@@ -2206,7 +2040,19 @@ var searchTool = createTool3({
|
|
|
2206
2040
|
inputSchema: searchInputSchema,
|
|
2207
2041
|
outputSchema: searchOutputSchema,
|
|
2208
2042
|
execute: async (input) => {
|
|
2209
|
-
const
|
|
2043
|
+
const rawInput = input?.context ?? input;
|
|
2044
|
+
if (Object.prototype.hasOwnProperty.call(rawInput, "include_details")) {
|
|
2045
|
+
return {
|
|
2046
|
+
ok: false,
|
|
2047
|
+
error: {
|
|
2048
|
+
code: "INVALID_INPUT",
|
|
2049
|
+
message: "include_details is no longer supported.",
|
|
2050
|
+
hint: "Remove include_details and use classification_summary only.",
|
|
2051
|
+
recoverable: true
|
|
2052
|
+
}
|
|
2053
|
+
};
|
|
2054
|
+
}
|
|
2055
|
+
const context = rawInput;
|
|
2210
2056
|
try {
|
|
2211
2057
|
return await executeSearch(context);
|
|
2212
2058
|
} catch (error) {
|