Skip to content

Commit 2855b71

Browse files
committed
Improve formatting of plugin error reports
1 parent 74c8535 commit 2855b71

File tree

8 files changed

+50
-8
lines changed

8 files changed

+50
-8
lines changed

src/lmstudio/plugin/hooks/prompt_preprocessor.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,9 @@ async def _invoke_hook(request: PromptPreprocessingRequest) -> None:
225225
err_msg = "Error calling prompt preprocessing hook"
226226
logger.error(err_msg, exc_info=True, exc=repr(exc))
227227
# TODO: Determine if it's practical to emit a stack trace the server can display
228+
ui_cause = f"{err_msg}\n({type(exc).__name__}: {exc})"
228229
error_details = SerializedLMSExtendedErrorDict(
229-
cause=repr(exc), stack="\n".join(format_tb(exc.__traceback__))
230+
cause=ui_cause, stack="\n".join(format_tb(exc.__traceback__))
230231
)
231232
else:
232233
if response is None:
@@ -240,8 +241,8 @@ async def _invoke_hook(request: PromptPreprocessingRequest) -> None:
240241
try:
241242
parsed_response = load_struct(response, expected_cls)
242243
except ValidationError as exc:
243-
err_msg = f"Failed to parse prompt preprocessing response as {expected_cls.__name__}"
244-
logger.error(err_msg, exc_info=True, exc=repr(exc))
244+
err_msg = f"Failed to parse prompt preprocessing response as {expected_cls.__name__}\n({exc})"
245+
logger.error(err_msg)
245246
error_details = SerializedLMSExtendedErrorDict(
246247
cause=err_msg
247248
)
@@ -255,6 +256,12 @@ async def _invoke_hook(request: PromptPreprocessingRequest) -> None:
255256
error_details = SerializedLMSExtendedErrorDict(cause=err_msg)
256257
channel_message: DictObject
257258
if error_details is not None:
259+
error_title = f"Prompt preprocessing error in plugin {plugin_name!r}"
260+
common_error_args: SerializedLMSExtendedErrorDict = {
261+
"title": error_title,
262+
"rootTitle": error_title,
263+
}
264+
error_details.update(common_error_args)
258265
channel_message = PromptPreprocessingErrorDict(
259266
type="error",
260267
taskId=request.task_id,

src/lmstudio/plugin/runner.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
TPluginConfigSchema,
3232
TGlobalConfigSchema,
3333
run_prompt_preprocessor,
34-
# run_token_generator,
35-
# run_tools_provider,
34+
run_token_generator,
35+
run_tools_provider,
3636
)
3737

3838
# Available as lmstudio.plugin.*
@@ -63,8 +63,8 @@
6363

6464
_HOOK_RUNNERS: dict[str, HookRunner[Any, Any, Any]] = {
6565
"preprocess_prompt": run_prompt_preprocessor,
66-
# "generate_tokens": run_token_generator,
67-
# "list_provided_tools": run_tools_provider,
66+
"generate_tokens": run_token_generator,
67+
"list_provided_tools": run_tools_provider,
6868
}
6969

7070

@@ -213,9 +213,10 @@ async def run_plugin(self, *, allow_local_imports: bool = False) -> int:
213213
)
214214
plugin = self.name
215215
if not implemented_hooks:
216+
hook_list = "\n - ".join(("", *sorted(_HOOK_RUNNERS)))
216217
print(
217218
f"No plugin hooks defined in {plugin!r}, "
218-
f"expected at least one of {sorted(_HOOK_RUNNERS)}"
219+
f"expected at least one of:{hook_list}"
219220
)
220221
return 1
221222
# Use anyio and exceptiongroup to handle the lack of native task
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "plugin",
3+
"runner": "python",
4+
"owner": "lmstudio",
5+
"name": "hook-exception",
6+
"revision": 1
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Plugin runner doesn't actually care these type hints are incorrect
2+
# It *does* care that an exception is raised
3+
class ExampleCustomException(Exception):
4+
pass
5+
6+
7+
async def preprocess_prompt(_ctl: None, _message: None) -> dict[None, None]:
8+
raise ExampleCustomException("Example plugin hook failure")
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "plugin",
3+
"runner": "python",
4+
"owner": "lmstudio",
5+
"name": "malformed-prompt",
6+
"revision": 1
7+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Plugin runner doesn't actually care these type hints are incorrect
2+
# It *does* care that the returned "user message" has no content
3+
async def preprocess_prompt(_ctl: None, _message: None) -> dict[None, None]:
4+
return {}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "plugin",
3+
"runner": "python",
4+
"owner": "lmstudio",
5+
"name": "no-hooks",
6+
"revision": 1
7+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# No hooks defined, runner will refuse to execute this plugin

0 commit comments

Comments
 (0)