mirror of
https://github.com/hanzoai/insights.git
synced 2026-10-30 16:15:31 +00:00
The tree was a debranded snapshot of upstream taken around 2026-02-20, and upstream has moved about five months since. This replaces it with upstream master, mechanically re-derived: bin/debrand does the rename, and the pipeline and squashed migrations are restored from the shipped tree. Not a merge. The previous import replaced the tree wholesale in a single commit, so there is no shared content history to merge against. Reproducing the rename on the new tree is what actually converges. What survives: .hanzo/workflows, the Dockerfiles and bin/docker* entrypoints, compose files, LLM.md, and insights/migrations. The squashed initial migration is load-bearing — the live database records it by name, so upstream's ~918 individual migrations cannot come back. Nine products are dropped as unreferenced. Twenty-one more that we do not run are kept anyway because the core app still imports them; unpicking those is a refactor and does not belong in a rebase. This base does not build yet, and the reasons are not in the rename: upstream now wants Python 3.13.13 against our 3.12.12 and Django 5.2 against our 4.2, and the dependency manifests still name upstream packages that we republish under our own names. Those are decisions, not renames.
65 lines
3.2 KiB
TypeScript
65 lines
3.2 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { isRegexPattern, type SearchableTool, searchToolsRanked, searchToolsRegex } from '@/tools/tool-search'
|
|
|
|
const TOOLS: SearchableTool[] = [
|
|
{ name: 'dashboard-create', title: 'Create dashboard', description: 'Create a new dashboard' },
|
|
{ name: 'dashboard-get-all', title: 'List dashboards', description: 'List all dashboards in the project' },
|
|
{ name: 'insight-create', title: 'Create insight', description: 'Create a new insight (graph/trend)' },
|
|
{ name: 'insight-get-all', title: 'List insights', description: 'List all insights' },
|
|
{ name: 'feature-flag-get-all', title: 'List feature flags', description: 'List all feature flags' },
|
|
{ name: 'query-run', title: 'Run query', description: 'Run an arbitrary InsightsQL query' },
|
|
{ name: 'experiment-create', title: 'Create experiment', description: 'Create a new experiment' },
|
|
]
|
|
|
|
describe('tool-search', () => {
|
|
describe('searchToolsRanked', () => {
|
|
it('surfaces the relevant create tools for a multi-word natural-language query', () => {
|
|
// The original single-regex predicate returned ZERO for this phrase —
|
|
// this is the regression the forgiving search exists to fix.
|
|
const ranked = searchToolsRanked(TOOLS, 'create dashboard insight')
|
|
expect(ranked.length).toBeGreaterThan(0)
|
|
expect(ranked.slice(0, 2).map((r) => r.name)).toEqual(['dashboard-create', 'insight-create'])
|
|
})
|
|
|
|
it('weights a name hit above a token that only appears in prose', () => {
|
|
// "experiment-create" matches two tokens in its name; tools that merely
|
|
// mention "create" elsewhere must not outrank it.
|
|
const ranked = searchToolsRanked(TOOLS, 'create experiment')
|
|
expect(ranked[0]?.name).toBe('experiment-create')
|
|
})
|
|
|
|
it('returns nothing when no token matches any field', () => {
|
|
expect(searchToolsRanked(TOOLS, 'nonexistent-token')).toEqual([])
|
|
})
|
|
})
|
|
|
|
describe('searchToolsRegex', () => {
|
|
it('matches a kebab-case prefix pattern against name/title/description', () => {
|
|
expect(searchToolsRegex(TOOLS, 'query-').map((t) => t.name)).toEqual(['query-run'])
|
|
})
|
|
|
|
it('matches every feature-flag tool', () => {
|
|
expect(searchToolsRegex(TOOLS, 'feature-flag').map((t) => t.name)).toEqual(['feature-flag-get-all'])
|
|
})
|
|
|
|
it('throws on an invalid regex so callers can surface their own message', () => {
|
|
expect(() => searchToolsRegex(TOOLS, '[invalid')).toThrow(/regular expression/i)
|
|
})
|
|
})
|
|
|
|
describe('isRegexPattern', () => {
|
|
it('treats kebab-case and regex patterns as regex', () => {
|
|
expect(isRegexPattern('query-')).toBe(true)
|
|
expect(isRegexPattern('feature-flag')).toBe(true)
|
|
expect(isRegexPattern('a|b')).toBe(true)
|
|
expect(isRegexPattern('get.*')).toBe(true)
|
|
})
|
|
|
|
it('treats plain words as non-regex so they route to ranked search', () => {
|
|
expect(isRegexPattern('dashboard')).toBe(false)
|
|
expect(isRegexPattern('create dashboard insight')).toBe(false)
|
|
})
|
|
})
|
|
})
|