Repository navigation
feat(model): route optimizer calls through a caller-supplied function - #346
Closed
Essam Gouda (egouda-colab) wants to merge 1 commit into
Closed
Essam Gouda (egouda-colab) wants to merge 1 commit into
Essam Gouda (egouda-colab) wants to merge 1 commit into
Conversation
Library users who must send every model call through their own client currently have to rebind `chat_optimizer` in each module that imported it by name and stub every provider backend. - `skillopt.model.set_optimizer_chat(fn)` / `reset_optimizer_chat()`: `chat_optimizer` and `chat_optimizer_messages` call the registered function first (it takes the `chat_optimizer_messages` arguments and returns `(text_or_message, usage)`). The dispatchers read it per call, so existing `from skillopt.model import chat_optimizer` imports pick it up unchanged. Usage is recorded in the token summary. - `model.optimizer_backend: custom` declares a caller-supplied optimizer; training refuses to start, and calls fail clearly, if none is registered. - `optimizer.strict_errors` (default false): optimizer stages re-raise a failed call instead of falling back (empty reflection, concatenated merge, truncated ranking, ...). - Resume: read stored `current_score`/`best_score` with `is None` checks so a real 0.0 no longer reruns the baseline evaluation and resets the best. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
This PR makes SkillOpt usable as a library behind a caller's own model client, with no monkeypatching.
skillopt.model.set_optimizer_chat(fn)/reset_optimizer_chat(). When a function is set,chat_optimizerandchat_optimizer_messagescall it before any built-in backend.model.optimizer_backend: customdeclares that the optimizer function comes from the caller.optimizer.strict_errors(defaultfalse). When it is on, an optimizer stage re-raises a failed call instead of silently using its fallback.0.0is no longer read back as "unscored".Why
Some library users must send every LLM call through their own client, for example to apply their own authentication, auditing, or data-governance controls. Today the provider dispatch is hard-coded, with Azure OpenAI as the fallback. So these users have to rebind
chat_optimizerin every module that imports it by name (trainer,reflect,aggregate,clip,rewrite,meta_skill,slow_update,lr_autonomous) and stub the provider backends.In that setup a broken client is also easy to miss. Optimizer failures are deliberately swallowed: reflect returns no edits, merge concatenates, and rank truncates. A run can therefore finish "successfully" with the skill unchanged.
API
chat_optimizer_messages:messagesplusmax_completion_tokens,retries,stage,reasoning_effort,tools,tool_choice,return_messageandtimeout. It returns(text, usage), or(message, usage)whenreturn_message=True.chat_optimizerpasses it the[system, user]messages.from skillopt.model import chat_optimizerimports pick it up without any edit to those modules.get_token_summary(), sosummary.jsonand the per-step token records stay complete.customset and no function registered,ReflACTTrainer.train()raises before any rollout runs, and a direct call raisesRuntimeError. Neither falls through to Azure.model.target_backend.strict_errorsapplies. Every optimizer fallback honors it: reflect (error and success analysts), merge (batch and final), rank, autonomous LR, rewrite, slow update, meta skill and appendix consolidation. Only exceptions are re-raised. Output that comes back but can't be used still takes the existing fallbacks.Backward compatibility
strict_errors: false(the default), dispatch, fallbacks and outputs behave exactly as before. Tests that patchmodule.chat_optimizerkeep working.customis never overridden. It is a new optimizer-only value. It is not a role default, somodel.backend/--backendrole resolution leaves it in place.runtime_state.jsonare now read withis Nonechecks. Previously a storedcurrent_score: 0.0became-1.0, which re-ran the baseline selection evaluation and overwrote the best score. fix(trainer): improve checkpoint consistency on resume #253 makes an equivalent change as part of a broader checkpoint refactor. If that lands first, I'm happy to drop this hunk.Tests
tests/test_custom_optimizer_chat.py:analyst,merge,lr_autonomous,ranking,slow_updateandmeta_skill. The test checks that no built-in provider client is created, the analyst's edit is applied, and the token summary counts every call.chat_optimizerandchat_optimizer_messages. A module that importedchat_optimizerby name (clip) uses the registered function.reset_optimizer_chat().customwith no function registered fails clearly, both on a direct call and in the trainer.strict_errorson, a fake that raises propagates out of each stage (parametrized over all of them) and, throughoptimizer.strict_errorsin the config, stopstrain(). With the default, the fallback still applies.tests/test_trainer_resume.py:0.0doesn't re-run the baseline and keepsbest_selection_hard == 0.0. This test fails onmain.Results:
python -m pytest -q(Python 3.12): 2022 passed, 11 skipped, 4 xfailed.mkdocs build --strictpasses.ruff checkreports no new findings in the touched files.Docs updated:
docs/guide/new-backend.md(new section),docs/reference/config.md,docs/reference/api.md,configs/_base_/default.yamlandCHANGELOG.md.Release question
The 0.2.0 wheel on PyPI doesn't include the prompt
.mdfiles, so the training loop can't run from a PyPI install. This is already fixed onmain(see the Unreleased changelog, #135/#137). Would you consider publishing a 0.2.1 with that fix?🤖 Generated with Claude Code