-
Notifications
You must be signed in to change notification settings - Fork 520
Expand file tree
/
Copy pathfree-agents.ts
More file actions
142 lines (118 loc) · 4.66 KB
/
free-agents.ts
File metadata and controls
142 lines (118 loc) · 4.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import { parseAgentId } from '../util/agent-id-parsing'
import type { CostMode } from './model-config'
/**
* The cost mode that indicates FREE mode.
* Only allowlisted agent+model combinations cost 0 credits in this mode.
*/
export const FREE_COST_MODE = 'free' as const
/**
* Agents that are allowed to run in FREE mode.
* Only these specific agents (and their expected models) get 0 credits in FREE mode.
* This prevents abuse by users trying to use arbitrary agents for free.
*
* The mapping also specifies which models each agent is allowed to use in free mode.
* If an agent uses a different model, it will be charged full credits.
*/
export const FREE_MODE_AGENT_MODELS: Record<string, Set<string>> = {
// Root orchestrator
'base2-free': new Set(['minimax/minimax-m2.5']),
// File exploration agents
'file-picker': new Set(['google/gemini-2.5-flash-lite']),
'file-picker-max': new Set(['google/gemini-3.1-flash-lite-preview']),
'file-lister': new Set(['google/gemini-3.1-flash-lite-preview']),
// Research agents
'researcher-web': new Set(['google/gemini-3.1-flash-lite-preview']),
'researcher-docs': new Set(['google/gemini-3.1-flash-lite-preview']),
// Command execution
'basher': new Set(['google/gemini-3.1-flash-lite-preview']),
// Editor for free mode
'editor-lite': new Set(['minimax/minimax-m2.5']),
// Code reviewer for free mode
'code-reviewer-lite': new Set(['minimax/minimax-m2.5']),
// Thinker for free mode
'thinker-with-files-gemini': new Set(['google/gemini-3.1-pro-preview']),
}
/**
* Agents that don't charge credits when credits would be very small (<5).
*
* These are typically lightweight utility agents that:
* - Use cheap models (e.g., Gemini Flash)
* - Have limited, programmatic capabilities
* - Are frequently spawned as subagents
*
* Making them free avoids user confusion when they connect their own
* Claude subscription (BYOK) but still see credit charges for non-Claude models.
*
* NOTE: This is separate from FREE_MODE_ALLOWED_AGENTS which is for the
* explicit "free" cost mode. These agents get free credits only when
* the cost would be trivial (<5 credits).
*/
export const FREE_TIER_AGENTS = new Set([
'file-picker',
'file-picker-max',
'file-lister',
'researcher-web',
'researcher-docs',
])
/**
* Check if the current cost mode is FREE mode.
* In FREE mode, agents using allowed models cost 0 credits.
*/
export function isFreeMode(costMode: CostMode | string | undefined): boolean {
return costMode === FREE_COST_MODE
}
/**
* Check if a specific agent is allowed to use a specific model in FREE mode.
* This is the strictest check - validates both the agent AND model combination.
*
* Returns true only if:
* 1. The agent has a valid agent ID
* 2. The agent is in the allowed free-mode agents list
* 3. The agent is either internal or published by 'codebuff' (prevents spoofing)
* 4. The model is in that agent's allowed model set
*/
export function isFreeModeAllowedAgentModel(
fullAgentId: string,
model: string,
): boolean {
const { publisherId, agentId } = parseAgentId(fullAgentId)
// Must have a valid agent ID
if (!agentId) return false
// Must be either internal (no publisher) or from codebuff
if (publisherId && publisherId !== 'codebuff') return false
// Get the allowed models for this agent
const allowedModels = FREE_MODE_AGENT_MODELS[agentId]
if (!allowedModels) return false
// Empty set means programmatic agent (no LLM calls expected)
// For these, any model check should fail (they shouldn't be making LLM calls)
if (allowedModels.size === 0) return false
// Exact match first
if (allowedModels.has(model)) return true
// OpenRouter may return dated variants (e.g. "minimax/minimax-m2.5-20260211")
// so also check if the returned model starts with any allowed model prefix.
for (const allowed of allowedModels) {
if (model.startsWith(allowed + '-')) return true
}
return false
}
/**
* Check if an agent should be free (no credit charge) for small requests.
* This is separate from FREE mode - these agents get free credits only
* when the cost would be trivial (<5 credits).
*
* Handles all agent ID formats:
* - 'file-picker'
* - 'file-picker@1.0.0'
* - 'codebuff/file-picker@0.0.2'
*/
export function isFreeAgent(fullAgentId: string): boolean {
const { publisherId, agentId } = parseAgentId(fullAgentId)
// Must have a valid agent ID
if (!agentId) return false
// Must be in the free tier agents list
if (!FREE_TIER_AGENTS.has(agentId)) return false
// Must be either internal (no publisher) or from codebuff
// This prevents publisher spoofing attacks
if (publisherId && publisherId !== 'codebuff') return false
return true
}