Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ jobs:
with:
persist-credentials: false
repository: RunanywhereAI/runanywhere-sdks
ref: e595580a72452595a4a5b8abc137cad10132ba75
ref: 8e3d147f4dea7609d48ff5bb7c75edb234051853
path: .deps/runanywhere-sdks
- name: Install ninja
run: brew install ninja
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ jobs:
with:
persist-credentials: false
repository: RunanywhereAI/runanywhere-sdks
ref: e595580a72452595a4a5b8abc137cad10132ba75
ref: 8e3d147f4dea7609d48ff5bb7c75edb234051853
path: .deps/runanywhere-sdks
- name: Install ninja
run: brew install ninja
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[package]
name = "wally"
# Must equal [product] version in versions.toml (scripts/ci/check-versions.py).
version = "0.8.11"
version = "0.8.12"
edition = "2021"
rust-version = "1.93"
license = "Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion Formula/wally-beta.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class WallyBeta < Formula
desc "Run language, speech and image models on your own machine (beta)"
desc "Run models on your machine or your RunAnywhere account (beta)"
homepage "https://github.com/RunanywhereAI/wally"
url "https://github.com/RunanywhereAI/wally/releases/download/v0.4.0-beta.1/wally-0.4.0-beta.1-Darwin-arm64.tar.gz"
sha256 "0000000000000000000000000000000000000000000000000000000000000000"
Expand Down
8 changes: 4 additions & 4 deletions Formula/wally.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# frozen_string_literal: true

class Wally < Formula
desc "Run language, speech and image models on your own machine"
desc "Run models on your machine or your RunAnywhere account"
homepage "https://github.com/RunanywhereAI/wally"
version "0.8.11"
version "0.8.12"
license "MIT"

# macOS arm64 ships the Swift MLX host
# (llama.cpp + ONNX + Sherpa + MLX). Linux is not in this cut.
on_macos do
on_arm do
url "https://github.com/RunanywhereAI/wally/releases/download/v0.8.11/wally-0.8.11-macos-arm64.tar.gz"
# Placeholder -- the v0.8.11 release has not published a wally-named asset
url "https://github.com/RunanywhereAI/wally/releases/download/v0.8.12/wally-0.8.12-macos-arm64.tar.gz"
# Placeholder -- the v0.8.12 release has not published a wally-named asset
# yet. scripts/release/update-tap.sh re-stamps this from the real release
# checksum; a stale value here fails brew install's own hash check
# rather than installing something unverified.
Expand Down
50 changes: 50 additions & 0 deletions scripts/test/e2e-modalities.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
# 4. `wally models list --json` downloaded rows whose modality matches
# 5. If WALLY_E2E_AUTO=1, small OSS catalog defaults the binary can run
#
# Decisions are opt-in by id only (they are a verb, not a discoverable
# modality): WALLY_E2E_DECISION scores text; WALLY_E2E_DECISION_IMAGE names a
# decision model that takes images and also exercises the local controls.
# A text-only WALLY_E2E_DECISION must refuse an image request.
#
# Skip = no model. Fail = a model was selected and the command failed.
# Public CI leaves every knob unset and stays green.
#
Expand Down Expand Up @@ -458,5 +463,50 @@ else
skipm "diarize (set WALLY_E2E_DIARIZE)"
fi

# A refusal is the expected outcome: the command must fail, and say why.
expect_refusal() {
local label="$1"
local needle="$2"
shift 2
set +e
"$@" >/dev/null 2>"${workdir}/err"
local rc=$?
set -e
if [[ "${rc}" -ne 0 ]] && grep -q "${needle}" "${workdir}/err"; then
ok "${label}"
else
bad "${label} (rc ${rc}; wanted a refusal naming '${needle}')"
fi
}

decision_questions=(--input "A customer reports every API call returns 401 since a key rotation."
--ask "Is this an authentication problem?" --choice "Team?=support,billing,sales")

if [[ -n "${WALLY_E2E_DECISION:-}" ]]; then
run_cmd "decision ${WALLY_E2E_DECISION}" \
"${WALLY}" decisions --local -m "${WALLY_E2E_DECISION}" "${decision_questions[@]}"
if [[ -s "${png}" && "${WALLY_E2E_DECISION}" != "${WALLY_E2E_DECISION_IMAGE:-}" ]]; then
expect_refusal "decision ${WALLY_E2E_DECISION} refuses an image" "images" \
"${WALLY}" decisions --local -m "${WALLY_E2E_DECISION}" --image "${png}" \
"${decision_questions[@]}"
fi
else
skipm "decision (set WALLY_E2E_DECISION to a local decision model id)"
fi

if [[ -n "${WALLY_E2E_DECISION_IMAGE:-}" && -s "${png}" ]]; then
run_cmd "decision+image ${WALLY_E2E_DECISION_IMAGE}" \
"${WALLY}" decisions --local -m "${WALLY_E2E_DECISION_IMAGE}" --image "${png}" \
--input "What colour is the picture?" --choice "Colour?=red,green,blue"
run_cmd "decision controls ${WALLY_E2E_DECISION_IMAGE}" \
"${WALLY}" decisions --local -m "${WALLY_E2E_DECISION_IMAGE}" --image "${png}" \
--grouping joint --max-pixels 200000 --max-length 8192 "${decision_questions[@]}"
expect_refusal "decision ${WALLY_E2E_DECISION_IMAGE} refuses an over-length question" "limit" \
"${WALLY}" decisions --local -m "${WALLY_E2E_DECISION_IMAGE}" --max-length 16 \
"${decision_questions[@]}"
else
skipm "decision+image (set WALLY_E2E_DECISION_IMAGE to a decision model that takes images)"
fi

echo "modalities: ${pass} passed, ${fail} failed, ${skip} skipped"
exit "${fail}"
5 changes: 4 additions & 1 deletion src/anthropic/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,10 @@ fn tools_to_openai(tools: &Value) -> Value {
}
let mut function = serde_json::Map::new();
function.insert("name".into(), json!(field(tool, "name")));
function.insert("parameters".into(), tool["input_schema"].clone());
function.insert(
"parameters".into(),
crate::util::tool_schema::without_null_fields(&tool["input_schema"]),
);
if let Some(desc) = tool.get("description").filter(|d| d.is_string()) {
function.insert("description".into(), desc.clone());
}
Expand Down
100 changes: 100 additions & 0 deletions src/catalog/catalog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2602,6 +2602,89 @@ const CLEF_27B_GGUF_FILES: &[CatalogFile] = &[CatalogFile {
checksum_sha256: None,
}];

/// `perplexity-ai/pplx-decider-flash-v1.2` (BF16, Apache-2.0) mirrored at commit 6d771ad7b5ec into
/// runanywhere/decision-models-stable-fork, pinned to the upload commit.
/// Loads as is: no conversion, the readout and both protocol configs ride beside the shards.
const PPLX_DECIDER_4B_MLX_FILES: &[CatalogFile] = &[
CatalogFile {
url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/bee2a09a0f7708ac40342b74a221a40e06fd870a/mlx/pplx-decider-4b/chat_template.jinja",
filename: "chat_template.jinja",
required: true,
size_bytes: 7756,
checksum_sha256: None,
},
CatalogFile {
url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/bee2a09a0f7708ac40342b74a221a40e06fd870a/mlx/pplx-decider-4b/config.json",
filename: "config.json",
required: true,
size_bytes: 2898,
checksum_sha256: None,
},
CatalogFile {
url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/bee2a09a0f7708ac40342b74a221a40e06fd870a/mlx/pplx-decider-4b/decision_config.json",
filename: "decision_config.json",
required: true,
size_bytes: 5435,
checksum_sha256: None,
},
CatalogFile {
url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/bee2a09a0f7708ac40342b74a221a40e06fd870a/mlx/pplx-decider-4b/joint_config.json",
filename: "joint_config.json",
required: true,
size_bytes: 248,
checksum_sha256: None,
},
CatalogFile {
url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/bee2a09a0f7708ac40342b74a221a40e06fd870a/mlx/pplx-decider-4b/model-00001-of-00002.safetensors",
filename: "model-00001-of-00002.safetensors",
required: true,
size_bytes: 4972946624,
checksum_sha256: Some("1c1a0c1ab331c7aec1b4b7932eabf80593b56c694fe2b779209c0e0413df1cef"),
},
CatalogFile {
url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/bee2a09a0f7708ac40342b74a221a40e06fd870a/mlx/pplx-decider-4b/model-00002-of-00002.safetensors",
filename: "model-00002-of-00002.safetensors",
required: true,
size_bytes: 4105669472,
checksum_sha256: Some("21ba8301660e066f5849b60b1a36a242fc54ca18dd9bd526fdcbc50889171b70"),
},
CatalogFile {
url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/bee2a09a0f7708ac40342b74a221a40e06fd870a/mlx/pplx-decider-4b/model.safetensors.index.json",
filename: "model.safetensors.index.json",
required: true,
size_bytes: 61898,
checksum_sha256: None,
},
CatalogFile {
url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/bee2a09a0f7708ac40342b74a221a40e06fd870a/mlx/pplx-decider-4b/processor_config.json",
filename: "processor_config.json",
required: true,
size_bytes: 1219,
checksum_sha256: None,
},
CatalogFile {
url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/bee2a09a0f7708ac40342b74a221a40e06fd870a/mlx/pplx-decider-4b/readout.safetensors",
filename: "readout.safetensors",
required: true,
size_bytes: 1305712,
checksum_sha256: Some("6751578171026190d4db8078e97162b404fd984646e0e9aec13844e4dd5b1711"),
},
CatalogFile {
url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/bee2a09a0f7708ac40342b74a221a40e06fd870a/mlx/pplx-decider-4b/tokenizer.json",
filename: "tokenizer.json",
required: true,
size_bytes: 19989492,
checksum_sha256: Some("6f32ce20dc35f57a7f9ad1eac03525bd7d30f9df8cea6507e958279cc3657706"),
},
CatalogFile {
url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/bee2a09a0f7708ac40342b74a221a40e06fd870a/mlx/pplx-decider-4b/tokenizer_config.json",
filename: "tokenizer_config.json",
required: true,
size_bytes: 1268,
checksum_sha256: None,
},
];

const PPLX_DECIDER_MLX_4BIT_FILES: &[CatalogFile] = &[
CatalogFile {
url: "https://huggingface.co/mlx-community/pplx-decider-v1.1-27b-4bit/resolve/main/chat_template.jinja",
Expand Down Expand Up @@ -4903,6 +4986,23 @@ const CATALOG: &[CatalogEntry] = &[
merge_key: Some("pplx-decider-27b"),
harness_compatible: false,
},
CatalogEntry {
id: "mlx-pplx-decider-4b",
alias: Some("pplx-decider-4b"),
name: "Pplx Decider 4B v1.2 (decision, text + images)",
category: v1::ModelCategory::Decision,
framework: v1::InferenceFramework::Mlx,
format: v1::ModelFormat::Safetensors,
url: None,
files: PPLX_DECIDER_4B_MLX_FILES,
download_size_bytes: 9099992022,
context_length: 262144,
supports_thinking: false,
memory_required_bytes: 0,
cua_profile: "",
merge_key: Some("pplx-decider-4b"),
harness_compatible: false,
},
CatalogEntry {
id: "lfm-d1-3b",
alias: Some("lfm-d1-3b-gguf"),
Expand Down
5 changes: 4 additions & 1 deletion src/codex/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@ fn function_tool(name: &str, description: Option<&Value>, parameters: Value) ->
if let Some(description) = description.filter(|d| d.is_string()) {
function.insert("description".into(), description.clone());
}
function.insert("parameters".into(), parameters);
function.insert(
"parameters".into(),
crate::util::tool_schema::without_null_fields(&parameters),
);
json!({"type": "function", "function": Value::Object(function)})
}

Expand Down
Loading
Loading