Skip to content

Add Novita provider integration#101

Open
Alex-wuhu wants to merge 3 commits intoHKUDS:mainfrom
Alex-wuhu:novita-integration
Open

Add Novita provider integration#101
Alex-wuhu wants to merge 3 commits intoHKUDS:mainfrom
Alex-wuhu:novita-integration

Conversation

@Alex-wuhu
Copy link

Summary

This PR adds Novita AI provider integration to CLI-Anything.

What's New

  • Novita CLI harness - cli-anything-novita command for accessing AI models via Novita's OpenAI-compatible API
  • Supports 3 models (per task spec, using / separator):
    • deepseek/deepseek-v3.2 (default)
    • zai-org/glm-5
    • minimax/minimax-m2.5
  • Feature parity with anygen - chat completion, streaming, model listing, config management, session tracking
  • OpenAI-compatible endpoint: https://api.novita.ai/openai

API Key Configuration

Follows existing pattern:

  • NOVITA_API_KEY environment variable
  • Config file: ~/.config/cli-anything-novita/config.json
  • CLI option: --api-key <key>

Tests

  • Unit tests with mocked API
  • E2E tests for full workflow
  • All tests follow existing patterns from other harnesses

Changes

  • novita/agent-harness/ - Complete CLI harness with backend, CLI, tests
  • registry.json - Added Novita entry
  • .gitignore - Added novita directory patterns

@sehawq
Copy link
Collaborator

sehawq commented Mar 18, 2026

Note: I noticed two small issues:

  • api_key_opt is only defined in the root CLI, but chat/stream reference it directly — this will raise NameError. Consider storing it in a module-level var or passing via Click context.
  • test_chat_completion_error uses requests.HTTPError without importing requests, so the test fails with NameError.

@Alex-wuhu
Copy link
Author

Thanks for the catch @sehawq! Both issues have been fixed in 7b5f2ca:

  1. api_key_opt NameError — Root CLI now stores the key in ctx.obj, and chat/stream read it via @click.pass_context.
  2. import requests in test — Added the missing import.

Also took the opportunity to align the harness structure with other providers:

  • Extracted ChatSessioncore/session.py
  • Converted flat session_* commands to @cli.group() subcommands (session status, session clear, session history)
  • Added missing utils/__init__.py

All 9 tests passing.

@Alex-wuhu Alex-wuhu marked this pull request as ready for review March 18, 2026 11:12
@sehawq
Copy link
Collaborator

sehawq commented Mar 19, 2026

Nice work overall — structure looks solid and aligns well with the existing harnesses.

A couple of things I noticed:

  1. save_history() never persists to diskChatSession.save_history() appends to self.history in memory, but _save() only writes self.messages to the JSON file. History is also never loaded back in __init__. So session history will always return empty after a restart.

  2. No file locking on session writes_save() does a plain open() + json.dump() with no locking. If two CLI invocations run concurrently (e.g. an agent spawning parallel commands), one write can silently clobber the other. Worth noting this is an active discussion in fix(session): add file locking to prevent race conditions in multi-session sync #52 and docs: add session file locking guidance to HARNESS.md #59.

  3. sys.path.insert in novita_cli.py — the file manually inserts the parent directory into sys.path. This shouldn't be needed if the package is installed via pip install -e . as intended. It can mask import issues during development and cause subtle breakage when the CLI is used as an installed package.

None of these are blockers, but (1) is a functional bug that will confuse users expecting session history to survive restarts.

Alex-wuhu added a commit to Alex-wuhu/CLI-Anything that referenced this pull request Mar 19, 2026
- save_history() now writes to session JSON so history survives restarts
- Use fcntl.flock exclusive locking on session writes (ported from blender harness)
- Reset modified flag after _save()
- Remove sys.path.insert; rely on proper package installation
- clear() also resets history

Addresses review feedback from sehawq on HKUDS#101.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Alex-wuhu and others added 3 commits March 19, 2026 18:53
- Implement novita/agent-harness with OpenAI-compatible API client
- Add chat completion, streaming, model listing support
- Include CLI with chat, session, and config commands
- Add tests with mocked API calls
- Update registry.json with Novita entry
- Update .gitignore to include novita/
- Fix NameError: pass api_key_opt via Click context to chat/stream commands
- Fix NameError: add missing `import requests` in test_core.py
- Extract ChatSession to core/session.py (matches other harness patterns)
- Convert flat session commands to @cli.group() subcommands
- Add missing utils/__init__.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- save_history() now writes to session JSON so history survives restarts
- Use fcntl.flock exclusive locking on session writes (ported from blender harness)
- Reset modified flag after _save()
- Remove sys.path.insert; rely on proper package installation
- clear() also resets history

Addresses review feedback from sehawq on HKUDS#101.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Alex-wuhu Alex-wuhu force-pushed the novita-integration branch from 2a4bacc to 77af57d Compare March 19, 2026 10:54
@Alex-wuhu
Copy link
Author

Thanks for the thorough review @sehawq! All three items
addressed in 2a4bacc:

  1. History persistence — save_history() now writes to the
    session JSON file alongside messages, and init loads it back on startup. clear() resets history too.
  2. File locking — Ported _locked_save_json() from the blender
    harness — uses fcntl.flock for exclusive locking on all session
    writes. Also fixed modified flag not resetting after save.
  3. sys.path.insert removed

@sehawq
Copy link
Collaborator

sehawq commented Mar 19, 2026

All three points from my previous comment have been properly addressed in version 2a4bacc 👍

  • Persistence of history datasave_history() now calls _save(), __init__ restores the history from disk, clear() resets it, and status() reports the history_count value. A complete cycle.
  • File locking_locked_save_json() has been moved from the Blender harness using fcntl.LOCK_EX, ensuring seamless backups on Windows.
  • sys.path.insert — Removed. Imports now pass through the namespace package as intended.

A broader topic worth discussing: current harnesses target GUI applications or complex API services (GIMP, Blender, AdGuardHome with 58 endpoints). Novita is an OpenAI-compatible chat API with just a few endpoints — something most agent frameworks can already use directly via an HTTP client. Wrapping this in a CLI harness is technically clean, but it could set a precedent for every API provider to add a thin wrapper here. It might be helpful to define where the line lies between “software that leverages CLI infrastructure” and “an API that already speaks the agent’s own language.” I’ll leave the detailed analysis to @yuh-yang

@Alex-wuhu
Copy link
Author

All three points from my previous comment have been properly addressed in version 2a4bacc 👍

* **Persistence of history data** — `save_history()` now calls `_save()`, `__init__` restores the history from disk, `clear()` resets it, and `status()` reports the `history_count` value. A complete cycle.

* **File locking** — `_locked_save_json()` has been moved from the Blender harness using `fcntl.LOCK_EX`, ensuring seamless backups on Windows.

* **sys.path.insert** — Removed. Imports now pass through the namespace package as intended.

A broader topic worth discussing: current harnesses target GUI applications or complex API services (GIMP, Blender, AdGuardHome with 58 endpoints). Novita is an OpenAI-compatible chat API with just a few endpoints — something most agent frameworks can already use directly via an HTTP client. Wrapping this in a CLI harness is technically clean, but it could set a precedent for every API provider to add a thin wrapper here. It might be helpful to define where the line lies between “software that leverages CLI infrastructure” and “an API that already speaks the agent’s own language.” I’ll leave the detailed analysis to @yuh-yang

Good point! , I'm thinking maybe a provider aggregator. It could be LLM, image, videos with different providers. How do you like that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants