@things-factory/integration-anthropic 0.0.0-stage → 10.1.239
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/dist-server/engine/connector/anthropic-admin-client.d.ts +28 -0
- package/dist-server/engine/connector/anthropic-admin-client.js +51 -0
- package/dist-server/engine/connector/anthropic-admin-client.js.map +1 -0
- package/dist-server/engine/connector/anthropic-admin-connector.d.ts +19 -0
- package/dist-server/engine/connector/anthropic-admin-connector.js +39 -0
- package/dist-server/engine/connector/anthropic-admin-connector.js.map +1 -0
- package/dist-server/engine/connector/index.d.ts +1 -0
- package/dist-server/engine/connector/index.js +4 -0
- package/dist-server/engine/connector/index.js.map +1 -0
- package/dist-server/engine/index.d.ts +2 -0
- package/dist-server/engine/index.js +5 -0
- package/dist-server/engine/index.js.map +1 -0
- package/dist-server/engine/task/anthropic-cost-report.d.ts +18 -0
- package/dist-server/engine/task/anthropic-cost-report.js +54 -0
- package/dist-server/engine/task/anthropic-cost-report.js.map +1 -0
- package/dist-server/engine/task/index.d.ts +1 -0
- package/dist-server/engine/task/index.js +4 -0
- package/dist-server/engine/task/index.js.map +1 -0
- package/dist-server/index.d.ts +3 -0
- package/dist-server/index.js +9 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/helps/integration/connector/anthropic-admin-connector.md +8 -0
- package/helps/integration/task/anthropic-cost-report.md +20 -0
- package/package.json +27 -4
- package/things-factory.config.js +1 -0
- package/translations/en.json +4 -0
- package/translations/es.json +4 -0
- package/translations/ja.json +4 -0
- package/translations/ko.json +4 -0
- package/translations/ms.json +4 -0
- package/translations/zh.json +4 -0
- package/README.md +0 -3
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Anthropic Admin API for an organization (ADR-0177 개정 3) - who the organization is and what its API usage cost.
|
|
3
|
+
* An Admin API key (`sk-ant-admin...`) only; a workspace key is refused by these endpoints.
|
|
4
|
+
*/
|
|
5
|
+
export interface CostResult {
|
|
6
|
+
amount: string;
|
|
7
|
+
currency: string;
|
|
8
|
+
description?: string | null;
|
|
9
|
+
model?: string | null;
|
|
10
|
+
cost_type?: string | null;
|
|
11
|
+
}
|
|
12
|
+
export declare class AnthropicAdminClient {
|
|
13
|
+
private readonly adminKey;
|
|
14
|
+
private readonly fetcher;
|
|
15
|
+
private readonly origin;
|
|
16
|
+
constructor(adminKey: string, origin?: string | null, fetcher?: typeof fetch);
|
|
17
|
+
private get;
|
|
18
|
+
/** The organization the key belongs to. */
|
|
19
|
+
organization(): Promise<{
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
}>;
|
|
23
|
+
/** The cost, day by day from `startingAt` to `endingAt` (RFC 3339), by description - every page. */
|
|
24
|
+
costs(startingAt: string, endingAt: string): Promise<{
|
|
25
|
+
starting_at: string;
|
|
26
|
+
results: CostResult[];
|
|
27
|
+
}[]>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The Anthropic Admin API for an organization (ADR-0177 개정 3) - who the organization is and what its API usage cost.
|
|
4
|
+
* An Admin API key (`sk-ant-admin...`) only; a workspace key is refused by these endpoints.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.AnthropicAdminClient = void 0;
|
|
8
|
+
const DEFAULT_ORIGIN = 'https://api.anthropic.com';
|
|
9
|
+
class AnthropicAdminClient {
|
|
10
|
+
constructor(adminKey, origin, fetcher = fetch) {
|
|
11
|
+
this.adminKey = adminKey;
|
|
12
|
+
this.fetcher = fetcher;
|
|
13
|
+
if (!adminKey)
|
|
14
|
+
throw new Error('the Anthropic connection has no Admin API key');
|
|
15
|
+
/* An Admin API key - never a workspace key, which these endpoints refuse. The value itself is never said. */
|
|
16
|
+
if (!adminKey.trim().startsWith('sk-ant-admin'))
|
|
17
|
+
throw new Error('the key is no Admin API key - create one in the Claude Console under Settings > Admin keys (sk-ant-admin...)');
|
|
18
|
+
this.adminKey = adminKey.trim();
|
|
19
|
+
this.origin = (origin || DEFAULT_ORIGIN).replace(/\/+$/, '');
|
|
20
|
+
}
|
|
21
|
+
async get(path, query = []) {
|
|
22
|
+
const url = new URL(`${this.origin}${path}`);
|
|
23
|
+
for (const [key, value] of query)
|
|
24
|
+
url.searchParams.append(key, value);
|
|
25
|
+
const response = await this.fetcher(url.toString(), { headers: { 'x-api-key': this.adminKey, 'anthropic-version': '2023-06-01' } });
|
|
26
|
+
const body = await response.json().catch(() => ({}));
|
|
27
|
+
if (!response.ok)
|
|
28
|
+
throw new Error(`${path} (${response.status}): ${body?.error?.message ?? response.statusText}`);
|
|
29
|
+
return body;
|
|
30
|
+
}
|
|
31
|
+
/** The organization the key belongs to. */
|
|
32
|
+
organization() {
|
|
33
|
+
return this.get('/v1/organizations/me');
|
|
34
|
+
}
|
|
35
|
+
/** The cost, day by day from `startingAt` to `endingAt` (RFC 3339), by description - every page. */
|
|
36
|
+
async costs(startingAt, endingAt) {
|
|
37
|
+
const buckets = [];
|
|
38
|
+
let page;
|
|
39
|
+
do {
|
|
40
|
+
const query = [['starting_at', startingAt], ['ending_at', endingAt], ['group_by[]', 'description'], ['limit', '31']];
|
|
41
|
+
if (page)
|
|
42
|
+
query.push(['page', page]);
|
|
43
|
+
const body = await this.get('/v1/organizations/cost_report', query);
|
|
44
|
+
buckets.push(...(body.data ?? []));
|
|
45
|
+
page = body.has_more ? body.next_page : undefined;
|
|
46
|
+
} while (page);
|
|
47
|
+
return buckets;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.AnthropicAdminClient = AnthropicAdminClient;
|
|
51
|
+
//# sourceMappingURL=anthropic-admin-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-admin-client.js","sourceRoot":"","sources":["../../../server/engine/connector/anthropic-admin-client.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,MAAM,cAAc,GAAG,2BAA2B,CAAA;AAUlD,MAAa,oBAAoB;IAG/B,YAA6B,QAAgB,EAAE,MAAsB,EAAmB,UAAwB,KAAK;QAAxF,aAAQ,GAAR,QAAQ,CAAQ;QAA2C,YAAO,GAAP,OAAO,CAAsB;QACnH,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;QAC/E,6GAA6G;QAC7G,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,8GAA8G,CAAC,CAAA;QAChL,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAA;QAC/B,IAAI,CAAC,MAAM,GAAG,CAAC,MAAM,IAAI,cAAc,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAC9D,CAAC;IAEO,KAAK,CAAC,GAAG,CAAC,IAAY,EAAE,QAA4B,EAAE;QAC5D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC,CAAA;QAC5C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,KAAK;YAAE,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QACrE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,QAAQ,EAAE,mBAAmB,EAAE,YAAY,EAAE,EAAE,CAAC,CAAA;QACnI,MAAM,IAAI,GAAQ,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACzD,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,KAAK,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,KAAK,EAAE,OAAO,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAA;QACjH,OAAO,IAAI,CAAA;IACb,CAAC;IAED,2CAA2C;IAC3C,YAAY;QACV,OAAO,IAAI,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAA;IACzC,CAAC;IAED,oGAAoG;IACpG,KAAK,CAAC,KAAK,CAAC,UAAkB,EAAE,QAAgB;QAC9C,MAAM,OAAO,GAAU,EAAE,CAAA;QACzB,IAAI,IAAwB,CAAA;QAC5B,GAAG,CAAC;YACF,MAAM,KAAK,GAAuB,CAAC,CAAC,aAAa,EAAE,UAAU,CAAC,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA;YACxI,IAAI,IAAI;gBAAE,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;YACpC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAA;YACnE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAA;YAClC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;QACnD,CAAC,QAAQ,IAAI,EAAC;QACd,OAAO,OAAO,CAAA;IAChB,CAAC;CACF;AAtCD,oDAsCC","sourcesContent":["/**\n * The Anthropic Admin API for an organization (ADR-0177 개정 3) - who the organization is and what its API usage cost.\n * An Admin API key (`sk-ant-admin...`) only; a workspace key is refused by these endpoints.\n */\n\nconst DEFAULT_ORIGIN = 'https://api.anthropic.com'\n\nexport interface CostResult {\n amount: string\n currency: string\n description?: string | null\n model?: string | null\n cost_type?: string | null\n}\n\nexport class AnthropicAdminClient {\n private readonly origin: string\n\n constructor(private readonly adminKey: string, origin?: string | null, private readonly fetcher: typeof fetch = fetch) {\n if (!adminKey) throw new Error('the Anthropic connection has no Admin API key')\n /* An Admin API key - never a workspace key, which these endpoints refuse. The value itself is never said. */\n if (!adminKey.trim().startsWith('sk-ant-admin')) throw new Error('the key is no Admin API key - create one in the Claude Console under Settings > Admin keys (sk-ant-admin...)')\n this.adminKey = adminKey.trim()\n this.origin = (origin || DEFAULT_ORIGIN).replace(/\\/+$/, '')\n }\n\n private async get(path: string, query: [string, string][] = []): Promise<any> {\n const url = new URL(`${this.origin}${path}`)\n for (const [key, value] of query) url.searchParams.append(key, value)\n const response = await this.fetcher(url.toString(), { headers: { 'x-api-key': this.adminKey, 'anthropic-version': '2023-06-01' } })\n const body: any = await response.json().catch(() => ({}))\n if (!response.ok) throw new Error(`${path} (${response.status}): ${body?.error?.message ?? response.statusText}`)\n return body\n }\n\n /** The organization the key belongs to. */\n organization(): Promise<{ id: string; name: string }> {\n return this.get('/v1/organizations/me')\n }\n\n /** The cost, day by day from `startingAt` to `endingAt` (RFC 3339), by description - every page. */\n async costs(startingAt: string, endingAt: string): Promise<{ starting_at: string; results: CostResult[] }[]> {\n const buckets: any[] = []\n let page: string | undefined\n do {\n const query: [string, string][] = [['starting_at', startingAt], ['ending_at', endingAt], ['group_by[]', 'description'], ['limit', '31']]\n if (page) query.push(['page', page])\n const body = await this.get('/v1/organizations/cost_report', query)\n buckets.push(...(body.data ?? []))\n page = body.has_more ? body.next_page : undefined\n } while (page)\n return buckets\n }\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Connector } from '@things-factory/integration-base';
|
|
2
|
+
/**
|
|
3
|
+
* Anthropic Admin API connector (ADR-0177 개정 3) - one connection an organization, its Admin API key a secret. The
|
|
4
|
+
* connection's endpoint is the API origin; empty is https://api.anthropic.com.
|
|
5
|
+
*/
|
|
6
|
+
export declare class AnthropicAdminConnector implements Connector {
|
|
7
|
+
ready(connectionConfigs: any): Promise<void>;
|
|
8
|
+
connect(connection: any): Promise<void>;
|
|
9
|
+
disconnect(connection: any): Promise<void>;
|
|
10
|
+
get parameterSpec(): {
|
|
11
|
+
type: string;
|
|
12
|
+
name: string;
|
|
13
|
+
label: string;
|
|
14
|
+
useDomainAttribute: boolean;
|
|
15
|
+
}[];
|
|
16
|
+
get taskPrefixes(): string[];
|
|
17
|
+
get help(): string;
|
|
18
|
+
get description(): string;
|
|
19
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AnthropicAdminConnector = void 0;
|
|
4
|
+
const integration_base_1 = require("@things-factory/integration-base");
|
|
5
|
+
const anthropic_admin_client_1 = require("./anthropic-admin-client");
|
|
6
|
+
/**
|
|
7
|
+
* Anthropic Admin API connector (ADR-0177 개정 3) - one connection an organization, its Admin API key a secret. The
|
|
8
|
+
* connection's endpoint is the API origin; empty is https://api.anthropic.com.
|
|
9
|
+
*/
|
|
10
|
+
class AnthropicAdminConnector {
|
|
11
|
+
async ready(connectionConfigs) {
|
|
12
|
+
await Promise.all(connectionConfigs.map(this.connect.bind(this)));
|
|
13
|
+
integration_base_1.ConnectionManager.logger.info('anthropic-admin-connector connections are ready');
|
|
14
|
+
}
|
|
15
|
+
async connect(connection) {
|
|
16
|
+
const { endpoint, params } = connection;
|
|
17
|
+
integration_base_1.ConnectionManager.addConnectionInstance(connection, { client: new anthropic_admin_client_1.AnthropicAdminClient(params?.adminKey, endpoint) });
|
|
18
|
+
integration_base_1.ConnectionManager.logger.info(`anthropic-admin-connector connection(${connection.name}) is connected`);
|
|
19
|
+
}
|
|
20
|
+
async disconnect(connection) {
|
|
21
|
+
integration_base_1.ConnectionManager.removeConnectionInstance(connection);
|
|
22
|
+
integration_base_1.ConnectionManager.logger.info(`anthropic-admin-connector connection(${connection.name}) is disconnected`);
|
|
23
|
+
}
|
|
24
|
+
get parameterSpec() {
|
|
25
|
+
return [{ type: 'secret', name: 'adminKey', label: 'admin-key', useDomainAttribute: true }];
|
|
26
|
+
}
|
|
27
|
+
get taskPrefixes() {
|
|
28
|
+
return ['anthropic'];
|
|
29
|
+
}
|
|
30
|
+
get help() {
|
|
31
|
+
return 'integration/connector/anthropic-admin-connector';
|
|
32
|
+
}
|
|
33
|
+
get description() {
|
|
34
|
+
return 'Anthropic Admin API Connector';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.AnthropicAdminConnector = AnthropicAdminConnector;
|
|
38
|
+
integration_base_1.ConnectionManager.registerConnector('anthropic-admin-connector', new AnthropicAdminConnector());
|
|
39
|
+
//# sourceMappingURL=anthropic-admin-connector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-admin-connector.js","sourceRoot":"","sources":["../../../server/engine/connector/anthropic-admin-connector.ts"],"names":[],"mappings":";;;AAAA,uEAA+E;AAE/E,qEAA+D;AAE/D;;;GAGG;AACH,MAAa,uBAAuB;IAClC,KAAK,CAAC,KAAK,CAAC,iBAAiB;QAC3B,MAAM,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjE,oCAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAA;IAClF,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,UAAU;QACtB,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,UAAU,CAAA;QACvC,oCAAiB,CAAC,qBAAqB,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,IAAI,6CAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAA;QACrH,oCAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,wCAAwC,UAAU,CAAC,IAAI,gBAAgB,CAAC,CAAA;IACxG,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,UAAU;QACzB,oCAAiB,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAA;QACtD,oCAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,wCAAwC,UAAU,CAAC,IAAI,mBAAmB,CAAC,CAAA;IAC3G,CAAC;IAED,IAAI,aAAa;QACf,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7F,CAAC;IAED,IAAI,YAAY;QACd,OAAO,CAAC,WAAW,CAAC,CAAA;IACtB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,iDAAiD,CAAA;IAC1D,CAAC;IAED,IAAI,WAAW;QACb,OAAO,+BAA+B,CAAA;IACxC,CAAC;CACF;AAhCD,0DAgCC;AAED,oCAAiB,CAAC,iBAAiB,CAAC,2BAA2B,EAAE,IAAI,uBAAuB,EAAE,CAAC,CAAA","sourcesContent":["import { ConnectionManager, Connector } from '@things-factory/integration-base'\n\nimport { AnthropicAdminClient } from './anthropic-admin-client'\n\n/**\n * Anthropic Admin API connector (ADR-0177 개정 3) - one connection an organization, its Admin API key a secret. The\n * connection's endpoint is the API origin; empty is https://api.anthropic.com.\n */\nexport class AnthropicAdminConnector implements Connector {\n async ready(connectionConfigs) {\n await Promise.all(connectionConfigs.map(this.connect.bind(this)))\n ConnectionManager.logger.info('anthropic-admin-connector connections are ready')\n }\n\n async connect(connection) {\n const { endpoint, params } = connection\n ConnectionManager.addConnectionInstance(connection, { client: new AnthropicAdminClient(params?.adminKey, endpoint) })\n ConnectionManager.logger.info(`anthropic-admin-connector connection(${connection.name}) is connected`)\n }\n\n async disconnect(connection) {\n ConnectionManager.removeConnectionInstance(connection)\n ConnectionManager.logger.info(`anthropic-admin-connector connection(${connection.name}) is disconnected`)\n }\n\n get parameterSpec() {\n return [{ type: 'secret', name: 'adminKey', label: 'admin-key', useDomainAttribute: true }]\n }\n\n get taskPrefixes() {\n return ['anthropic']\n }\n\n get help() {\n return 'integration/connector/anthropic-admin-connector'\n }\n\n get description() {\n return 'Anthropic Admin API Connector'\n }\n}\n\nConnectionManager.registerConnector('anthropic-admin-connector', new AnthropicAdminConnector())\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './anthropic-admin-connector';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/engine/connector/index.ts"],"names":[],"mappings":";;AAAA,uCAAoC","sourcesContent":["import './anthropic-admin-connector'\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/engine/index.ts"],"names":[],"mappings":";;AAAA,uBAAoB;AACpB,kBAAe","sourcesContent":["import './connector'\nimport './task'\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CostResult } from '../connector/anthropic-admin-client';
|
|
2
|
+
export interface MonthCosts {
|
|
3
|
+
month: string;
|
|
4
|
+
lines: {
|
|
5
|
+
label: string;
|
|
6
|
+
amount: number;
|
|
7
|
+
}[];
|
|
8
|
+
}
|
|
9
|
+
/** The day buckets summed by month and by model, in dollars to the cent. */
|
|
10
|
+
export declare function costsByMonth(buckets: {
|
|
11
|
+
starting_at: string;
|
|
12
|
+
results: CostResult[];
|
|
13
|
+
}[]): MonthCosts[];
|
|
14
|
+
/** The closed months to read: the `months` before the one `today` is in. */
|
|
15
|
+
export declare function windowOf(today: Date, months: number): {
|
|
16
|
+
startingAt: string;
|
|
17
|
+
endingAt: string;
|
|
18
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.costsByMonth = costsByMonth;
|
|
4
|
+
exports.windowOf = windowOf;
|
|
5
|
+
const integration_base_1 = require("@things-factory/integration-base");
|
|
6
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
7
|
+
/** The day buckets summed by month and by model, in dollars to the cent. */
|
|
8
|
+
function costsByMonth(buckets) {
|
|
9
|
+
const months = new Map();
|
|
10
|
+
for (const bucket of buckets) {
|
|
11
|
+
const month = String(bucket.starting_at).slice(0, 7);
|
|
12
|
+
const lines = months.get(month) ?? new Map();
|
|
13
|
+
for (const one of bucket.results ?? []) {
|
|
14
|
+
const label = one.model || one.description || one.cost_type || 'usage';
|
|
15
|
+
lines.set(label, (lines.get(label) ?? 0) + Number(one.amount || 0));
|
|
16
|
+
}
|
|
17
|
+
months.set(month, lines);
|
|
18
|
+
}
|
|
19
|
+
return [...months.entries()]
|
|
20
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
21
|
+
.map(([month, lines]) => ({
|
|
22
|
+
month,
|
|
23
|
+
lines: [...lines.entries()]
|
|
24
|
+
.map(([label, cents]) => ({ label, amount: Math.round(cents) / 100 }))
|
|
25
|
+
.filter(line => line.amount)
|
|
26
|
+
.sort((a, b) => b.amount - a.amount)
|
|
27
|
+
}))
|
|
28
|
+
.filter(one => one.lines.length);
|
|
29
|
+
}
|
|
30
|
+
/** The closed months to read: the `months` before the one `today` is in. */
|
|
31
|
+
function windowOf(today, months) {
|
|
32
|
+
const start = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth() - months, 1));
|
|
33
|
+
const end = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), 1));
|
|
34
|
+
const iso = (day) => `${day.getUTCFullYear()}-${pad(day.getUTCMonth() + 1)}-01T00:00:00Z`;
|
|
35
|
+
return { startingAt: iso(start), endingAt: iso(end) };
|
|
36
|
+
}
|
|
37
|
+
async function AnthropicCostReport(step, context) {
|
|
38
|
+
const { connection: connectionName, params } = step;
|
|
39
|
+
const { domain } = context;
|
|
40
|
+
const instance = await integration_base_1.ConnectionManager.getConnectionInstanceByName(domain, connectionName);
|
|
41
|
+
const client = instance?.client;
|
|
42
|
+
if (!client)
|
|
43
|
+
throw new Error(`no connection '${connectionName}'`);
|
|
44
|
+
const months = Math.min(Math.max(Number(params?.months) || 3, 1), 12);
|
|
45
|
+
const { startingAt, endingAt } = windowOf(new Date(), months);
|
|
46
|
+
const organization = await client.organization();
|
|
47
|
+
return {
|
|
48
|
+
data: { vendorAccount: organization.id, vendorName: organization.name, currency: 'USD', months: costsByMonth(await client.costs(startingAt, endingAt)) }
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
AnthropicCostReport.parameterSpec = [{ type: 'number', name: 'months', label: 'months', placeholder: '3 (1-12)' }];
|
|
52
|
+
AnthropicCostReport.help = 'integration/task/anthropic-cost-report';
|
|
53
|
+
integration_base_1.TaskRegistry.registerTaskHandler('anthropic-cost-report', AnthropicCostReport);
|
|
54
|
+
//# sourceMappingURL=anthropic-cost-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-cost-report.js","sourceRoot":"","sources":["../../../server/engine/task/anthropic-cost-report.ts"],"names":[],"mappings":"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","sourcesContent":["import { ConnectionManager, TaskRegistry } from '@things-factory/integration-base'\n\nimport type { AnthropicAdminClient, CostResult } from '../connector/anthropic-admin-client'\n\n/*\n * What an organization's API usage cost, month by month (ADR-0177 개정 3): the closed months before this one, a line a\n * model (or a description when no model - web search, code execution). The cost report gives US cents as decimal\n * strings, day by day; the months here are in dollars. A scenario hands them to whoever keeps bills (saas `syncSaasCosts`).\n */\n\nexport interface MonthCosts {\n month: string\n lines: { label: string; amount: number }[]\n}\n\nconst pad = (n: number) => String(n).padStart(2, '0')\n\n/** The day buckets summed by month and by model, in dollars to the cent. */\nexport function costsByMonth(buckets: { starting_at: string; results: CostResult[] }[]): MonthCosts[] {\n const months = new Map<string, Map<string, number>>()\n for (const bucket of buckets) {\n const month = String(bucket.starting_at).slice(0, 7)\n const lines = months.get(month) ?? new Map<string, number>()\n for (const one of bucket.results ?? []) {\n const label = one.model || one.description || one.cost_type || 'usage'\n lines.set(label, (lines.get(label) ?? 0) + Number(one.amount || 0))\n }\n months.set(month, lines)\n }\n return [...months.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([month, lines]) => ({\n month,\n lines: [...lines.entries()]\n .map(([label, cents]) => ({ label, amount: Math.round(cents) / 100 }))\n .filter(line => line.amount)\n .sort((a, b) => b.amount - a.amount)\n }))\n .filter(one => one.lines.length)\n}\n\n/** The closed months to read: the `months` before the one `today` is in. */\nexport function windowOf(today: Date, months: number): { startingAt: string; endingAt: string } {\n const start = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth() - months, 1))\n const end = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), 1))\n const iso = (day: Date) => `${day.getUTCFullYear()}-${pad(day.getUTCMonth() + 1)}-01T00:00:00Z`\n return { startingAt: iso(start), endingAt: iso(end) }\n}\n\nasync function AnthropicCostReport(step, context) {\n const { connection: connectionName, params } = step\n const { domain } = context\n const instance = await ConnectionManager.getConnectionInstanceByName(domain, connectionName)\n const client: AnthropicAdminClient | undefined = instance?.client\n if (!client) throw new Error(`no connection '${connectionName}'`)\n const months = Math.min(Math.max(Number(params?.months) || 3, 1), 12)\n const { startingAt, endingAt } = windowOf(new Date(), months)\n const organization = await client.organization()\n return {\n data: { vendorAccount: organization.id, vendorName: organization.name, currency: 'USD', months: costsByMonth(await client.costs(startingAt, endingAt)) }\n }\n}\n\nAnthropicCostReport.parameterSpec = [{ type: 'number', name: 'months', label: 'months', placeholder: '3 (1-12)' }]\nAnthropicCostReport.help = 'integration/task/anthropic-cost-report'\n\nTaskRegistry.registerTaskHandler('anthropic-cost-report', AnthropicCostReport)\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './anthropic-cost-report';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/engine/task/index.ts"],"names":[],"mappings":";;AAAA,mCAAgC","sourcesContent":["import './anthropic-cost-report'\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.costsByMonth = exports.AnthropicAdminClient = void 0;
|
|
4
|
+
require("./engine");
|
|
5
|
+
var anthropic_admin_client_1 = require("./engine/connector/anthropic-admin-client");
|
|
6
|
+
Object.defineProperty(exports, "AnthropicAdminClient", { enumerable: true, get: function () { return anthropic_admin_client_1.AnthropicAdminClient; } });
|
|
7
|
+
var anthropic_cost_report_1 = require("./engine/task/anthropic-cost-report");
|
|
8
|
+
Object.defineProperty(exports, "costsByMonth", { enumerable: true, get: function () { return anthropic_cost_report_1.costsByMonth; } });
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;AAAA,oBAAiB;AAEjB,oFAAgF;AAAvE,8HAAA,oBAAoB,OAAA;AAC7B,6EAAkE;AAAzD,qHAAA,YAAY,OAAA","sourcesContent":["import './engine'\n\nexport { AnthropicAdminClient } from './engine/connector/anthropic-admin-client'\nexport { costsByMonth } from './engine/task/anthropic-cost-report'\n"]}
|