Repository navigation
Phase 9/10: plugin update compatibility gate, execution timeout, Stellar notifier example, and default price table - #502
Merged
Ayinkx merged 3 commits intoOct 17, 2026
Conversation
The Phase 10 budget-alert test merged in AyinkxLab#500 has an invalid parameter list (self/ app), which prevents pytest from collecting tests/test_notifications.py at all. Restore the comma so the suite can run.
Ship per-1k input/output estimates for every model exposed by the built-in providers, with the mock provider pinned at zero cost. Entries are explicitly marked as estimates via ModelPrice.estimated and ESTIMATE_DISCLAIMER; unknown provider/model lookups return None rather than assuming zero. Lookups are case/whitespace insensitive, token counts are validated, and price_table() exposes the grouped table for operator-facing surfaces.
…ellar example Refs AyinkxLab#405, AyinkxLab#408, AyinkxLab#415. - AyinkxLab#405: add an owner-only update endpoint plus update_plugin(), identity-bound to the registered id/entry point. The manifest's PEP 440 compatibility range is enforced before any write, with an error naming the range and the running app version. - AyinkxLab#408: run plugin event handlers and lifecycle hooks with a configurable PLUGIN_EXECUTION_TIMEOUT budget in a daemon thread. Overruns are abandoned, recorded as one bounded error report, and dispatch/lifecycle state changes continue safely. - AyinkxLab#415: add examples/plugins/stellar_notifier, a read-only, offline example that formats bounded summaries for stellar.analysis.completed, with schema/load/event/bounding tests.
|
@Hey-Yetunde Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Contributor
Author
|
CI note:
No new failures are introduced by this branch: |
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.
Summary
This PR resolves four Phase 9/10 issues in
ai-code-assistant:update_plugin(). The manifest is validated and identity-bound, and its declared PEP 440 range is enforced against the running app before anything is written. An incompatible range is refused with a message naming both the range and the current app version, leaving the registered plugin untouched.PLUGIN_EXECUTION_TIMEOUTbudget. A slow callback is abandoned, recorded as one bounded error report (dispatch:<event>/hook:<hook>), and dispatch or the lifecycle state change continues safely.examples/plugins/stellar_notifiersubscribes tostellar.analysis.completed, formats a bounded, read-only summary, and stays offline. Covered by schema, load/register, event-path, bounding, read-only, and no-network tests.app/services/pricing.pyprovides documented per-1k input/output estimates for every model exposed by the built-in providers, with the mock provider pinned at zero cost. Every vendor entry is explicitly marked as an estimate, lookups are case-insensitive, and unknown models returnNoneinstead of assuming zero.Linked issue
Closes #405
Closes #408
Closes #415
Closes #439
Changes
app/services/plugin_compat.py—enforce_compatible()andIncompatibleCompatibilityError; the install route reuses the same helper.app/plugins/routes.py,app/services/plugin_ops.py—POST .../plugins/<plugin_id>/updateandupdate_plugin()with id/entry-point binding and clear 400/409/404 responses. Nothing is persisted when the gate refuses an update.app/services/plugin_execution.py—run_with_timeout()andPluginTimeoutError(daemon worker, app context preserved, non-positive timeout disables the bound).app/services/events.py,app/services/plugins.py— handler and hook calls wrapped in the timeout.app/config.py,.env.example—PLUGIN_EXECUTION_TIMEOUT(default 5 seconds).app/services/pricing.py,docs/providers.md— price table, lookup/estimate helpers, and the "verify these estimates" disclaimer.examples/plugins/stellar_notifier/*,docs/plugins.md— example plugin, README, and documentation for the update gate, timeout, and example.tests/test_pricing.py,tests/test_plugin_update.py,tests/test_plugin_timeout.py,tests/test_stellar_notifier_example.py.Validation
ruff check .— passesblack --check .— passespytest -q— all tests pass except the two pre-existingTestBudgetAlertDeduplicationtests described below (verified locally by running the suite with that class excluded).Notes for reviewers
Upstream
mainis currently broken intests/test_notifications.py(from the #500 merge):self/ app), which stops pytest from collecting it. This PR includes a one-character repair in a separate commit (test: fix syntax error blocking notifications collection).TestBudgetAlertDeduplicationtests still fail because they importapp.services.budget_alerts, which does not exist onmain(the merged change addedBudgetAlertDeduplicatortoapp/services/token_usage.pyinstead). This is unrelated to these four issues, so I left it alone rather than colliding with the Phase 10 budget work.The execution timeout abandons an over-budget callback because Python cannot interrupt threads; callbacks must therefore be idempotent. This limitation is documented in
docs/plugins.md.