Text Generation
Transformers
Safetensors
gemma3_text
agent
tool-use
function-calling
on-device
beamcore
sft
trl
conversational
text-generation-inference
Instructions to use beamcore/tools with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use beamcore/tools with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="beamcore/tools") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# Load model directly from transformers import AutoTokenizer, AutoModelForMultimodalLM tokenizer = AutoTokenizer.from_pretrained("beamcore/tools") model = AutoModelForMultimodalLM.from_pretrained("beamcore/tools") messages = [ {"role": "user", "content": "Who are you?"}, ] inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use beamcore/tools with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "beamcore/tools" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "beamcore/tools", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/beamcore/tools
- SGLang
How to use beamcore/tools with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "beamcore/tools" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "beamcore/tools", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "beamcore/tools" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "beamcore/tools", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use beamcore/tools with Docker Model Runner:
docker model run hf.co/beamcore/tools
Upload tools model (git: 1ec0ff3)
Browse files- .gitattributes +1 -0
- README.md +115 -1
- chat_template.jinja +279 -0
- config.json +62 -0
- generation_config.json +15 -0
- model.safetensors +3 -0
- tokenizer.json +3 -0
- tokenizer_config.json +27 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -1,3 +1,117 @@
|
|
| 1 |
---
|
| 2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
base_model: google/functiongemma-270m-it
|
| 3 |
+
library_name: transformers
|
| 4 |
+
model_name: beamcore/tools
|
| 5 |
+
tags:
|
| 6 |
+
- agent
|
| 7 |
+
- tool-use
|
| 8 |
+
- function-calling
|
| 9 |
+
- on-device
|
| 10 |
+
- beamcore
|
| 11 |
+
- sft
|
| 12 |
+
- trl
|
| 13 |
+
license: gemma
|
| 14 |
---
|
| 15 |
+
|
| 16 |
+
# 🛠️ beamcore/tools
|
| 17 |
+
|
| 18 |
+
This is a highly optimized, lightweight (270M parameters) function-calling model fine-tuned on top of `google/functiongemma-270m-it`. It is specifically designed to run **on-device (locally)** as a pre-flight search and routing assistant for the Elixir-native [Beamcore agent harness](https://beamcore.dev).
|
| 19 |
+
|
| 20 |
+
## 🚀 Purpose & Workflow
|
| 21 |
+
|
| 22 |
+
In agentic software engineering workflows, sending large workspace structures, complete file contents, and extensive tool schemas to massive frontier models is slow, expensive, and leads to context pollution.
|
| 23 |
+
|
| 24 |
+
`beamcore/tools` solves this by running locally to perform **pre-flight search routing**:
|
| 25 |
+
1. **Analyze Intent**: When a user issues a request, `beamcore/tools` determines whether search/traversal tools are needed to gather codebase context.
|
| 26 |
+
2. **Execute Tools**: If context is missing, it emits structured tool calls (e.g., `glob`, `grep`, `tree`, `read`) to fetch local file structures or code.
|
| 27 |
+
3. **Minimize Tokens**: If no tools are required (or after search tools run and collect the necessary files), the main reasoning model is invoked with a minimal, relevant context, drastically reducing token overhead and billing.
|
| 28 |
+
|
| 29 |
+
```mermaid
|
| 30 |
+
graph TD
|
| 31 |
+
User([User Request]) --> Helper[beamcore/tools (Local 270M)]
|
| 32 |
+
Helper -->|Needs Context?| ToolCall{Tool Call?}
|
| 33 |
+
ToolCall -->|Yes| Exec[Execute Local Tool]
|
| 34 |
+
Exec --> Read[Read/Grep/Glob Result]
|
| 35 |
+
Read --> Main[Main Beamcore Agent]
|
| 36 |
+
ToolCall -->|No / Finished| Main
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
## 🛠️ Supported Tools
|
| 40 |
+
|
| 41 |
+
The model is fine-tuned to work with the following four workspace-inspection tools:
|
| 42 |
+
|
| 43 |
+
### 1. `glob`
|
| 44 |
+
Find workspace files matching a glob pattern relative to a path.
|
| 45 |
+
- **Parameters**: `pattern` (string, required), `path` (string, optional), `all` (boolean, optional).
|
| 46 |
+
- **Example**: `{"pattern": "**/*.ex"}`
|
| 47 |
+
|
| 48 |
+
### 2. `grep`
|
| 49 |
+
Search workspace file contents by regex with optional includes.
|
| 50 |
+
- **Parameters**: `pattern` (string, required), `path` (string, optional), `include` (string, optional), `all` (boolean, optional).
|
| 51 |
+
- **Example**: `{"pattern": "defmodule", "include": "*.ex"}`
|
| 52 |
+
|
| 53 |
+
### 3. `tree`
|
| 54 |
+
Show a compact workspace directory tree with sizes.
|
| 55 |
+
- **Parameters**: `path` (string, optional).
|
| 56 |
+
- **Example**: `{"path": "lib/"}`
|
| 57 |
+
|
| 58 |
+
### 4. `read`
|
| 59 |
+
Read a workspace-relative file or directory with offset/limit parameters.
|
| 60 |
+
- **Parameters**: `filePath` (string, required), `offset` (integer, optional), `limit` (integer, optional).
|
| 61 |
+
- **Example**: `{"filePath": "lib/beamcore.ex", "limit": 100}`
|
| 62 |
+
|
| 63 |
+
---
|
| 64 |
+
|
| 65 |
+
## 💻 Quickstart (Inference)
|
| 66 |
+
|
| 67 |
+
You can run `beamcore/tools` locally using `transformers`:
|
| 68 |
+
|
| 69 |
+
```python
|
| 70 |
+
import json
|
| 71 |
+
from transformers import AutoTokenizer, AutoModelForCausalLM
|
| 72 |
+
from transformers.utils import get_json_schema
|
| 73 |
+
|
| 74 |
+
# Define tool signatures (converted to JSON Schema)
|
| 75 |
+
def glob(pattern: str, path: str = None, all: bool = False): pass
|
| 76 |
+
def grep(pattern: str, path: str = None, include: str = None, all: bool = False): pass
|
| 77 |
+
def tree(path: str = None): pass
|
| 78 |
+
def read(filePath: str, offset: int = 1, limit: int = 200): pass
|
| 79 |
+
|
| 80 |
+
tools = [
|
| 81 |
+
get_json_schema(glob),
|
| 82 |
+
get_json_schema(grep),
|
| 83 |
+
get_json_schema(tree),
|
| 84 |
+
get_json_schema(read)
|
| 85 |
+
]
|
| 86 |
+
|
| 87 |
+
# Load model and tokenizer
|
| 88 |
+
model_id = "beamcore/tools"
|
| 89 |
+
model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto")
|
| 90 |
+
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
| 91 |
+
|
| 92 |
+
# System prompt
|
| 93 |
+
system_msg = "You are a pre-flight search assistant for a coding agent. Your ONLY job is to analyze the user request and determine if search or directory traversal tools are needed to find relevant code or files before the main coding agent answers."
|
| 94 |
+
|
| 95 |
+
messages = [
|
| 96 |
+
{"role": "developer", "content": system_msg},
|
| 97 |
+
{"role": "user", "content": "Find all Elixir source files in the project lib/ directory"}
|
| 98 |
+
]
|
| 99 |
+
|
| 100 |
+
# Format chat using tools
|
| 101 |
+
inputs = tokenizer.apply_chat_template(messages, tools=tools, return_tensors="pt").to(model.device)
|
| 102 |
+
outputs = model.generate(inputs, max_new_tokens=256)
|
| 103 |
+
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
## 📈 Training Details
|
| 107 |
+
|
| 108 |
+
- **Base Model**: `google/functiongemma-270m-it`
|
| 109 |
+
- **Training Method**: Supervised Fine-Tuning (SFT) using TRL
|
| 110 |
+
- **Dataset**: Custom search routing examples representing diverse developer queries (directory tree traversal, pattern matching, file reads, and conversational non-search queries).
|
| 111 |
+
|
| 112 |
+
### Framework Versions
|
| 113 |
+
- TRL: 1.5.1
|
| 114 |
+
- Transformers: 5.10.2
|
| 115 |
+
- Pytorch: 2.12.0
|
| 116 |
+
- Datasets: 5.0.0
|
| 117 |
+
- Tokenizers: 0.22.2
|
chat_template.jinja
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{%- macro format_parameters(properties, required) -%}
|
| 2 |
+
{%- set standard_keys = ['description', 'type', 'properties', 'required', 'nullable'] -%}
|
| 3 |
+
{%- set ns = namespace(found_first=false) -%}
|
| 4 |
+
{%- for key, value in properties | dictsort -%}
|
| 5 |
+
{%- if key not in standard_keys -%}
|
| 6 |
+
{%- if ns.found_first %},{% endif -%}
|
| 7 |
+
{%- set ns.found_first = true -%}
|
| 8 |
+
{{- key }}:{description:<escape>{{ value['description'] }}<escape>
|
| 9 |
+
{%- if value['type'] | upper == 'STRING' -%}
|
| 10 |
+
{%- if value['enum'] -%}
|
| 11 |
+
,enum:{{ format_argument(value['enum']) }}
|
| 12 |
+
{%- endif -%}
|
| 13 |
+
{%- elif value['type'] | upper == 'OBJECT' -%}
|
| 14 |
+
,properties:{
|
| 15 |
+
{%- if value['properties'] is defined and value['properties'] is mapping -%}
|
| 16 |
+
{{- format_parameters(value['properties'], value['required'] | default([])) -}}
|
| 17 |
+
{%- elif value is mapping -%}
|
| 18 |
+
{{- format_parameters(value, value['required'] | default([])) -}}
|
| 19 |
+
{%- endif -%}
|
| 20 |
+
}
|
| 21 |
+
{%- if value['required'] -%}
|
| 22 |
+
,required:[
|
| 23 |
+
{%- for item in value['required'] | default([]) -%}
|
| 24 |
+
<escape>{{- item -}}<escape>
|
| 25 |
+
{%- if not loop.last %},{% endif -%}
|
| 26 |
+
{%- endfor -%}
|
| 27 |
+
]
|
| 28 |
+
{%- endif -%}
|
| 29 |
+
{%- elif value['type'] | upper == 'ARRAY' -%}
|
| 30 |
+
{%- if value['items'] is mapping and value['items'] -%}
|
| 31 |
+
,items:{
|
| 32 |
+
{%- set ns_items = namespace(found_first=false) -%}
|
| 33 |
+
{%- for item_key, item_value in value['items'] | dictsort -%}
|
| 34 |
+
{%- if item_value is not none -%}
|
| 35 |
+
{%- if ns_items.found_first %},{% endif -%}
|
| 36 |
+
{%- set ns_items.found_first = true -%}
|
| 37 |
+
{%- if item_key == 'properties' -%}
|
| 38 |
+
properties:{
|
| 39 |
+
{%- if item_value is mapping -%}
|
| 40 |
+
{{- format_parameters(item_value, value['items']['required'] | default([])) -}}
|
| 41 |
+
{%- endif -%}
|
| 42 |
+
}
|
| 43 |
+
{%- elif item_key == 'required' -%}
|
| 44 |
+
required:[
|
| 45 |
+
{%- for req_item in item_value -%}
|
| 46 |
+
<escape>{{- req_item -}}<escape>
|
| 47 |
+
{%- if not loop.last %},{% endif -%}
|
| 48 |
+
{%- endfor -%}
|
| 49 |
+
]
|
| 50 |
+
{%- elif item_key == 'type' -%}
|
| 51 |
+
{%- if item_value is string -%}
|
| 52 |
+
type:{{ format_argument(item_value | upper) }}
|
| 53 |
+
{%- else -%}
|
| 54 |
+
type:{{ format_argument(item_value | map('upper') | list) }}
|
| 55 |
+
{%- endif -%}
|
| 56 |
+
{%- else -%}
|
| 57 |
+
{{ item_key }}:{{ format_argument(item_value) }}
|
| 58 |
+
{%- endif -%}
|
| 59 |
+
{%- endif -%}
|
| 60 |
+
{%- endfor -%}
|
| 61 |
+
}
|
| 62 |
+
{%- endif -%}
|
| 63 |
+
{%- endif -%}
|
| 64 |
+
,type:<escape>{{ value['type'] | upper }}<escape>}
|
| 65 |
+
{%- endif -%}
|
| 66 |
+
{%- endfor -%}
|
| 67 |
+
{%- endmacro -%}
|
| 68 |
+
{% macro format_function_declaration(tool_data) -%}
|
| 69 |
+
declaration:{{- tool_data['function']['name'] -}}
|
| 70 |
+
{description:<escape>{{- tool_data['function']['description'] -}}<escape>
|
| 71 |
+
{%- set params = tool_data['function']['parameters'] -%}
|
| 72 |
+
{%- if params -%}
|
| 73 |
+
,parameters:{
|
| 74 |
+
{%- if params['properties'] -%}
|
| 75 |
+
properties:{ {{- format_parameters(params['properties'], params['required']) -}} },
|
| 76 |
+
{%- endif -%}
|
| 77 |
+
{%- if params['required'] -%}
|
| 78 |
+
required:[
|
| 79 |
+
{%- for item in params['required'] -%}
|
| 80 |
+
<escape>{{- item -}}<escape>
|
| 81 |
+
{{- ',' if not loop.last -}}
|
| 82 |
+
{%- endfor -%}
|
| 83 |
+
],
|
| 84 |
+
{%- endif -%}
|
| 85 |
+
{%- if params['type'] -%}
|
| 86 |
+
type:<escape>{{- params['type'] | upper -}}<escape>}
|
| 87 |
+
{%- endif -%}
|
| 88 |
+
{%- endif -%}
|
| 89 |
+
}
|
| 90 |
+
{%- endmacro -%}
|
| 91 |
+
{% macro format_argument(argument, escape_keys=True) -%}
|
| 92 |
+
{%- if argument is string -%}
|
| 93 |
+
{{- '<escape>' + argument + '<escape>' -}}
|
| 94 |
+
{%- elif argument is boolean -%}
|
| 95 |
+
{%- if argument -%}
|
| 96 |
+
{{- 'true' -}}
|
| 97 |
+
{%- else -%}
|
| 98 |
+
{{- 'false' -}}
|
| 99 |
+
{%- endif -%}
|
| 100 |
+
{%- elif argument is mapping -%}
|
| 101 |
+
{{- '{' -}}
|
| 102 |
+
{%- set ns = namespace(found_first=false) -%}
|
| 103 |
+
{%- for key, value in argument | dictsort -%}
|
| 104 |
+
{%- if ns.found_first %},{% endif -%}
|
| 105 |
+
{%- set ns.found_first = true -%}
|
| 106 |
+
{%- if escape_keys -%}
|
| 107 |
+
{{- '<escape>' + key + '<escape>' -}}
|
| 108 |
+
{%- else -%}
|
| 109 |
+
{{- key -}}
|
| 110 |
+
{%- endif -%}
|
| 111 |
+
:{{- format_argument(value, escape_keys=escape_keys) -}}
|
| 112 |
+
{%- endfor -%}
|
| 113 |
+
{{- '}' -}}
|
| 114 |
+
{%- elif argument is sequence -%}
|
| 115 |
+
{{- '[' -}}
|
| 116 |
+
{%- for item in argument -%}
|
| 117 |
+
{{- format_argument(item, escape_keys=escape_keys) -}}
|
| 118 |
+
{%- if not loop.last %},{% endif -%}
|
| 119 |
+
{%- endfor -%}
|
| 120 |
+
{{- ']' -}}
|
| 121 |
+
{%- else -%}
|
| 122 |
+
{{- argument -}}
|
| 123 |
+
{%- endif -%}
|
| 124 |
+
{%- endmacro -%}
|
| 125 |
+
{{ bos_token }}
|
| 126 |
+
{%- set ns = namespace(prev_message_type=None) -%}
|
| 127 |
+
{#- Tool Declarations -#}
|
| 128 |
+
{%- set loop_messages = messages -%}
|
| 129 |
+
{%- if tools or messages[0]['role'] == 'system' or messages[0]['role'] == 'developer' -%}
|
| 130 |
+
{{- '<start_of_turn>developer\n' -}}
|
| 131 |
+
{%- if messages[0]['role'] == 'system' or messages[0]['role'] == 'developer' -%}
|
| 132 |
+
{%- if messages[0]['content'] is string -%}
|
| 133 |
+
{{- messages[0]['content'] | trim -}}
|
| 134 |
+
{%- elif messages[0]['content'] is sequence -%}
|
| 135 |
+
{%- for item in messages[0]['content'] -%}
|
| 136 |
+
{%- if item['type'] == 'text' -%}
|
| 137 |
+
{{- item['text'] | trim -}}
|
| 138 |
+
{%- endif -%}
|
| 139 |
+
{%- endfor -%}
|
| 140 |
+
{%- endif -%}
|
| 141 |
+
{%- set loop_messages = messages[1:] -%}
|
| 142 |
+
{%- endif -%}
|
| 143 |
+
{%- if tools -%}
|
| 144 |
+
{%- for tool in tools %}
|
| 145 |
+
{{- '<start_function_declaration>' -}}
|
| 146 |
+
{{- format_function_declaration(tool) | trim }}
|
| 147 |
+
{{- '<end_function_declaration>' -}}
|
| 148 |
+
{%- endfor %}
|
| 149 |
+
{%- endif -%}
|
| 150 |
+
{{- '<end_of_turn>\n' }}
|
| 151 |
+
{%- endif %}
|
| 152 |
+
{#- Loop through messages. -#}
|
| 153 |
+
{%- for message in loop_messages -%}
|
| 154 |
+
{%- if (message['role'] == 'assistant') -%}
|
| 155 |
+
{#- Rename "assistant" to "model". -#}
|
| 156 |
+
{%- set role = "model" -%}
|
| 157 |
+
{%- else -%}
|
| 158 |
+
{%- set role = message['role'] -%}
|
| 159 |
+
{%- endif -%}
|
| 160 |
+
{%- if role != 'tool' -%}
|
| 161 |
+
{%- if ns.prev_message_type != 'tool_response' -%}
|
| 162 |
+
{{- '<start_of_turn>' + role + '\n' }}
|
| 163 |
+
{%- endif -%}
|
| 164 |
+
{%- set ns.prev_message_type = None -%}
|
| 165 |
+
{%- if 'content' in message and message['content'] is not none -%}
|
| 166 |
+
{%- if message['content'] is string -%}
|
| 167 |
+
{{ message['content'] | trim }}
|
| 168 |
+
{%- elif message['content'] is sequence -%}
|
| 169 |
+
{%- for item in message['content'] -%}
|
| 170 |
+
{%- if item['type'] == 'image' -%}
|
| 171 |
+
{{ '<start_of_image>' }}
|
| 172 |
+
{%- elif item['type'] == 'text' -%}
|
| 173 |
+
{{ item['text'] | trim }}
|
| 174 |
+
{%- endif -%}
|
| 175 |
+
{%- endfor -%}
|
| 176 |
+
{%- else -%}
|
| 177 |
+
{{ raise_exception("Invalid content type in user/assistant message") }}
|
| 178 |
+
{%- endif -%}
|
| 179 |
+
{%- set ns.prev_message_type = 'content' -%}
|
| 180 |
+
{%- endif -%}
|
| 181 |
+
{%- if 'tool_calls' in message and message['tool_calls'] and message['tool_calls'] is iterable -%}
|
| 182 |
+
{#- Tool Calls -#}
|
| 183 |
+
{%- for tool_call in message['tool_calls'] -%}
|
| 184 |
+
{% set function = tool_call['function'] %}
|
| 185 |
+
{{- '<start_function_call>call:' + function['name'] + '{' -}}
|
| 186 |
+
{%- if 'arguments' in function -%}
|
| 187 |
+
{%- if function['arguments'] is mapping -%}
|
| 188 |
+
{%- set ns = namespace(found_first=false) -%}
|
| 189 |
+
{%- for key, value in function['arguments'] | dictsort -%}
|
| 190 |
+
{%- if ns.found_first %},{% endif -%}
|
| 191 |
+
{%- set ns.found_first = true -%}
|
| 192 |
+
{{- key -}}:{{- format_argument(value, escape_keys=False) -}}
|
| 193 |
+
{%- endfor -%}
|
| 194 |
+
{%- elif function['arguments'] is string -%}
|
| 195 |
+
{# This handles string-JSON, just in case #}
|
| 196 |
+
{{ function['arguments'] }}
|
| 197 |
+
{%- endif %}
|
| 198 |
+
{%- endif -%}
|
| 199 |
+
{{- '}<end_function_call>' -}}
|
| 200 |
+
{%- endfor -%}
|
| 201 |
+
{%- if loop.last -%}
|
| 202 |
+
{{ '<start_function_response>' }}
|
| 203 |
+
{%- endif -%}
|
| 204 |
+
{%- set ns.prev_message_type = 'tool_call' -%}
|
| 205 |
+
{%- endif -%}
|
| 206 |
+
{%- else -%}
|
| 207 |
+
{#- Tool Responses -#}
|
| 208 |
+
{%- if 'content' in message and message['content'] -%}
|
| 209 |
+
{%- if message['content'] is mapping -%}
|
| 210 |
+
{%- if 'name' in message['content'] and 'response' in message['content'] -%}
|
| 211 |
+
{{ '<start_function_response>response:' + message['content']['name'] | trim + '{' }}
|
| 212 |
+
{%- set response_ns = namespace(found_first=false) -%}
|
| 213 |
+
{%- for key, value in message['content']['response'] | dictsort -%}
|
| 214 |
+
{%- if response_ns.found_first %},{% endif -%}
|
| 215 |
+
{%- set response_ns.found_first = true -%}
|
| 216 |
+
{{- key -}}:{{- format_argument(value, escape_keys=False) -}}
|
| 217 |
+
{%- endfor -%}
|
| 218 |
+
{{- '}<end_function_response>' -}}
|
| 219 |
+
{%- elif 'name' in message -%}
|
| 220 |
+
{{ '<start_function_response>response:' + message['name'] | trim + '{' }}
|
| 221 |
+
{%- set response_ns = namespace(found_first=false) -%}
|
| 222 |
+
{%- for key, value in message['content'] | dictsort -%}
|
| 223 |
+
{%- if response_ns.found_first %},{% endif -%}
|
| 224 |
+
{%- set response_ns.found_first = true -%}
|
| 225 |
+
{{- key -}}:{{- format_argument(value, escape_keys=False) -}}
|
| 226 |
+
{%- endfor -%}
|
| 227 |
+
{{- '}<end_function_response>' -}}
|
| 228 |
+
{%- else -%}
|
| 229 |
+
{{ raise_exception("Invalid tool response mapping: must contain 'name' and 'response' keys, or 'name' must be in the message.") }}
|
| 230 |
+
{%- endif -%}
|
| 231 |
+
{%- elif message['content'] is string -%}
|
| 232 |
+
{%- if 'name' in message -%}
|
| 233 |
+
{{ '<start_function_response>response:' + message['name'] | trim + '{value:' + format_argument(message['content'], escape_keys=False) + '}<end_function_response>' }}
|
| 234 |
+
{%- else -%}
|
| 235 |
+
{{ raise_exception("Invalid tool response: 'name' must be provided.") }}
|
| 236 |
+
{%- endif -%}
|
| 237 |
+
{%- elif message['content'] is sequence -%}
|
| 238 |
+
{%- for item in message['content'] -%}
|
| 239 |
+
{%- if item is mapping -%}
|
| 240 |
+
{%- if 'name' in item and 'response' in item -%}
|
| 241 |
+
{{ '<start_function_response>response:' + item['name'] | trim + '{' }}
|
| 242 |
+
{%- set response_ns = namespace(found_first=false) -%}
|
| 243 |
+
{%- for key, value in item['response'] | dictsort -%}
|
| 244 |
+
{%- if response_ns.found_first %},{% endif -%}
|
| 245 |
+
{%- set response_ns.found_first = true -%}
|
| 246 |
+
{{- key -}}:{{- format_argument(value, escape_keys=False) -}}
|
| 247 |
+
{%- endfor -%}
|
| 248 |
+
{{- '}<end_function_response>' -}}
|
| 249 |
+
{%- elif 'name' in message -%}
|
| 250 |
+
{{ '<start_function_response>response:' + message['name'] | trim + '{' }}
|
| 251 |
+
{%- set response_ns = namespace(found_first=false) -%}
|
| 252 |
+
{%- for key, value in item | dictsort -%}
|
| 253 |
+
{%- if response_ns.found_first %},{% endif -%}
|
| 254 |
+
{%- set response_ns.found_first = true -%}
|
| 255 |
+
{{- key -}}:{{- format_argument(value, escape_keys=False) -}}
|
| 256 |
+
{%- endfor -%}
|
| 257 |
+
{{- '}<end_function_response>' -}}
|
| 258 |
+
{%- else -%}
|
| 259 |
+
{{ raise_exception("Invalid tool response mapping: must contain 'name' and 'response' keys, or 'name' must be in the message.") }}
|
| 260 |
+
{%- endif -%}
|
| 261 |
+
{%- else -%}
|
| 262 |
+
{{ raise_exception("Invalid tool response message: multiple responses must all be mappings") }}
|
| 263 |
+
{%- endif -%}
|
| 264 |
+
{%- endfor -%}
|
| 265 |
+
{%- else -%}
|
| 266 |
+
{{ raise_exception("Invalid content type in tool message: must be mapping, sequence of mappings, or string.") }}
|
| 267 |
+
{%- endif -%}
|
| 268 |
+
{%- endif -%}
|
| 269 |
+
{%- set ns.prev_message_type = 'tool_response' -%}
|
| 270 |
+
{%- endif -%}
|
| 271 |
+
{%- if ns.prev_message_type not in ['tool_call', 'tool_response'] -%}
|
| 272 |
+
{{ '<end_of_turn>\n' }}
|
| 273 |
+
{%- endif -%}
|
| 274 |
+
{%- endfor -%}
|
| 275 |
+
{%- if add_generation_prompt -%}
|
| 276 |
+
{%- if ns.prev_message_type != 'tool_response' -%}
|
| 277 |
+
{{- '<start_of_turn>model\n' -}}
|
| 278 |
+
{%- endif -%}
|
| 279 |
+
{%- endif -%}
|
config.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_sliding_window_pattern": 6,
|
| 3 |
+
"architectures": [
|
| 4 |
+
"Gemma3ForCausalLM"
|
| 5 |
+
],
|
| 6 |
+
"attention_bias": false,
|
| 7 |
+
"attention_dropout": 0.0,
|
| 8 |
+
"attn_logit_softcapping": null,
|
| 9 |
+
"bos_token_id": 2,
|
| 10 |
+
"dtype": "bfloat16",
|
| 11 |
+
"eos_token_id": 1,
|
| 12 |
+
"final_logit_softcapping": null,
|
| 13 |
+
"head_dim": 256,
|
| 14 |
+
"hidden_activation": "gelu_pytorch_tanh",
|
| 15 |
+
"hidden_size": 640,
|
| 16 |
+
"initializer_range": 0.02,
|
| 17 |
+
"intermediate_size": 2048,
|
| 18 |
+
"layer_types": [
|
| 19 |
+
"sliding_attention",
|
| 20 |
+
"sliding_attention",
|
| 21 |
+
"sliding_attention",
|
| 22 |
+
"sliding_attention",
|
| 23 |
+
"sliding_attention",
|
| 24 |
+
"full_attention",
|
| 25 |
+
"sliding_attention",
|
| 26 |
+
"sliding_attention",
|
| 27 |
+
"sliding_attention",
|
| 28 |
+
"sliding_attention",
|
| 29 |
+
"sliding_attention",
|
| 30 |
+
"full_attention",
|
| 31 |
+
"sliding_attention",
|
| 32 |
+
"sliding_attention",
|
| 33 |
+
"sliding_attention",
|
| 34 |
+
"sliding_attention",
|
| 35 |
+
"sliding_attention",
|
| 36 |
+
"full_attention"
|
| 37 |
+
],
|
| 38 |
+
"max_position_embeddings": 32768,
|
| 39 |
+
"model_type": "gemma3_text",
|
| 40 |
+
"num_attention_heads": 4,
|
| 41 |
+
"num_hidden_layers": 18,
|
| 42 |
+
"num_key_value_heads": 1,
|
| 43 |
+
"pad_token_id": 0,
|
| 44 |
+
"query_pre_attn_scalar": 256,
|
| 45 |
+
"rms_norm_eps": 1e-06,
|
| 46 |
+
"rope_parameters": {
|
| 47 |
+
"full_attention": {
|
| 48 |
+
"rope_theta": 1000000.0,
|
| 49 |
+
"rope_type": "default"
|
| 50 |
+
},
|
| 51 |
+
"sliding_attention": {
|
| 52 |
+
"rope_theta": 10000.0,
|
| 53 |
+
"rope_type": "default"
|
| 54 |
+
}
|
| 55 |
+
},
|
| 56 |
+
"sliding_window": 512,
|
| 57 |
+
"tie_word_embeddings": true,
|
| 58 |
+
"transformers_version": "5.10.2",
|
| 59 |
+
"use_bidirectional_attention": false,
|
| 60 |
+
"use_cache": false,
|
| 61 |
+
"vocab_size": 262144
|
| 62 |
+
}
|
generation_config.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"bos_token_id": 2,
|
| 3 |
+
"cache_implementation": "hybrid",
|
| 4 |
+
"do_sample": true,
|
| 5 |
+
"eos_token_id": [
|
| 6 |
+
1,
|
| 7 |
+
1,
|
| 8 |
+
50,
|
| 9 |
+
106
|
| 10 |
+
],
|
| 11 |
+
"pad_token_id": 0,
|
| 12 |
+
"top_k": 64,
|
| 13 |
+
"top_p": 0.95,
|
| 14 |
+
"transformers_version": "5.10.2"
|
| 15 |
+
}
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:0970a77b160df827b6785fae49a97f304622c8ff0d5f9cb2b9009f3f4b8d1b4d
|
| 3 |
+
size 536223056
|
tokenizer.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:80d7f800b949accd7eb940bac75e642f9468e4df157403032a55bf54ed23b650
|
| 3 |
+
size 33384898
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"backend": "tokenizers",
|
| 3 |
+
"boi_token": "<start_of_image>",
|
| 4 |
+
"bos_token": "<bos>",
|
| 5 |
+
"clean_up_tokenization_spaces": false,
|
| 6 |
+
"eoi_token": "<end_of_image>",
|
| 7 |
+
"eos_token": "<eos>",
|
| 8 |
+
"image_token": "<image_soft_token>",
|
| 9 |
+
"is_local": false,
|
| 10 |
+
"local_files_only": false,
|
| 11 |
+
"mask_token": "<mask>",
|
| 12 |
+
"model_max_length": 1000000000000000019884624838656,
|
| 13 |
+
"model_specific_special_tokens": {
|
| 14 |
+
"boi_token": "<start_of_image>",
|
| 15 |
+
"eoi_token": "<end_of_image>",
|
| 16 |
+
"image_token": "<image_soft_token>",
|
| 17 |
+
"sfr_token": "<start_function_response>"
|
| 18 |
+
},
|
| 19 |
+
"pad_token": "<pad>",
|
| 20 |
+
"padding_side": "left",
|
| 21 |
+
"sfr_token": "<start_function_response>",
|
| 22 |
+
"sp_model_kwargs": null,
|
| 23 |
+
"spaces_between_special_tokens": false,
|
| 24 |
+
"tokenizer_class": "GemmaTokenizer",
|
| 25 |
+
"unk_token": "<unk>",
|
| 26 |
+
"use_default_system_prompt": false
|
| 27 |
+
}
|