Skip to content

Commit e57eb1f

Browse files
committed
docs(cli): make the search help explain OSW-ID titles
- rename full_text_search to search_titles: it searches titles only - drop "full-text" from the group help, module docstring and docs - state that OSW pages are titled by OSW-ID, so names are not in titles - add a wildcard label example to `search ask`, with the caveat that the property name depends on the instance schema (not run against a wiki) - document the --limit default and the {titles, count, truncated} shape
1 parent 568205b commit e57eb1f

4 files changed

Lines changed: 56 additions & 11 deletions

File tree

‎docs/cli-and-mcp.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ Failures exit non-zero with a short message on stderr and no traceback.
8888

8989
`osw[mcp]` ships an [MCP](https://modelcontextprotocol.io) server that exposes a
9090
live OpenSemanticLab instance to MCP clients such as Claude Code. It wraps
91-
`OswExpress` and provides tools to search (semantic / SPARQL / full-text),
91+
`OswExpress` and provides tools to search (semantic / SPARQL / page titles),
9292
introspect category schemas, read entities and every page slot, create/update
9393
and delete entities, and read and write file pages as text. The transport is
9494
stdio; SSE and HTTP are not supported.

‎src/osw/cli/main.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ def command(**kwargs: Any) -> None:
189189
"instance": "Inspect the OSL instances this process can connect to.",
190190
"ledger": "The local provenance ledger of pages written from here.",
191191
"schema": "Category JSON Schemas.",
192-
"search": "Query the instance: semantic, full-text or SPARQL.",
192+
"search": "Find pages. OSW pages are titled by OSW-ID, so use 'ask' "
193+
"to search by name.",
193194
"slot": "Read and write individual page slots.",
194195
}
195196

‎src/osw/service/ops/search.py‎

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Search and query operations: semantic (SMW ask), full-text, instances, SPARQL."""
1+
"""Search and query operations: semantic (SMW ask), titles, instances, SPARQL."""
22

33
from __future__ import annotations
44

@@ -22,8 +22,25 @@
2222
def search_entities(ctx: Context, ask_query: str, limit: Optional[int] = None) -> dict:
2323
"""Run a Semantic MediaWiki 'ask' query and return matching page titles.
2424
25-
The query uses SMW ask syntax, e.g. ``[[Category:Item]]`` or
26-
``[[Category:Item]][[Keyword::sensor]]``. Returns full page titles.
25+
This is the only search that can find an entity by a property value, such
26+
as its name. OSW pages are titled by OSW-ID, for example
27+
``Item:OSW7ec...``, so searching titles for a name finds nothing.
28+
29+
The query uses SMW ask syntax. Examples:
30+
31+
\b
32+
[[Category:Item]]
33+
[[Category:Item]][[Keyword::sensor]]
34+
[[Category:Item]][[HasName::~*sensor*]]
35+
36+
``~`` starts a wildcard comparison and ``*`` matches any text. Which
37+
property holds the name depends on the instance's schema: ``HasName``,
38+
``Display_title_of`` and ``HasLabel`` are the usual candidates. Read the
39+
category schema (``osw schema get``) if a name query returns nothing.
40+
41+
``limit`` defaults to ``OSW_MAX_RESULTS`` (100 when that is unset).
42+
Returns ``{titles, count, truncated}``, where ``titles`` are full page
43+
names and ``count`` is how many the wiki returned.
2744
"""
2845
lim = ctx.limit(limit)
2946
titles = ctx.osw.site.semantic_search(
@@ -39,8 +56,21 @@ def search_entities(ctx: Context, ask_query: str, limit: Optional[int] = None) -
3956
read_only_hint=True,
4057
idempotent_hint=True,
4158
)
42-
def full_text_search(ctx: Context, text: str, limit: Optional[int] = None) -> dict:
43-
"""Prefix/full-text search for pages whose title matches ``text``."""
59+
def search_titles(ctx: Context, text: str, limit: Optional[int] = None) -> dict:
60+
"""Search page titles by prefix. This does not search page content.
61+
62+
Matches pages whose title starts with ``text``, via the MediaWiki
63+
``prefixsearch`` API. OSW pages are titled by OSW-ID, for example
64+
``Item:OSW7ec...``, so an entity's name is not part of its title and
65+
cannot be found here. Use ``osw search ask`` to search by name.
66+
67+
Useful for the titles that are readable: categories, properties,
68+
templates and other schema pages.
69+
70+
``limit`` defaults to ``OSW_MAX_RESULTS`` (100 when that is unset).
71+
Returns ``{titles, count, truncated}``, where ``titles`` are full page
72+
names and ``count`` is how many the wiki returned.
73+
"""
4474
lim = ctx.limit(limit)
4575
titles = ctx.osw.site.prefix_search(WtSite.SearchParam(query=text, limit=lim))
4676
capped, total, truncated = cap_list(titles, lim)
@@ -58,7 +88,14 @@ def list_instances_of_category(
5888
) -> dict:
5989
"""List full page titles of all instances of a category.
6090
61-
``category`` is a full category page name, e.g. ``Category:Item``.
91+
``category`` is a full category page name, e.g. ``Category:Item`` or
92+
``Category:OSW...``. This runs the ask query
93+
``[[HasType::Category:<category>]]``, so it lists the pages that declare
94+
this exact category as their type.
95+
96+
``limit`` defaults to ``OSW_MAX_RESULTS`` (100 when that is unset).
97+
Returns ``{titles, count, truncated}``, where ``titles`` are full page
98+
names and ``count`` is how many the wiki returned.
6299
"""
63100
lim = ctx.limit(limit)
64101
titles = ctx.osw.query_instances(
@@ -82,7 +119,14 @@ def sparql_query(
82119
"""Run a raw SPARQL query against the instance's SPARQL endpoint.
83120
84121
The endpoint defaults to ``OSW_SPARQL_ENDPOINT``; pass ``endpoint`` to
85-
override. Returns ``{vars, bindings, count, truncated}``.
122+
override. If neither is set the command fails.
123+
124+
``limit`` caps the returned bindings and defaults to 500. It is applied
125+
to the response, not added to the query, so a large query still costs the
126+
endpoint its full work.
127+
128+
Returns ``{vars, bindings, count, truncated}``, where ``count`` is how
129+
many bindings the endpoint returned.
86130
"""
87131
ep = endpoint or ctx.settings.sparql_endpoint
88132
if not ep:

‎tests/test_service_ops_search.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ def test_search_entities_calls_semantic_search():
3131
osw.site.semantic_search.assert_called_once()
3232

3333

34-
def test_full_text_search_calls_prefix_search():
34+
def test_search_titles_calls_prefix_search():
3535
osw = MagicMock()
3636
osw.site.prefix_search.return_value = ["Item:OSW1"]
3737
ctx = Context(_settings(), Policy(), osw=osw)
3838

39-
result = search.full_text_search(ctx, text="OSW")
39+
result = search.search_titles(ctx, text="OSW")
4040

4141
assert result["titles"] == ["Item:OSW1"]
4242
assert result["count"] == 1

0 commit comments

Comments
 (0)