detect_agent 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- detect_agent/__init__.py +121 -0
- detect_agent/py.typed +0 -0
- detect_agent-0.1.0.dist-info/METADATA +118 -0
- detect_agent-0.1.0.dist-info/RECORD +5 -0
- detect_agent-0.1.0.dist-info/WHEEL +4 -0
detect_agent/__init__.py
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Literal, TypedDict, Union
|
|
4
|
+
|
|
5
|
+
DEVIN_LOCAL_PATH = "/opt/.devin"
|
|
6
|
+
|
|
7
|
+
CURSOR: Literal["cursor"] = "cursor"
|
|
8
|
+
CURSOR_CLI: Literal["cursor-cli"] = "cursor-cli"
|
|
9
|
+
CLAUDE: Literal["claude"] = "claude"
|
|
10
|
+
COWORK: Literal["cowork"] = "cowork"
|
|
11
|
+
DEVIN: Literal["devin"] = "devin"
|
|
12
|
+
REPLIT: Literal["replit"] = "replit"
|
|
13
|
+
GEMINI: Literal["gemini"] = "gemini"
|
|
14
|
+
CODEX: Literal["codex"] = "codex"
|
|
15
|
+
ANTIGRAVITY: Literal["antigravity"] = "antigravity"
|
|
16
|
+
AUGMENT_CLI: Literal["augment-cli"] = "augment-cli"
|
|
17
|
+
OPENCODE: Literal["opencode"] = "opencode"
|
|
18
|
+
GITHUB_COPILOT: Literal["github-copilot"] = "github-copilot"
|
|
19
|
+
GITHUB_COPILOT_CLI: Literal["github-copilot-cli"] = "github-copilot-cli"
|
|
20
|
+
|
|
21
|
+
KnownAgentNames = Literal[
|
|
22
|
+
"cursor",
|
|
23
|
+
"cursor-cli",
|
|
24
|
+
"claude",
|
|
25
|
+
"cowork",
|
|
26
|
+
"devin",
|
|
27
|
+
"replit",
|
|
28
|
+
"gemini",
|
|
29
|
+
"codex",
|
|
30
|
+
"antigravity",
|
|
31
|
+
"augment-cli",
|
|
32
|
+
"opencode",
|
|
33
|
+
"github-copilot",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class KnownAgentDetails(TypedDict):
|
|
38
|
+
name: KnownAgentNames
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class AgentResultAgent(TypedDict):
|
|
42
|
+
is_agent: Literal[True]
|
|
43
|
+
agent: KnownAgentDetails
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class AgentResultNone(TypedDict):
|
|
47
|
+
is_agent: Literal[False]
|
|
48
|
+
agent: None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
AgentResult = Union[AgentResultAgent, AgentResultNone]
|
|
52
|
+
|
|
53
|
+
KNOWN_AGENTS = {
|
|
54
|
+
"CURSOR": CURSOR,
|
|
55
|
+
"CURSOR_CLI": CURSOR_CLI,
|
|
56
|
+
"CLAUDE": CLAUDE,
|
|
57
|
+
"COWORK": COWORK,
|
|
58
|
+
"DEVIN": DEVIN,
|
|
59
|
+
"REPLIT": REPLIT,
|
|
60
|
+
"GEMINI": GEMINI,
|
|
61
|
+
"CODEX": CODEX,
|
|
62
|
+
"ANTIGRAVITY": ANTIGRAVITY,
|
|
63
|
+
"AUGMENT_CLI": AUGMENT_CLI,
|
|
64
|
+
"OPENCODE": OPENCODE,
|
|
65
|
+
"GITHUB_COPILOT": GITHUB_COPILOT,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def determine_agent() -> AgentResult:
|
|
70
|
+
ai_agent = os.environ.get("AI_AGENT")
|
|
71
|
+
if ai_agent:
|
|
72
|
+
name = ai_agent.strip()
|
|
73
|
+
if name:
|
|
74
|
+
if name in (GITHUB_COPILOT, GITHUB_COPILOT_CLI):
|
|
75
|
+
return {"is_agent": True, "agent": {"name": GITHUB_COPILOT}}
|
|
76
|
+
return {"is_agent": True, "agent": {"name": name}} # type: ignore[return-value]
|
|
77
|
+
|
|
78
|
+
if os.environ.get("CURSOR_TRACE_ID"):
|
|
79
|
+
return {"is_agent": True, "agent": {"name": CURSOR}}
|
|
80
|
+
|
|
81
|
+
if os.environ.get("CURSOR_AGENT"):
|
|
82
|
+
return {"is_agent": True, "agent": {"name": CURSOR_CLI}}
|
|
83
|
+
|
|
84
|
+
if os.environ.get("GEMINI_CLI"):
|
|
85
|
+
return {"is_agent": True, "agent": {"name": GEMINI}}
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
os.environ.get("CODEX_SANDBOX")
|
|
89
|
+
or os.environ.get("CODEX_CI")
|
|
90
|
+
or os.environ.get("CODEX_THREAD_ID")
|
|
91
|
+
):
|
|
92
|
+
return {"is_agent": True, "agent": {"name": CODEX}}
|
|
93
|
+
|
|
94
|
+
if os.environ.get("ANTIGRAVITY_AGENT"):
|
|
95
|
+
return {"is_agent": True, "agent": {"name": ANTIGRAVITY}}
|
|
96
|
+
|
|
97
|
+
if os.environ.get("AUGMENT_AGENT"):
|
|
98
|
+
return {"is_agent": True, "agent": {"name": AUGMENT_CLI}}
|
|
99
|
+
|
|
100
|
+
if os.environ.get("OPENCODE_CLIENT"):
|
|
101
|
+
return {"is_agent": True, "agent": {"name": OPENCODE}}
|
|
102
|
+
|
|
103
|
+
if os.environ.get("CLAUDECODE") or os.environ.get("CLAUDE_CODE"):
|
|
104
|
+
if os.environ.get("CLAUDE_CODE_IS_COWORK"):
|
|
105
|
+
return {"is_agent": True, "agent": {"name": COWORK}}
|
|
106
|
+
return {"is_agent": True, "agent": {"name": CLAUDE}}
|
|
107
|
+
|
|
108
|
+
if os.environ.get("REPL_ID"):
|
|
109
|
+
return {"is_agent": True, "agent": {"name": REPLIT}}
|
|
110
|
+
|
|
111
|
+
if (
|
|
112
|
+
os.environ.get("COPILOT_MODEL")
|
|
113
|
+
or os.environ.get("COPILOT_ALLOW_ALL")
|
|
114
|
+
or os.environ.get("COPILOT_GITHUB_TOKEN")
|
|
115
|
+
):
|
|
116
|
+
return {"is_agent": True, "agent": {"name": GITHUB_COPILOT}}
|
|
117
|
+
|
|
118
|
+
if Path(DEVIN_LOCAL_PATH).exists():
|
|
119
|
+
return {"is_agent": True, "agent": {"name": DEVIN}}
|
|
120
|
+
|
|
121
|
+
return {"is_agent": False, "agent": None}
|
detect_agent/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: detect_agent
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Detect if code is running in an AI agent or automated development environment
|
|
5
|
+
Project-URL: Homepage, https://github.com/togethercomputer/detect_agent
|
|
6
|
+
Project-URL: Repository, https://github.com/togethercomputer/detect_agent
|
|
7
|
+
Project-URL: Changelog, https://github.com/togethercomputer/detect_agent/blob/main/CHANGELOG.md
|
|
8
|
+
Requires-Python: >=3.9
|
|
9
|
+
Provides-Extra: dev
|
|
10
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
11
|
+
Requires-Dist: ruff>=0.8.0; extra == 'dev'
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# detect_agent
|
|
15
|
+
|
|
16
|
+
> This is a Python Port of Vercels NPM package
|
|
17
|
+
|
|
18
|
+
A lightweight utility for detecting if code is being executed by an AI agent or automated development environment.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
uv add detect_agent
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from detect_agent import determine_agent
|
|
30
|
+
|
|
31
|
+
result = determine_agent()
|
|
32
|
+
|
|
33
|
+
if result["is_agent"]:
|
|
34
|
+
print(f"Running in {result["agent"]["name"]} environment");
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Supported Agents
|
|
38
|
+
|
|
39
|
+
This package can detect the following AI agents and development environments:
|
|
40
|
+
|
|
41
|
+
- **Custom agents** via `AI_AGENT` environment variable
|
|
42
|
+
- **Cursor** (cursor editor and cursor-cli)
|
|
43
|
+
- **Claude Code** (Anthropic's Claude)
|
|
44
|
+
- **Devin** (Cognition Labs)
|
|
45
|
+
- **Gemini CLI** (Google)
|
|
46
|
+
- **Codex** (OpenAI)
|
|
47
|
+
- **Antigravity** (Google DeepMind)
|
|
48
|
+
- **GitHub Copilot** (via `AI_AGENT=github-copilot|github-copilot-cli`, `COPILOT_MODEL`, `COPILOT_ALLOW_ALL`, or `COPILOT_GITHUB_TOKEN`)
|
|
49
|
+
- **Replit** (online IDE)
|
|
50
|
+
|
|
51
|
+
## The AI_AGENT Standard
|
|
52
|
+
|
|
53
|
+
We're promoting `AI_AGENT` as a universal environment variable standard for AI development tools. This allows any tool or library to easily detect when it's running in an AI-driven environment.
|
|
54
|
+
|
|
55
|
+
### For AI Tool Developers
|
|
56
|
+
|
|
57
|
+
Set the `AI_AGENT` environment variable to identify your tool:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
export AI_AGENT="your-tool-name"
|
|
61
|
+
# or
|
|
62
|
+
AI_AGENT="your-tool-name" your-command
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Recommended Naming Convention
|
|
66
|
+
|
|
67
|
+
- Use lowercase with hyphens for multi-word names
|
|
68
|
+
- Include version information if needed, separated by an `@` symbol
|
|
69
|
+
- Examples: `claude-code`, `cursor-cli`, `devin@1`, `custom-agent@2.0`
|
|
70
|
+
|
|
71
|
+
## Development
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
uv sync --extra dev
|
|
75
|
+
uv run pytest
|
|
76
|
+
# Lint and format check (CI)
|
|
77
|
+
uv run ruff check . && uv run ruff format --check .
|
|
78
|
+
# Fix and format
|
|
79
|
+
uv run ruff check . --fix && uv run ruff format .
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Use Cases
|
|
83
|
+
|
|
84
|
+
### Adaptive Behavior
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from detect_agent import determine_agent
|
|
88
|
+
import os
|
|
89
|
+
|
|
90
|
+
def setup_environment():
|
|
91
|
+
result = determine_agent()
|
|
92
|
+
|
|
93
|
+
if (result["is_agent"]) {
|
|
94
|
+
# Running in AI environment - adjust behavior
|
|
95
|
+
os.environ.setdefault("TOGETHER_LOG", "debug")
|
|
96
|
+
print(f"🤖 Detected AI agent: {result["agent"]["name"]}");
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Telemetry and Analytics
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from detect_agent import determine_agent
|
|
103
|
+
|
|
104
|
+
def track_usage(event: string):
|
|
105
|
+
result = determine_agent();
|
|
106
|
+
|
|
107
|
+
analytics.track(event, {
|
|
108
|
+
"agent": result["agent"]["name"] if result["is_agent"] else "human",
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
### Adding New Agent Support
|
|
112
|
+
|
|
113
|
+
To add support for a new AI agent:
|
|
114
|
+
|
|
115
|
+
1. Add detection logic to `main.py`
|
|
116
|
+
2. Add comprehensive test cases in `test.py`
|
|
117
|
+
3. Update this README with the new agent information
|
|
118
|
+
4. Follow the existing priority order pattern
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
detect_agent/__init__.py,sha256=jFCeNQyMjXSqwYRbQx3-IpeV1aKTX72pwjM_Tcy3TpM,3469
|
|
2
|
+
detect_agent/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
detect_agent-0.1.0.dist-info/METADATA,sha256=ZIF5W8J0e-slmiQuWOb3ndXGiaY2DbWysxf8Grv3bf8,3170
|
|
4
|
+
detect_agent-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
5
|
+
detect_agent-0.1.0.dist-info/RECORD,,
|