Initial Commit
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
"""
|
||||
title: Quantitative Question Nudge
|
||||
author: owuitools
|
||||
version: 0.2.0
|
||||
description: Raises tool-use salience on measurement-bearing questions that are phrased casually.
|
||||
"""
|
||||
|
||||
# WHY THIS EXISTS
|
||||
#
|
||||
# The system prompt already says that reasoning tasks need tools and that
|
||||
# ruling a cause out is itself a claim. It does not fire on questions that
|
||||
# are phrased conversationally. Measured case:
|
||||
#
|
||||
# "im logging vibration off a motor at 500Hz, motor runs 3600 rpm but
|
||||
# the biggest fft peak is at 40Hz. is my sensor broken?"
|
||||
#
|
||||
# Zero tool calls, and the answer stated "aliasing cannot move a 60 Hz peak
|
||||
# to 40 Hz - so 40 Hz is a REAL vibration". True of the fundamental and
|
||||
# wrong as an elimination: the 9th harmonic at 540 Hz folds to exactly
|
||||
# 40.0 Hz at that sample rate. That sends someone hunting a phantom
|
||||
# resonance instead of fitting an anti-alias filter. Adding a paragraph to
|
||||
# the system prompt did not change it - which is this suite's most repeated
|
||||
# finding: static prompt text loses to the shape of the conversation.
|
||||
#
|
||||
# An inlet note is a different lever. It arrives as the most recent thing
|
||||
# in the conversation rather than as line 40 of a long preamble, so it is
|
||||
# read as part of the current task. It is invisible to the user: inlet
|
||||
# rewrites what goes to the model, not what is displayed.
|
||||
#
|
||||
# Deliberately narrow. It fires only when a message carries an actual
|
||||
# measurement - a number with a unit - because that is what distinguishes
|
||||
# "is my sensor broken" from "is Postgres a good choice". A nudge on every
|
||||
# message would be one more paragraph the model learns to skim.
|
||||
#
|
||||
# WHY IT NAMES THE TOOLS
|
||||
#
|
||||
# The first version said "check it with a tool" and left the choice open.
|
||||
# On a compound-interest question the model duly reached for a tool - and
|
||||
# reached for web_search, to look up a formula it already knew, then did
|
||||
# the actual arithmetic in its head and got it wrong. Tool-seeking without
|
||||
# tool-selection. The note now says which tool does what, and says out loud
|
||||
# that searching for a formula you know is not the point.
|
||||
|
||||
import re
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
# A number bound to a unit. Bare numbers are excluded on purpose: "give me
|
||||
# 3 options" is not a measurement. Currency and durations are in because
|
||||
# "$4,000 at 5% for 10 years" is as quantitative as anything in volts, and
|
||||
# the arithmetic is exactly where in-head answers go wrong.
|
||||
_MEASUREMENT = re.compile(
|
||||
r"[$£€]\s?\d"
|
||||
r"|\b\d+(?:\.\d+)?\s?"
|
||||
r"(?:hz|khz|mhz|ghz|rpm|v|kv|mv|a|ma|w|kw|mw|va|kva|ohm|ohms|"
|
||||
r"db|dbm|s|ms|us|ns|m|mm|cm|km|kg|g|n|nm|pa|kpa|bar|psi|"
|
||||
r"c|f|k|%|gb|mb|kb|tb|bps|kbps|mbps|gbps|awg|bit|bits|"
|
||||
r"years?|yrs?|months?|weeks?|days?)\b",
|
||||
re.I,
|
||||
)
|
||||
|
||||
_NOTE = (
|
||||
"Reminder for this question: it contains measurements, so it is a technical question "
|
||||
"however casually it is worded. Before asserting any number, mechanism or standard, check "
|
||||
"it with a tool: the calculators (ohms_law_power, component_calc, wiring_calc, pcb_calc, "
|
||||
"subnet_calc) for what they cover, matlab_run for any other arithmetic - compounding, unit "
|
||||
"conversions, statistics, counting - and web_search then fetch_page for facts and "
|
||||
"standards, not for formulas you already know. In particular, if you are about to rule a "
|
||||
"cause OUT, enumerate the variants of that cause and test the ones you have not considered "
|
||||
"- a correct elimination of the obvious version and a missed elimination of a subtler "
|
||||
"version look identical in the answer, and send the user to fix the wrong thing."
|
||||
)
|
||||
|
||||
|
||||
class Filter:
|
||||
class Valves(BaseModel):
|
||||
enabled: bool = Field(
|
||||
default=True,
|
||||
description="Turn the nudge off without deleting the filter.",
|
||||
)
|
||||
min_chars: int = Field(
|
||||
default=40,
|
||||
description="Skip very short messages. 'what is 3 dB' needs no reminder.",
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.valves = self.Valves()
|
||||
|
||||
async def inlet(self, body: dict, __user__=None) -> dict:
|
||||
if not self.valves.enabled:
|
||||
return body
|
||||
try:
|
||||
messages = body.get("messages") or []
|
||||
if not messages:
|
||||
return body
|
||||
|
||||
last_user = None
|
||||
for message in reversed(messages):
|
||||
if message.get("role") == "user":
|
||||
last_user = message
|
||||
break
|
||||
if last_user is None:
|
||||
return body
|
||||
|
||||
text = last_user.get("content")
|
||||
if not isinstance(text, str) or len(text) < self.valves.min_chars:
|
||||
return body
|
||||
if not _MEASUREMENT.search(text):
|
||||
return body
|
||||
|
||||
# Appended AFTER the user's turn, not before it. Inserted
|
||||
# before, this was read as more preamble and changed nothing;
|
||||
# the last message in the list is the one that gets weight.
|
||||
messages.append({"role": "system", "content": _NOTE})
|
||||
body["messages"] = messages
|
||||
except Exception:
|
||||
return body
|
||||
return body
|
||||
Reference in New Issue
Block a user