agent-cli-proxy 0.1.0 → 0.2.6

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.
@@ -1,9 +1,16 @@
1
1
  CREATE TABLE IF NOT EXISTS request_logs (
2
2
  id INTEGER PRIMARY KEY AUTOINCREMENT,
3
+ request_id TEXT,
3
4
  provider TEXT NOT NULL,
4
5
  model TEXT NOT NULL,
6
+ actual_model TEXT,
7
+ actual_provider TEXT,
8
+ proxy_api_key_id INTEGER REFERENCES api_keys(id),
5
9
  tool TEXT DEFAULT 'unknown',
6
10
  client_id TEXT DEFAULT 'unknown',
11
+ agent TEXT,
12
+ source TEXT DEFAULT 'proxy',
13
+ msg_id TEXT,
7
14
  path TEXT NOT NULL,
8
15
  streamed INTEGER NOT NULL DEFAULT 0,
9
16
  status INTEGER,
@@ -11,16 +18,40 @@ CREATE TABLE IF NOT EXISTS request_logs (
11
18
  completion_tokens INTEGER DEFAULT 0,
12
19
  cache_creation_tokens INTEGER DEFAULT 0,
13
20
  cache_read_tokens INTEGER DEFAULT 0,
21
+ reasoning_tokens INTEGER DEFAULT 0,
14
22
  total_tokens INTEGER DEFAULT 0,
15
23
  cost_usd REAL DEFAULT 0,
24
+ cost_status TEXT NOT NULL DEFAULT 'unresolved'
25
+ CHECK(cost_status IN ('unresolved', 'ok', 'pending', 'unsupported')),
26
+ lifecycle_status TEXT NOT NULL DEFAULT 'pending'
27
+ CHECK(lifecycle_status IN ('pending', 'completed', 'error', 'aborted')),
16
28
  incomplete INTEGER NOT NULL DEFAULT 0,
17
29
  error_code TEXT,
30
+ error_message TEXT,
18
31
  latency_ms INTEGER,
19
32
  started_at TEXT NOT NULL,
20
33
  finished_at TEXT,
21
- meta_json TEXT
34
+ finalized_at TEXT,
35
+ meta_json TEXT,
36
+ user_agent TEXT,
37
+ source_ip TEXT,
38
+ cliproxy_account TEXT,
39
+ cliproxy_auth_index TEXT,
40
+ cliproxy_source TEXT,
41
+ correlated_at TEXT
22
42
  );
23
43
 
44
+ CREATE INDEX IF NOT EXISTS idx_request_logs_started_at ON request_logs(started_at);
45
+ CREATE INDEX IF NOT EXISTS idx_request_logs_tool ON request_logs(tool);
46
+ CREATE INDEX IF NOT EXISTS idx_request_logs_client_id ON request_logs(client_id);
47
+ CREATE INDEX IF NOT EXISTS idx_request_logs_cliproxy_account ON request_logs(cliproxy_account);
48
+ CREATE INDEX IF NOT EXISTS idx_request_logs_cliproxy_auth_index ON request_logs(cliproxy_auth_index);
49
+ CREATE INDEX IF NOT EXISTS idx_request_logs_provider_cliproxy_account_started_at ON request_logs(provider, cliproxy_account, started_at);
50
+ CREATE INDEX IF NOT EXISTS idx_request_logs_request_id ON request_logs(request_id);
51
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_request_logs_msg_id ON request_logs(msg_id) WHERE msg_id IS NOT NULL;
52
+ CREATE INDEX IF NOT EXISTS idx_request_logs_lifecycle_status ON request_logs(lifecycle_status);
53
+ CREATE INDEX IF NOT EXISTS idx_request_logs_cost_status ON request_logs(cost_status);
54
+
24
55
  CREATE TABLE IF NOT EXISTS daily_usage (
25
56
  day TEXT NOT NULL,
26
57
  provider TEXT NOT NULL,
@@ -35,7 +66,64 @@ CREATE TABLE IF NOT EXISTS daily_usage (
35
66
  PRIMARY KEY (day, provider, model)
36
67
  );
37
68
 
38
- CREATE INDEX IF NOT EXISTS idx_request_logs_started_at ON request_logs(started_at);
39
- CREATE INDEX IF NOT EXISTS idx_request_logs_tool ON request_logs(tool);
40
- CREATE INDEX IF NOT EXISTS idx_request_logs_client_id ON request_logs(client_id);
41
69
  CREATE INDEX IF NOT EXISTS idx_daily_usage_day ON daily_usage(day);
70
+
71
+ CREATE TABLE IF NOT EXISTS daily_account_usage (
72
+ day TEXT NOT NULL,
73
+ provider TEXT NOT NULL,
74
+ model TEXT NOT NULL,
75
+ cliproxy_account TEXT NOT NULL,
76
+ cliproxy_auth_index TEXT,
77
+ request_count INTEGER DEFAULT 0,
78
+ prompt_tokens INTEGER DEFAULT 0,
79
+ completion_tokens INTEGER DEFAULT 0,
80
+ cache_creation_tokens INTEGER DEFAULT 0,
81
+ cache_read_tokens INTEGER DEFAULT 0,
82
+ reasoning_tokens INTEGER DEFAULT 0,
83
+ total_tokens INTEGER DEFAULT 0,
84
+ cost_usd REAL DEFAULT 0,
85
+ PRIMARY KEY (day, provider, model, cliproxy_account)
86
+ );
87
+
88
+ CREATE INDEX IF NOT EXISTS idx_daily_account_usage_day ON daily_account_usage(day);
89
+ CREATE INDEX IF NOT EXISTS idx_daily_account_usage_account ON daily_account_usage(cliproxy_account);
90
+
91
+ CREATE TABLE IF NOT EXISTS quota_snapshots (
92
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
93
+ timestamp TEXT NOT NULL,
94
+ provider TEXT NOT NULL,
95
+ account TEXT NOT NULL,
96
+ quota_type TEXT NOT NULL,
97
+ model TEXT,
98
+ used_pct REAL,
99
+ remaining REAL,
100
+ remaining_raw TEXT,
101
+ resets_at TEXT,
102
+ raw_json TEXT
103
+ );
104
+
105
+ CREATE INDEX IF NOT EXISTS idx_quota_snapshots_provider ON quota_snapshots(provider, account, timestamp);
106
+
107
+ CREATE TABLE IF NOT EXISTS cost_audit (
108
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
109
+ request_log_id INTEGER REFERENCES request_logs(id),
110
+ model TEXT,
111
+ provider TEXT,
112
+ source TEXT,
113
+ base_cost_usd REAL,
114
+ calc_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
115
+ );
116
+
117
+ CREATE INDEX IF NOT EXISTS idx_cost_audit_request_log_id ON cost_audit(request_log_id);
118
+
119
+ CREATE TABLE IF NOT EXISTS api_keys (
120
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
121
+ key_hash TEXT NOT NULL UNIQUE,
122
+ key_prefix TEXT NOT NULL,
123
+ name TEXT NOT NULL,
124
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
125
+ revoked_at TEXT,
126
+ last_used_at TEXT,
127
+ allowed_accounts TEXT,
128
+ allowed_providers TEXT
129
+ );
@@ -0,0 +1,2 @@
1
+ CREATE INDEX IF NOT EXISTS idx_request_logs_provider_cliproxy_account_started_at
2
+ ON request_logs(provider, cliproxy_account, started_at);
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "agent-cli-proxy",
3
- "version": "0.1.0",
4
- "description": "Self-hosted AI API proxy with per-tool usage monitoring, usage attribution, cost tracking, and subscription metadata for OpenAI/Anthropic-compatible APIs.",
5
- "module": "src/index.ts",
3
+ "version": "0.2.6",
4
+ "description": "Self-hosted AI API proxy with per-tool usage monitoring, account attribution, and cost tracking for OpenAI/Anthropic-compatible APIs.",
5
+ "module": "./dist/index.js",
6
6
  "type": "module",
7
7
  "private": false,
8
8
  "author": "Agent CLI Proxy contributors",
@@ -27,7 +27,7 @@
27
27
  "self-hosted"
28
28
  ],
29
29
  "engines": {
30
- "bun": ">=1.0.0",
30
+ "bun": ">=1.3.0",
31
31
  "node": ">=20.0.0"
32
32
  },
33
33
  "bin": {
@@ -36,27 +36,32 @@
36
36
  "files": [
37
37
  "dist",
38
38
  "README.md",
39
+ "CHANGELOG.md",
39
40
  "LICENSE"
40
41
  ],
41
42
  "scripts": {
42
43
  "dev": "bun run --watch src/index.ts",
43
- "build": "bun build src/index.ts src/cli.ts --target=bun --outdir=./dist && rm -rf dist/migrations && cp -R src/storage/migrations dist/migrations && mkdir -p dist/data && cp data/plans.default.json dist/data/plans.default.json && bun run scripts/post-build.ts",
44
+ "build": "bun build src/index.ts src/cli.ts --target=bun --outdir=./dist && rm -rf dist/migrations && cp -R src/storage/migrations dist/migrations && bun run scripts/post-build.ts",
44
45
  "typecheck": "bunx tsc --noEmit",
45
46
  "test": "bun test",
46
- "release-check": "bun run typecheck && bun run test && bun run build && (bunx publint dist || bun run scripts/release-fallback-check.ts)",
47
+ "release-check": "bun run typecheck && bun run test && bun run build && (bunx publint . || bun run scripts/release-fallback-check.ts)",
47
48
  "prepublishOnly": "bun run release-check",
48
49
  "pack:check": "bun pm pack --dry-run",
49
50
  "test:e2e": "bun test tests/e2e/",
50
- "test:e2e:mock": "MOCK_CLI_PROXY=1 CLI_PROXY_API_URL=http://localhost:18317 bun test tests/e2e/",
51
+ "test:e2e:mock": "MOCK_CLI_PROXY=1 CLI_PROXY_API_URL=http://localhost:18317 bun test tests/e2e/admin-auth.test.ts && MOCK_CLI_PROXY=1 CLI_PROXY_API_URL=http://localhost:18317 bun test tests/e2e/body-size-limit.test.ts && MOCK_CLI_PROXY=1 CLI_PROXY_API_URL=http://localhost:18317 bun test tests/e2e/ready.test.ts && MOCK_CLI_PROXY=1 CLI_PROXY_API_URL=http://localhost:18317 bun test tests/e2e/proxy.test.ts && MOCK_CLI_PROXY=1 CLI_PROXY_API_URL=http://localhost:18317 bun test tests/e2e/transforms.test.ts",
51
52
  "start": "bun run dist/index.js",
52
- "backfill:costs": "bun run src/cli.ts backfill-costs --env .env"
53
+ "backfill:costs": "bun run src/cli.ts backfill-costs --env .env",
54
+ "release": "bun run scripts/release.ts",
55
+ "release:patch": "bun run scripts/release.ts patch",
56
+ "release:minor": "bun run scripts/release.ts minor",
57
+ "release:major": "bun run scripts/release.ts major",
58
+ "release:dry-run": "bun run scripts/release.ts --dry-run"
53
59
  },
54
60
  "devDependencies": {
55
61
  "@types/bun": "latest",
56
- "@tokscale/core": "^1.4.3"
62
+ "@types/node": "^25.9.1"
57
63
  },
58
64
  "peerDependencies": {
59
65
  "typescript": "^5"
60
- },
61
- "dependencies": {}
66
+ }
62
67
  }
@@ -1,93 +0,0 @@
1
- {
2
- "plans": [
3
- {
4
- "code": "claude_pro",
5
- "provider": "anthropic",
6
- "display_name": "Anthropic Claude Pro",
7
- "monthly_price_usd": 20,
8
- "currency": "USD",
9
- "billing_period_days": 30,
10
- "vendor_url": "https://www.anthropic.com/claude/pricing",
11
- "notes": "Conservative estimate — verify with vendor — last updated 2026-05"
12
- },
13
- {
14
- "code": "claude_max5",
15
- "provider": "anthropic",
16
- "display_name": "Anthropic Claude Max 5x",
17
- "monthly_price_usd": 100,
18
- "currency": "USD",
19
- "billing_period_days": 30,
20
- "vendor_url": "https://www.anthropic.com/claude/pricing",
21
- "notes": "Conservative estimate — verify with vendor — last updated 2026-05"
22
- },
23
- {
24
- "code": "claude_max20",
25
- "provider": "anthropic",
26
- "display_name": "Anthropic Claude Max 20x",
27
- "monthly_price_usd": 200,
28
- "currency": "USD",
29
- "billing_period_days": 30,
30
- "vendor_url": "https://www.anthropic.com/claude/pricing",
31
- "notes": "Conservative estimate — verify with vendor — last updated 2026-05"
32
- },
33
- {
34
- "code": "chatgpt_plus",
35
- "provider": "openai",
36
- "display_name": "OpenAI ChatGPT Plus",
37
- "monthly_price_usd": 20,
38
- "currency": "USD",
39
- "billing_period_days": 30,
40
- "vendor_url": "https://openai.com/chatgpt/pricing/",
41
- "notes": "Conservative estimate — verify with vendor — last updated 2026-05"
42
- },
43
- {
44
- "code": "chatgpt_pro",
45
- "provider": "openai",
46
- "display_name": "OpenAI ChatGPT Pro",
47
- "monthly_price_usd": 200,
48
- "currency": "USD",
49
- "billing_period_days": 30,
50
- "vendor_url": "https://openai.com/chatgpt/pricing/",
51
- "notes": "Conservative estimate — verify with vendor — last updated 2026-05"
52
- },
53
- {
54
- "code": "chatgpt_business",
55
- "provider": "openai",
56
- "display_name": "OpenAI ChatGPT Business",
57
- "monthly_price_usd": 25,
58
- "currency": "USD",
59
- "billing_period_days": 30,
60
- "vendor_url": "https://openai.com/chatgpt/pricing/",
61
- "notes": "Conservative estimate (per-seat); verify with vendor — last updated 2026-05"
62
- },
63
- {
64
- "code": "kimi_pro",
65
- "provider": "moonshot",
66
- "display_name": "Moonshot Kimi",
67
- "monthly_price_usd": 15,
68
- "currency": "USD",
69
- "billing_period_days": 30,
70
- "vendor_url": "https://www.moonshot.cn/",
71
- "notes": "Conservative estimate — verify with vendor — last updated 2026-05"
72
- },
73
- {
74
- "code": "glm_pro",
75
- "provider": "bigmodel",
76
- "display_name": "BigModel GLM",
77
- "monthly_price_usd": 10,
78
- "currency": "USD",
79
- "billing_period_days": 30,
80
- "vendor_url": "https://open.bigmodel.cn/",
81
- "notes": "Conservative estimate — verify with vendor — last updated 2026-05"
82
- },
83
- {
84
- "code": "local_byok",
85
- "provider": "local",
86
- "display_name": "Bring Your Own Key (BYOK / Self-hosted)",
87
- "monthly_price_usd": 0,
88
- "currency": "USD",
89
- "billing_period_days": 30,
90
- "notes": "Self-hosted or BYOK provider. No vendor billing. verify with vendor — last updated 2026-05"
91
- }
92
- ]
93
- }
@@ -1,25 +0,0 @@
1
- -- Add agent attribution columns to request_logs
2
- ALTER TABLE request_logs ADD COLUMN IF NOT EXISTS agent TEXT;
3
- ALTER TABLE request_logs ADD COLUMN IF NOT EXISTS source TEXT DEFAULT 'proxy';
4
- ALTER TABLE request_logs ADD COLUMN IF NOT EXISTS msg_id TEXT;
5
-
6
- -- Unique index for dedup (only for non-null msg_id)
7
- CREATE UNIQUE INDEX IF NOT EXISTS idx_request_logs_msg_id
8
- ON request_logs(msg_id) WHERE msg_id IS NOT NULL;
9
-
10
- -- Quota snapshots table
11
- CREATE TABLE IF NOT EXISTS quota_snapshots (
12
- id INTEGER PRIMARY KEY AUTOINCREMENT,
13
- timestamp TEXT NOT NULL,
14
- provider TEXT NOT NULL,
15
- account TEXT NOT NULL,
16
- quota_type TEXT NOT NULL,
17
- used_pct REAL,
18
- remaining REAL,
19
- remaining_raw TEXT,
20
- resets_at TEXT,
21
- raw_json TEXT
22
- );
23
-
24
- CREATE INDEX IF NOT EXISTS idx_quota_snapshots_provider
25
- ON quota_snapshots(provider, account, timestamp);
@@ -1,3 +0,0 @@
1
- ALTER TABLE request_logs ADD COLUMN actual_model TEXT;
2
- ALTER TABLE request_logs ADD COLUMN source_ip TEXT;
3
- ALTER TABLE request_logs ADD COLUMN user_agent TEXT;
@@ -1,40 +0,0 @@
1
- -- Add CLIProxyAPI account attribution
2
- ALTER TABLE request_logs ADD COLUMN cliproxy_account TEXT;
3
- ALTER TABLE request_logs ADD COLUMN cliproxy_auth_index TEXT;
4
- ALTER TABLE request_logs ADD COLUMN cliproxy_source TEXT;
5
- ALTER TABLE request_logs ADD COLUMN request_id TEXT;
6
- ALTER TABLE request_logs ADD COLUMN reasoning_tokens INTEGER DEFAULT 0;
7
- ALTER TABLE request_logs ADD COLUMN actual_model TEXT;
8
- ALTER TABLE request_logs ADD COLUMN user_agent TEXT;
9
- ALTER TABLE request_logs ADD COLUMN source_ip TEXT;
10
- ALTER TABLE request_logs ADD COLUMN correlated_at TEXT;
11
-
12
- CREATE INDEX IF NOT EXISTS idx_request_logs_cliproxy_account
13
- ON request_logs(cliproxy_account);
14
- CREATE INDEX IF NOT EXISTS idx_request_logs_cliproxy_auth_index
15
- ON request_logs(cliproxy_auth_index);
16
- CREATE INDEX IF NOT EXISTS idx_request_logs_request_id
17
- ON request_logs(request_id);
18
-
19
- -- Daily usage breakdown by cliproxy account
20
- CREATE TABLE IF NOT EXISTS daily_account_usage (
21
- day TEXT NOT NULL,
22
- provider TEXT NOT NULL,
23
- model TEXT NOT NULL,
24
- cliproxy_account TEXT NOT NULL,
25
- cliproxy_auth_index TEXT,
26
- request_count INTEGER DEFAULT 0,
27
- prompt_tokens INTEGER DEFAULT 0,
28
- completion_tokens INTEGER DEFAULT 0,
29
- cache_creation_tokens INTEGER DEFAULT 0,
30
- cache_read_tokens INTEGER DEFAULT 0,
31
- reasoning_tokens INTEGER DEFAULT 0,
32
- total_tokens INTEGER DEFAULT 0,
33
- cost_usd REAL DEFAULT 0,
34
- PRIMARY KEY (day, provider, model, cliproxy_account)
35
- );
36
-
37
- CREATE INDEX IF NOT EXISTS idx_daily_account_usage_day
38
- ON daily_account_usage(day);
39
- CREATE INDEX IF NOT EXISTS idx_daily_account_usage_account
40
- ON daily_account_usage(cliproxy_account);
@@ -1,39 +0,0 @@
1
- ALTER TABLE request_logs ADD COLUMN lifecycle_status TEXT NOT NULL DEFAULT 'pending' CHECK(lifecycle_status IN ('pending', 'completed', 'error', 'aborted'));
2
- ALTER TABLE request_logs ADD COLUMN cost_status TEXT NOT NULL DEFAULT 'unresolved' CHECK(cost_status IN ('unresolved', 'ok', 'pending', 'unsupported'));
3
- ALTER TABLE request_logs ADD COLUMN subscription_code TEXT;
4
- ALTER TABLE request_logs ADD COLUMN finalized_at TEXT;
5
- ALTER TABLE request_logs ADD COLUMN error_message TEXT;
6
-
7
- UPDATE request_logs
8
- SET lifecycle_status = CASE
9
- WHEN incomplete = 1
10
- OR error_code IS NOT NULL
11
- OR status >= 400 THEN 'error'
12
- ELSE 'completed'
13
- END,
14
- finalized_at = COALESCE(finished_at, started_at),
15
- cost_status = CASE
16
- WHEN cost_usd > 0 THEN 'ok'
17
- ELSE 'pending'
18
- END;
19
-
20
- CREATE INDEX IF NOT EXISTS idx_request_logs_lifecycle_status
21
- ON request_logs(lifecycle_status);
22
- CREATE INDEX IF NOT EXISTS idx_request_logs_cost_status
23
- ON request_logs(cost_status);
24
- CREATE INDEX IF NOT EXISTS idx_request_logs_subscription_code
25
- ON request_logs(subscription_code) WHERE subscription_code IS NOT NULL;
26
-
27
- CREATE TABLE IF NOT EXISTS cost_audit (
28
- id INTEGER PRIMARY KEY AUTOINCREMENT,
29
- request_log_id INTEGER,
30
- model TEXT,
31
- provider TEXT,
32
- source TEXT,
33
- base_cost_usd REAL,
34
- calc_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
35
- FOREIGN KEY (request_log_id) REFERENCES request_logs(id)
36
- );
37
-
38
- CREATE INDEX IF NOT EXISTS idx_cost_audit_request_log_id
39
- ON cost_audit(request_log_id);
@@ -1,8 +0,0 @@
1
- CREATE TABLE IF NOT EXISTS account_subscriptions (
2
- cliproxy_account TEXT PRIMARY KEY,
3
- subscription_code TEXT NOT NULL,
4
- bound_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
5
- );
6
-
7
- CREATE INDEX IF NOT EXISTS idx_account_subscriptions_subscription_code
8
- ON account_subscriptions(subscription_code);