GH-INFERENCE
Text in, text out. Quantized models run on GitHub servers.
Your Python client only connects, submits prompts, and retrieves answers. Model downloads, model loading, inference, and optional prompt refinement all happen inside GitHub Actions. No model runtime or GPU is required on your machine.
Start
Install the client in your environment (Python 3.9+):
pip install gh-inference
export GH_AI_TOKEN="your-github-token"
Use a classic GitHub token with repo and workflow scopes. Do not commit it.
from gh_inference import Agent
agent = Agent()
print(agent.run("Explain recursion briefly."))
That is the whole flow. The first call automatically creates or reuses the
ai-inference-runner repository, installs the workflow, starts a GitHub worker,
and returns its answer as a plain string. agent("prompt") is equivalent.
You can also pass Agent(github_token=...) instead of setting the environment.
agent.connect() optionally prepares the repository ahead of the first prompt;
it is never required. Connecting does not start or reserve a model worker.
Built-in writing models
Four tested Q4_K_M writing models are included as ready-to-use aliases:
| Alias | Model | Weight download |
|---|---|---|
glitter-12b |
Gemma 3 Glitter 12B | 7.30 GB |
gemma-4-12b |
Gemma 4 12B Instruct | 7.12 GB |
gemma-4-styletune-12b |
Gemma 4 12B StyleTune | 7.95 GB |
rocinante-x-12b |
Rocinante-X 12B v1 | 7.48 GB |
Downloads are pinned to verified publisher commits and SHA-256 checksums. These are weights only; runtime and context need additional RAM. Start with a 16 GB runner and a 4,096-token context, as used in our scene comparisons:
from gh_inference import Agent, GitHubAIRunner
writer = Agent(model="glitter-12b", n_ctx=4096,
runner=GitHubAIRunner(runner_ram_gb=16))
print(writer.run("Write a tense scene between two estranged crewmates."))
For either Gemma 4 alias, set
model_options={"chat_template_options": {"enable_thinking": False}}
to request direct writing without a thinking phase. These models are useful
candidates, not a guaranteed ranking of literary quality.
Models and every published GGUF variant
The 16 pinned aliases below remain convenient defaults. Model support is open: use any public, ungated Hugging Face GGUF repository supported by the installed llama.cpp runtime. Search discovers Qwen, Llama, Gemma, Phi, Mistral, DeepSeek, SmolLM and other families, with no project parameter-count ceiling. A model being discoverable does not mean it fits your runner or its architecture is supported.
from gh_inference import Agent, search_models, list_quantizations
print(search_models("Qwen3"))
print(list_quantizations("Qwen/Qwen2.5-0.5B-Instruct-GGUF"))
agent = Agent(model="Qwen/Qwen2.5-0.5B-Instruct-GGUF", quantization="Q8_0")
print(agent("Explain quantization in one sentence."))
quantization defaults to Q4_K_M for repository selections. All published GGUF
labels can be selected, including Q2/Q3/Q4/Q5/Q6/Q8, K-quants, IQ, TQ and floating
point variants when provided and supported by your backend. We do not manufacture
missing variants or convert weights. AWQ/GPTQ/Safetensors require other backends
and are not accepted by this GGUF CPU runner. Model licenses still apply.
For ambiguous repositories use Agent(model="owner/repo", filename="exact.gguf").
You can also paste a Hugging Face repository URL or an exact GGUF blob/resolve
URL directly into Agent(model=...). File links select that file (and its complete
shard group); repository links default to Q4_K_M. Links are resolved to a pinned
commit and verified checksums, just like repository names.
agent = Agent(model="https://huggingface.co/Qwen/Qwen2.5-0.5B-Instruct-GGUF")
For your own public single-file GGUF download on another host, register its link with the publisher's actual SHA-256 and byte size:
from gh_inference import Agent, add_model
model = add_model(
"https://your-host.example/writer.gguf",
sha256=publisher_sha256,
size_bytes=publisher_size_bytes,
max_n_ctx=8192, # optional advertised context ceiling
)
agent = Agent(model=model)
Registration lasts for the Python process; each submitted job carries the model metadata to its worker. Weights download only on GitHub and are verified before loading. Custom hosts must allow unauthenticated HTTPS downloads. The model must fit the runner and use a GGUF architecture supported by the installed llama.cpp runtime; a link does not add a new inference backend. Resource checks still apply.
Split GGUF files are grouped, all shards are checked and downloaded, and the first
shard is loaded. Incomplete shard groups are excluded. list_quantizations lists
exact filenames and aggregate bytes; projector files are excluded (text only).
Selections resolve metadata once per client process and pin a Hub commit plus
each file's SHA-256 and size. Workers verify downloads before loading. Subsequent
jobs reuse the Actions weights cache when eligible; run_many() keeps one model
resident in RAM throughout that job. An Actions job ending releases its RAM.
Use revision="commit-or-tag" for reproducibility; clear_model_cache() refreshes
cached branch metadata. Hub metadata calls download no model weights locally.
Context defaults to about 8K (or a known smaller ceiling). Existing aliases retain
their documented limits; arbitrary repositories use Hub GGUF context_length
when supplied. If absent, the advertised ceiling is unknown, not invented.
RAM estimates for arbitrary models are approximate; architecture and KV cache
shape affect actual usage. Limits and Agent.experimental() below remain
available, but cannot create RAM, extend GitHub quotas, or add backend support.
gh-inference models Qwen3
gh-inference variants Qwen/Qwen2.5-0.5B-Instruct-GGUF
gh-inference run "What is recursion?" --model qwen0.5b --track-time
For source development, pip install -e '.[dev]' installs this checkout. The
legacy gh_ai_runner import remains supported; new code can use gh_inference.
Publishing
The publish.yml workflow builds and tests the wheel before publishing to PyPI
using GitHub OIDC, with no stored PyPI token. Configure the PyPI trusted publisher
for owner TanishC4444, repository GH-INFERENCE, workflow publish.yml, and
environment pypi, then run it with publish=true or publish a v* release.
You can also publish by updating .github/release.json on main to the package
version; the workflow checks that they match before building and uploading.
Each version is immutable on PyPI; bump gh_ai_runner.__version__ for a release.
New repositories are private by default. Existing visibility is never changed.
Actions must be enabled. Private Actions usage consumes included minutes and can
incur charges. Use a dedicated repository: the package manages and can overwrite
run_inference.py and .github/workflows/inference.yml there.
Experiments: remove project ceilings
from gh_ai_runner import Agent
agent = Agent.experimental(
model="qwen0.5b",
n_ctx=65536, # Deliberately above this model's advertised 32K.
max_tokens=None, # Ask the runtime to use remaining context for the answer.
track_time=True,
)
print(agent.run("Explain context windows."))
print(agent.last_result.usage)
Agent.experimental() uses Limits.unrestricted(), trim_history=False, and
max_history_turns=None. It removes our advertised model/output checks, estimated
RAM/disk rejection, temperature bounds, prompt-character cap, batch-count cap,
formatting reserves, cache-size threshold, and project workflow-input budget.
Default context remains 8K (2K for TinyLlama) unless you set n_ctx; default answer
length remains 512 unless you change max_tokens. All computation stays on GitHub.
This permits an attempt; it does not guarantee that the backend can execute it.
A bigger n_ctx allocates a bigger window. Sending more messages alone does not.
Going beyond a model's trained/advertised length may require positional scaling
and can produce poor answers. Disabling memory checks cannot create memory.
Edit individual rules
from gh_ai_runner import Agent, Limits
limits = Limits.unrestricted(
check_resources=True,
max_prompts=100,
max_cached_model_gb=6,
job_timeout_minutes=90,
)
agent = Agent.experimental(limits=limits, n_ctx=16384, max_tokens=2048)
Limits() preserves standard checks. Limits.unrestricted(**overrides) disables
project ceilings and applies your overrides. Both accept every field below. Pass
the configuration to Agent, GitHubAIRunner, ai_call, or an individual
InferenceRequest/submit(); request settings override runner defaults.
Configurations are immutable: make a new one or use dataclasses.replace().
Limits field |
Standard default | Meaning / override |
|---|---|---|
enforce_model_limits |
True |
Advertised context and recorded output ceilings; False permits attempts beyond them. |
enforce_output_budget |
True |
Reject an explicit answer limit at least as large as n_ctx and reserve the answer during trimming; False delegates answer-space handling to the runtime. |
check_resources |
True |
Estimated RAM/disk checks on client and worker; False lets allocation/downloads proceed to real limits. |
max_prompt_chars |
60000 |
Current prompt plus instructions; None removes the project check. |
max_workflow_input_chars |
65000 |
Serialized workflow-input budget; None removes this budget. GitHub's service limit remains. |
max_prompts |
32 |
Prompts per run_many(); None removes the count cap. |
min_temperature, max_temperature |
0.0, 2.0 |
Either bound can be None; values must still be finite. |
context_reserve_tokens |
128 |
Conservative extra allowance; can be 0. |
message_overhead_tokens |
32 |
Formatting allowance per message; can be 0. Actual formatting still uses tokens. |
max_cached_model_gb |
6.0 |
Cache files below this decimal-GB threshold; None permits all sizes, 0 skips caching. |
runtime_overhead_gb |
1.5 |
Estimated RAM above weights/context. |
disk_reserve_gb |
2.0 |
Additional estimated free disk. |
ram_per_1k_ctx_gb |
None |
Use catalog's estimate; a number overrides it. Changing estimates does not change real allocation. |
job_timeout_minutes |
30 |
Remote timeout; unrestricted preset uses 360. Hosted GitHub jobs have a six-hour service maximum. |
artifact_retention_days |
3 |
Requested result retention, subject to repository policy. |
download_timeout_seconds |
30 |
Model-download socket timeout. |
provider_timeout_seconds |
300 |
Legacy hosted-provider request timeout. |
refiner_min_tokens |
128 |
Minimum prompt size considered for refinement. |
refiner_max_tokens |
512 |
Rewrite ceiling, also bounded by original length and available context. |
refiner_context_fraction |
0.25 |
Context fraction used to plan the rewrite allowance. |
The unrestricted preset sets the three enforcement flags to False; optional
prompt, workflow-budget, batch, temperature, and cache-size limits to None;
formatting reserves to 0; and remote timeout to 360. Other defaults remain.
The experimental agent factory additionally disables trimming and turn-count caps.
Explicit arguments to the factory override those choices.
Model loading and sampling
agent = Agent.experimental(
n_ctx=65536,
max_tokens=4096,
model_options={
"n_threads": 2,
"n_batch": 256,
"rope_scaling_type": "yarn",
"rope_freq_scale": 0.5,
"yarn_orig_ctx": 32768,
"yarn_ext_factor": 1.0,
},
generation_options={"top_k": 40, "top_p": 0.9, "repeat_penalty": 1.1, "seed": 42},
)
model_options forwards JSON-compatible keywords to
llama_cpp.Llama,
including CPU threads, batch sizes, KV settings, and positional scaling.
rope_scaling_type accepts a backend integer enum or a name such as "yarn" or
"linear". These are experimental settings, not verified 64K quality claims.
Increasing context does not retrain the weights. Qwen 7B/14B still apply their
published factor-4 YaRN recipe above 32K unless you override it. Beyond advertised
lengths, choose and evaluate scaling yourself. Other entries keep GGUF metadata.
generation_options forwards sampling keywords to create_chat_completion,
including top_k, top_p, min_p, penalties, seed, and stop. It applies to
main answers; refinement uses separate deterministic sampling. Unknown keywords
are rejected by the installed backend. Use named n_ctx, max_tokens, and
temperature arguments for those values. Extra-option dictionaries cannot replace
the managed model path, CPU/RAM placement, messages, or nonstreaming text contract.
max_tokens=None requests remaining context. Standard model-limit enforcement
still applies a recorded publisher output ceiling; unrestricted mode does not.
The runtime can shorten an explicit answer allowance to remaining space and stop
early at EOS. Input exceeding allocated n_ctx is rejected by llama-cpp-python.
Custom policies/options are sent to the worker and covered by request checksums.
Connection and waiting
from gh_ai_runner import Agent, GitHubAIRunner, Limits
runner = GitHubAIRunner(
limits=Limits.unrestricted(job_timeout_minutes=90),
completion_timeout=5500,
run_discovery_timeout=300,
poll_interval=10,
http_timeout=60,
artifact_timeout=120,
workflow_registration_timeout=120,
)
agent = Agent.experimental(runner=runner, limits=runner.limits)
Runner defaults, all in seconds: completion_timeout=1800,
run_discovery_timeout=180, poll_interval=8, http_timeout=30,
artifact_timeout=60, workflow_registration_timeout=60. Values must be finite
and positive; there is no project upper bound. HTTP timeout applies per API
request. Discovery/completion/artifact deadlines apply to their own phases.
agent.run(prompt, timeout=...) bounds waiting/result retrieval after dispatch,
not repository preparation or model execution. A client timeout does not cancel
the remote job. Increase client waiting alongside longer remote job timeouts.
External limits remain
- GitHub workflow inputs have a 65,535-character service limit including history, configuration, escaping, and JSON overhead. Characters are not tokens. This version has no alternate large-prompt transport, even when model context is 128K or larger.
- GitHub Actions limits include the six-hour hosted-job maximum, account minutes, concurrency, storage, and API limits. A larger configured timeout cannot extend the service maximum.
- Real RAM/disk, CPU time, backend numeric ranges, supported architectures and scaling, and model quality remain constraints. Allocation, disk-full, timeout, and worker-termination failures are possible when resource checks are disabled.
The curated 16B catalog is not a mathematical parameter-count cap; larger entries need verified GGUF download metadata and appropriate workers. Valid input types, checksums, and job identity checks remain required in both presets.
Choose a model or role
agent = Agent(model="qwen", instructions="You are a concise coding assistant.")
answer = agent.run("Write a function that merges overlapping intervals.")
The default qwen0.5b is a roughly 491 MB Q4_K_M starter model. Larger models can
provide better answers but take more download time, RAM, and CPU time.
| Model keys | Parameter sizes |
|---|---|
qwen0.5b, tinyllama, llama, qwen |
0.5B, 1.1B, 1B, 1.5B |
gemma2, qwen3b, phi3, deepseek |
2B, 3B, 3.8B, 1.5B |
qwen7b, qwen-coder7b, llama8b, gemma9b |
7B, 7B, 8B, 9B |
mistral12b, qwen14b, qwen-coder14b, deepseek-coder16b |
12B, 14B, 14B, 16B |
All catalog entries are prequantized GGUF files. Their sizes and SHA-256 hashes
are recorded in models.py; new downloads must match both before loading.
Reuse one loaded model
answers = agent.run_many([
"Explain a Python list.",
"Compare it with a tuple.",
"Give a small example using both.",
])
for answer in answers:
print(answer)
By default, up to 32 prompts run sequentially in one GitHub job. Change
Limits.max_prompts to raise/remove that cap. The full quantized model
loads into CPU RAM once and remains loaded for all those prompts and refinement
steps. Memory mapping and GPU offloading are disabled; memory locking is requested,
subject to the worker OS's permissions.
Separate run() calls create separate workers. Hosted GitHub workers cannot keep
RAM between jobs. Group prompts with run_many() to avoid repeated model loading.
GitHub caches downloaded weights and the Python environment across jobs, although
caches can be evicted. Model cache keys include the expected weight checksum.
Setup prefers official prebuilt CPU packages so a new worker normally avoids
compiling the inference runtime; source compilation is a fallback.
By default, files at least 6 GB skip weight caching because uploading their archive can need
another model-sized copy on the worker's limited disk. They still load once per
run_many() job, but a new job downloads them again.
Set max_cached_model_gb=None to permit all sizes, or cache=False on Agent
to skip weight caching. Unrestricted mode permits all sizes; cache archives can
still fail if the worker's disk or GitHub cache storage is too small.
Timing
agent = Agent(track_time=True)
print(agent.run("What is a B-tree?"))
print(agent.last_result.timings)
The return value stays plain text. Optional details are in agent.last_result
and agent.last_results: token usage, download/load/generation timing, weight-cache
hits, and within-job model reuse. agent.last_job exposes the Actions URL and
low-level status/cancellation handle.
total_seconds measures worker time for that prompt, including shared setup on
the first prompt. remote_seconds measures the full client operation, including
repository preparation, queuing, waiting, and result retrieval. For run_many(),
the whole-job remote duration appears on every result; do not sum it.
Override tracking per call with agent.run(prompt, track_time=True).
Controlled writing comparison
python examples/writing_benchmark.py --output writing-results.json
With GH_AI_TOKEN set, this compares Magnum v4 12B, Gemma 4 12B, Gemma 3 12B,
Gemma 3 Glitter 12B, and Qwen3.5 9B on strict dialogue, rhetoric, and JSON-scene
prompts. Five independent jobs reuse one loaded model each for three independent
samples. The benchmark explicitly configures a 16 GB runner budget, 4K context,
768 output tokens, four CPU threads, fixed sampling settings, and no automatic
repair or grammar constraints. It requires a repository whose workers really
have 16 GB; the budget itself does not upgrade hardware.
The report preserves prompts, pinned GGUF revisions/checksums, full raw samples, rule violations, worker resources/runtime version, and Actions URLs. Mechanical constraint scores do not measure literary quality, and one sample per case is exploratory evidence. A loading/runtime failure is not scored as bad writing. Large model downloads and runtime preparation can dominate cold job latency.
Worker environments are pinned to llama-cpp-python 0.3.36 with a versioned cache
key. New architectures require a compatible runtime, not just a GGUF filename.
model_options={"chat_template_options": {"enable_thinking": False}} binds that
option to the embedded default template, allowing supported reasoning models to
produce final artifacts without requesting reasoning. It does not strip or
rewrite output; unsupported templates fail explicitly. Currently only the boolean
enable_thinking template option is accepted.
examples/story_turn_contract.json proposes the next input/output boundary:
application-owned identities/routing, visibility-filtered context, generated content,
strict validation, and a committed event. It is a design proposal, not an
implemented persistent-worker service.
Efficient draft, review, and revision
from gh_inference import Agent
agent = Agent(model="qwen0.5b", max_tokens=None, track_time=True)
answer = agent.review("Write a scene between a cautious pilot and an impatient scientist.",
revisions=2)
This executes writer → reviewer → writer → reviewer → writer in one job with
one model load. Reviews receive the latest draft. Revisions receive that draft
and its review; obsolete drafts and reviews are not automatically accumulated.
The method returns the final answer. last_results contains every step.
For directed handoffs, multiple reviewers, or sharing selected outputs, use a plan:
outputs = agent.pipeline("Write a tense two-character scene.", [
{"agent": "writer", "instruction": "Draft the scene.", "inputs": []},
{"agent": "dialogue-critic", "instruction": "Check distinct character voices.", "inputs": [0]},
{"agent": "continuity-critic", "instruction": "Check facts and continuity.", "inputs": [0]},
{"agent": "writer", "instruction": "Revise using both reviews.", "inputs": [0, 1, 2]},
])
Step indices start at zero. An omitted inputs selects the preceding step; []
selects none. References must name earlier steps. Repeated indices are forwarded
only once, in the supplied order. A reviewer only receives selected source outputs,
not other reviewers' replies. To broadcast a draft, let several steps reference it;
to gather feedback, select those review indices on the receiving step.
The client sends the task and plan once. Intermediate outputs remain in worker memory; source blocks are formatted once and reused for recipients. Shared source text is placed before varying role/instruction text to enable prefix reuse between recipients of the same draft. No workflow launch, artifact download, or client/GitHub round trip occurs between steps. Each model call must still process its supplied context; references do not eliminate that computation. Turns execute sequentially, with the same loaded model and backend prefix reuse. These methods do not create separate per-agent KV caches or persistent multi-runner actors. Step names identify roles, not separate models.
Inspect last_results[i].agent_id, .step_index, .input_steps, .handoff_chars,
and .handoff_bytes for routing diagnostics, plus .usage.prompt_tokens for actual
whole-input token usage. Handoff size measures the selected in-memory payload,
including source labels; it is not network traffic. With timing enabled,
.timings.routing_seconds measures preparation of each step's handoff.
Whole-job resources are shared across results; count them once. Existing Agent
conversation history is neither sent to a plan nor replaced by it. No automatic
summarization is performed, and the shared task plus selected inputs must fit the
configured prompt/context limits. Limits.max_prompts bounds the total step count.
Faster agent discussions on one worker
gh-inference discuss "Improve this inference library" --agents 20 --rounds 3 --topology ring
This runs 60 logical turns in one GitHub job, with one model kept in RAM. Messages pass directly between rounds inside the worker. It avoids 59 workflow launches and their setup, polling, and result downloads. Agents take turns on one shared model; this mode does not provide 20 simultaneous inference workers. Whether it beats independent workers in elapsed time depends on prompt/output length and available parallel hardware. It is intended to reduce orchestration and repeated computation for small, closely interacting agents.
from gh_inference import Agent, Limits
agent = Agent(model="qwen0.5b", max_tokens=None, track_time=True,
limits=Limits(max_prompts=60))
rounds = agent.discuss("Improve this inference library", agents=20, rounds=3,
topology="ring")
print(rounds[-1]) # Last round's 20 replies, in agent order.
topology="all" (the Python default) shares the previous round's replies with
every agent. topology="ring" shares only the previous neighbor's reply, reducing
peer-message entries per later round from N² to N. This changes the discussion's
information flow; it is an explicit option. Peer replies default to 240 characters.
Each agent has an identity, and no agent sees partially completed current rounds.
The existing conversation on the Agent is neither read nor replaced by a discussion.
last_results holds every turn in round order. Whole-job resources are shared
across all results and must be counted only once.
Repeated generation now lets llama.cpp reuse matching prompt prefixes rather than forcing a reset before each reply. The backend compares exact tokens and discards nonmatching suffixes; this is computation reuse, not implicit conversation memory. See the backend's prefix matching implementation. The worker also caches repeated token-count calculations within a turn. Shared model download/load time is attributed only to the first turn.
Both discuss and stress accept --max-tokens auto for dynamic output length,
subject to remaining context, model limits and job timeout. Long responses can
increase latency; dynamic length is not itself a speed optimization.
Twenty-agent interaction stress test
gh-inference stress --agents 20 --rounds 3 --output stress-results.json
Use --topology ring to reduce peer traffic while retaining independent parallel
workers; the default remains all-to-all. Or use stress_test() from Python. One command compares qwen0.5b, llama,
qwen, and tinyllama: five agents per model, 20 concurrent client calls per
round, three synchronized rounds, 60 remote jobs total. Each round broadcasts
all successful agents' previous replies to all agents, capped at 240 characters
per reply. Agents critique peers and propose improvements. Conversation is
bounded to the previous round; increase rounds for longer interaction.
GitHub account concurrency and available capacity determine actual simultaneous
workers. These jobs consume your Actions allowance.
The JSON report saves answers, errors, Actions links, settings, and per-model
summaries after each round. It separates generation throughput (completion tokens
per second, including prompt processing) from client latency (including queue and
setup), process CPU seconds, and process peak memory. CPU seconds include all
inference process threads, model loading, and refinement; they exclude workflow
installation/cache steps. Agent.last_result.resources exposes these worker
counters. Resources describe the entire job: for run_many(), all results share
them, so count them once. Old workers without CPU counters report None.
Hosted worker energy is unavailable here. --estimated-worker-watts 40 optionally
calculates assumed constant watts × inference-worker wall seconds / 3600, labeled
estimated Wh. It excludes provisioning, dependency installation, cache transfer,
and data-center overhead; it is neither measured power nor total job energy.
No default wattage is invented.
Use --models qwen0.5b llama to choose candidates. Compare both failure rates and
throughput; the benchmark does not score answer quality or establish a universal
best model. It resets model RAM every job, so later rounds can reuse downloaded
weights but do not measure resident-model serving speed. Use run_many() when
measuring repeated inference within one loaded model.
Optional prompt refinement
agent = Agent(refine_prompt=True, track_time=True)
print(agent.run("Your detailed task and constraints ..."))
print(agent.last_result.refinement.tokens_saved)
Refinement runs on the same loaded model on GitHub, not a separate service or second model. Short prompts are skipped. A rewrite is accepted only when it uses fewer main-model tokens, finishes normally, and preserves protected numbers, URLs, double-quoted literals, and code. Otherwise the original prompt is retained.
It can reduce the main generation's input processing, but adds its own tokens
and time. Total usage includes that work; last_result.refinement.usage reports
it separately. Shorter input does not shrink model weights or automatically reduce
the allocated context cache. Literal checks do not guarantee unchanged meaning.
Conversation and limits
Conversation is remembered on the agent object and passed to subsequent GitHub
jobs. run_many() manages it within the same worker. No prompt/output history is
automatically written to disk by Agent. Use remember=False for independent
prompts and agent.reset() to forget previous turns.
Older conversation turns are dropped as needed to leave room for the new prompt and answer. Current prompt text is never silently truncated. The main options are:
| Option | Default | Limit |
|---|---|---|
max_tokens |
512 | Positive integer or None; standard policy checks output/context ceilings |
n_ctx |
8,192; TinyLlama: 2,048 | Positive integer; advertised ceiling and resource checks are editable policies |
temperature |
0.7 | Finite number; standard bounds are 0 to 2 |
max_history_turns |
6 | Any positive integer, or None for no exchange-count cap |
trim_history |
True |
Set False to retain all exchanges and pass overflow to the model runtime |
Context includes instructions, history, formatting, and the answer. Worker
tokenization supplies actual usage; context planning includes a conservative
formatting allowance. The model can stop before reaching max_tokens.
Context ceilings
The old blanket 8,192-context and 4,096-output caps are removed. Standard starting windows are
8,192 total tokens, except TinyLlama, whose supported maximum is only 2,048.
These advertised ceilings are enforced by standard policy and bypassable with
enforce_model_limits=False. They describe support, not a promise that a worker has enough
RAM or CPU time to use them. The catalog includes each limit's publisher source
in MODELS[key]["context_source"].
| Model keys | Maximum total context | Separate published output ceiling |
|---|---|---|
tinyllama |
2,048 | — |
gemma2, gemma9b |
8,192 | — |
qwen0.5b, qwen, qwen3b |
32,768 | 8,192 |
qwen7b, qwen14b |
131,072 | 8,192 |
qwen-coder7b, qwen-coder14b |
131,072 | — |
llama, llama8b, phi3, deepseek |
131,072 | — |
mistral12b, deepseek-coder16b |
131,072 (128K) | — |
glitter-12b, rocinante-x-12b |
131,072 | — |
gemma-4-12b, gemma-4-styletune-12b |
262,144 | — |
— means no separate output ceiling is recorded; the available total context
still bounds generation. It does not mean unlimited or tested long-form output.
Sources include the Qwen 0.5B model card,
Qwen 7B long-context recipe,
Gemma 2 model card, and the
individual publisher links in the catalog.
agent = Agent(model="qwen0.5b", n_ctx=32768, max_tokens=8192)
print(agent.run("Explain the design in detail."))
The answer allowance shares the window with instructions, history, and your prompt. Increasing context increases RAM usage even if the current prompt is short. The worker automatically enables Qwen's factor-4 YaRN settings above 32,768 tokens for the 7B/14B Qwen and Qwen Coder entries. Other models retain the scaling encoded in their GGUF files. Long-context quality and peak RAM are not verified at every ceiling.
When a conversation grows past its window
A 32K model can participate in a conversation totaling 64K tokens across many calls. It can only receive one window's worth on any given call. This agent keeps the instructions and current prompt, reserves the requested answer allowance, and removes the oldest complete user/assistant pairs until the request fits. It does not automatically summarize or retrieve the removed messages. Details that appeared only in those messages are no longer available to the model.
The default history cap is also six previous exchanges, even when context has
space. Increase max_history_turns or set it to None to retain more exchanges; the token
budget and workflow transport can still trim them earlier. n_ctx=32768 must be
set explicitly to use a 32K window instead of the 8K default.
agent = Agent(model="qwen0.5b", n_ctx=32768, max_history_turns=32)
print(agent.run("Continue our discussion."))
print(agent.last_result.dropped_history_turns) # history removed to fit context/transport
With the default trimming policy, one oversized current prompt is rejected, rather than cut silently. A 64K-token prompt cannot fit an allocated 32K window. Standard policy rejects allocations above the advertised maximum; experimental mode allows those attempts to reach the runtime.
Experiment without automatic history removal
agent = Agent(
model="qwen0.5b",
n_ctx=8192, # Try 16384 or 32768 in a separate experiment.
trim_history=False,
track_time=True,
)
print(agent.run("Remember this fact: my project is called Cedar."))
print(agent.run("What is my project called?"))
print(agent.last_result.usage)
trim_history=False disables all automatic history removal: the exchange-count
cap, token-budget trimming on GitHub, and client-side transport trimming.
max_history_turns is ignored in this mode. Completed exchanges stay on the agent
until you call reset() or discard the object; remember=False still disables
conversation memory entirely. This does not restore messages removed earlier.
The full retained history is passed to llama-cpp-python without our pre-generation
fit check. It does not enlarge n_ctx, bypass model ceilings or RAM checks, or
promise that the runtime accepts overflow. The runtime may reject an oversized
input or shorten generation to the remaining context. Use Agent.experimental()
or custom Limits to bypass the separate advertised-ceiling/resource policies.
Check the Actions job/logs
via agent.last_job.actions_url if a call fails. A failed call does not replace
the client's previously retained conversation or append its failed prompt.
GitHub's workflow-input transport limit still applies. When it is exceeded, the
call fails instead of dropping history, before starting a new worker. Setting a
32K context and sending 64K of messages therefore does not create 64K memory.
For controlled comparisons, start fresh agents with the same prompts, disable
refinement (the default), and vary n_ctx while keeping answer length fixed.
Standard policy limits prompt plus instructions to 60,000 characters, and the complete
workflow-input payload must fit GitHub's limit. Oversized jobs are rejected before
provisioning. These are separate transport limits, not token limits: a model
can allow 128K context while this version cannot transmit a full 128K-token prompt
or history through workflow inputs. With trim_history=True, history may be trimmed to satisfy transport
before it reaches the model. Workflow timeout and client completion wait default
to 30 minutes; both are editable as described above.
A client timeout does not automatically cancel a job; use agent.last_job when
you need to inspect or cancel it.
Tools, file access, Python callbacks, and shell execution are deliberately out of scope. This version is text in, text out.
Larger workers
The default client budget is 8 GB RAM and 14 GB workspace disk. GitHub lists 8 GB RAM for standard private Linux workers and 16 GB for public ones. See GitHub runner specifications.
from gh_ai_runner import Agent, GitHubAIRunner
runner = GitHubAIRunner(
runner_label="your-linux-32gb-runner",
runner_ram_gb=32,
runner_disk_gb=40,
)
agent = Agent(model="deepseek-coder16b", runner=runner)
print(agent.run("Explain this algorithm."))
The runner label must already be available to your repository; changing budgets
does not purchase hardware. To deliberately create a public standard runner,
configure a new repo_name, private=False, and runner_ram_gb=16. Existing
visibility is never changed automatically.
RAM/disk estimates are checked before dispatch and available resources are checked again on the worker. Large CPU models can be slow even when they fit.
Quantization shrinks weight storage, not the parameter count. Idealized 16B weights take 32 GB at 16 bits or 8 GB at 4 bits; actual Q4_K_M mixes precisions and includes scales/metadata. The catalog's 16B file is 10.36 GB. RAM also needs context/KV cache and computation buffers. See llama.cpp quantization.
Existing APIs
ai_call(token, prompt, ...) remains a blocking text-returning helper. Explicit
track_time=True returns an InferenceResult with .output and .timings.
GitHubAIRunner() also reads GH_AI_TOKEN automatically and retains submission,
batch/comparison, polling, cancellation, retry, resume, and hosted-provider APIs.
submit_batch() launches independent workflows; Agent.run_many() reuses one
worker/model. Only failed workflow conclusions are automatically retried when
requested by RetryPolicy, avoiding duplicate work after uncertain dispatches.
Privacy and verification
Prompts, history, and answers are sent to GitHub. Results are Actions artifacts, retained for three days. Public repository permissions and Actions logs matter. Checksums verify job identity, requests, output, and structured agent results; they are not signatures protecting against a compromised worker/repository.
Test/build CI runs on GitHub. The manual GitHub model smoke test workflow also downloads a real small model and checks that two prompts reuse it in RAM. Client orchestration tests use simulated API/model responses. No model runtime is installed by this package on the client.
MIT license. See LICENSE.
Metadata
Release files for gh-inference 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| gh_inference-0.6.0.tar.gz | 124.3 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gh_inference-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 189.2 kB
Release files / gh_inference-0.6.0.tar.gz
| Download URL | gh_inference-0.6.0.tar.gz |
|---|---|
| Size | 124.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fb94c92c7b00e76436988c047a5c0f63a97f6f07a47472045bc3a9e008663286
|
|
BLAKE2b-256 checksum How to use checksums |
f528df46b891ae7ef89cd12cc7fabaaa189290c73f0abe5ef46a6216676dfbd2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logRelease files / gh_inference-0.6.0-py3-none-any.whl
| Download URL | gh_inference-0.6.0-py3-none-any.whl |
|---|---|
| Size | 64.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8026a97d677259c22f846f95942bc090666d5cdc58cbd3c2d80380914654391b
|
|
BLAKE2b-256 checksum How to use checksums |
2f312534df522fa89bc0d9421a353667bfc3de461c5e5c240595f63c87e30f6b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logSecurity for gh-inference 0.6.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for gh_inference-0.6.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.