Skip to content

Commit 3e12cec

Browse files
committed
Simplify agent detection data model
Signed-off-by: simon <simon.faltum@databricks.com>
1 parent 04fa424 commit 3e12cec

1 file changed

Lines changed: 49 additions & 119 deletions

File tree

  • databricks-sdk-java/src/main/java/com/databricks/sdk/core

databricks-sdk-java/src/main/java/com/databricks/sdk/core/UserAgent.java

Lines changed: 49 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -237,52 +237,15 @@ private static String cicdProvider() {
237237
return cicdProvider;
238238
}
239239

240-
// Matches an environment variable. If value is empty, matching is
241-
// presence-only (any value, including empty string, counts as a match). If
242-
// value is non-empty, the env var must be set to exactly that value.
243-
private static class EnvMatcher {
244-
private final String envVar;
245-
private final String value;
246-
247-
EnvMatcher(String envVar) {
248-
this(envVar, "");
249-
}
250-
251-
EnvMatcher(String envVar, String value) {
252-
this.envVar = envVar;
253-
this.value = value;
254-
}
255-
256-
boolean fires(Environment env) {
257-
String v = env.get(envVar);
258-
if (v == null) {
259-
return false;
260-
}
261-
if (value.isEmpty()) {
262-
return true;
263-
}
264-
return v.equals(value);
265-
}
266-
}
267-
268-
// Describes a single AI coding agent and the environment matchers that
269-
// identify it. The agent is detected if ANY matcher in matchAny fires.
240+
// Describes a single AI coding agent: the env var that identifies it and the
241+
// product name reported in the user agent.
270242
private static class KnownAgent {
243+
private final String envVar;
271244
private final String product;
272-
private final List<EnvMatcher> matchAny;
273245

274-
KnownAgent(String product, List<EnvMatcher> matchAny) {
246+
KnownAgent(String envVar, String product) {
247+
this.envVar = envVar;
275248
this.product = product;
276-
this.matchAny = matchAny;
277-
}
278-
279-
boolean fires(Environment env) {
280-
for (EnvMatcher m : matchAny) {
281-
if (m.fires(env)) {
282-
return true;
283-
}
284-
}
285-
return false;
286249
}
287250
}
288251

@@ -295,64 +258,26 @@ boolean fires(Environment env) {
295258
// Agents are listed alphabetically by product name.
296259
private static List<KnownAgent> listKnownAgents() {
297260
return Arrays.asList(
298-
// Amp also sets AGENT=amp; handled by the central AGENT fallback.
299-
new KnownAgent(
300-
"amp",
301-
Collections.singletonList(
302-
new EnvMatcher("AMP_CURRENT_THREAD_ID"))), // https://ampcode.com/
303-
new KnownAgent(
304-
"antigravity",
305-
Collections.singletonList(
306-
new EnvMatcher("ANTIGRAVITY_AGENT"))), // Closed source (Google)
307261
new KnownAgent(
308-
"augment",
309-
Collections.singletonList(
310-
new EnvMatcher("AUGMENT_AGENT"))), // https://www.augmentcode.com/
311-
new KnownAgent(
312-
"claude-code",
313-
Collections.singletonList(
314-
new EnvMatcher("CLAUDECODE"))), // https://github.com/anthropics/claude-code
315-
new KnownAgent(
316-
"cline",
317-
Collections.singletonList(
318-
new EnvMatcher("CLINE_ACTIVE"))), // https://github.com/cline/cline (v3.24.0+)
319-
new KnownAgent(
320-
"codex",
321-
Collections.singletonList(
322-
new EnvMatcher("CODEX_CI"))), // https://github.com/openai/codex
323-
new KnownAgent(
324-
"copilot-cli",
325-
Collections.singletonList(
326-
new EnvMatcher("COPILOT_CLI"))), // https://github.com/features/copilot
262+
"AMP_CURRENT_THREAD_ID",
263+
"amp"), // https://ampcode.com/ (also sets AGENT=amp, handled centrally)
264+
new KnownAgent("ANTIGRAVITY_AGENT", "antigravity"), // Closed source (Google)
265+
new KnownAgent("AUGMENT_AGENT", "augment"), // https://www.augmentcode.com/
266+
new KnownAgent("CLAUDECODE", "claude-code"), // https://github.com/anthropics/claude-code
267+
new KnownAgent("CLINE_ACTIVE", "cline"), // https://github.com/cline/cline (v3.24.0+)
268+
new KnownAgent("CODEX_CI", "codex"), // https://github.com/openai/codex
269+
new KnownAgent("COPILOT_CLI", "copilot-cli"), // https://github.com/features/copilot
327270
// VS Code Copilot terminal; best-effort heuristic, not officially identified.
271+
new KnownAgent("COPILOT_MODEL", "copilot-vscode"),
272+
new KnownAgent("CURSOR_AGENT", "cursor"), // Closed source
273+
new KnownAgent("GEMINI_CLI", "gemini-cli"), // https://google-gemini.github.io/gemini-cli
328274
new KnownAgent(
329-
"copilot-vscode", Collections.singletonList(new EnvMatcher("COPILOT_MODEL"))),
330-
new KnownAgent(
331-
"cursor", Collections.singletonList(new EnvMatcher("CURSOR_AGENT"))), // Closed source
332-
new KnownAgent(
333-
"gemini-cli",
334-
Collections.singletonList(
335-
new EnvMatcher("GEMINI_CLI"))), // https://google-gemini.github.io/gemini-cli
336-
// Goose also sets AGENT=goose; handled by the central AGENT fallback.
337-
new KnownAgent(
338-
"goose",
339-
Collections.singletonList(
340-
new EnvMatcher("GOOSE_TERMINAL"))), // https://block.github.io/goose/
341-
new KnownAgent(
342-
"kiro",
343-
Collections.singletonList(new EnvMatcher("KIRO"))), // https://kiro.dev/ (Amazon)
344-
new KnownAgent(
345-
"openclaw",
346-
Collections.singletonList(
347-
new EnvMatcher("OPENCLAW_SHELL"))), // https://github.com/anthropics/openclaw
348-
new KnownAgent(
349-
"opencode",
350-
Collections.singletonList(
351-
new EnvMatcher("OPENCODE"))), // https://github.com/opencode-ai/opencode
352-
new KnownAgent(
353-
"windsurf",
354-
Collections.singletonList(
355-
new EnvMatcher("WINDSURF_AGENT")))); // https://codeium.com/windsurf (Codeium)
275+
"GOOSE_TERMINAL",
276+
"goose"), // https://block.github.io/goose/ (also sets AGENT=goose, handled centrally)
277+
new KnownAgent("KIRO", "kiro"), // https://kiro.dev/ (Amazon)
278+
new KnownAgent("OPENCLAW_SHELL", "openclaw"), // https://github.com/anthropics/openclaw
279+
new KnownAgent("OPENCODE", "opencode"), // https://github.com/opencode-ai/opencode
280+
new KnownAgent("WINDSURF_AGENT", "windsurf")); // https://codeium.com/windsurf (Codeium)
356281
}
357282

358283
// Looks up the active agent provider based on environment variables.
@@ -376,33 +301,38 @@ private static List<KnownAgent> listKnownAgents() {
376301
// e.g. AGENT=cursor + CLAUDECODE=1 yields "claude-code", and
377302
// AGENT=goose + CLAUDECODE=1 also yields "claude-code".
378303
private static String lookupAgentProvider(Environment env) {
379-
List<KnownAgent> knownAgents = listKnownAgents();
380-
String detected = "";
381-
int count = 0;
382-
for (KnownAgent agent : knownAgents) {
383-
if (agent.fires(env)) {
384-
detected = agent.product;
385-
count++;
386-
if (count > 1) {
387-
break;
388-
}
304+
List<KnownAgent> agents = listKnownAgents();
305+
306+
List<String> matches = new ArrayList<>();
307+
for (KnownAgent a : agents) {
308+
if (env.get(a.envVar) != null) {
309+
matches.add(a.product);
389310
}
390311
}
391-
if (count == 1) {
392-
return detected;
312+
313+
if (matches.size() == 1) {
314+
return matches.get(0);
393315
}
394-
if (count == 0) {
395-
String agentValue = env.get(AGENT_ENV_VAR);
396-
if (agentValue != null && !agentValue.isEmpty()) {
397-
for (KnownAgent agent : knownAgents) {
398-
if (agent.product.equals(agentValue)) {
399-
return agentValue;
400-
}
401-
}
402-
return "unknown";
316+
if (matches.size() > 1) {
317+
return ""; // ambiguity
318+
}
319+
return agentEnvFallback(env, agents);
320+
}
321+
322+
// agentEnvFallback honors the agents.md AGENT=<name> standard.
323+
// Returns the value if it matches a known product name, "unknown" if AGENT
324+
// is set to any other non-empty value, and "" if AGENT is unset or empty.
325+
private static String agentEnvFallback(Environment env, List<KnownAgent> agents) {
326+
String v = env.get(AGENT_ENV_VAR);
327+
if (v == null || v.isEmpty()) {
328+
return "";
329+
}
330+
for (KnownAgent a : agents) {
331+
if (a.product.equals(v)) {
332+
return v;
403333
}
404334
}
405-
return "";
335+
return "unknown";
406336
}
407337

408338
// Thread-safe lazy initialization of agent provider detection

0 commit comments

Comments
 (0)