Cassini is a series of small language models fine-tuned for static code feature extraction. Given a source file, it produces the structured symbolic metadata that powers dependency resolution, call graph construction, and type inference at scale.

Model Highlights

  • Fine-tuned on Python, JavaScript, and TypeScript for structured code feature extraction
  • Purpose-built for extraction. Trained to read code the way a static analyzer does, symbolically and structurally. Outputs valid JSON consumed directly by downstream dependency resolvers and call graph engines
  • Extracts six symbolic fields per source file — imports, definitions, references, calls, type assignments, and rich definition metadata — in a single inference pass
  • Built for engineering teams who need structured code intelligence at scale. Dependency analysis across large or monorepo codebases, call graph and impact analysis pipelines, and tooling that requires symbolic metadata without the overhead of a full compiler or language server
  • State-of-the-art cost efficiency for structured code extraction — Cassini-1.0 achieves 77.6% F1 matching or exceeding general-purpose models that cost 17–43× more: Qwen3.7-Max ($3.03, 77.6%), Gemini 3.5 Flash ($5.84, 74.2%), and Gemini 3.1 Pro ($7.57, 72.5%) — all at a total inference cost of $0.17

cost_vs_f1_150

What Cassini Extracts

Field In plain terms Example Used for
imports Every internal dependency a file pulls in — what is imported, from where, and under what alias from .utils import helper as h Building the file-to-file dependency graph
definitions Every class, function, and constant defined at the top level of the file class UserService, def get_user, MAX_RETRIES Populating the project-wide symbol index
references When a whole module is imported and its attributes are accessed later in code import pkg then pkg.connect() → records connect on pkg Resolving module-level attribute call sites
calls Every function or method invocation — who is calling, what is being called, how it is called, and on what receiver self.cache.get(key) inside UserService.fetch Constructing the call graph, one edge per invocation
type_assignments Every variable binding where the type can be inferred, including factory calls where only the function name is known self.db = Database() or result = build_result() Inferring receiver types so method calls resolve to the right class
definitions_rich Extended metadata per definition — kind, parent class, base classes, parameters, return type, and line number create is a method on UserService, returns User, takes data: dict Inheritance resolution, super() walking, and return-type back-filling for factory functions

Technical Specifications

Parameter Value
Framework Unsloth + TRL SFTTrainer
Training method Supervised Finetuning using LoRA
Base model Qwen/Qwen3-4B
Precision bf16
Max sequence length 20,480 tokens
Epochs 5
Per-device batch size 16
Gradient accumulation steps 2
Effective batch size 32
Learning rate 8e-4
LR scheduler Cosine
Warmup steps 10
Weight decay 0.01
Optimizer AdamW 8-bit
LoRA rank (r) 1
LoRA alpha 2
LoRA dropout 0
LoRA target modules q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj
Hardware NVIDIA RTX Pro 9000 (96 GB VRAM)

Usage

Cassini-1.0 is served via vLLM and queried through its OpenAI-compatible endpoint. The model takes a source file as input and returns a structured JSON object containing six symbolic extraction fields.


Prerequisites

1. Install dependencies

pip install vllm openai pyyaml

2. Download the prompt template

The extraction prompt is shipped as python.yaml and javascript.yaml (for both JS and TS) in this repository. Clone or download it before running inference:

# Clone the full repo
git clone https://huggingface.co/LatentForce-ai/Cassini-1.0

# Or download the prompt file only
wget https://huggingface.co/LatentForce-ai/Cassini-1.0/resolve/main/prompts/javascript.yaml

3. Start the vLLM server

In a separate terminal, serve the model:

vllm serve LatentForce-ai/Cassini-1.0 --max-model-len 20480

The server will be available at http://127.0.0.1:8000 by default. Allow 1–2 minutes for the model to load before sending requests.


Minimal Inference

The following snippet runs inference on a single source file and prints the extracted JSON. Point SOURCE_FILE at any .py file, and run.

import json
import yaml
from openai import OpenAI

# ---------------------------------------------------------------------------
# Config
# ---------------------------------------------------------------------------

VLLM_URL    = "http://127.0.0.1:8000/v1"
MODEL_ID    = "LatentForce-ai/Cassini-1.0"
PROMPT_YAML = "python.yaml"           # path to the prompt template from this repo
SOURCE_FILE = "main.py"  # path to the source file to analyze
MAX_TOKENS  = 6144

# ---------------------------------------------------------------------------
# Load prompt template
# ---------------------------------------------------------------------------

with open(PROMPT_YAML) as f:
    config = yaml.safe_load(f)

prompt_template = config["prompt"]

# ---------------------------------------------------------------------------
# Prepare prompt
# ---------------------------------------------------------------------------

with open(SOURCE_FILE) as f:
    source_code = f.read()

prompt = (
    prompt_template
    .replace("FILEPATH_PLACEHOLDER", SOURCE_FILE)
    .replace("CONTENT_PLACEHOLDER", source_code)
)

# ---------------------------------------------------------------------------
# Run inference
# ---------------------------------------------------------------------------

client = OpenAI(base_url=VLLM_URL, api_key="no-key")

response = client.chat.completions.create(
    model=MODEL_ID,
    messages=[{"role": "user", "content": prompt}],
    temperature=0,
    max_tokens=MAX_TOKENS,
    extra_body={"chat_template_kwargs": {"enable_thinking": False}},
)

# ---------------------------------------------------------------------------
# Parse output
# ---------------------------------------------------------------------------

raw = response.choices[0].message.content


def parse_json_response(text: str) -> dict | None:
    """Strip markdown fences if present and parse JSON."""
    text = text.strip()
    if text.startswith("```"):
        first_newline = text.find("\n")
        if first_newline != -1:
            inner = text[first_newline + 1:]
            close = inner.rfind("```")
            if close != -1:
                inner = inner[:close]
            text = inner.strip()
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        pass
    # Fallback: find first complete JSON object
    start, end = text.find("{"), text.rfind("}")
    if start != -1 and end != -1 and end > start:
        try:
            return json.loads(text[start:end + 1])
        except json.JSONDecodeError:
            pass
    return None


result = parse_json_response(raw)

if result is None:
    print("Warning: model output could not be parsed as JSON.")
    print("Raw output:", raw)
else:
    print(json.dumps(result, indent=2))

Example Output

Suppose for a small Python file given below

"""
Declare and configure the signals for the impress core application
"""

from functools import partial

from django.core.cache import cache
from django.db import transaction
from django.db.models import signals
from django.dispatch import receiver

from core import models
from core.tasks.search import trigger_batch_document_indexer
from core.utils.users import get_users_sharing_documents_with_cache_key


@receiver(signals.post_save, sender=models.Document)
def document_post_save(sender, instance, **kwargs):  # pylint: disable=unused-argument
    """
    Asynchronous call to the document indexer at the end of the transaction.
    Note : Within the transaction we can have an empty content and a serialization
    error.
    """
    transaction.on_commit(partial(trigger_batch_document_indexer, instance))


@receiver(signals.post_save, sender=models.DocumentAccess)
def document_access_post_save(sender, instance, created, **kwargs):  # pylint: disable=unused-argument
    """
    Asynchronous call to the document indexer at the end of the transaction.
    Clear cache for the affected user.
    """
    if not created:
        transaction.on_commit(
            partial(trigger_batch_document_indexer, instance.document)
        )

    # Invalidate cache for the user
    if instance.user:
        cache_key = get_users_sharing_documents_with_cache_key(instance.user)
        cache.delete(cache_key)


@receiver(signals.post_delete, sender=models.DocumentAccess)
def document_access_post_delete(sender, instance, **kwargs):  # pylint: disable=unused-argument
    """
    Clear cache for the affected user when document access is deleted.
    """
    if instance.user:
        cache_key = get_users_sharing_documents_with_cache_key(instance.user)
        cache.delete(cache_key)

Cassini-1.0 produces the following structured JSON

{
  "imports": [
    {
      "module": "core",
      "names": [
        "models"
      ],
      "alias": {}
    },
    {
      "module": "core.tasks.search",
      "names": [
        "trigger_batch_document_indexer"
      ],
      "alias": {}
    },
    {
      "module": "core.utils.users",
      "names": [
        "get_users_sharing_documents_with_cache_key"
      ],
      "alias": {}
    }
  ],
  "references": [],
  "calls": [
    {
      "caller": "__module__",
      "callee_text": "receiver",
      "kind": "free",
      "receiver": null,
      "receiver_type_hint": null,
      "callee_file_hint": "external",
      "line": 14
    },
    {
      "caller": "document_post_save",
      "callee_text": "on_commit",
      "kind": "method",
      "receiver": "transaction",
      "receiver_type_hint": null,
      "callee_file_hint": "external",
      "line": 21
    },
    {
      "caller": "document_post_save",
      "callee_text": "partial",
      "kind": "free",
      "receiver": null,
      "receiver_type_hint": null,
      "callee_file_hint": "external",
      "line": 21
    },
    {
      "caller": "document_post_save",
      "callee_text": "trigger_batch_document_indexer",
      "kind": "hook",
      "receiver": null,
      "receiver_type_hint": null,
      "callee_file_hint": "core/tasks/search.py",
      "line": 21
    },
    {
      "caller": "__module__",
      "callee_text": "receiver",
      "kind": "free",
      "receiver": null,
      "receiver_type_hint": null,
      "callee_file_hint": "external",
      "line": 24
    },
    {
      "caller": "document_access_post_save",
      "callee_text": "on_commit",
      "kind": "method",
      "receiver": "transaction",
      "receiver_type_hint": null,
      "callee_file_hint": "external",
      "line": 31
    },
    {
      "caller": "document_access_post_save",
      "callee_text": "partial",
      "kind": "free",
      "receiver": null,
      "receiver_type_hint": null,
      "callee_file_hint": "external",
      "line": 32
    },
    {
      "caller": "document_access_post_save",
      "callee_text": "trigger_batch_document_indexer",
      "kind": "hook",
      "receiver": null,
      "receiver_type_hint": null,
      "callee_file_hint": "core/tasks/search.py",
      "line": 32
    },
    {
      "caller": "document_access_post_save",
      "callee_text": "get_users_sharing_documents_with_cache_key",
      "kind": "free",
      "receiver": null,
      "receiver_type_hint": null,
      "callee_file_hint": "core/utils/users.py",
      "line": 37
    },
    {
      "caller": "document_access_post_save",
      "callee_text": "delete",
      "kind": "method",
      "receiver": "cache",
      "receiver_type_hint": null,
      "callee_file_hint": "external",
      "line": 38
    },
    {
      "caller": "__module__",
      "callee_text": "receiver",
      "kind": "free",
      "receiver": null,
      "receiver_type_hint": null,
      "callee_file_hint": "external",
      "line": 41
    },
    {
      "caller": "document_access_post_delete",
      "callee_text": "get_users_sharing_documents_with_cache_key",
      "kind": "free",
      "receiver": null,
      "receiver_type_hint": null,
      "callee_file_hint": "core/utils/users.py",
      "line": 47
    },
    {
      "caller": "document_access_post_delete",
      "callee_text": "delete",
      "kind": "method",
      "receiver": "cache",
      "receiver_type_hint": null,
      "callee_file_hint": "external",
      "line": 48
    }
  ],
  "type_assignments": [
    {
      "scope": "document_access_post_save",
      "var": "cache_key",
      "type": null,
      "type_module": null,
      "from_call": "get_users_sharing_documents_with_cache_key"
    },
    {
      "scope": "document_access_post_delete",
      "var": "cache_key",
      "type": null,
      "type_module": null,
      "from_call": "get_users_sharing_documents_with_cache_key"
    }
  ],
  "definitions": [
    "document_post_save",
    "document_access_post_save",
    "document_access_post_delete"
  ],
  "definitions_rich": [
    {
      "name": "document_post_save",
      "kind": "function",
      "parent": null,
      "bases": [],
      "params": [
        {
          "name": "sender",
          "type": null
        },
        {
          "name": "instance",
          "type": null
        }
      ],
      "returns": null,
      "line": 15
    },
    {
      "name": "document_access_post_save",
      "kind": "function",
      "parent": null,
      "bases": [],
      "params": [
        {
          "name": "sender",
          "type": null
        },
        {
          "name": "instance",
          "type": null
        },
        {
          "name": "created",
          "type": null
        }
      ],
      "returns": null,
      "line": 25
    },
    {
      "name": "document_access_post_delete",
      "kind": "function",
      "parent": null,
      "bases": [],
      "params": [
        {
          "name": "sender",
          "type": null
        },
        {
          "name": "instance",
          "type": null
        }
      ],
      "returns": null,
      "line": 42
    }
  ]
}

Downloads last month
5
Safetensors
Model size
4B params
Tensor type
BF16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for LatentForce-ai/Cassini-1.0

Finetuned
Qwen/Qwen3-4B
Finetuned
(705)
this model

Space using LatentForce-ai/Cassini-1.0 1