Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 11 additions & 0 deletions .github/agentic-price-check-providers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,14 @@ providers:
The Cursor Models table is the complete in-scope catalog. Compare Input, Cache Read, and Output with input_mtok,
cache_read_mtok, and output_mtok. Cache Write is not priced. Treat each Fast row as a separate variant. Exclude third-party
models, the Cursor Token Rate, usage pools, plan allowances, regional uplifts, Legacy Enterprise Auto, and legacy Max Mode.

- name: Arcee
file: prices/providers/arcee.yml
scope: Models in Arcee's public Text Models pricing table.
sources:
- https://docs.arcee.ai/get-started/pricing
notes: >-
The Text Models table is the complete in-scope catalog. Compare Input, Cached, and Output with input_mtok,
cache_read_mtok, and output_mtok. Exclude context windows and image, request, and cache-write rates because the public
pricing page does not publish them. Match exact model IDs and do not treat their third-party namespaces as provider
ownership.
10 changes: 5 additions & 5 deletions .github/workflows/AGENTIC_PRICE_CHECK.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ pricing page** and file a GitHub issue when they diverge. This complements the
existing aggregator-based checks (`make check-for-price-discrepancies`, which
uses LiteLLM / OpenRouter / etc.) by reading the authoritative source directly.

| Workflow | Providers | Issue |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
| `agentic-price-check-openai-anthropic.md` | OpenAI, Anthropic | `[price-check/openai-anthropic] …` |
| `agentic-price-check-google-mistral.md` | Google (Gemini), Mistral | `[price-check/google-mistral] …` |
| `agentic-price-check-direct-providers.md` | DeepSeek, xAI, Groq, Cerebras, MiniMax, MoonshotAI, Avian, Perplexity, Cohere, Voyage AI, Cloudflare Workers AI, Cursor | `[price-check/direct-providers] …` |
| Workflow | Providers | Issue |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------- |
| `agentic-price-check-openai-anthropic.md` | OpenAI, Anthropic | `[price-check/openai-anthropic] …` |
| `agentic-price-check-google-mistral.md` | Google (Gemini), Mistral | `[price-check/google-mistral] …` |
| `agentic-price-check-direct-providers.md` | DeepSeek, xAI, Groq, Cerebras, MiniMax, MoonshotAI, Avian, Perplexity, Cohere, Voyage AI, Cloudflare Workers AI, Cursor, Arcee | `[price-check/direct-providers] …` |

Each agent is told the **exact pricing URL** to fetch per provider, reads the recorded
`prices:` from the YAML, and compares. The direct-provider workflow reads its provider
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/agentic-price-check-direct-providers.lock.yml

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions .github/workflows/agentic-price-check-direct-providers.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
emoji: '🏷️'
name: 'Price Check: Direct Providers'
description: 'Check twelve direct provider catalogs for changed prices, new models, removed models, and unreadable sources.'
description: 'Check thirteen direct provider catalogs for changed prices, new models, removed models, and unreadable sources.'
on:
workflow_dispatch:
schedule: weekly on monday
Expand Down Expand Up @@ -77,6 +77,7 @@ network:
- docs.voyageai.com
- developers.cloudflare.com
- cursor.com
- docs.arcee.ai
---

# Price Check: Direct Providers
Expand Down Expand Up @@ -145,5 +146,5 @@ If any price change, new model, potential removal, unchecked field, or unreadabl
Use tables and one row per finding. End with `Checked YYYY-MM-DD.` using the run date.

Call `safeoutputs noop` only when all manifest providers and sources were read successfully, every active price field and tier was
checked, every recorded value matched, and catalog comparison found no new or potentially removed models. State that all twelve
checked, every recorded value matched, and catalog comparison found no new or potentially removed models. State that all thirteen
direct providers match.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ huggingface-get: ## get huggingface prices
cloudflare-get: ## get cloudflare workers ai prices
uv run -m prices get_cloudflare_prices

.PHONY: arcee-get
arcee-get: ## get arcee model prices
uv run -m prices get_arcee_prices

.PHONY: cursor-get
cursor-get: ## get cursor model prices
uv run -m prices get_cursor_prices
Expand All @@ -80,7 +84,7 @@ quicksilverpro-get: ## get quicksilver pro prices
uv run -m prices get_quicksilverpro_prices

.PHONY: get-all-prices
get-all-prices: helicone-get openrouter-get litellm-get simonw-prices-get huggingface-get cloudflare-get cursor-get ovhcloud-get quicksilverpro-get ## get all prices
get-all-prices: helicone-get openrouter-get litellm-get simonw-prices-get huggingface-get arcee-get cloudflare-get cursor-get ovhcloud-get quicksilverpro-get ## get all prices

.PHONE: update-price-discrepancies
update-price-discrepancies: ## update price discrepancies
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The following providers are currently supported:
[comment]: <> (providers-start)

- [Anthropic](prices/providers/anthropic.yml) - 23 models
- [Arcee](prices/providers/arcee.yml) - 6 models
- [Avian](prices/providers/avian.yml) - 17 models
- [AWS Bedrock](prices/providers/aws.yml) - 86 models
- [Microsoft Azure](prices/providers/azure.yml) - 23 models
Expand Down
23 changes: 23 additions & 0 deletions packages/js/src/__tests__/extractUsage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { data } from '../data'
import { calcPrice, extractUsage } from '../index'

const anthropicProvider: Provider = data.find((provider) => provider.id === 'anthropic')!
const arceeProvider: Provider = data.find((provider) => provider.id === 'arcee')!
const cursorProvider: Provider = data.find((provider) => provider.id === 'cursor')!
const fractionalProvider: Provider = {
api_pattern: 'fractional',
Expand Down Expand Up @@ -60,6 +61,28 @@ describe('extractUsage', () => {
expect(price?.total_price).toBeCloseTo(0.00099, 8)
})

it.each(['default', 'chat'])('should extract Arcee %s usage', (apiFlavor) => {
const responseData = {
model: 'deepseek/deepseek-v4-flash-latest',
usage: {
completion_tokens: 40,
completion_tokens_details: { reasoning_tokens: 10 },
prompt_tokens: 100,
prompt_tokens_details: { cached_tokens: 30 },
},
}

const { model, usage } = extractUsage(arceeProvider, responseData, apiFlavor)

expect(model).toBe('deepseek/deepseek-v4-flash-latest')
expect(usage).toEqual({
cache_read_tokens: 30,
input_tokens: 100,
output_reasoning_tokens: 10,
output_tokens: 40,
})
})

it('should extract usage with cache tokens', () => {
const responseData = {
id: 'msg_0152tnC3YpjyASTB9qxqDJXu',
Expand Down
15 changes: 15 additions & 0 deletions packages/js/src/__tests__/generatedData.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,21 @@ describe('generated data split', () => {
expect(result?.total_price).toBe(expectedTotalPrice)
})

it.each([
{ expectedTotalPrice: 0.448, model: 'deepseek/deepseek-v4-flash-latest' },
{ expectedTotalPrice: 5.42, model: 'deepseek/deepseek-v4-pro' },
{ expectedTotalPrice: 18.3, model: 'moonshotai/kimi-k3' },
{ expectedTotalPrice: 1.8, model: 'thinkingmachines/inkling-small' },
{ expectedTotalPrice: 1.11, model: 'trinity-large-thinking' },
{ expectedTotalPrice: 6.06, model: 'zai-org/glm-5.2' },
])('prices Arcee $model', ({ expectedTotalPrice, model }) => {
const result = calcPrice({ cache_read_tokens: 1_000_000, input_tokens: 2_000_000, output_tokens: 1_000_000 }, model, {
providerId: 'arcee',
})

expect(result?.total_price).toBeCloseTo(expectedTotalPrice, 12)
})

it.each([
{ expectedInputPrice: (200_000 * 3) / 1_000_000, inputTokens: 200_000 },
{ expectedInputPrice: (200_001 * 6) / 1_000_000, inputTokens: 200_001 },
Expand Down
6 changes: 6 additions & 0 deletions packages/js/src/__tests__/matcher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,18 @@ describe('Provider Matching', () => {
expect(matchProvider(actualProviders, { modelId: 'composer-2.5' })?.id).toBe('cursor')
expect(matchProvider(actualProviders, { modelId: 'grok-4.6' })?.id).not.toBe('cursor')
})

it('does not claim third-party model namespaces for Arcee', () => {
expect(matchProvider(actualProviders, { modelId: 'deepseek/deepseek-v4-pro' })?.id).not.toBe('arcee')
})
})

describe('matchProvider with providerId', () => {
it('should find providers by exact ID match', () => {
expect(matchProvider(actualProviders, { providerId: 'google' })?.id).toBe('google')
expect(matchProvider(actualProviders, { providerId: 'anthropic' })?.id).toBe('anthropic')
expect(matchProvider(actualProviders, { providerId: 'openai' })?.id).toBe('openai')
expect(matchProvider(actualProviders, { providerId: 'arcee' })?.id).toBe('arcee')
expect(matchProvider(actualProviders, { providerId: 'cursor' })?.id).toBe('cursor')
})

Expand Down Expand Up @@ -99,6 +104,7 @@ describe('Provider Matching', () => {

it('should match a provider at the start of the URL', () => {
expect(matchProvider(actualProviders, { providerApiUrl: 'https://api.openai.com/v1/chat/completions' })?.id).toBe('openai')
expect(matchProvider(actualProviders, { providerApiUrl: 'https://api.arcee.ai/api/v1/chat/completions' })?.id).toBe('arcee')
expect(matchProvider(actualProviders, { providerApiUrl: 'https://api.cursor.com/v1/agents' })?.id).toBe('cursor')
})

Expand Down
142 changes: 142 additions & 0 deletions packages/js/src/data.ts

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

Loading