feat: add bounded marketplace research

This commit is contained in:
Mikei386
2026-08-24 13:54:17 +02:00
parent 308b8a4d1f
commit 0a5da6e5f1
6 changed files with 137 additions and 7 deletions
@@ -1,7 +1,7 @@
"""
title: MikeAI Auto Tool Selector
author: MikeAI
version: 4.2.0
version: 4.3.0
description: Keeps broad web access available and adds relevant portable MCP domains without acting as a gate.
"""
@@ -90,8 +90,32 @@ class Filter:
),
)
def _needs_marketplace_research(self, raw_text: str) -> bool:
"""Recognise shopping/listing research without requiring a site adapter."""
text = self._normalise(raw_text)
search_intent = self._matches(
text,
(
r"\b(?:such|find|recherchier|pr[uü]f|schau|vergleich)\w*\b",
r"\b(?:ich\s+suche|ich\s+m[oö]chte\s+kaufen|kaufberatung)\b",
),
)
marketplace_context = self._matches(
text,
(
r"\b(?:ebay|kleinanzeigen|etsy|amazon|makerworld|marktplatz|marketplace|verkaufsplattform|online[- ]shop)\b",
r"\b(?:angebot(?:e|en)?|artikel|produkt|preis(?:e|en)?|versand(?:kosten)?|sofort[- ]kaufen|auktion|gebraucht(?:markt)?)\b",
),
)
return search_intent and marketplace_context
@staticmethod
def _add_system_rule(body: dict, labels: list[str], selected: list[str]) -> None:
def _add_system_rule(
body: dict,
labels: list[str],
selected: list[str],
marketplace_research: bool = False,
) -> None:
rule = (
"MikeAI automatic tool selection made these capabilities available for "
f"this request: {', '.join(labels)}. Availability is not authorization. "
@@ -140,6 +164,21 @@ class Filter:
"the same YAML read, state lookup, or validation unless new evidence "
"or a changed configuration makes the repetition necessary."
)
if marketplace_research:
rule += (
" Marketplace research protocol: this is a general shopping/listing "
"task, not a request for a site-specific tool. Start with one focused "
"search and use at most two reformulations. Prefer marketplace search, "
"category, and result pages when individual listing pages are blocked; "
"their snippets may contain price, shipping, condition, and location. "
"Build a small candidate set, deduplicate by listing URL or item number, "
"and fetch only the most promising candidates. For a normal request, "
"stop after roughly three searches and five page fetches unless the user "
"explicitly requests an exhaustive audit. Call a listing active only "
"when current evidence shows a price, remaining time, bid, or buy status; "
"otherwise label it possibly active. Never invent missing commerce fields, "
"and finish with the verified shortlist instead of repeating synonyms."
)
messages = body.setdefault("messages", [])
for message in messages:
if message.get("role") == "system" and isinstance(message.get("content"), str):
@@ -301,7 +340,8 @@ class Filter:
return body
latest_text = self._latest_user_text(body)
needs_native_web = self._needs_native_web(latest_text)
marketplace_research = self._needs_marketplace_research(latest_text)
needs_native_web = self._needs_native_web(latest_text) or marketplace_research
selected = self._classify(latest_text)
# Web work gets two independent, general-purpose engines. Native
# OpenWebUI search has good result rendering but can return empty sets
@@ -321,6 +361,10 @@ class Filter:
metadata_features = metadata.setdefault("features", {})
if isinstance(metadata_features, dict):
metadata_features["web_search"] = True
if marketplace_research:
# Consumed by the versioned Open WebUI continuation patch.
# This is a request-local execution policy, not a site rule.
metadata["mikeai_marketplace_research"] = True
if not selected:
return body
@@ -353,7 +397,12 @@ class Filter:
if needs_native_web:
labels.append("native Websuche")
if selected:
self._add_system_rule(body, labels, selected)
self._add_system_rule(
body,
labels,
selected,
marketplace_research=marketplace_research,
)
if needs_native_web:
for message in body.get("messages", []):
if message.get("role") == "system" and isinstance(message.get("content"), str):
@@ -39,6 +39,13 @@ replacement = """ tool_call_iterations = 0
max_single_tool_result_chars = 12000
max_total_tool_result_chars = 64000
tool_result_chars_used = 0
marketplace_research = bool(
(metadata or {}).get('mikeai_marketplace_research', False)
)
marketplace_search_executions = 0
marketplace_fetch_executions = 0
max_marketplace_search_executions = 3
max_marketplace_fetch_executions = 5
tool_execution_counts = {}
tool_signature_counts = {}
max_tool_call_iterations = getattr(
@@ -61,6 +68,13 @@ replacement = """ response_tool_calls = tool_calls.pop(0)
for candidate in response_tool_calls:
function = candidate.get('function') or candidate
tool_name = function.get('name') or candidate.get('name') or 'unknown'
normalized_tool_name = tool_name.casefold()
is_marketplace_search = normalized_tool_name in ('search', 'search_web', 'research') or normalized_tool_name.endswith(
('web-general-local_search', 'web-general-local_research')
)
is_marketplace_fetch = normalized_tool_name in ('fetch_url', 'scrape_urls') or normalized_tool_name.endswith(
'web-general-local_scrape_urls'
)
arguments = function.get('arguments') or candidate.get('arguments') or ''
signature = f'{tool_name}:{arguments}'
if tool_call_executions + len(accepted_tool_calls) >= max_tool_call_executions:
@@ -75,7 +89,27 @@ replacement = """ response_tool_calls = tool_calls.pop(0)
skipped_tool_calls.append(candidate)
skip_reasons.append(f'repeated identical call suppressed for {tool_name}')
continue
if (
marketplace_research
and is_marketplace_search
and marketplace_search_executions >= max_marketplace_search_executions
):
skipped_tool_calls.append(candidate)
skip_reasons.append('marketplace search budget reached')
continue
if (
marketplace_research
and is_marketplace_fetch
and marketplace_fetch_executions >= max_marketplace_fetch_executions
):
skipped_tool_calls.append(candidate)
skip_reasons.append('marketplace fetch budget reached')
continue
accepted_tool_calls.append(candidate)
if marketplace_research and is_marketplace_search:
marketplace_search_executions += 1
if marketplace_research and is_marketplace_fetch:
marketplace_fetch_executions += 1
tool_signature_counts[signature] = tool_signature_counts.get(signature, 0) + 1
tool_execution_counts[tool_name] = tool_execution_counts.get(tool_name, 0) + 1
response_tool_calls = accepted_tool_calls