manifest 5.32.0 → 5.33.0
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.
- package/README.md +36 -63
- package/dist/backend/analytics/analytics.module.js +2 -0
- package/dist/backend/analytics/controllers/agent-analytics.controller.js +2 -2
- package/dist/backend/analytics/controllers/agents.controller.js +7 -7
- package/dist/backend/analytics/controllers/costs.controller.js +3 -3
- package/dist/backend/analytics/controllers/tokens.controller.js +3 -3
- package/dist/backend/analytics/services/agent-lifecycle.service.js +102 -0
- package/dist/backend/analytics/services/aggregation.service.js +1 -73
- package/dist/backend/analytics/services/timeseries-queries.service.js +17 -112
- package/dist/backend/app.module.js +1 -3
- package/dist/backend/common/guards/api-key.guard.js +5 -1
- package/dist/backend/common/utils/cost-calculator.js +18 -0
- package/dist/backend/{routing → common/utils}/provider-aliases.js +1 -1
- package/dist/backend/database/local-bootstrap.service.js +2 -2
- package/dist/backend/database/ollama-sync.service.js +1 -1
- package/dist/backend/main.js +0 -7
- package/dist/backend/{routing/model-discovery → model-discovery}/model-discovery.module.js +4 -4
- package/dist/backend/{routing/model-discovery → model-discovery}/model-discovery.service.js +8 -8
- package/dist/backend/{routing/model-discovery → model-discovery}/model-fallback.js +2 -2
- package/dist/backend/{routing/model-discovery → model-discovery}/provider-model-fetcher.service.js +3 -3
- package/dist/backend/{routing/model-discovery → model-discovery}/provider-model-registry.service.js +1 -1
- package/dist/backend/model-prices/model-name-normalizer.js +5 -0
- package/dist/backend/model-prices/model-prices.module.js +1 -1
- package/dist/backend/model-prices/model-pricing-cache.service.js +1 -1
- package/dist/backend/otlp/guards/{otlp-auth.guard.js → agent-key-auth.guard.js} +15 -11
- package/dist/backend/otlp/otlp.module.js +4 -38
- package/dist/backend/otlp/services/api-key.service.js +2 -2
- package/dist/backend/routing/copilot.controller.js +79 -0
- package/dist/backend/routing/{custom-provider.controller.js → custom-provider/custom-provider.controller.js} +12 -12
- package/dist/backend/routing/custom-provider/custom-provider.module.js +27 -0
- package/dist/backend/routing/{custom-provider.service.js → custom-provider/custom-provider.service.js} +12 -12
- package/dist/backend/routing/model.controller.js +105 -0
- package/dist/backend/routing/oauth/minimax-oauth-helpers.js +70 -0
- package/dist/backend/routing/{minimax-oauth.controller.js → oauth/minimax-oauth.controller.js} +2 -2
- package/dist/backend/routing/{minimax-oauth.service.js → oauth/minimax-oauth.service.js} +32 -86
- package/dist/backend/routing/oauth/oauth.module.js +29 -0
- package/dist/backend/routing/{openai-oauth.controller.js → oauth/openai-oauth.controller.js} +15 -11
- package/dist/backend/routing/{openai-oauth.service.js → oauth/openai-oauth.service.js} +10 -13
- package/dist/backend/routing/provider.controller.js +152 -0
- package/dist/backend/routing/proxy/provider-client-converters.js +179 -0
- package/dist/backend/routing/proxy/provider-client.js +14 -155
- package/dist/backend/routing/proxy/proxy-fallback.service.js +213 -0
- package/dist/backend/routing/proxy/proxy-message-dedup.js +121 -0
- package/dist/backend/routing/proxy/proxy-message-recorder.js +31 -137
- package/dist/backend/routing/proxy/proxy-response-handler.js +162 -0
- package/dist/backend/routing/proxy/proxy-transport.js +90 -0
- package/dist/backend/{otlp/interfaces/otlp-log.js → routing/proxy/proxy-types.js} +1 -1
- package/dist/backend/routing/proxy/proxy.controller.js +19 -137
- package/dist/backend/routing/proxy/proxy.module.js +58 -0
- package/dist/backend/routing/proxy/proxy.service.js +36 -238
- package/dist/backend/routing/{resolve.controller.js → resolve/resolve.controller.js} +11 -11
- package/dist/backend/routing/resolve/resolve.module.js +28 -0
- package/dist/backend/routing/{resolve.service.js → resolve/resolve.service.js} +20 -16
- package/dist/backend/routing/routing-core/provider-key.service.js +180 -0
- package/dist/backend/routing/{routing.service.js → routing-core/provider.service.js} +66 -309
- package/dist/backend/routing/{resolve-agent.service.js → routing-core/resolve-agent.service.js} +2 -2
- package/dist/backend/routing/routing-core/routing-core.module.js +56 -0
- package/dist/backend/routing/{routing-invalidation.service.js → routing-core/routing-invalidation.service.js} +2 -2
- package/dist/backend/routing/{tier-auto-assign.service.js → routing-core/tier-auto-assign.service.js} +3 -3
- package/dist/backend/routing/routing-core/tier.service.js +179 -0
- package/dist/backend/routing/routing.module.js +20 -78
- package/dist/backend/routing/tier.controller.js +129 -0
- package/dist/backend/{routing/scorer → scoring}/__tests__/fixtures.js +5 -4
- package/dist/backend/scoring/config.js +383 -0
- package/dist/backend/{routing/scorer → scoring}/dimensions/contextual-dimensions.js +1 -3
- package/dist/backend/{routing/scorer → scoring}/dimensions/keyword-dimensions.js +1 -2
- package/dist/backend/{routing/scorer → scoring}/dimensions/structural-dimensions.js +1 -3
- package/dist/backend/{routing/scorer → scoring}/index.js +48 -35
- package/dist/backend/{routing/scorer → scoring}/momentum.js +1 -3
- package/dist/backend/{routing/scorer → scoring}/sigmoid.js +1 -5
- package/dist/index.js +8 -32
- package/dist/openclaw.plugin.json +14 -54
- package/dist/package.json +0 -1
- package/openclaw.plugin.json +14 -54
- package/package.json +9 -48
- package/public/assets/{Account-DAuDXzZL.js → Account-q2AcI1Fo.js} +1 -1
- package/public/assets/CopyButton-BrMDM22y.js +1 -0
- package/public/assets/{Limits-Do11RNu3.js → Limits-ReFWKJgq.js} +1 -1
- package/public/assets/{Login-CspKakT4.js → Login-BglUBPGW.js} +1 -1
- package/public/assets/MessageLog-D9C9HoEv.js +1 -0
- package/public/assets/{ModelPrices-D5TKbvU4.js → ModelPrices-BcaC13F4.js} +1 -1
- package/public/assets/Overview-C2sdWWbc.js +1 -0
- package/public/assets/{Register-D7KJjUkO.js → Register-C1SJfrvo.js} +1 -1
- package/public/assets/{ResetPassword-D2dm6bNn.js → ResetPassword-D1orZ45X.js} +1 -1
- package/public/assets/Routing-CznazwUp.js +3 -0
- package/public/assets/Settings-BKqYei3a.js +1 -0
- package/public/assets/SetupStepAddProvider-lHaGi8dV.js +4 -0
- package/public/assets/{SocialButtons-D-eCHUAq.js → SocialButtons-z4qd8zv0.js} +1 -1
- package/public/assets/index-DBDD7Bu4.css +1 -0
- package/public/assets/{index-DaGKqcbR.js → index-fn4HLThn.js} +2 -2
- package/public/assets/{model-display-q35tNU84.js → model-display-j5Ud1w_i.js} +1 -1
- package/public/assets/overview-CZD_Wg_N.css +1 -0
- package/public/assets/overview-CezrfEru.js +1 -0
- package/public/index.html +2 -2
- package/LICENSE.md +0 -21
- package/dist/backend/otlp/interfaces/index.js +0 -21
- package/dist/backend/otlp/interfaces/otlp-common.js +0 -3
- package/dist/backend/otlp/interfaces/otlp-metric.js +0 -3
- package/dist/backend/otlp/interfaces/otlp-trace.js +0 -3
- package/dist/backend/otlp/otlp.controller.js +0 -132
- package/dist/backend/otlp/proto/otlp-proto-defs.js +0 -187
- package/dist/backend/otlp/services/log-ingest.service.js +0 -61
- package/dist/backend/otlp/services/metric-ingest.service.js +0 -119
- package/dist/backend/otlp/services/otlp-decoder.service.js +0 -86
- package/dist/backend/otlp/services/otlp-helpers.js +0 -84
- package/dist/backend/otlp/services/trace-ingest.service.js +0 -570
- package/dist/backend/routing/routing.controller.js +0 -335
- package/dist/backend/routing/scorer/config.js +0 -130
- package/dist/backend/telemetry/dto/create-telemetry.dto.js +0 -89
- package/dist/backend/telemetry/telemetry.controller.js +0 -51
- package/dist/backend/telemetry/telemetry.module.js +0 -26
- package/dist/backend/telemetry/telemetry.service.js +0 -121
- package/dist/index.js.map +0 -7
- package/dist/json-file.js +0 -3
- package/dist/local-mode.js +0 -22
- package/dist/subscription.js +0 -3
- package/public/assets/MessageLog-DjaiR720.js +0 -1
- package/public/assets/Overview-ZRP_-v3U.js +0 -1
- package/public/assets/Routing-CqViGh6v.js +0 -3
- package/public/assets/Settings-BAFYf_4D.js +0 -1
- package/public/assets/SetupStepInstall-gm9pOgFh.js +0 -1
- package/public/assets/SetupStepVerify-B01hQCeb.js +0 -3
- package/public/assets/index-CbWrZHJK.css +0 -1
- package/public/assets/overview-7SUic0us.js +0 -1
- package/public/assets/overview-C3ErufU1.css +0 -1
- package/skills/manifest/SKILL.md +0 -247
- /package/dist/backend/{routing → common/utils}/subscription-support.js +0 -0
- /package/dist/backend/{routing/model-discovery → model-discovery}/model-fetcher.js +0 -0
- /package/dist/backend/routing/{copilot-device-auth.service.js → oauth/copilot-device-auth.service.js} +0 -0
- /package/dist/backend/routing/{openai-oauth.types.js → oauth/openai-oauth.types.js} +0 -0
- /package/dist/backend/routing/{routing-cache.service.js → routing-core/routing-cache.service.js} +0 -0
- /package/dist/backend/{routing/scorer → scoring}/dimensions/index.js +0 -0
- /package/dist/backend/{routing/scorer → scoring}/keyword-trie.js +0 -0
- /package/dist/backend/{routing/scorer → scoring}/overrides.js +0 -0
- /package/dist/backend/{routing/scorer → scoring}/text-extractor.js +0 -0
- /package/dist/backend/{routing/scorer → scoring}/types.js +0 -0
package/README.md
CHANGED
|
@@ -7,8 +7,7 @@
|
|
|
7
7
|
</picture>
|
|
8
8
|
</p>
|
|
9
9
|
<p align="center">
|
|
10
|
-
|
|
11
|
-
OpenClaw costs
|
|
10
|
+
Take control of your OpenClaw costs
|
|
12
11
|
</p>
|
|
13
12
|
|
|
14
13
|
|
|
@@ -34,94 +33,68 @@ OpenClaw costs
|
|
|
34
33
|
<a href="https://trendshift.io/repositories/12890" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12890" alt="mnfst%2Fmanifest | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
|
35
34
|
</p>
|
|
36
35
|
|
|
37
|
-
## What
|
|
36
|
+
## What is Manifest?
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
- 🔄 **Automatic fallbacks** — if a model fails, retry with backup models instantly
|
|
41
|
-
- 🔔 **Set limits** — get alerts when usage goes over a threshold
|
|
38
|
+
Manifest is a model provider for OpenClaw. It sits between your agent and your LLM providers, scores each request, and routes it to the cheapest model that can handle it. Simple questions go to fast, cheap models. Hard problems go to expensive ones. You save money without thinking about it.
|
|
42
39
|
|
|
43
|
-
|
|
40
|
+
- Route requests to the right model -- cut costs up to 70%
|
|
41
|
+
- Automatic fallbacks -- if a model fails, the next one picks up
|
|
42
|
+
- Set limits -- get alerts when usage crosses a threshold
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
## Quick start
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
Unlike almost all alternatives, everything stays on your machine. No suspicious installer, no black box, no third party, no crypto.
|
|
50
|
-
|
|
51
|
-
## Quick Start
|
|
52
|
-
|
|
53
|
-
### Cloud vs Local
|
|
54
|
-
|
|
55
|
-
Manifest is available in cloud and local versions. While both versions install the same OpenClaw Plugin, the local version stores the telemetry data on your computer and the cloud version uses our secure platform.
|
|
56
|
-
|
|
57
|
-
#### Use cloud if
|
|
58
|
-
- You want a quick install
|
|
59
|
-
- You want to access the dashboard from different devices
|
|
60
|
-
- You want to connect multiple agents
|
|
61
|
-
|
|
62
|
-
#### Use local if
|
|
63
|
-
- You don't want the telemetry data to move from your computer
|
|
64
|
-
- You don’t need multi-device access
|
|
65
|
-
- You don't want to subscribe to a cloud service
|
|
66
|
-
- You are using a local model like Ollama
|
|
67
|
-
|
|
68
|
-
If you don't know which version to choose, start with the **cloud version**.
|
|
69
|
-
|
|
70
|
-
### Cloud (default)
|
|
46
|
+
### Cloud
|
|
71
47
|
|
|
72
48
|
```bash
|
|
73
|
-
openclaw plugins install manifest
|
|
74
|
-
openclaw
|
|
49
|
+
openclaw plugins install manifest-provider
|
|
50
|
+
openclaw providers setup manifest-provider
|
|
75
51
|
openclaw gateway restart
|
|
76
52
|
```
|
|
77
53
|
|
|
78
|
-
|
|
54
|
+
The setup wizard prompts for your API key from [app.manifest.build](https://app.manifest.build). After setup, `manifest/auto` is available as a model.
|
|
79
55
|
|
|
80
56
|
### Local
|
|
81
57
|
|
|
58
|
+
For a self-contained setup where everything stays on your machine:
|
|
59
|
+
|
|
82
60
|
```bash
|
|
83
61
|
openclaw plugins install manifest
|
|
84
|
-
openclaw config set plugins.entries.manifest.config.mode local
|
|
85
62
|
openclaw gateway restart
|
|
86
63
|
```
|
|
87
64
|
|
|
88
|
-
Dashboard opens at **http://127.0.0.1:2099**.
|
|
65
|
+
Dashboard opens at **http://127.0.0.1:2099**. The plugin starts an embedded server, runs the dashboard locally, and registers itself as a provider automatically. No account or API key needed.
|
|
89
66
|
|
|
90
|
-
|
|
67
|
+
### Cloud vs local
|
|
91
68
|
|
|
92
|
-
|
|
93
|
-
tailscale serve --bg 2099
|
|
94
|
-
```
|
|
69
|
+
Pick **cloud** (`manifest-provider`) if you want quick setup, multi-device access, or multiple agents. Pick **local** (`manifest`) if you want all data on your machine, don't need remote access, or use local models like Ollama.
|
|
95
70
|
|
|
96
|
-
|
|
71
|
+
Not sure? Start with cloud. You can switch anytime.
|
|
97
72
|
|
|
98
|
-
|
|
99
|
-
- **Real-time dashboard** — tokens, costs, messages, and model usage at a glance
|
|
100
|
-
- **No coding required** — Simple install as OpenClaw plugin
|
|
101
|
-
- **OTLP-native** — standard OpenTelemetry ingestion (traces, metrics, logs)
|
|
73
|
+
## How it works
|
|
102
74
|
|
|
103
|
-
|
|
75
|
+
Every request to `manifest/auto` goes through a 23-dimension scoring algorithm (runs in under 2ms). The scorer picks a tier -- simple, standard, complex, or reasoning -- and routes to the best model in that tier from your connected providers.
|
|
104
76
|
|
|
105
|
-
|
|
77
|
+
All routing data (tokens, costs, model, duration) is recorded automatically. You see it in the dashboard. No extra setup.
|
|
106
78
|
|
|
107
|
-
|
|
79
|
+
## Privacy
|
|
108
80
|
|
|
109
|
-
|
|
81
|
+
**Cloud mode**: Manifest proxies your request to the LLM provider. It records metadata (model name, token counts, latency, cost) but never stores prompt or response content. The proxy is blind to your data by design.
|
|
110
82
|
|
|
83
|
+
**Local mode**: Everything stays on your machine. No data leaves your network.
|
|
111
84
|
|
|
112
85
|
## Manifest vs OpenRouter
|
|
113
86
|
|
|
114
|
-
| | Manifest
|
|
115
|
-
| ------------ |
|
|
116
|
-
| Architecture |
|
|
117
|
-
| Cost | Free
|
|
118
|
-
| Source code | MIT
|
|
119
|
-
| Data privacy |
|
|
120
|
-
| Transparency | Open scoring
|
|
87
|
+
| | Manifest | OpenRouter |
|
|
88
|
+
| ------------ | ------------------------------------------------- | ------------------------------------------------------------- |
|
|
89
|
+
| Architecture | Proxy -- your requests, your providers | Cloud proxy -- all traffic through their servers |
|
|
90
|
+
| Cost | Free | 5% fee on every API call |
|
|
91
|
+
| Source code | MIT, fully open | Proprietary |
|
|
92
|
+
| Data privacy | Metadata only (cloud) or fully local | Prompts and responses pass through a third party |
|
|
93
|
+
| Transparency | Open scoring -- see exactly why a model is chosen | No visibility into routing decisions |
|
|
121
94
|
|
|
122
|
-
## Supported
|
|
95
|
+
## Supported providers
|
|
123
96
|
|
|
124
|
-
Works with
|
|
97
|
+
Works with 300+ models across these providers:
|
|
125
98
|
|
|
126
99
|
| Provider | Models |
|
|
127
100
|
|----------|--------|
|
|
@@ -137,15 +110,15 @@ Works with **300+ models** across these providers:
|
|
|
137
110
|
| [Amazon Nova](https://aws.amazon.com/ai/nova/) | `nova-pro`, `nova-lite`, `nova-micro` + 5 more |
|
|
138
111
|
| [Z.ai (Zhipu)](https://z.ai/) | `glm-5`, `glm-4.7`, `glm-4.5` + 5 more |
|
|
139
112
|
| [OpenRouter](https://openrouter.ai/) | 300+ models from all providers |
|
|
140
|
-
| [Ollama](https://ollama.com/) | Run any model locally (Llama, Gemma, Mistral,
|
|
113
|
+
| [Ollama](https://ollama.com/) | Run any model locally (Llama, Gemma, Mistral, ...) |
|
|
141
114
|
|
|
142
115
|
## Contributing
|
|
143
116
|
|
|
144
|
-
Manifest is open source under the [MIT license](LICENSE). See [CONTRIBUTING.md](CONTRIBUTING.md) for
|
|
117
|
+
Manifest is open source under the [MIT license](LICENSE). See [CONTRIBUTING.md](CONTRIBUTING.md) for dev setup, architecture, and workflow. Join the conversation on [Discord](https://discord.gg/FepAked3W7).
|
|
145
118
|
|
|
146
|
-
>
|
|
119
|
+
> Want a hosted version? Check out [app.manifest.build](https://app.manifest.build)
|
|
147
120
|
|
|
148
|
-
## Quick
|
|
121
|
+
## Quick links
|
|
149
122
|
|
|
150
123
|
- [GitHub](https://github.com/mnfst/manifest)
|
|
151
124
|
- [Docs](https://manifest.build/docs)
|
|
@@ -17,6 +17,7 @@ const tool_execution_entity_1 = require("../entities/tool-execution.entity");
|
|
|
17
17
|
const agent_log_entity_1 = require("../entities/agent-log.entity");
|
|
18
18
|
const otlp_module_1 = require("../otlp/otlp.module");
|
|
19
19
|
const aggregation_service_1 = require("./services/aggregation.service");
|
|
20
|
+
const agent_lifecycle_service_1 = require("./services/agent-lifecycle.service");
|
|
20
21
|
const timeseries_queries_service_1 = require("./services/timeseries-queries.service");
|
|
21
22
|
const messages_query_service_1 = require("./services/messages-query.service");
|
|
22
23
|
const message_details_service_1 = require("./services/message-details.service");
|
|
@@ -46,6 +47,7 @@ exports.AnalyticsModule = AnalyticsModule = __decorate([
|
|
|
46
47
|
],
|
|
47
48
|
providers: [
|
|
48
49
|
aggregation_service_1.AggregationService,
|
|
50
|
+
agent_lifecycle_service_1.AgentLifecycleService,
|
|
49
51
|
timeseries_queries_service_1.TimeseriesQueriesService,
|
|
50
52
|
messages_query_service_1.MessagesQueryService,
|
|
51
53
|
message_details_service_1.MessageDetailsService,
|
|
@@ -16,7 +16,7 @@ exports.AgentAnalyticsController = void 0;
|
|
|
16
16
|
const common_1 = require("@nestjs/common");
|
|
17
17
|
const cache_manager_1 = require("@nestjs/cache-manager");
|
|
18
18
|
const public_decorator_1 = require("../../common/decorators/public.decorator");
|
|
19
|
-
const
|
|
19
|
+
const agent_key_auth_guard_1 = require("../../otlp/guards/agent-key-auth.guard");
|
|
20
20
|
const agent_analytics_service_1 = require("../services/agent-analytics.service");
|
|
21
21
|
const range_query_dto_1 = require("../../common/dto/range-query.dto");
|
|
22
22
|
const agent_cache_interceptor_1 = require("../../common/interceptors/agent-cache.interceptor");
|
|
@@ -61,7 +61,7 @@ __decorate([
|
|
|
61
61
|
exports.AgentAnalyticsController = AgentAnalyticsController = __decorate([
|
|
62
62
|
(0, common_1.Controller)('api/v1/agent'),
|
|
63
63
|
(0, public_decorator_1.Public)(),
|
|
64
|
-
(0, common_1.UseGuards)(
|
|
64
|
+
(0, common_1.UseGuards)(agent_key_auth_guard_1.AgentKeyAuthGuard),
|
|
65
65
|
(0, common_1.UseInterceptors)(agent_cache_interceptor_1.AgentCacheInterceptor),
|
|
66
66
|
(0, cache_manager_1.CacheTTL)(cache_constants_1.DASHBOARD_CACHE_TTL_MS),
|
|
67
67
|
__metadata("design:paramtypes", [agent_analytics_service_1.AgentAnalyticsService])
|
|
@@ -18,7 +18,7 @@ const typeorm_1 = require("typeorm");
|
|
|
18
18
|
const cache_manager_1 = require("@nestjs/cache-manager");
|
|
19
19
|
const config_1 = require("@nestjs/config");
|
|
20
20
|
const timeseries_queries_service_1 = require("../services/timeseries-queries.service");
|
|
21
|
-
const
|
|
21
|
+
const agent_lifecycle_service_1 = require("../services/agent-lifecycle.service");
|
|
22
22
|
const api_key_service_1 = require("../../otlp/services/api-key.service");
|
|
23
23
|
const current_user_decorator_1 = require("../../auth/current-user.decorator");
|
|
24
24
|
const create_agent_dto_1 = require("../../common/dto/create-agent.dto");
|
|
@@ -30,14 +30,14 @@ const slugify_1 = require("../../common/utils/slugify");
|
|
|
30
30
|
const tenant_cache_service_1 = require("../../common/services/tenant-cache.service");
|
|
31
31
|
let AgentsController = class AgentsController {
|
|
32
32
|
timeseries;
|
|
33
|
-
|
|
33
|
+
lifecycle;
|
|
34
34
|
apiKeyGenerator;
|
|
35
35
|
config;
|
|
36
36
|
tenantCache;
|
|
37
37
|
cacheManager;
|
|
38
|
-
constructor(timeseries,
|
|
38
|
+
constructor(timeseries, lifecycle, apiKeyGenerator, config, tenantCache, cacheManager) {
|
|
39
39
|
this.timeseries = timeseries;
|
|
40
|
-
this.
|
|
40
|
+
this.lifecycle = lifecycle;
|
|
41
41
|
this.apiKeyGenerator = apiKeyGenerator;
|
|
42
42
|
this.config = config;
|
|
43
43
|
this.tenantCache = tenantCache;
|
|
@@ -99,7 +99,7 @@ let AgentsController = class AgentsController {
|
|
|
99
99
|
throw new common_1.BadRequestException('Agent name produces an empty slug');
|
|
100
100
|
}
|
|
101
101
|
const displayName = body.name.trim();
|
|
102
|
-
await this.
|
|
102
|
+
await this.lifecycle.renameAgent(user.id, agentName, slug, displayName);
|
|
103
103
|
await this.cacheManager.del(this.agentListCacheKey(user.id));
|
|
104
104
|
return { renamed: true, name: slug, display_name: displayName };
|
|
105
105
|
}
|
|
@@ -107,7 +107,7 @@ let AgentsController = class AgentsController {
|
|
|
107
107
|
if (this.config.get('MANIFEST_MODE') === 'local' && agentName === local_mode_constants_1.LOCAL_AGENT_NAME) {
|
|
108
108
|
throw new common_1.ForbiddenException('Cannot delete the default local agent');
|
|
109
109
|
}
|
|
110
|
-
await this.
|
|
110
|
+
await this.lifecycle.deleteAgent(user.id, agentName);
|
|
111
111
|
await this.cacheManager.del(this.agentListCacheKey(user.id));
|
|
112
112
|
return { deleted: true };
|
|
113
113
|
}
|
|
@@ -167,7 +167,7 @@ exports.AgentsController = AgentsController = __decorate([
|
|
|
167
167
|
(0, common_1.Controller)('api/v1'),
|
|
168
168
|
__param(5, (0, common_1.Inject)(cache_manager_1.CACHE_MANAGER)),
|
|
169
169
|
__metadata("design:paramtypes", [timeseries_queries_service_1.TimeseriesQueriesService,
|
|
170
|
-
|
|
170
|
+
agent_lifecycle_service_1.AgentLifecycleService,
|
|
171
171
|
api_key_service_1.ApiKeyGeneratorService,
|
|
172
172
|
config_1.ConfigService,
|
|
173
173
|
tenant_cache_service_1.TenantCacheService, Object])
|
|
@@ -32,9 +32,9 @@ let CostsController = class CostsController {
|
|
|
32
32
|
async getCosts(query, user) {
|
|
33
33
|
const range = query.range ?? '7d';
|
|
34
34
|
const agentName = query.agent_name;
|
|
35
|
-
const [hourly, daily, byModel, prevCost] = await Promise.all([
|
|
36
|
-
this.timeseries.
|
|
37
|
-
this.timeseries.
|
|
35
|
+
const [{ costUsage: hourly }, { costUsage: daily }, byModel, prevCost] = await Promise.all([
|
|
36
|
+
this.timeseries.getTimeseries(range, user.id, true, undefined, agentName),
|
|
37
|
+
this.timeseries.getTimeseries(range, user.id, false, undefined, agentName),
|
|
38
38
|
this.timeseries.getCostByModel(range, user.id, agentName),
|
|
39
39
|
this.aggregation.getPreviousCostTotal(range, user.id, agentName),
|
|
40
40
|
]);
|
|
@@ -32,9 +32,9 @@ let TokensController = class TokensController {
|
|
|
32
32
|
async getTokens(query, user) {
|
|
33
33
|
const range = query.range ?? '24h';
|
|
34
34
|
const agentName = query.agent_name;
|
|
35
|
-
const [hourly, daily, prevTokens] = await Promise.all([
|
|
36
|
-
this.timeseries.
|
|
37
|
-
this.timeseries.
|
|
35
|
+
const [{ tokenUsage: hourly }, { tokenUsage: daily }, prevTokens] = await Promise.all([
|
|
36
|
+
this.timeseries.getTimeseries(range, user.id, true, undefined, agentName),
|
|
37
|
+
this.timeseries.getTimeseries(range, user.id, false, undefined, agentName),
|
|
38
38
|
this.aggregation.getPreviousTokenTotal(range, user.id, agentName),
|
|
39
39
|
]);
|
|
40
40
|
const inputTotal = hourly.reduce((s, h) => s + h.input_tokens, 0);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.AgentLifecycleService = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const typeorm_1 = require("@nestjs/typeorm");
|
|
18
|
+
const typeorm_2 = require("typeorm");
|
|
19
|
+
const agent_entity_1 = require("../../entities/agent.entity");
|
|
20
|
+
let AgentLifecycleService = class AgentLifecycleService {
|
|
21
|
+
agentRepo;
|
|
22
|
+
dataSource;
|
|
23
|
+
constructor(agentRepo, dataSource) {
|
|
24
|
+
this.agentRepo = agentRepo;
|
|
25
|
+
this.dataSource = dataSource;
|
|
26
|
+
}
|
|
27
|
+
async deleteAgent(userId, agentName) {
|
|
28
|
+
const agent = await this.agentRepo
|
|
29
|
+
.createQueryBuilder('a')
|
|
30
|
+
.leftJoin('a.tenant', 't')
|
|
31
|
+
.where('t.name = :userId', { userId })
|
|
32
|
+
.andWhere('a.name = :agentName', { agentName })
|
|
33
|
+
.getOne();
|
|
34
|
+
if (!agent) {
|
|
35
|
+
throw new common_1.NotFoundException(`Agent "${agentName}" not found`);
|
|
36
|
+
}
|
|
37
|
+
await this.agentRepo.delete(agent.id);
|
|
38
|
+
}
|
|
39
|
+
async renameAgent(userId, currentName, newName, displayName) {
|
|
40
|
+
const agent = await this.agentRepo
|
|
41
|
+
.createQueryBuilder('a')
|
|
42
|
+
.leftJoin('a.tenant', 't')
|
|
43
|
+
.where('t.name = :userId', { userId })
|
|
44
|
+
.andWhere('a.name = :currentName', { currentName })
|
|
45
|
+
.getOne();
|
|
46
|
+
if (!agent) {
|
|
47
|
+
throw new common_1.NotFoundException(`Agent "${currentName}" not found`);
|
|
48
|
+
}
|
|
49
|
+
if (newName === currentName) {
|
|
50
|
+
if (displayName !== undefined) {
|
|
51
|
+
await this.agentRepo
|
|
52
|
+
.createQueryBuilder()
|
|
53
|
+
.update('agents')
|
|
54
|
+
.set({ display_name: displayName })
|
|
55
|
+
.where('id = :id', { id: agent.id })
|
|
56
|
+
.execute();
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const duplicate = await this.agentRepo
|
|
61
|
+
.createQueryBuilder('a')
|
|
62
|
+
.leftJoin('a.tenant', 't')
|
|
63
|
+
.where('t.name = :userId', { userId })
|
|
64
|
+
.andWhere('a.name = :newName', { newName })
|
|
65
|
+
.getOne();
|
|
66
|
+
if (duplicate) {
|
|
67
|
+
throw new common_1.ConflictException(`Agent "${newName}" already exists`);
|
|
68
|
+
}
|
|
69
|
+
await this.dataSource.transaction(async (manager) => {
|
|
70
|
+
const agentUpdate = { name: newName };
|
|
71
|
+
if (displayName !== undefined)
|
|
72
|
+
agentUpdate['display_name'] = displayName;
|
|
73
|
+
await manager
|
|
74
|
+
.createQueryBuilder()
|
|
75
|
+
.update('agents')
|
|
76
|
+
.set(agentUpdate)
|
|
77
|
+
.where('id = :id', { id: agent.id })
|
|
78
|
+
.execute();
|
|
79
|
+
const tables = [
|
|
80
|
+
'agent_messages',
|
|
81
|
+
'notification_rules',
|
|
82
|
+
'notification_logs',
|
|
83
|
+
'token_usage_snapshots',
|
|
84
|
+
'cost_snapshots',
|
|
85
|
+
];
|
|
86
|
+
await Promise.all(tables.map((table) => manager
|
|
87
|
+
.createQueryBuilder()
|
|
88
|
+
.update(table)
|
|
89
|
+
.set({ agent_name: newName })
|
|
90
|
+
.where('agent_name = :currentName', { currentName })
|
|
91
|
+
.execute()));
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
exports.AgentLifecycleService = AgentLifecycleService;
|
|
96
|
+
exports.AgentLifecycleService = AgentLifecycleService = __decorate([
|
|
97
|
+
(0, common_1.Injectable)(),
|
|
98
|
+
__param(0, (0, typeorm_1.InjectRepository)(agent_entity_1.Agent)),
|
|
99
|
+
__metadata("design:paramtypes", [typeorm_2.Repository,
|
|
100
|
+
typeorm_2.DataSource])
|
|
101
|
+
], AgentLifecycleService);
|
|
102
|
+
//# sourceMappingURL=agent-lifecycle.service.js.map
|
|
@@ -17,20 +17,17 @@ const common_1 = require("@nestjs/common");
|
|
|
17
17
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
18
18
|
const typeorm_2 = require("typeorm");
|
|
19
19
|
const agent_message_entity_1 = require("../../entities/agent-message.entity");
|
|
20
|
-
const agent_entity_1 = require("../../entities/agent.entity");
|
|
21
20
|
const range_util_1 = require("../../common/utils/range.util");
|
|
22
21
|
const query_helpers_1 = require("./query-helpers");
|
|
23
22
|
const tenant_cache_service_1 = require("../../common/services/tenant-cache.service");
|
|
24
23
|
const sql_dialect_1 = require("../../common/utils/sql-dialect");
|
|
25
24
|
let AggregationService = class AggregationService {
|
|
26
25
|
turnRepo;
|
|
27
|
-
agentRepo;
|
|
28
26
|
dataSource;
|
|
29
27
|
tenantCache;
|
|
30
28
|
dialect;
|
|
31
|
-
constructor(turnRepo,
|
|
29
|
+
constructor(turnRepo, dataSource, tenantCache) {
|
|
32
30
|
this.turnRepo = turnRepo;
|
|
33
|
-
this.agentRepo = agentRepo;
|
|
34
31
|
this.dataSource = dataSource;
|
|
35
32
|
this.tenantCache = tenantCache;
|
|
36
33
|
this.dialect = (0, sql_dialect_1.detectDialect)(this.dataSource.options.type);
|
|
@@ -196,81 +193,12 @@ let AggregationService = class AggregationService {
|
|
|
196
193
|
messages: { value: curMsgs, trend_pct: (0, query_helpers_1.computeTrend)(curMsgs, prevMsgs) },
|
|
197
194
|
};
|
|
198
195
|
}
|
|
199
|
-
async deleteAgent(userId, agentName) {
|
|
200
|
-
const agent = await this.agentRepo
|
|
201
|
-
.createQueryBuilder('a')
|
|
202
|
-
.leftJoin('a.tenant', 't')
|
|
203
|
-
.where('t.name = :userId', { userId })
|
|
204
|
-
.andWhere('a.name = :agentName', { agentName })
|
|
205
|
-
.getOne();
|
|
206
|
-
if (!agent) {
|
|
207
|
-
throw new common_1.NotFoundException(`Agent "${agentName}" not found`);
|
|
208
|
-
}
|
|
209
|
-
await this.agentRepo.delete(agent.id);
|
|
210
|
-
}
|
|
211
|
-
async renameAgent(userId, currentName, newName, displayName) {
|
|
212
|
-
const agent = await this.agentRepo
|
|
213
|
-
.createQueryBuilder('a')
|
|
214
|
-
.leftJoin('a.tenant', 't')
|
|
215
|
-
.where('t.name = :userId', { userId })
|
|
216
|
-
.andWhere('a.name = :currentName', { currentName })
|
|
217
|
-
.getOne();
|
|
218
|
-
if (!agent) {
|
|
219
|
-
throw new common_1.NotFoundException(`Agent "${currentName}" not found`);
|
|
220
|
-
}
|
|
221
|
-
if (newName === currentName) {
|
|
222
|
-
if (displayName !== undefined) {
|
|
223
|
-
await this.agentRepo
|
|
224
|
-
.createQueryBuilder()
|
|
225
|
-
.update('agents')
|
|
226
|
-
.set({ display_name: displayName })
|
|
227
|
-
.where('id = :id', { id: agent.id })
|
|
228
|
-
.execute();
|
|
229
|
-
}
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
const duplicate = await this.agentRepo
|
|
233
|
-
.createQueryBuilder('a')
|
|
234
|
-
.leftJoin('a.tenant', 't')
|
|
235
|
-
.where('t.name = :userId', { userId })
|
|
236
|
-
.andWhere('a.name = :newName', { newName })
|
|
237
|
-
.getOne();
|
|
238
|
-
if (duplicate) {
|
|
239
|
-
throw new common_1.ConflictException(`Agent "${newName}" already exists`);
|
|
240
|
-
}
|
|
241
|
-
await this.dataSource.transaction(async (manager) => {
|
|
242
|
-
const agentUpdate = { name: newName };
|
|
243
|
-
if (displayName !== undefined)
|
|
244
|
-
agentUpdate['display_name'] = displayName;
|
|
245
|
-
await manager
|
|
246
|
-
.createQueryBuilder()
|
|
247
|
-
.update('agents')
|
|
248
|
-
.set(agentUpdate)
|
|
249
|
-
.where('id = :id', { id: agent.id })
|
|
250
|
-
.execute();
|
|
251
|
-
const tables = [
|
|
252
|
-
'agent_messages',
|
|
253
|
-
'notification_rules',
|
|
254
|
-
'notification_logs',
|
|
255
|
-
'token_usage_snapshots',
|
|
256
|
-
'cost_snapshots',
|
|
257
|
-
];
|
|
258
|
-
await Promise.all(tables.map((table) => manager
|
|
259
|
-
.createQueryBuilder()
|
|
260
|
-
.update(table)
|
|
261
|
-
.set({ agent_name: newName })
|
|
262
|
-
.where('agent_name = :currentName', { currentName })
|
|
263
|
-
.execute()));
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
196
|
};
|
|
267
197
|
exports.AggregationService = AggregationService;
|
|
268
198
|
exports.AggregationService = AggregationService = __decorate([
|
|
269
199
|
(0, common_1.Injectable)(),
|
|
270
200
|
__param(0, (0, typeorm_1.InjectRepository)(agent_message_entity_1.AgentMessage)),
|
|
271
|
-
__param(1, (0, typeorm_1.InjectRepository)(agent_entity_1.Agent)),
|
|
272
201
|
__metadata("design:paramtypes", [typeorm_2.Repository,
|
|
273
|
-
typeorm_2.Repository,
|
|
274
202
|
typeorm_2.DataSource,
|
|
275
203
|
tenant_cache_service_1.TenantCacheService])
|
|
276
204
|
], AggregationService);
|
|
@@ -35,112 +35,6 @@ let TimeseriesQueriesService = class TimeseriesQueriesService {
|
|
|
35
35
|
this.tenantCache = tenantCache;
|
|
36
36
|
this.dialect = (0, sql_dialect_1.detectDialect)(this.dataSource.options.type);
|
|
37
37
|
}
|
|
38
|
-
async getHourlyTokens(range, userId, agentName) {
|
|
39
|
-
const tenantId = (await this.tenantCache.resolve(userId)) ?? undefined;
|
|
40
|
-
const interval = (0, range_util_1.rangeToInterval)(range);
|
|
41
|
-
const cutoff = (0, sql_dialect_1.computeCutoff)(interval);
|
|
42
|
-
const hourExpr = (0, sql_dialect_1.sqlHourBucket)('at.timestamp', this.dialect);
|
|
43
|
-
const qb = this.turnRepo
|
|
44
|
-
.createQueryBuilder('at')
|
|
45
|
-
.select(hourExpr, 'hour')
|
|
46
|
-
.addSelect('COALESCE(SUM(at.input_tokens), 0)', 'input_tokens')
|
|
47
|
-
.addSelect('COALESCE(SUM(at.output_tokens), 0)', 'output_tokens')
|
|
48
|
-
.where('at.timestamp >= :cutoff', { cutoff });
|
|
49
|
-
(0, query_helpers_1.addTenantFilter)(qb, userId, agentName, tenantId);
|
|
50
|
-
const rows = await qb.groupBy('hour').orderBy('hour', 'ASC').getRawMany();
|
|
51
|
-
return rows.map((r) => ({
|
|
52
|
-
hour: String(r['hour']),
|
|
53
|
-
input_tokens: Number(r['input_tokens'] ?? 0),
|
|
54
|
-
output_tokens: Number(r['output_tokens'] ?? 0),
|
|
55
|
-
}));
|
|
56
|
-
}
|
|
57
|
-
async getDailyTokens(range, userId, agentName) {
|
|
58
|
-
const tenantId = (await this.tenantCache.resolve(userId)) ?? undefined;
|
|
59
|
-
const interval = (0, range_util_1.rangeToInterval)(range);
|
|
60
|
-
const cutoff = (0, sql_dialect_1.computeCutoff)(interval);
|
|
61
|
-
const dateExpr = (0, sql_dialect_1.sqlDateBucket)('at.timestamp', this.dialect);
|
|
62
|
-
const qb = this.turnRepo
|
|
63
|
-
.createQueryBuilder('at')
|
|
64
|
-
.select(dateExpr, 'date')
|
|
65
|
-
.addSelect('COALESCE(SUM(at.input_tokens), 0)', 'input_tokens')
|
|
66
|
-
.addSelect('COALESCE(SUM(at.output_tokens), 0)', 'output_tokens')
|
|
67
|
-
.where('at.timestamp >= :cutoff', { cutoff });
|
|
68
|
-
(0, query_helpers_1.addTenantFilter)(qb, userId, agentName, tenantId);
|
|
69
|
-
const rows = await qb.groupBy('date').orderBy('date', 'ASC').getRawMany();
|
|
70
|
-
return rows.map((r) => ({
|
|
71
|
-
date: String(r['date']),
|
|
72
|
-
input_tokens: Number(r['input_tokens'] ?? 0),
|
|
73
|
-
output_tokens: Number(r['output_tokens'] ?? 0),
|
|
74
|
-
}));
|
|
75
|
-
}
|
|
76
|
-
async getHourlyCosts(range, userId, agentName) {
|
|
77
|
-
const tenantId = (await this.tenantCache.resolve(userId)) ?? undefined;
|
|
78
|
-
const interval = (0, range_util_1.rangeToInterval)(range);
|
|
79
|
-
const cutoff = (0, sql_dialect_1.computeCutoff)(interval);
|
|
80
|
-
const hourExpr = (0, sql_dialect_1.sqlHourBucket)('at.timestamp', this.dialect);
|
|
81
|
-
const qb = this.turnRepo
|
|
82
|
-
.createQueryBuilder('at')
|
|
83
|
-
.select(hourExpr, 'hour')
|
|
84
|
-
.addSelect(`COALESCE(SUM(${(0, sql_dialect_1.sqlSanitizeCost)('at.cost_usd')}), 0)`, 'cost')
|
|
85
|
-
.where('at.timestamp >= :cutoff', { cutoff });
|
|
86
|
-
(0, query_helpers_1.addTenantFilter)(qb, userId, agentName, tenantId);
|
|
87
|
-
const rows = await qb.groupBy('hour').orderBy('hour', 'ASC').getRawMany();
|
|
88
|
-
return rows.map((r) => ({
|
|
89
|
-
hour: String(r['hour']),
|
|
90
|
-
cost: Number(r['cost'] ?? 0),
|
|
91
|
-
}));
|
|
92
|
-
}
|
|
93
|
-
async getDailyCosts(range, userId, agentName) {
|
|
94
|
-
const tenantId = (await this.tenantCache.resolve(userId)) ?? undefined;
|
|
95
|
-
const interval = (0, range_util_1.rangeToInterval)(range);
|
|
96
|
-
const cutoff = (0, sql_dialect_1.computeCutoff)(interval);
|
|
97
|
-
const dateExpr = (0, sql_dialect_1.sqlDateBucket)('at.timestamp', this.dialect);
|
|
98
|
-
const qb = this.turnRepo
|
|
99
|
-
.createQueryBuilder('at')
|
|
100
|
-
.select(dateExpr, 'date')
|
|
101
|
-
.addSelect(`COALESCE(SUM(${(0, sql_dialect_1.sqlSanitizeCost)('at.cost_usd')}), 0)`, 'cost')
|
|
102
|
-
.where('at.timestamp >= :cutoff', { cutoff });
|
|
103
|
-
(0, query_helpers_1.addTenantFilter)(qb, userId, agentName, tenantId);
|
|
104
|
-
const rows = await qb.groupBy('date').orderBy('date', 'ASC').getRawMany();
|
|
105
|
-
return rows.map((r) => ({
|
|
106
|
-
date: String(r['date']),
|
|
107
|
-
cost: Number(r['cost'] ?? 0),
|
|
108
|
-
}));
|
|
109
|
-
}
|
|
110
|
-
async getHourlyMessages(range, userId, agentName) {
|
|
111
|
-
const tenantId = (await this.tenantCache.resolve(userId)) ?? undefined;
|
|
112
|
-
const interval = (0, range_util_1.rangeToInterval)(range);
|
|
113
|
-
const cutoff = (0, sql_dialect_1.computeCutoff)(interval);
|
|
114
|
-
const hourExpr = (0, sql_dialect_1.sqlHourBucket)('at.timestamp', this.dialect);
|
|
115
|
-
const qb = this.turnRepo
|
|
116
|
-
.createQueryBuilder('at')
|
|
117
|
-
.select(hourExpr, 'hour')
|
|
118
|
-
.addSelect('COUNT(*)', 'count')
|
|
119
|
-
.where('at.timestamp >= :cutoff', { cutoff });
|
|
120
|
-
(0, query_helpers_1.addTenantFilter)(qb, userId, agentName, tenantId);
|
|
121
|
-
const rows = await qb.groupBy('hour').orderBy('hour', 'ASC').getRawMany();
|
|
122
|
-
return rows.map((r) => ({
|
|
123
|
-
hour: String(r['hour']),
|
|
124
|
-
count: Number(r['count'] ?? 0),
|
|
125
|
-
}));
|
|
126
|
-
}
|
|
127
|
-
async getDailyMessages(range, userId, agentName) {
|
|
128
|
-
const tenantId = (await this.tenantCache.resolve(userId)) ?? undefined;
|
|
129
|
-
const interval = (0, range_util_1.rangeToInterval)(range);
|
|
130
|
-
const cutoff = (0, sql_dialect_1.computeCutoff)(interval);
|
|
131
|
-
const dateExpr = (0, sql_dialect_1.sqlDateBucket)('at.timestamp', this.dialect);
|
|
132
|
-
const qb = this.turnRepo
|
|
133
|
-
.createQueryBuilder('at')
|
|
134
|
-
.select(dateExpr, 'date')
|
|
135
|
-
.addSelect('COUNT(*)', 'count')
|
|
136
|
-
.where('at.timestamp >= :cutoff', { cutoff });
|
|
137
|
-
(0, query_helpers_1.addTenantFilter)(qb, userId, agentName, tenantId);
|
|
138
|
-
const rows = await qb.groupBy('date').orderBy('date', 'ASC').getRawMany();
|
|
139
|
-
return rows.map((r) => ({
|
|
140
|
-
date: String(r['date']),
|
|
141
|
-
count: Number(r['count'] ?? 0),
|
|
142
|
-
}));
|
|
143
|
-
}
|
|
144
38
|
async getTimeseries(range, userId, hourly, tenantId, agentName) {
|
|
145
39
|
const interval = (0, range_util_1.rangeToInterval)(range);
|
|
146
40
|
const cutoff = (0, sql_dialect_1.computeCutoff)(interval);
|
|
@@ -162,14 +56,15 @@ let TimeseriesQueriesService = class TimeseriesQueriesService {
|
|
|
162
56
|
const costUsage = [];
|
|
163
57
|
const messageUsage = [];
|
|
164
58
|
for (const r of rows) {
|
|
165
|
-
const
|
|
59
|
+
const parsed = this.parseBucketRow(r, bucketAlias);
|
|
60
|
+
const bucketKey = { hour: parsed.hour, date: parsed.date };
|
|
166
61
|
tokenUsage.push({
|
|
167
|
-
|
|
168
|
-
input_tokens:
|
|
169
|
-
output_tokens:
|
|
62
|
+
...bucketKey,
|
|
63
|
+
input_tokens: parsed.input_tokens,
|
|
64
|
+
output_tokens: parsed.output_tokens,
|
|
170
65
|
});
|
|
171
|
-
costUsage.push({
|
|
172
|
-
messageUsage.push({
|
|
66
|
+
costUsage.push({ ...bucketKey, cost: parsed.cost });
|
|
67
|
+
messageUsage.push({ ...bucketKey, count: parsed.count });
|
|
173
68
|
}
|
|
174
69
|
return { tokenUsage, costUsage, messageUsage };
|
|
175
70
|
}
|
|
@@ -318,6 +213,16 @@ let TimeseriesQueriesService = class TimeseriesQueriesService {
|
|
|
318
213
|
};
|
|
319
214
|
});
|
|
320
215
|
}
|
|
216
|
+
parseBucketRow(r, bucketAlias) {
|
|
217
|
+
const row = {
|
|
218
|
+
input_tokens: Number(r['input_tokens'] ?? 0),
|
|
219
|
+
output_tokens: Number(r['output_tokens'] ?? 0),
|
|
220
|
+
cost: Number(r['cost'] ?? 0),
|
|
221
|
+
count: Number(r['count'] ?? 0),
|
|
222
|
+
};
|
|
223
|
+
row[bucketAlias] = String(r[bucketAlias]);
|
|
224
|
+
return row;
|
|
225
|
+
}
|
|
321
226
|
};
|
|
322
227
|
exports.TimeseriesQueriesService = TimeseriesQueriesService;
|
|
323
228
|
exports.TimeseriesQueriesService = TimeseriesQueriesService = __decorate([
|